Come leggere un UDT da un Postgres funzione memorizzati
-
09-10-2019 - |
Domanda
Non riesco a leggere un UDT correttamente da una funzione memorizzata con il il driver JDBC Postgres. Questo è un codice di esempio:
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;
Ora le opere di cui sopra perfettamente in Postgres. Posso anche selezionare l'UDT t_author.address colonna con un'istruzione SQL SELECT direttamente. Ma quando Seleziono dal p_enhance_address2 funzione memorizzata tramite JDBC, ho un strano comportamento. Ho provato questi due schemi di invocazione:
connection.prepareStatement("select * from p_enhance_address2()");
connection.prepareCall("{ call p_enhance_address2(?) }");
// the latter with an output parameter registered
Entrambi i sistemi di chiamata indurre lo stesso comportamento (in realtà la CallableStatement non è altro che selezionare dalla funzione). Sembra che ci siano due problemi ben distinte:
La struttura UDT nidificato completamente le viti fino risultati fetching. Questo è quello che ottengo con 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));
}
Output:
Numero di colonne: 6 ( "(" "Parliament Hill" "77)", NW31A9)
Perché ci sono 6 colonne? E perché è l'UDT in modo non corretto inverosimile (molti campi mancanti)
Un po 'di miglioramento può essere raggiunto, quando l'UDT nidificato u_street_type è "appiattita" ad un varchar, che conduce ai presupposto che nidificati di UDT sono scarsamente supportati dal driver 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))
Poi i risultati saranno qualcosa di simile:
Numero di colonne: 6 ( "Parliament Hill 77", NW31A9, Hampstead, Inghilterra, 1980-01-01,)
Il record UDT ora sembra corretto (prelevato dalla serie di risultati a posizione 1). Ma ci sono ancora 6 colonne del set di risultati.
Alcuni fatti:
- I non si verificano questi problemi in pgAdmin III
- Io uso PostgreSQL 9.0.1, compilato da Visual C ++ di build 1500, a 64 bit
- I usare PostgreSQL-9.0-801.jdbc4.jar
Qualcuno ha qualche idea di cosa c'è che non va?
Soluzione
posso riprodurre questo e sembra che si tratta di un bug.
Vorrei suggerire di postare questo alla mailing list di PostgreSQL JDBC, in modo che gli sviluppatori possano risolvere il problema.
Altri suggerimenti
Se non am UDT sbagliato (utente tipo definito) non ufficialmente supportato (JDBC conformità) da parte dei conducenti postgres9.4 (postgresql-9.0-801.jdbc4.jar). Ho molto anche di fronte a problemi durante postgres chiamando la funzione codice del modulo Java. Ho usato qui di seguito i driver e risolto il mio problema.
ecco il link pilota non ufficiale, http://impossibl.github.io/pgjdbc-ng/ modulo pilota copiare il link Crea connessione come spiegato nel seguente
si prega di vedere sotto esempio di lavoro dalla mia POC Oracle10g a Postgres9.4 l'attività di migrazione vedi sotto esempio 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;
==========================
Funzione principale di chiamata,
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");
}