Как прочитать UDT из хранимой функции postgres - PullRequest
2 голосов
/ 11 января 2011

Я не могу правильно прочитать UDT из хранимой функции с Postgres JDBC драйвер. Вот пример кода:

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-bit
  • Я использую postgresql-9.0-801.jdbc4.jar

Кто-нибудь знает, что не так?

Ответы [ 2 ]

2 голосов
/ 12 октября 2015

Если не ошибаюсь, 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");
       }
1 голос
/ 11 января 2011

Я могу воспроизвести это, и кажется, что это ошибка.

Я бы предложил вам опубликовать это в списке рассылки PostgreSQL JDBC, чтобы разработчики могли это исправить.

...