PostGIS使用ST_MakeEnvelope()时相似INSERT查询仅单个生效的原因排查
为何结构相似的两条插入查询,仅一条可正常执行
我需要创建BBOX多边形存入graphs表的bbox几何列,但目前只有硬编码坐标的写法能跑通,这类写法无法替换为自定义动态数值,不支持批量写入。
可正常执行的查询
res <- DBI::dbExecute(con, "INSERT INTO graphs ( left_xmin, bottom_ymin, right_xmax, top_ymax, filename, BBOX_Diagonale, file, bbox) VALUES ($1,$2, $3, $4,$5, $6,$7,ST_GeomFromText(ST_AsText(ST_MakeEnvelope(11.29589921, 47.5205857, 12.21999367, 48.14282422, 4326) )));", list(round(bbox_dimensions[[1]],digits=8), round(bbox_dimensions[[2]],digits=8), round(bbox_dimensions[[3]],digits=8), round(bbox_dimensions[[4]],digits=8), filename_save, bbox_diagonale, paste0( "\\x",paste(data, collapse = ""))))
执行报错的查询
res <- DBI::dbExecute(con, "INSERT INTO graphs ( left_xmin, bottom_ymin, right_xmax, top_ymax, filename, BBOX_Diagonale, file, bbox) VALUES ($1,$2, $3, $4,$5, $6,$7,$8);", list(round(bbox_dimensions[[1]],digits=8), round(bbox_dimensions[[2]],digits=8), round(bbox_dimensions[[3]],digits=8), round(bbox_dimensions[[4]],digits=8), filename_save, bbox_diagonale, paste0( "\\x",paste(data, collapse = "")), paste0("ST_GeomFromText(ST_AsText(ST_MakeEnvelope(11.29589921, 47.5205857, 12.21999367, 48.14282422, 4326) )))"))
想要实现把ST_MakeEnvelope里硬编码的固定坐标,替换为动态传入的bbox对象值,最初打算通过R的paste0把几何生成逻辑拼接成字符串当参数传入,实际执行抛出以下错误:
Error: Failed to fetch row: ERROR: parse error - invalid geometry HINT: "ST" <-- parse error at position 2 within geometry
几何列定义
bbox列是通过标准PostGIS语句创建的,完全符合POLYGON类型的写入规范:
SELECT AddGeometryColumn('graphs', 'bbox', 4326, 'POLYGON', 2 );
按照PostGIS的逻辑,ST_MakeEnvelope的输出完全匹配几何列的类型要求,本应正常写入。现在需要明确两个问题:
- 两条结构相似的查询为何执行结果差异巨大?
- 动态传入bbox坐标值的正确实现方式是什么?
问题根源
参数绑定的执行逻辑和预期存在本质差异:
- 写在SQL语句字符串内的
ST_GeomFromText(...)属于SQL语法,会被数据库服务端解析为函数调用,走PostGIS内置的几何生成流程。 - 通过
$8参数传入的字符串"ST_GeomFromText(ST_AsText(ST_MakeEnvelope(...)))",会被数据库识别为纯文本值,直接传入几何列时,数据库会按照*WKT(熟知文本)*格式尝试解析这个字符串。由于该字符串开头为ST,不符合WKT的格式规范(合法WKT格式如POLYGON((x1 y1, x2 y2...))),因此抛出解析错误,提示在位置2识别到无效字符ST。
动态写入的正确实现
完全不需要在R侧拼接SQL函数字符串,直接将坐标值作为参数,传入SQL内定义的ST_MakeEnvelope函数即可:
res <- DBI::dbExecute(con, "INSERT INTO graphs ( left_xmin, bottom_ymin, right_xmax, top_ymax, filename, BBOX_Diagonale, file, bbox) VALUES ($1,$2, $3, $4,$5, $6,$7, ST_MakeEnvelope($1, $2, $3, $4, 4326));", list(round(bbox_dimensions[[1]],digits=8), round(bbox_dimensions[[2]],digits=8), round(bbox_dimensions[[3]],digits=8), round(bbox_dimensions[[4]],digits=8), filename_save, bbox_diagonale, paste0( "\\x",paste(data, collapse = ""))))
实现时可注意两个优化点:
ST_MakeEnvelope的返回值本身就是符合要求的POLYGON几何对象,无需嵌套ST_GeomFromText(ST_AsText(...))这类绕路的格式转换,直接写入列即可,性能更好也不会引入格式转换风险。- 坐标值可直接复用前面已经绑定的
$1-$4参数,无需单独为几何函数传值,减少参数冗余。如果需要动态传入SRID值,只要在函数参数位置新增占位符,将SRID作为参数传入即可,全程符合参数绑定的安全规范,不会引入SQL注入风险。
内容的提问来源于stack exchange,提问作者Andreas
相关产品推荐
相关产品推荐

