Как прочитать UDT из сохраненной функции postgres
-
09-10-2019 - |
Вопрос
Я не могу показаться, чтобы правильно читать определяемого пользователем типа с сохраненной функции с драйвер JDBC для базы данных Postgres.Это некоторый пример кода:
CREATE TYPE u_country AS ENUM ('Brazil', 'England', 'Germany')
CREATE TYPE u_street_type AS (
street VARCHAR(100),
no VARCHAR(30)
)
CREATE TYPE u_address_type AS (
street u_street_type,
zip VARCHAR(50),
city VARCHAR(50),
country u_country,
since DATE,
code INTEGER
)
CREATE TABLE t_author (
id INTEGER NOT NULL PRIMARY KEY,
first_name VARCHAR(50),
last_name VARCHAR(50) NOT NULL,
date_of_birth DATE,
year_of_birth INTEGER,
address u_address_type
)
INSERT INTO t_author VALUES (1, 'George', 'Orwell',
TO_DATE('1903-06-25', 'YYYY-MM-DD'), 1903, ROW(ROW('Parliament Hill',
'77'), 'NW31A9', 'Hampstead', 'England', '1980-01-01', null))
INSERT INTO t_author VALUES (2, 'Paulo', 'Coelho',
TO_DATE('1947-08-24', 'YYYY-MM-DD'), 1947, ROW(ROW('Caixa Postal',
'43.003'), null, 'Rio de Janeiro', 'Brazil', '1940-01-01', 2))
CREATE FUNCTION p_enhance_address2 (address OUT u_address_type)
AS $$
BEGIN
SELECT t_author.address
INTO address
FROM t_author
WHERE first_name = 'George';
END;
$$ LANGUAGE plpgsql;
Теперь все вышесказанное отлично работает в postgres.Я также могу выбрать столбец UDT t_author.address напрямую с помощью инструкции SQL SELECT.Но когда Я выбираю из сохраненной функции p_enhance_address2 через JDBC, я получаю странное поведение.Я попробовал эти две схемы вызова:
connection.prepareStatement("select * from p_enhance_address2()");
connection.prepareCall("{ call p_enhance_address2(?) }");
// the latter with an output parameter registered
Обе схемы вызова вызывают одинаковое поведение (на самом деле CallableStatement - это не что иное, как выбор из функции).По-видимому, существуют две совершенно разные проблемы:
Вложенная структура UDT полностью портит получение результатов.Это то, что я получаю с JDBC:
PreparedStatement stmt = connection.prepareStatement(
"select * from p_enhance_address2()");
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
System.out.println("# of columns: " +
rs.getMetaData().getColumnCount());
System.out.println(rs.getObject(1));
}
Выходной сигнал:
количество колонок:6 ("(""Парламентский холм"",77)",NW31A9)
Почему здесь 6 колонок?И почему неправильно выбран UDT (многие поля отсутствуют)
Небольшого улучшения можно добиться, когда вложенный UDT u_street_type "сглажен" до varchar, что приводит к предположение, что вложенные UDT плохо поддерживаются драйвером JDBC:
CREATE TYPE u_address_type AS (
street VARCHAR(80),
zip VARCHAR(50),
city VARCHAR(50),
country u_country,
since DATE,
code INTEGER
)
INSERT INTO t_author VALUES (1, 'George', 'Orwell',
TO_DATE('1903-06-25', 'YYYY-MM-DD'), 1903, ROW('Parliament Hill 77',
'NW31A9', 'Hampstead', 'England', '1980-01-01', null))
INSERT INTO t_author VALUES (2, 'Paulo', 'Coelho',
TO_DATE('1947-08-24', 'YYYY-MM-DD'), 1947, ROW('Caixa Postal 43.003',
null, 'Rio de Janeiro', 'Brazil', '1940-01-01', 2))
Тогда результаты будут примерно такими:
количество колонок:6 ("Парламентский холм 77", NW31A9, Хэмпстед, Англия,1980-01-01,)
Запись UDT теперь выглядит корректной (извлечена из результирующего набора в позиции 1).Но в результирующем наборе все еще есть 6 столбцов.
Некоторые факты:
- Я не испытываю этих проблем в pgAdmin III
- Я использую PostgreSQL 9.0.1, скомпилированный Visual C ++ build 1500, 64-разрядный
- Я использую postgresql-9.0-801.jdbc4.jar
У кого-нибудь есть какие-нибудь идеи, в чем дело?
Решение
Я могу воспроизвести это, и кажется, что это ошибка.
Я бы посоветовал вам опубликовать это в списке рассылки PostgreSQL JDBC, чтобы разработчики могли это исправить.
Другие советы
Если я не ошибаюсь, UDT (определяемый пользователем тип) официально не поддерживается (соответствие JDBC) драйверами postgres9.4 (postgresql-9.0-801.jdbc4.jar).Я также сталкиваюсь с большой проблемой при вызове функции postgres из java-кода.Я использовал приведенные ниже драйверы и решил свою проблему.
вот неофициальная ссылка на драйвер, http://impossibl.github.io/pgjdbc-ng/ скопируйте драйвер по ссылке и создайте соединение, как описано ниже
пожалуйста, смотрите ниже рабочий пример из моего POC Oracle10g в Postgres9.4 активность по миграции смотрите ниже пример POC,
-- Function: fn_test_t(text)
-- DROP FUNCTION fn_test_t(text);
CREATE OR REPLACE FUNCTION fn_test_t(
IN txt text,
OUT a typ_address[],
OUT b typ_address[])
RETURNS record AS
$BODY$
DECLARE
address typ_address[];
BEGIN
RAISE INFO '@@ inside fn_test:(%)',111;
address[1] := ROW('Amravati', 'Mahalaxmi', ROW('Test1'));
address[2] := ROW('Pune', 'NICMAR',ROW('Test2'));
address[3] := ROW('', '',ROW('Test3'));
RAISE INFO 'array of address:(%)',address;
--a := ROW(address);
--b := ROW(address);
a := address;
b := address;
RAISE INFO 'typ_address_t a:(%)',a;
RAISE INFO 'typ_address_t b:(%)',b;
-- RETURN address;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION fn_test_t(text)
OWNER TO postgres;
=========================
-- Type: typ_address
-- DROP TYPE typ_address;
CREATE TYPE typ_address AS
(add1 character varying,
add2 character varying,
t typ_test);
ALTER TYPE typ_address
OWNER TO postgres;
==========================
-- Type: typ_test
-- DROP TYPE typ_test;
CREATE TYPE typ_test AS
(t1 character varying);
ALTER TYPE typ_test
OWNER TO postgres;
==========================
Вызов основной функции,
public static void oracleToPosgresUDTCall() {
System.out.println("@@@ inside oracleToPosgresUDTCall...");
Connection c = null;
try {
Class.forName("com.impossibl.postgres.jdbc.PGDriver");
c = DriverManager
.getConnection("jdbc:pgsql://localhost:5433/orapg", "postgres", "root");
System.out.println(c.getMetaData().getDriverVersion());
//you can map your UDT to pojo here Great !!!
Map<String, Class<?>> m = c.getTypeMap();
m.put("typ_address", Address.class);
m.put("typ_test", AddressTypeTest.class);
c.setTypeMap(m);
// Procedure call
CallableStatement cstmt = c.prepareCall("{call fn_test_t(?,?,?)}");
cstmt.setString(1, "791000252423");
cstmt.registerOutParameter(2, Types.ARRAY);
cstmt.registerOutParameter(3, Types.ARRAY);
boolean b = cstmt.execute();
Array arr = cstmt.getArray(1); //output array starts from index 1
System.out.println("arr:" + arr.getBaseTypeName());
Object obj = arr.getArray();
System.out.println("Address obj:" + obj);
Address[] a = (Address[])obj;
System.out.println("Address obj:" + a[0].getAdd1());
System.out.println("Address obj:" + a[0].getTypeTest().getT1());
System.out.println("=======================================================");
//MORE
List<Address> list = Arrays.asList(a);
for(Address aa: list){
System.out.println(aa.getAdd1());
System.out.println(aa.getAdd2());
System.out.println("t1:" + aa.getTypeTest().getT1());
}
cstmt.close();
} catch (Exception e) {
e.printStackTrace();
System.err.println(e.getClass().getName()+": "+e.getMessage());
System.exit(0);
}
System.out.println("Opened database successfully");
}