PostgreSQL 知道一些时髦的 ASCII 艺术运算符,它们在名称中使用问号字符,例如 这些 JSON 运算符:
?
字符串是否作为 JSON 值中的顶级键存在??|
这些数组字符串中的任何一个是否作为顶级键存在??&
所有这些数组字符串都作为顶级键存在吗?问题是官方的 PostgreSQL JDBC 驱动似乎不能正确解析包含此类运算符的 SQL 字符串。它假设问号是一个普通的 JDBC 绑定变量。下面的代码...
try (PreparedStatement s = c.prepareStatement("select '{}'::jsonb ?| array['a', 'b']");
ResultSet rs = s.executeQuery()) {
...
}
...抛出异常:
org.postgresql.util.PSQLException: Für den Parameter 1 wurde kein Wert angegeben.
at org.postgresql.core.v3.SimpleParameterList.checkAllParametersSet(SimpleParameterList.java:225)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:190)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:424)
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:161)
at org.postgresql.jdbc.PgPreparedStatement.executeQuery(PgPreparedStatement.java:114)
如何使用这个运算符?
有两种可能的解决方法:
这是最简单的解决方法,但是您失去了准备好的语句的所有好处(性能、SQL 注入保护等)。但是,这会起作用
try (Statement s = c.createStatement();
ResultSet rs = s.executeQuery("select '{}'::jsonb ?| array['a', 'b']")) {
...
}
运算符只是
pg_catalog
中存在的支持函数的语法糖。以下是查找这些函数名称的方法:
SELECT
oprname,
oprcode || '(' || format_type(oprleft, NULL::integer) || ', '
|| format_type(oprright, NULL::integer) || ')' AS function
FROM pg_operator
WHERE oprname = '?|';
以上产量:
oprname function
----------------------------------------------------------------------------------
?| point_vert(point, point)
?| lseg_vertical(-, lseg)
?| line_vertical(-, line)
?| jsonb_exists_any(jsonb, text[]) <--- this is the one we're looking for
?| exists_any(hstore, text[])
所以,最简单的解决方法就是不使用运算符,而是使用相应的函数:
try (PreparedStatement s = c.prepareStatement(
"select jsonb_exists_any('{}'::jsonb, array['a', 'b']");
ResultSet rs = s.executeQuery()) {
...
}
JDBC 文档 描述了如何使用包含问号的运算符:
在JDBC中,问号(
)是一个?
的位置参数的占位符。但是,有许多 PostgreSQL® 运算符包含问号。为了防止 SQL 语句中的此类问号被解释为位置参数,请使用两个问号 (PreparedStatement
) 作为转义序列。您也可以在??
中使用此转义序列,但这不是必需的。Statement