Fix setArray() when using the v3 protocol (was Re: Postgres 8.0 + JDBC) - Mailing list pgsql-jdbc
From | Oliver Jowett |
---|---|
Subject | Fix setArray() when using the v3 protocol (was Re: Postgres 8.0 + JDBC) |
Date | |
Msg-id | 4165F7B2.70705@opencloud.com Whole thread Raw |
In response to | Re: Postgres 8.0 + JDBC (Oliver Jowett <oliver@opencloud.com>) |
Responses |
Re: Fix setArray() when using the v3 protocol (was Re: Postgres 8.0 + JDBC)
Re: Fix setArray() when using the v3 protocol (was Re: Postgres |
List | pgsql-jdbc |
Oliver Jowett wrote: > Oliver Jowett wrote: > >> It seems possible to fix the driver to handle this case by making >> setArray() derive a proper array type name i.e. ("_" + >> Array.getBaseType()), and using that rather than 'text' as the >> parameter type. > > > I've done this (plus tests) and it seems to work OK. I can't generate a > patch right now as gborg seems to be having some problems (I get 70% > packet loss on the last hop, which pretty much hoses CVS access) Here is the patch. I made it fail if the array type can't be found, rather than risking the backend interpreting the value in an unpredictable way. -O Index: org/postgresql/errors.properties =================================================================== RCS file: /usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/errors.properties,v retrieving revision 1.37 diff -u -c -r1.37 errors.properties *** org/postgresql/errors.properties 6 Oct 2004 18:40:19 -0000 1.37 --- org/postgresql/errors.properties 8 Oct 2004 02:10:58 -0000 *************** *** 71,76 **** --- 71,77 ---- postgresql.prep.param:No value specified for parameter {0} postgresql.prep.range:Parameter index out of range. postgresql.prep.type:Unknown Types value. + postgresql.prep.typenotfound:Unknown type {0}. postgresql.prep.zeroinstring:Zero bytes may not occur in string parameters. postgresql.res.badbigdec:Bad BigDecimal {0} postgresql.res.badbyte:Bad Byte {0} Index: org/postgresql/core/Oid.java =================================================================== RCS file: /usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/core/Oid.java,v retrieving revision 1.1 diff -u -c -r1.1 Oid.java *** org/postgresql/core/Oid.java 29 Jun 2004 06:43:25 -0000 1.1 --- org/postgresql/core/Oid.java 8 Oct 2004 02:10:58 -0000 *************** *** 5,10 **** --- 5,11 ---- * use. */ public class Oid { + public static final int INVALID = 0; public static final int INT2 = 21; public static final int INT4 = 23; public static final int INT8 = 20; Index: org/postgresql/jdbc2/AbstractJdbc2Connection.java =================================================================== RCS file: /usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/jdbc2/AbstractJdbc2Connection.java,v retrieving revision 1.16 diff -u -c -r1.16 AbstractJdbc2Connection.java *** org/postgresql/jdbc2/AbstractJdbc2Connection.java 20 Sep 2004 08:36:50 -0000 1.16 --- org/postgresql/jdbc2/AbstractJdbc2Connection.java 8 Oct 2004 02:10:58 -0000 *************** *** 871,877 **** public int getPGType(String typeName) throws SQLException { if (typeName == null) ! return 0; synchronized (this) { Integer oidValue = (Integer) typeOidCache.get(typeName); --- 871,877 ---- public int getPGType(String typeName) throws SQLException { if (typeName == null) ! return Oid.INVALID; synchronized (this) { Integer oidValue = (Integer) typeOidCache.get(typeName); *************** *** 879,885 **** return oidValue.intValue(); // it's not in the cache, so perform a query, and add the result to the cache ! int oid = 0; PreparedStatement query; if (haveMinimumServerVersion("7.3")) --- 879,885 ---- return oidValue.intValue(); // it's not in the cache, so perform a query, and add the result to the cache ! int oid = Oid.INVALID; PreparedStatement query; if (haveMinimumServerVersion("7.3")) *************** *** 912,918 **** */ public String getPGType(int oid) throws SQLException { ! if (oid == 0) return null; synchronized (this) { --- 912,918 ---- */ public String getPGType(int oid) throws SQLException { ! if (oid == Oid.INVALID) return null; synchronized (this) { Index: org/postgresql/jdbc2/AbstractJdbc2Statement.java =================================================================== RCS file: /usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/jdbc2/AbstractJdbc2Statement.java,v retrieving revision 1.31 diff -u -c -r1.31 AbstractJdbc2Statement.java *** org/postgresql/jdbc2/AbstractJdbc2Statement.java 21 Sep 2004 01:14:06 -0000 1.31 --- org/postgresql/jdbc2/AbstractJdbc2Statement.java 8 Oct 2004 02:10:59 -0000 *************** *** 2443,2449 **** public void setArray(int i, java.sql.Array x) throws SQLException { checkClosed(); ! setString(i, x.toString()); } public void setBlob(int i, Blob x) throws SQLException --- 2443,2462 ---- public void setArray(int i, java.sql.Array x) throws SQLException { checkClosed(); ! ! // This only works for Array implementations that return a valid array ! // literal from Array.toString(), such as the implementation we return ! // from ResultSet.getArray(). Eventually we need a proper implementation ! // here that works for any Array implementation. ! ! // Use a typename that is "_" plus the base type; this matches how the ! // backend looks for array types. ! String typename = "_" + x.getBaseTypeName(); ! int oid = connection.getPGType(typename); ! if (oid == Oid.INVALID) ! throw new PSQLException("postgresql.prep.typenotfound", PSQLState.INVALID_PARAMETER_TYPE, typename); ! ! setString(i, x.toString(), oid); } public void setBlob(int i, Blob x) throws SQLException Index: org/postgresql/test/jdbc2/ArrayTest.java =================================================================== RCS file: /usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/test/jdbc2/ArrayTest.java,v retrieving revision 1.2 diff -u -c -r1.2 ArrayTest.java *** org/postgresql/test/jdbc2/ArrayTest.java 20 Jul 2004 00:24:37 -0000 1.2 --- org/postgresql/test/jdbc2/ArrayTest.java 8 Oct 2004 02:10:59 -0000 *************** *** 3,14 **** import org.postgresql.test.TestUtil; import java.sql.*; import java.math.BigDecimal; import junit.framework.TestCase; public class ArrayTest extends TestCase { - private Connection conn; public ArrayTest(String name) --- 3,14 ---- import org.postgresql.test.TestUtil; import java.sql.*; import java.math.BigDecimal; + import java.util.Map; import junit.framework.TestCase; public class ArrayTest extends TestCase { private Connection conn; public ArrayTest(String name) *************** *** 19,30 **** protected void setUp() throws SQLException { conn = TestUtil.openDB(); - TestUtil.createTable(conn, "arrtest", "intarr int[], decarr decimal(2,1)[], strarr text[]"); - Statement stmt = conn.createStatement(); - // you need a lot of backslashes to get a double quote in. - stmt.executeUpdate("INSERT INTO arrtest VALUES ('{1,2,3}','{3.1,1.4}', '{abc,f''a,\"fa\\\\\"b\",def}')"); - stmt.close(); } protected void tearDown() throws SQLException --- 19,25 ---- *************** *** 35,40 **** --- 30,39 ---- public void testRetrieveArrays() throws SQLException { Statement stmt = conn.createStatement(); + + // you need a lot of backslashes to get a double quote in. + stmt.executeUpdate("INSERT INTO arrtest VALUES ('{1,2,3}','{3.1,1.4}', '{abc,f''a,\"fa\\\\\"b\",def}')"); + ResultSet rs = stmt.executeQuery("SELECT intarr, decarr, strarr FROM arrtest"); assertTrue(rs.next()); *************** *** 66,71 **** --- 65,74 ---- public void testRetrieveResultSets() throws SQLException { Statement stmt = conn.createStatement(); + + // you need a lot of backslashes to get a double quote in. + stmt.executeUpdate("INSERT INTO arrtest VALUES ('{1,2,3}','{3.1,1.4}', '{abc,f''a,\"fa\\\\\"b\",def}')"); + ResultSet rs = stmt.executeQuery("SELECT intarr, decarr, strarr FROM arrtest"); assertTrue(rs.next()); *************** *** 113,117 **** --- 116,166 ---- stmt.close(); } + private static class SimpleArray implements Array { + SimpleArray(int baseType, String baseTypeName, String value) { + this.baseType = baseType; + this.baseTypeName = baseTypeName; + this.value = value; + } + + public Object getArray() { throw new UnsupportedOperationException(); } + public Object getArray(long index, int count) { throw new UnsupportedOperationException(); } + public Object getArray(long index, int count, Map map) { throw new UnsupportedOperationException(); } + public Object getArray(Map map) { throw new UnsupportedOperationException(); } + public ResultSet getResultSet() { throw new UnsupportedOperationException(); } + public ResultSet getResultSet(long index, int count) { throw new UnsupportedOperationException(); } + public ResultSet getResultSet(long index, int count, Map map) { throw new UnsupportedOperationException(); } + public ResultSet getResultSet(Map map) { throw new UnsupportedOperationException(); } + + public int getBaseType() { return baseType; } + public String getBaseTypeName() { return baseTypeName; } + + public String toString() { return value; } + + private final int baseType; + private final String baseTypeName; + private final String value; + } + + + public void testSetArray() throws SQLException { + PreparedStatement stmt = conn.prepareStatement("INSERT INTO arrtest(intarr) VALUES (?)"); + stmt.setArray(1, new SimpleArray(Types.INTEGER, "int4", "{1,2,3}")); + stmt.executeUpdate(); + + Statement select = conn.createStatement(); + ResultSet rs = select.executeQuery("SELECT intarr FROM arrtest"); + assertTrue(rs.next()); + + Array result = rs.getArray(1); + assertEquals(Types.INTEGER, result.getBaseType()); + assertEquals("int4", result.getBaseTypeName()); + + int intarr[] = (int[])result.getArray(); + assertEquals(3,intarr.length); + assertEquals(1,intarr[0]); + assertEquals(2,intarr[1]); + assertEquals(3,intarr[2]); + } }
pgsql-jdbc by date: