将 SQL 参数替换为 ?在单引号( ' ) [重复] 内不起作用

Substitute SQL parameter with ? is not working inside single quote( ' ) [duplicate]

提问人:Sharath K P 提问时间:11/10/2020 更新时间:11/11/2020 访问量:440

问:

我正在尝试使用SqlExecuter运行查询,方法是替换以下SQL单引号内的占位符(?)

SQL: SELECT name, sum(marks) FROM scores WHERE datetime >= now() - interval '?hours' 按名称分组;

我正在尝试替换参数的 Java 代码

Integer hourCount = 72; //String type also did not work
SQL_QUERY = "SELECT name, sum(marks) FROM scores WHERE datetime >= now() - interval '? hours' GROUP BY name;"
Map<String, Integer> scoreCount = new HashMap<>();
SqlExecutor sqlExecutor = new SqlExecutor(dbConfig);
scoreCount = sqlExecutor.executeForResultSet(SQL_QUERY, resultSet -> {
    Map<String, Integer> results = new HashMap<>();
    while (resultSet.next()) {
        results.put(resultSet.getString(1), resultSet.getInt(2));
    }
    return results;
}, hourCount);

我收到上述代码片段的以下异常

09/Nov/2020 20:47:05:271 [ajp-apr-127.0.0.1-8019-exec-5] ERROR  com.xyz.admin.utils.abc getScoreCount  - org.postgresql.util.PSQLException: The column index is out of range: 1, number of columns: 0.
org.postgresql.util.PSQLException: The column index is out of range: 1, number of columns: 0.
        at org.postgresql.core.v3.SimpleParameterList.bind(SimpleParameterList.java:56)
        at org.postgresql.core.v3.SimpleParameterList.setBinaryParameter(SimpleParameterList.java:122)
        at org.postgresql.jdbc2.AbstractJdbc2Statement.bindBytes(AbstractJdbc2Statement.java:2312)
        at org.postgresql.jdbc2.AbstractJdbc2Statement.setInt(AbstractJdbc2Statement.java:1288)
        at org.postgresql.jdbc2.AbstractJdbc2Statement.setObject(AbstractJdbc2Statement.java:1900)
        at org.postgresql.jdbc3g.AbstractJdbc3gStatement.setObject(AbstractJdbc3gStatement.java:36)
        at org.postgresql.jdbc4.AbstractJdbc4Statement.setObject(AbstractJdbc4Statement.java:48)

在在线检查问题时,根据 https://github.com/Microsoft/mssql-jdbc/issues/932, 它建议将单引号内的整个字符串内容作为参数传递,如下所示。还提到,在构造查询时,PreparedStatement 会自动在传递的参数周围添加引号

String hourCount = 72;
sqlExecutor.executeForResultSet("SELECT name, sum(marks) FROM scores WHERE datetime >= now() - interval ? GROUP BY name;", resultSet -> {
    Map<String, Integer> results = new HashMap<>();
    while (resultSet.next()) {
        results.put(resultSet.getString(1), resultSet.getInt(2));
    }
    return results;
}, hourCount + " hours");

这导致了以下错误

09/Nov/2020 21:21:56:594 [ajp-apr-127.0.0.1-8019-exec-2] ERROR  com.xyz.tips.admin.utils.abc getScoreCount  - org.postgresql.util.PSQLException: ERROR: syntax error at or near "$1"
  Position: 84
org.postgresql.util.PSQLException: ERROR: syntax error at or near "$1"
  Position: 84
        at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2270)
        at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1998)
        at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)
        at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:570)
        at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:420)
        at org.postgresql.jdbc2.AbstractJdbc2Statement.executeQuery(AbstractJdbc2Statement.java:305)
        at com.avenda.tips.utils.sql.AbstractJdbcOperations$3.run(AbstractJdbcOperations.java:64)
        at com.avenda.tips.utils.sql.AbstractJdbcOperations$2.run(AbstractJdbcOperations.java:46)
        at com.avenda.tips.utils.sql.SqlExecutor.execute(SqlExecutor.java:32)
        at com.avenda.tips.utils.sql.AbstractJdbcOperations.execute(AbstractJdbcOperations.java:40)
        at com.avenda.tips.utils.sql.AbstractJdbcOperations.executeForResultSet(AbstractJdbcOperations.java:59)

由于以上两种方法都不起作用,因此我使用

SQL_QUERY = "SELECT name, sum(marks) FROM scores WHERE datetime >= now() - interval '? hours' GROUP BY name;"
SQL_QUERY.replace("?", hourCount) 

我能知道我在这里缺少什么,以及如何在查询包含上述单引号时避免 sql 注入吗?

java postgresql jdbc 准备语句 sql 注入

评论

0赞 richyen 11/10/2020
也许尝试使用该功能?postgresql.org/docs/current/functions-datetime.htmlstackoverflow.com/questions/43656783/......make_interval()
0赞 Don Ha 11/10/2020
不能将 bind 变量用于间隔,因为它采用字符串文字。如上所述,将其替换为 make_interval(),以便您可以使用绑定变量。您使用预格式化的方法可能有效,但不建议它可能容易受到 SQL 注入的影响。
0赞 Sharath K P 11/10/2020
make_interval() 将用于避免使用单引号。谢谢!最终 SQL ' SELECT name, sum(marks) FROM scores WHERE datetime >= now() - make_interval(hours => 200) GROUP BY name;`

答:

0赞 Laurenz Albe 11/10/2020 #1

是的,字符串文本中的问号不会被视为参数,也不会被替换。

试试这个:

SQL_QUERY = "SELECT name, sum(marks) FROM scores WHERE datetime >= now() - interval '1 hour' * ? GROUP BY name;"

评论

0赞 Sharath K P 11/10/2020
按预期工作。谢谢!还找到了具有 make 间隔功能的替代解决方案。