Postgres bytea error when binding null to prepared statements

坚强是说给别人听的谎言 提交于 2020-03-03 09:01:59

问题


I am working with a Java application which uses JPA and a Postgres database, and I am trying to create a flexible prepared statement which can handle a variable number of input parameters. An example query would best explain this:

SELECT *
FROM my_table
WHERE
    (string_col = :param1 OR :param1 IS NULL) AND
    (double_col = :param2 OR :param2 IS NULL);

The idea behind this "trick" is that if a user specifies only one parameter, say :param1, we can just bind null to :param2, and the WHERE clause would then behave as if only the first parameter were even being checked. This approach lets us handle, in theory, any number of input parameters using a single prepared statement, instead of needing to maintain many different statements.

I have gotten a simple POC working locally using pure JDBC prepared statements. However, doing so required casting the parameter before comparing it to NULL, e.g.

WHERE (double_col = ? OR ?::numeric IS NULL)
                         ^^ does not work without cast

However, my actual application is using JPA, and I keep getting the following persistent error:

Caused by: org.postgresql.util.PSQLException: ERROR: operator does not exist: double precision = bytea
  Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.

The problem does not occur with string/text columns, but only with columns which are double precision in my Postgres table. I have tried all combinations of casting, and nothing works:

(double_col = :param2 OR CAST(:param2 AS double precision) IS NULL);
(CAST(double_col AS double precision) = :param2 OR :param2 IS NULL);
(CAST(double_col AS double precision) = :param2 OR CAST(:param2 AS double precision) IS NULL);

The error seems to be saying that JDBC is sending Postgres a bytea type for the double columns, and then Postgres is rolling over because it can't find a way to cast byte to double precision.

The Java code looks something like:

Query query = entityManager.createNativeQuery(sqlString, MyEntity.class);
query.setParameter("param1", "some value");
// bind other parameters here
List<MyEntity> = query.getResultList();

For reference, here are the versions of everything I am using:

Hibernate version         | 4.3.7.Final
Spring data JPA vesion    | 1.7.1.RELEASE
Postgres driver version   | 42.2.2
Postgres database version | 9.6.10
Java version              | 1.8.0_171

回答1:


Not having received any feedback in the form of answers or even a comment, I was getting ready to give up, when I stumbled onto this excellent blog post:

How to bind custom Hibernate parameter types to JPA queries

The post gives two options for controlling the types which JPA passes through the driver to Postgres (or whatever the underlying database actually is). I went with the approach using TypedParameterValue. Here is what my code looks like continuing with the example given above:

Query query = entityManager.createNativeQuery(sqlString, MyEntity.class);
query.setParameter("param1", new TypedParameterValue(StringType.INSTANCE, null));
query.setParameter("param2", new TypedParameterValue(DoubleType.INSTANCE, null));
List<MyEntity> = query.getResultList();

Of course, it is trivial to be passing null for every parameter in the query, but I am doing this mainly to show the syntax for the text and double columns. In practice, we would expect at least a few of the parameters to be non null, but the above syntax handles all values, null or otherwise.



来源:https://stackoverflow.com/questions/57865149/postgres-bytea-error-when-binding-null-to-prepared-statements

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!