Postgresql 将null绑定到准备好的语句时出现Postgres bytea错误

Postgresql 将null绑定到准备好的语句时出现Postgres bytea错误,postgresql,jpa,jdbc,prepared-statement,Postgresql,Jpa,Jdbc,Prepared Statement,我正在使用一个使用JPA和Postgres数据库的Java应用程序,我正在尝试创建一个灵活的prepared语句,它可以处理数量可变的输入参数。一个示例查询可以最好地解释这一点: SELECT * FROM my_table WHERE (string_col = :param1 OR :param1 IS NULL) AND (double_col = :param2 OR :param2 IS NULL); 这个“技巧”背后的思想是,如果用户只指定一个参数,比如说:para

我正在使用一个使用JPA和Postgres数据库的Java应用程序,我正在尝试创建一个灵活的prepared语句,它可以处理数量可变的输入参数。一个示例查询可以最好地解释这一点:

SELECT *
FROM my_table
WHERE
    (string_col = :param1 OR :param1 IS NULL) AND
    (double_col = :param2 OR :param2 IS NULL);
这个“技巧”背后的思想是,如果用户只指定一个参数,比如说
:param1
,我们可以将
null
绑定到
:param2
,然后
WHERE
子句的行为就好像只检查了第一个参数一样。理论上,这种方法允许我们使用一条准备好的语句处理任意数量的输入参数,而不需要维护许多不同的语句

我得到了一个简单的POC,它使用纯JDBC编写的语句在本地工作。但是,这样做需要在将参数与
NULL
进行比较之前强制转换参数,例如:

WHERE (double_col = ? OR ?::numeric IS NULL)
                         ^^ does not work without cast
然而,我的实际应用程序正在使用JPA,并且我不断得到以下持久性错误:

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.
字符串/文本列不会出现问题,但仅在my Postgres表中的双精度列出现问题。我尝试了所有的铸造组合,但没有任何效果:

(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);
这个错误似乎是说JDBC向Postgres发送了一个双列的
bytea
类型,然后Postgres开始滚动,因为它找不到将
byte
转换为双精度的方法

Java代码如下所示:

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

在没有收到任何反馈的情况下,我准备放弃,但我无意中发现了这篇优秀的博文:

post提供了两个选项来控制JPA通过驱动程序传递给Postgres的类型(或者底层数据库的实际类型)。我使用了
TypedParameterValue
的方法。下面是我的代码,继续上面给出的示例:

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();
Query Query=entityManager.createNativeQuery(sqlString,MyEntity.class);
setParameter(“param1”,新的TypedParameterValue(StringType.INSTANCE,null));
setParameter(“param2”,新的TypedParameterValue(DoubleType.INSTANCE,null));
List=query.getResultList();

当然,为查询中的每个参数传递
null
并不重要,但我这样做主要是为了显示文本和双列的语法。实际上,我们希望至少有一部分参数是非空的,但上面的语法处理所有值,空值或其他值。

由于没有收到任何回答或评论形式的反馈,当我无意中发现这篇优秀的博文时,我正准备放弃:

post提供了两个选项来控制JPA通过驱动程序传递给Postgres的类型(或者底层数据库的实际类型)。我使用了
TypedParameterValue
的方法。下面是我的代码,继续上面给出的示例:

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();
Query Query=entityManager.createNativeQuery(sqlString,MyEntity.class);
setParameter(“param1”,新的TypedParameterValue(StringType.INSTANCE,null));
setParameter(“param2”,新的TypedParameterValue(DoubleType.INSTANCE,null));
List=query.getResultList();

当然,为查询中的每个参数传递
null
并不重要,但我这样做主要是为了显示文本和双列的语法。实际上,我们希望至少有一些参数是非空的,但上面的语法处理所有值,空值或其他值。

如果您想继续使用带有自动参数绑定的普通查询,可以尝试以下方法

WHERE (? IS NULL OR (CAST(CAST(? AS TEXT) AS DOUBLE PRECISION) = double_col

这似乎满足了PostgreSQL驱动程序的类型检查,并产生了正确的结果。我没有做太多的测试,但是性能影响似乎很小,因为
转换发生在一个常量值上,而不是数据库中的行上。

如果您想继续使用带有自动参数绑定的普通查询,可以尝试以下方法

WHERE (? IS NULL OR (CAST(CAST(? AS TEXT) AS DOUBLE PRECISION) = double_col
这似乎满足了PostgreSQL驱动程序的类型检查,并产生了正确的结果。我没有做太多的测试,但是性能的影响似乎很小,因为
CAST
s发生在一个常量值上,而不是数据库中的行上