【问题标题】:PreparedStatement: Missing expression on single quote (ORA-00936)PreparedStatement:单引号上缺少表达式 (ORA-00936)
【发布时间】:2019-03-09 03:02:52
【问题描述】:

我正在像这样查询一个 Oracle 数据库:

try (Connection c = dataSource.getConnection();
    PreparedStatement p = c.prepareStatement(
        "SELECT * FROM table WHERE column_string = ?")) {
    p.setString(1, input);

    try (ResultSet r = p.executeQuery()) {
        // handle ResultSet
    }
}

并且从用户那里收到input 字符串。此调用适用于普通输入字符串,例如:

hello world
special: characters 0_2 (ftlo) -

但是对于这样的输入字符串失败:

7-8 l/o y-S '

(注意最后的破折号、正斜杠和单引号)

我以为它与单引号有关,但我的印象是 PreparedStatement 会为您处理所有转义。有没有人看到过这样的问题,或者对 oracle JDBC 驱动程序中的字符转义有更多了解?

我正在使用:

  • Java:1.8.0_181
  • Jboss:EAP 6.4.7.GA
  • JDBC:ojdbc6 版本 11.2.0.3.0
  • 数据库:Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

堆栈跟踪:

SQLSyntaxErrorException: ORA-00936: missing expression
oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:445)
oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396)
oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:879)
oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:450)
oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:192)
oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531)
oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:207)
oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:884)
oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1167)
oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1289)
oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3584)
oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3628)
oracle.jdbc.driver.OraclePreparedStatementWrapper.executeQuery(OraclePreparedStatementWrapper.java:1493)
org.jboss.jca.adapters.jdbc.WrappedPreparedStatement.executeQuery(WrappedPreparedStatement.java:462)
... <my classes>

【问题讨论】:

  • 编译错误:1) The method openConnection() is undefined for the type DataSource 2) The method setString(int, String) in the type PreparedStatement is not applicable for the arguments (String)

标签: java oracle jdbc prepared-statement ojdbc


【解决方案1】:

事实证明,我收到的错误代码与我想象的不同。在主查询完成后,我的 ResultSetHandler 正在执行一些额外的清理逻辑,这就是抛出 SQLException(缺少表达式)。由于 apache DButils 和 JDBC 库的实现,错误被吞并并没有以有用的方式打印出来。很抱歉造成混乱。

【讨论】:

    【解决方案2】:

    可能是单引号引起的问题,因为在 Oracle 中,最后一个必须重复两次才能输入为单引号或整个字符串必须包含在 q'{...}' 构造中,其中 ... 是给定的字符串。

    【讨论】:

    • 通常由 1PreparedStatement.setString()` 处理。至少这是PreparedStatement的目的之一
    【解决方案3】:

    无法重现。从here 添加文件ojdbc6-11.2.0.3.jar

    针对 12.1.0.2 服务器运行MCVE 代码getConnection 的值当然已被屏蔽)

    public static void main(String[] args) throws Exception {
        test("hello world");
        test("special: characters 0_2 (ftlo) -");
        test("7-8 l/o y-S '");
        test("X");
    }
    private static void test(String input) throws SQLException {
        System.out.println(input);
        try (Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@XXX:1521:XXX", "XXX", "XXX")) {
            String sql = "select DUMMY from DUAL where DUMMY = ?";
            try (PreparedStatement stmt = conn.prepareStatement(sql)) {
                stmt.setString(1, input);
                try (ResultSet rs = stmt.executeQuery()) {
                    int count = 0;
                    while (rs.next()) {
                        System.out.println("  " + rs.getString("DUMMY"));
                        count++;
                    }
                    System.out.println("  " + count + " rows");
                }
            }
        }
    }
    

    输出

    hello world
      0 rows
    special: characters 0_2 (ftlo) -
      0 rows
    7-8 l/o y-S '
      0 rows
    X
      X
      1 rows
    

    【讨论】:

    • 不过,我并不认为这是一个有效的测试,因为 SELECT 语句似乎为任何不是“X”的字符串返回 0 行。
    • @JeffBrower 查询是否实际返回数据并不重要。问题中的错误是 SQL Syntax 错误,这意味着它是 解析 SQL 语句的问题,而不是执行它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-18
    • 2017-08-31
    • 1970-01-01
    相关资源
    最近更新 更多