对于 postgresql,java sql 准备好的语句不能正确转义
Posted
技术标签:
【中文标题】对于 postgresql,java sql 准备好的语句不能正确转义【英文标题】:java sql prepared statement doesn't escape correctly for postgresql 【发布时间】:2021-06-23 01:41:09 【问题描述】:我在 Java 中使用 PreparedStatement 为 postgresql 创建 sql 命令,但是所有占位符都用单引号转义,这与使用双引号的 postgresql 要求不同。
下面是日志和错误消息
2021-06-22 18:33:08,157 INFO [ai.tus.map.fea.per.uti.MapperHelper] (executor-thread-199) Insert prepared statement: wrapped[ insert into "known_fruits" (?) VALUES (?) ]
2021-06-22 18:33:08,158 INFO [ai.tus.map.fea.per.uti.MapperHelper] (executor-thread-199) Insert statement: wrapped[ insert into "known_fruits" ('name') VALUES ('ddf') ]
2021-06-22 18:33:08,159 ERROR [ai.tus.map.fea.FruitResource] (executor-thread-199) Failed to handle request: org.postgresql.util.PSQLException: ERROR: syntax error at or near "$1"
Position: 29
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2553)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2285)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:323)
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:481)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:401)
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:164)
at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:130)
at io.agroal.pool.wrapper.PreparedStatementWrapper.executeUpdate(PreparedStatementWrapper.java:88)
对应的代码是:
LOGGER.info("Insert prepared statement: " + stmt.toString());
for (int i = 1; i <= fieldNum; ++i)
stmt.setString(i, existFields.get(i - 1).name);
stmt.setObject(i + fieldNum, existFiledVals.get(i - 1));
LOGGER.info("Insert statement: " + stmt.toString());
编辑:
我要构建的 sql 字符串:
insert into "known_fruits" ("name") VALUES ("ddf")
我用占位符放入 PreparedStatement 的 sql 字符串是:
insert into "known_fruits" (?) VALUES (?)
我得到的最后一个 sql 字符串是:
insert into "known_fruits" ('name') VALUES ('ddf')
正如@Andreas 指出的那样,我不应该将?
用于表名或列名,它们仅用于值注入。所以我的问题是有什么方法可以安全地使 sql 处理转义表名或列名?由于这些值是运行时确定的,所以不知道是否会有一些与sql关键字相同的表名需要转义。
【问题讨论】:
您不能使用?
参数标记来注入标识符,例如表名和列名。您只能注入 值。您必须使用字符串连接来插入列名,然后使用?
来处理值。
请edit您的问题并向我们展示您正在构建的完整 SQL 字符串。
@Andreas 有没有让 sql 安全地注入表名或列名?因为这些仍然是运行时值,所以我不知道是否需要转义它们
values ("ddf")
开头是错误的,因为"ddf"
指的是列名。它不是 SQL 字符串常量
表名和列名是否来自可信来源?如果是,例如代码中其他地方的硬编码列表,那么您不需要转义。如果没有,例如它们是 CSV 文件中的标题名称,那么您绝对需要验证或转义这些名称。 --- 如果您希望名称不被引用(推荐),那么您应该简单地验证名称仅包含有效字符,这基本上意味着匹配正则表达式\w+
。
【参考方案1】:
你不能为列名使用参数,比如在
insert into "known_fruits" (?) VALUES (?)
您必须构造一个查询字符串,其中包含作为文字的列名。
【讨论】:
OP 从未编写过$1
,JDBC 驱动程序 将?
替换为$1
。
@Andreas 啊,我明白了,是的。我已经确定了答案。以上是关于对于 postgresql,java sql 准备好的语句不能正确转义的主要内容,如果未能解决你的问题,请参考以下文章