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 函数的主要内容,如果未能解决你的问题,请参考以下文章

将自定义类型传递给 Oracle 过程

Android将自定义对象从服务传递给活动

尝试将自定义 C++ 矩阵传递给 numpy 数组

Paypal 结帐按钮未将自定义字段传递给 PIN 消息

微信小程序将自定义组件获取的值传递给页面

微信小程序将自定义组件获取的值传递给页面