问题
I have a postgres function which takes a complex user defined type as an input.
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)
);
Now I need to call the function from Java. What I understood is that I need to pass a String which will be typecasted to the UDT by db.
When I am passing the user without the address, then its working fine. But if I pass the array of address as well, then it is giving me the error.
ERROR: malformed array literal: "{(1"
DETAIL: Unexpected end of input.
SQL state: 22P02
Character: 23
I could reproduce the issue with the postgres select statement as well. For example following works fine
Select * from addUser('(1, "Vishal", {})');
But when I pass the addresses, then its a problem
Select * from addUser('(1, "Vishal", {(1,"tet")})');
Select * from addUser('(1, "Vishal", {"(1,)"})');
Select * from addUser('(1, "Vishal", {"(1,null)"})')
I believe I am not able to construct the string properly. Any idea what is wrong here?
Update
Java code to call the function
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);
}
}
Error returned by the jdbc is:
Caused by: org.postgresql.util.PSQLException: ERROR: malformed array literal: " array[(1"
Detail: Array value must start with "{" or dimension information.
回答1:
I found 2 ways to pass the required value to the function:
- It is difficult to create the string of the UDT if its complex. The easiest way is to do the reverse engineering. Create the UDT in the plpgsql and print it. This way you will get the string that need to be pass from Java. Now in Java code write a logic to create such string.
- Another way is to pass the value in the json format and in the function, parse the json and construct the UDT by your own.
I choose the 2nd approach as it is easy to maintain.
回答2:
You need to pass the O_ADDRESS array with array literal and typecasting the array to O_ADDRESS[]. The following select statements are valid.
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[]));
来源:https://stackoverflow.com/questions/59085449/postgres-passing-custom-types-from-java-to-postgres-function