PostgreSQL knows a couple of funky ASCII-art operators that use the question mark character in their names, for instance these JSON operators:
?
does the string exist as a top-level key within the JSON value??|
Do any of these array strings exist as top-level keys??&
Do all of these array strings exist as top-level keys?The problem is that the official PostgreSQL JDBC driver does not seem to correctly parse SQL strings containing such operators. It assumes that the question mark is an ordinary JDBC bind variable. The following code...
try (PreparedStatement s = c.prepareStatement("select '{}'::jsonb ?| array['a', 'b']");
ResultSet rs = s.executeQuery()) {
...
}
... throws an 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)
How can I use this operator?
Querying the JSON documentPostgreSQL has two native operators -> and ->> to query JSON documents. The first operator -> returns a JSON object, while the operator ->> returns text. These operators work on both JSON as well as JSONB columns. There are additional operators available for JSONB columns.
You can save any valid json value to either json or to a jsonb column. But you cannot bind it as string/ text / varchar , if you use prepared statements (use casts instead in sql, like UPDATE ... SET json_col = $1::json or bind it as unknown ).
PostgreSQL offers two types for storing JSON data: json and jsonb . To implement efficient query mechanisms for these data types, PostgreSQL also provides the jsonpath data type described in Section 8.14. 7. The json and jsonb data types accept almost identical sets of values as input.
There are two possible workarounds:
This is the simplest workaround, but you lose all the benefits from prepared statements (performance, SQL injection protection, etc.). However, this will work
try (Statement s = c.createStatement();
ResultSet rs = s.executeQuery("select '{}'::jsonb ?| array['a', 'b']")) {
...
}
Operators are just syntax sugar for a backing function that exists in the pg_catalog
. Here's how to find the name of these functions:
SELECT
oprname,
oprcode || '(' || format_type(oprleft, NULL::integer) || ', '
|| format_type(oprright, NULL::integer) || ')' AS function
FROM pg_operator
WHERE oprname = '?|';
The above yields:
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[])
So, the simplest workaround is to just not use the operator, but the corresponding function instead:
try (PreparedStatement s = c.prepareStatement(
"select jsonb_exists_any('{}'::jsonb, array['a', 'b']");
ResultSet rs = s.executeQuery()) {
...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With