Postgres:将自定义类型从 Java 传递给 postgres 函数
Posted
技术标签:
【中文标题】Postgres:将自定义类型从 Java 传递给 postgres 函数【英文标题】:Postgres: Passing custom types from Java to postgres function 【发布时间】:2019-11-28 09:25:49 【问题描述】:我有一个 postgres 函数,它接受一个复杂的用户定义类型作为输入。
CREATE OR REPLACE FUNCTION addUser(user IN O_USER) RETURNS VOID
AS
$$
BEGIN
end;
$$ language plpgsql;
CREATE TYPE O_USER AS (
id NUMERIC,
name VARCHAR(50),
addresses O_ADDRESS[]
);
CREATE TYPE O_ADDRESS AS (
id NUMERIC,
city VARCHAR(50)
);
现在我需要从 Java 中调用该函数。 我的理解是我需要传递一个字符串,该字符串将由 db 类型转换为 UDT。
当我传递没有地址的用户时,它工作正常。但是如果我也传递地址数组,那么它会给我错误。
ERROR: malformed array literal: "(1"
DETAIL: Unexpected end of input.
SQL state: 22P02
Character: 23
我也可以使用 postgres select 语句重现该问题。例如以下工作正常
Select * from addUser('(1, "Vishal", )');
但是当我传递地址时,它就是一个问题
Select * from addUser('(1, "Vishal", (1,"tet"))');
Select * from addUser('(1, "Vishal", "(1,)")');
Select * from addUser('(1, "Vishal", "(1,null)")')
我相信我无法正确构造字符串。知道这里有什么问题吗?
更新
调用函数的Java代码
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.object.StoredProcedure;
import javax.sql.DataSource;
import java.sql.Types;
import java.util.HashMap;
import java.util.Map;
public class AddUserProcedurePostgres extends StoredProcedure
public AddUserProcedurePostgres(DataSource dataSource)
super(dataSource, "addUser");
setFunction(true);
declareParameter(new SqlParameter("i_User", Types.OTHER, "O_USER"));
compile();
public void execute()
Map<String, Object> input = new HashMap<>();
input.put("i_User", "(1, Vishal, array[(1,tet)]::O_ADDRESS[])");
execute(input);
jdbc 返回的错误是:
Caused by: org.postgresql.util.PSQLException: ERROR: malformed array literal: " array[(1"
Detail: Array value must start with "" or dimension information.
【问题讨论】:
【参考方案1】:我找到了两种将所需值传递给函数的方法:
-
如果 UDT 的字符串很复杂,则很难创建它。最简单的方法是进行逆向工程。在 plpgsql 中创建 UDT 并打印它。这样,您将获得需要从 Java 传递的字符串。现在在 Java 代码中编写一个逻辑来创建这样的字符串。
另一种方式是传json格式的值,在函数中,解析json,自己构造UDT。
我选择第二种方法,因为它易于维护。
【讨论】:
【参考方案2】:您需要使用array
文字传递O_ADDRESS
数组并将该数组类型转换为O_ADDRESS[]
。以下select
语句有效。
select * from addUser(cast(row(1, 'Vishal', array[cast(row(1,'tet') as O_ADDRESS)]) as O_USER));
select * from addUser((1, 'Vishal', array[]::O_ADDRESS[])::O_USER);
select * from addUser((1, 'Vishal', array[]::O_ADDRESS[]));
select * from addUser((1, 'Vishal', array[(1,'tet')]::O_ADDRESS[]));
【讨论】:
感谢@Rahul Sharma 的回复。正如我所说,我需要从 Java 调用该函数。不知道如何从 Java 代码中传递数组字面量。 您只需要从您的代码中构建字符串。不知道问题出在哪里。可能,您可以在生成查询并难以构建字符串的位置显示一些代码。 我已在问题中添加了调用该函数的 Java 代码。 先把这个字符串"(1, Vishal, array[(1,tet)]::O_ADDRESS[])"
修改为"(1, 'Vishal', array[(1,'tet')]::O_ADDRESS[])"
。尝试在您的代码将查询转换为字符串之前添加日志,并查看构建的字符串是什么。
我按照建议更改了参数,但同样的错误即将到来。参数为(1, 'Vishal', array[(1,'tet')]::O_ADDRESS[])
,查询为select * from addUser(?) as result
以上是关于Postgres:将自定义类型从 Java 传递给 postgres 函数的主要内容,如果未能解决你的问题,请参考以下文章