如何通过JDBC使用包含问号“?”的PostgreSQL JSON(B)运算符

PostgreSQL知道一些在其名称中使用问号字符的时髦ASCII艺术运算符,例如这些JSON运算符 :

  • ? 字符串是否作为JSON值中的顶级键存在?
  • ?| 这些数组字符串中是否存在顶级键?
  • ?&所有这些数组字符串都作为顶级键存在吗?

问题是官方PostgreSQL JDBC驱动程序似乎无法正确解析包含此类运算符的SQL字符串。 它假定问号是普通的JDBC绑定变量。 以下代码……

 try (PreparedStatement s = c.prepareStatement("select '{}'::jsonb ?| array['a', 'b']"); ResultSet rs = s.executeQuery()) { ... } 

…引发exception:

 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()) { ... }