mohamnag mohamnag - 6 months ago 15
Java Question

JDBC Prepared statement parameter inside json

I have a table which has a data column with an structure similar to following:

{"title": "some title", "objects": [{"id": "id1"}, {"id": "id2"}]}


now I want to find all rows that have an object with specific id in their objects array inside data. Following query works perfectly from PSQL console:

SELECT id, data FROM table_name WHERE data->'objects' @> '[{"id": "id1"}]'


however I can not get this to work as a prepared statement over JDBC driver. the value for id should be a parameter, so I tried this as the string that is passed to
connection.prepareStatement(query);
:

"SELECT id, data FROM table_name WHERE data->'objects' @> '[{\"id\": ?}]'"


here when I try to set arguments I get this exception:

org.postgresql.util.PSQLException: The column index is out of range: 1, number of columns: 0.


when I try any of the following the argument is set correctly:

"SELECT id, data FROM table_name WHERE data->'objects' @> [{\"id\": ?}]"
"SELECT id, data FROM table_name WHERE data->'objects' @> [{'id': ?}]"


but the result is obviously not a properly formatted query:

SELECT id, data FROM table_name WHERE data->'objects' @> [{"id": 'id1'}]
SELECT id, data FROM table_name WHERE data->'objects' @> [{'id': 'id1'}]


in both cases I get following exception:

org.postgresql.util.PSQLException: ERROR: syntax error at or near "["


What is the correct syntax to set a parameter inside JSON?
I'm using PostgreSql 9.5

Answer

I actually reached out to JDBC developers over at Github and after some discussions it seems that currently the best solution is to have the prepared statement as follows:

String query = "SELECT id, data FROM table_name WHERE data->'objects' @> ?::jsonb";

and pass the whole search criteria as stringified JSON object for the parameter:

PreparedStatement st = connection.prepareStatement(query);
st.setString(1, "[\"id\":" + "id1" + "]");
st.executeQuery();

thats not a perfect solution but seems the best possible due to lack of server capabilities. At the end its not so bad as there is (theoretically) no risk of SQL injection.

More details on the linked Github issue.

Comments