如果SQL:parameter在DB2 JDBC中为'ALL',如何匹配所有行?

nkhmeac6  于 2022-11-07  发布在  DB2
关注(0)|答案(1)|浏览(199)

这只是一个重现错误的示例代码

SELECT *
FROM ( VALUES (10,'A'),(20,'B'),(30,'C'),(40,'D') ) AS T(COL1,COL2)
WHERE T.COL2 = :PARAM OR :PARAM = 'ALL'

如果将'A'赋给PARAM参数,则上述语句应返回第一行;如果将'B'赋给PARAM,则上述语句应返回第二行,依此类推。否则,如果将'ALL'赋给PARAM,则应返回所有行。

String PARAM = "ALL";

// SQL = SQL.replaceAll(":PARAM", "'" + PARAM + "'"); // Uncomment me

try (Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
        DB2PreparedStatement statement = (DB2PreparedStatement) connection.prepareStatement(SQL)) {

    print(connection.getMetaData());

    statement.setJccStringAtName("PARAM", PARAM); // Comment me
    try (ResultSet resultSet = statement.executeQuery()) {
        print(resultSet);
    }
} catch (SQLException exception) {
    print(exception);
}

令人惊讶的是,它不起作用。
以下是应用程序输出:

Database Product Name: DB2/LINUXX8664
Database Product Version: SQL110551
Database Version: 11.5
Driver Name: IBM Data Server Driver for JDBC and SQLJ
Driver Version: 4.29.24
JDBC Version: 4.1
SQLException information:
Error msg: DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null, DRIVER=4.29.24
SQLSTATE: 22001
Error code: -302
com.ibm.db2.jcc.am.SqlDataException: DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null, DRIVER=4.29.24
    at com.ibm.db2.jcc.am.b7.a(b7.java:802)
    at com.ibm.db2.jcc.am.b7.a(b7.java:66)
    at com.ibm.db2.jcc.am.b7.a(b7.java:140)
    at com.ibm.db2.jcc.am.k9.c(k9.java:2844)
    at com.ibm.db2.jcc.am.k9.a(k9.java:2281)
    at com.ibm.db2.jcc.t4.ab.r(ab.java:1670)
    at com.ibm.db2.jcc.t4.ab.l(ab.java:754)
    at com.ibm.db2.jcc.t4.ab.d(ab.java:110)
    at com.ibm.db2.jcc.t4.p.c(p.java:44)
    at com.ibm.db2.jcc.t4.av.j(av.java:162)
    at com.ibm.db2.jcc.am.k9.an(k9.java:2276)
    at com.ibm.db2.jcc.am.k_.a(k_.java:4699)
    at com.ibm.db2.jcc.am.k_.b(k_.java:4215)
    at com.ibm.db2.jcc.am.k_.a(k_.java:4860)
    at com.ibm.db2.jcc.am.k_.b(k_.java:4215)
    at com.ibm.db2.jcc.am.k_.bd(k_.java:785)
    at com.ibm.db2.jcc.am.k_.executeQuery(k_.java:750)
    at com.ibm.db2.jcc.am.d0.executeQuery(d0.java:297)
    at com.example.App.main(App.java:38)

The JDBC trace file is uploaded here
我将完整的示例项目代码推送到了https://github.com/noureldin-eg/db2-sql-error,并在README中添加了构建和运行它所需的所有步骤。
我知道有很多变通办法(例如,如果参数在java中被替换,它会按预期工作,如注解中所示),但我想了解我在这里遗漏了什么。

更新时间:2021年10月22日下午1:30(UTC)

我发现ParameterMetaData API在调试这个问题时非常有用。

int parameterCount = parameterMetaData.getParameterCount();
System.out.println("Number of statement parameters: " + parameterCount);
for (int i = 1; i <= parameterCount; i++) {
    String sqlType = parameterMetaData.getParameterTypeName(i);
    int precision = parameterMetaData.getPrecision(i);
    System.out.printf("SQL type of parameter %d is %s(%d)%n", i, sqlType, precision);
}

上面的代码显示,我的命名参数在后台被转换为参数标记样式中的2个问号(?)。我已经从跟踪文件中注意到了这一点,但现在很清楚,每个都有自己的类型和长度。

Number of statement parameters: 2
SQL type of parameter 1 is VARCHAR(1)
SQL type of parameter 2 is VARCHAR(3)

这就是为什么如果我的参数的字符长度超过其中任何一个,我会得到SqlDataException。我希望这可以帮助任何面临类似错误的人。

68de4m5k

68de4m5k1#

我会称之为“功能”,而不是“错误”。

CALL ADMIN_CMD ('DESCRIBE SELECT * FROM ( VALUES (10,''A''),(20,''B''),(30,''C''),(40,''D'') ) AS T(COL1,COL2)');

| SQL类型标识|数据库类型|长度|SQL比例|数据库名称|SQL名称长度|SQL数据类型_名称_数据|SQLDATATYPE_NAME_LENGTH(数据类型名称长度)|
| - -|- -|- -|- -|- -|- -|- -|- -|
| 四百九十六|整数|四个|第0页|COL1|四个||第0页|
| 四百四十八|变量字符|一个|第0页|COL 2系统|四个||第0页|
COL2具有VARCHAR(1)数据类型。因此,当您使用WHERE T.COL2 = :PARAM时,编译时不知道参数的数据类型和长度,Db2尝试从上下文派生它-它假定:它的数据类型和长度等于T2.COL2 == VARCHAR(1)的数据类型和长度。但您提供参数值'ALL'数据类型为VARCHAR(3),并在OPEN调用中获取SQLCODE=-302.
对于:PARAM = 'ALL'也是如此。如果您提供了一个长度〈=3的实际参数值,它就可以工作,否则就失败(比如说,在'ALL 1'值上)。
解决方法是明确指定所有参数标记的数据类型和长度。例如,如果要提供长度不超过3个字节的值,则:

WHERE T.COL2 = CAST (:PARAM AS VARCHAR(3)) OR :PARAM = 'ALL'

如果不是,则应使用以下格式,其中x是要提供的参数值的最大长度:

WHERE T.COL2 = CAST (:PARAM AS VARCHAR(x)) OR CAST (:PARAM AS VARCHAR(x)) = 'ALL'

相关问题