Thread: Re: [JDBC] Anoter JDBC Error

Re: [JDBC] Anoter JDBC Error

From
Kris Jurka
Date:
The following patch fixes this bug and the potential source of similar
bugs.  When creating the ResultSets for DatabaseMetaData calls, the code
creates byte arrays for each row something like...

byte tuple[][] = new byte[18][0];

Unless a call "tuple[n] = null;" is made then it has an array of zero
length which does in fact get turned into the zero length string being
seen.  I have changed these allocations to...

byte tuple[][] = new byte[18][];

Kris Jurka


On Sat, 19 Oct 2002, Aaron Mulder wrote:

>     Ahh, never mind.  I tried again a few minutes later, and got the
> new behavior, which is to say a SQLException.  But I don't
> understand why this is happening.  Here's what I'm doing:
>
>     I create the database "test" (in my PG 7.2.2 DB) with a table with
> 3 columns, all integers.  I connect using the JDBC3 driver, get a
> connection, get the databasemetadata, call
>
>     dbmd.getColumns("test",null,"tablename","%");
>
>     I get back a ResultSet.  Column 9 is an integer column,
> DECIMAL_DIGITS.  If I call getObject, it tries to get an Integer object,
> so even the ResultSet thinks it's an integer column.  However, the result
> of getString/getFixedString used for new Integer(getFixedString()) is
> apparently an empty String, causing the SQLException due to a badly
> formatted Integer value.
>
>     So now I'm confused.  What's an empty String doing in an integer
> column when (if you believe the logic in getFixedString) the value was not
> null?  Is this broken null handling?  Test program and results attached...
>
> Aaron
>
> import java.sql.*;
>
> public class PostgresTest{
>     public static void main(String args[]) {
>         try {
>             Class.forName("org.postgresql.Driver");
>             Connection con =
> DriverManager.getConnection("jdbc:postgresql://localhost/test", "test",
> "password");
>             DatabaseMetaData dmd = con.getMetaData();
>             ResultSet rs = dmd.getColumns("test", null, "tablename", "%");
>             rs.next();
>             System.out.println("Col 9: "+rs.getInt(9)); // getObject(9)
>             rs.close();
>             con.close();
>         } catch(Exception e) {
>             e.printStackTrace();
>         }
>     }
> }
>
>
> Bad Integer
>     at
> org.postgresql.jdbc1.AbstractJdbc1ResultSet.toInt(AbstractJdbc1ResultSet.java:708)
>     at
> org.postgresql.jdbc1.AbstractJdbc1ResultSet.getInt(AbstractJdbc1ResultSet.java:148)
>     at PostgresTest.main(PostgresTest.java:12)
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 6: Have you searched our list archives?
>
> http://archives.postgresql.org
>


Attachment

Re: [JDBC] Anoter JDBC Error

From
Barry Lind
Date:
Patch applied.

thanks,
--Barry


Kris Jurka wrote:
> The following patch fixes this bug and the potential source of similar
> bugs.  When creating the ResultSets for DatabaseMetaData calls, the code
> creates byte arrays for each row something like...
>
> byte tuple[][] = new byte[18][0];
>
> Unless a call "tuple[n] = null;" is made then it has an array of zero
> length which does in fact get turned into the zero length string being
> seen.  I have changed these allocations to...
>
> byte tuple[][] = new byte[18][];
>
> Kris Jurka
>
>
> On Sat, 19 Oct 2002, Aaron Mulder wrote:
>
>
>>    Ahh, never mind.  I tried again a few minutes later, and got the
>>new behavior, which is to say a SQLException.  But I don't
>>understand why this is happening.  Here's what I'm doing:
>>
>>    I create the database "test" (in my PG 7.2.2 DB) with a table with
>>3 columns, all integers.  I connect using the JDBC3 driver, get a
>>connection, get the databasemetadata, call
>>
>>    dbmd.getColumns("test",null,"tablename","%");
>>
>>    I get back a ResultSet.  Column 9 is an integer column,
>>DECIMAL_DIGITS.  If I call getObject, it tries to get an Integer object,
>>so even the ResultSet thinks it's an integer column.  However, the result
>>of getString/getFixedString used for new Integer(getFixedString()) is
>>apparently an empty String, causing the SQLException due to a badly
>>formatted Integer value.
>>
>>    So now I'm confused.  What's an empty String doing in an integer
>>column when (if you believe the logic in getFixedString) the value was not
>>null?  Is this broken null handling?  Test program and results attached...
>>
>>Aaron
>>
>>import java.sql.*;
>>
>>public class PostgresTest{
>>    public static void main(String args[]) {
>>        try {
>>            Class.forName("org.postgresql.Driver");
>>            Connection con =
>>DriverManager.getConnection("jdbc:postgresql://localhost/test", "test",
>>"password");
>>            DatabaseMetaData dmd = con.getMetaData();
>>            ResultSet rs = dmd.getColumns("test", null, "tablename", "%");
>>            rs.next();
>>            System.out.println("Col 9: "+rs.getInt(9)); // getObject(9)
>>            rs.close();
>>            con.close();
>>        } catch(Exception e) {
>>            e.printStackTrace();
>>        }
>>    }
>>}
>>
>>
>>Bad Integer
>>    at
>>org.postgresql.jdbc1.AbstractJdbc1ResultSet.toInt(AbstractJdbc1ResultSet.java:708)
>>    at
>>org.postgresql.jdbc1.AbstractJdbc1ResultSet.getInt(AbstractJdbc1ResultSet.java:148)
>>    at PostgresTest.main(PostgresTest.java:12)
>>
>>
>>---------------------------(end of broadcast)---------------------------
>>TIP 6: Have you searched our list archives?
>>
>>http://archives.postgresql.org
>>
>
>
>
> ------------------------------------------------------------------------
>
> Index: src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java
> ===================================================================
> RCS file:
/projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java,v
> retrieving revision 1.8
> diff -c -r1.8 AbstractJdbc1DatabaseMetaData.java
> *** src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java    2002/10/08 01:47:55    1.8
> --- src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java    2002/10/22 21:00:52
> ***************
> *** 1854,1860 ****
>
>               // decide if we are returning a single column result.
>               if (!returnTypeType.equals("c")) {
> !                 byte[][] tuple = new byte[13][0];
>                   tuple[0] = null;
>                   tuple[1] = schema;
>                   tuple[2] = procedureName;
> --- 1854,1860 ----
>
>               // decide if we are returning a single column result.
>               if (!returnTypeType.equals("c")) {
> !                 byte[][] tuple = new byte[13][];
>                   tuple[0] = null;
>                   tuple[1] = schema;
>                   tuple[2] = procedureName;
> ***************
> *** 1874,1880 ****
>               // Add a row for each argument.
>               for (int i=0; i<argTypes.size(); i++) {
>                   int argOid = ((Integer)argTypes.elementAt(i)).intValue();
> !                 byte[][] tuple = new byte[13][0];
>                   tuple[0] = null;
>                   tuple[1] = schema;
>                   tuple[2] = procedureName;
> --- 1874,1880 ----
>               // Add a row for each argument.
>               for (int i=0; i<argTypes.size(); i++) {
>                   int argOid = ((Integer)argTypes.elementAt(i)).intValue();
> !                 byte[][] tuple = new byte[13][];
>                   tuple[0] = null;
>                   tuple[1] = schema;
>                   tuple[2] = procedureName;
> ***************
> *** 1897,1903 ****
>                   ResultSet columnrs = connection.createStatement().executeQuery(columnsql);
>                   while (columnrs.next()) {
>                       int columnTypeOid = columnrs.getInt("atttypid");
> !                     byte[][] tuple = new byte[13][0];
>                       tuple[0] = null;
>                       tuple[1] = schema;
>                       tuple[2] = procedureName;
> --- 1897,1903 ----
>                   ResultSet columnrs = connection.createStatement().executeQuery(columnsql);
>                   while (columnrs.next()) {
>                       int columnTypeOid = columnrs.getInt("atttypid");
> !                     byte[][] tuple = new byte[13][];
>                       tuple[0] = null;
>                       tuple[1] = schema;
>                       tuple[2] = procedureName;
> ***************
> *** 2199,2205 ****
>           f[0] = new Field(connection, new String("TABLE_TYPE"), iVarcharOid, getMaxNameLength());
>           for (i=0; i < types.length; i++)
>           {
> !             byte[][] tuple = new byte[1][0];
>               tuple[0] = types[i].getBytes();
>               v.addElement(tuple);
>           }
> --- 2199,2205 ----
>           f[0] = new Field(connection, new String("TABLE_TYPE"), iVarcharOid, getMaxNameLength());
>           for (i=0; i < types.length; i++)
>           {
> !             byte[][] tuple = new byte[1][];
>               tuple[0] = types[i].getBytes();
>               v.addElement(tuple);
>           }
> ***************
> *** 2318,2324 ****
>           ResultSet rs = connection.createStatement().executeQuery(sql);
>           while (rs.next())
>           {
> !             byte[][] tuple = new byte[18][0];
>               int typeOid = rs.getInt("atttypid");
>
>               tuple[0] = null;                    // Catalog name, not supported
> --- 2318,2324 ----
>           ResultSet rs = connection.createStatement().executeQuery(sql);
>           while (rs.next())
>           {
> !             byte[][] tuple = new byte[18][];
>               int typeOid = rs.getInt("atttypid");
>
>               tuple[0] = null;                    // Catalog name, not supported
> ***************
> *** 2329,2334 ****
> --- 2329,2339 ----
>               String pgType = connection.getPGType(typeOid);
>               tuple[5] = pgType.getBytes();        // Type name
>
> +             // by default no decimal_digits
> +             // if the type is numeric or decimal we will
> +             // overwrite later.
> +             tuple[8] = "0".getBytes();
> +
>               if (pgType.equals("bpchar") || pgType.equals("varchar"))
>               {
>                   int atttypmod = rs.getInt("atttypmod");
> ***************
> *** 2465,2471 ****
>                   for (int j=0; j<grantees.size(); j++) {
>                       String grantee = (String)grantees.elementAt(j);
>                       String grantable = owner.equals(grantee) ? "YES" : "NO";
> !                     byte[][] tuple = new byte[8][0];
>                       tuple[0] = null;
>                       tuple[1] = schemaName;
>                       tuple[2] = tableName;
> --- 2470,2476 ----
>                   for (int j=0; j<grantees.size(); j++) {
>                       String grantee = (String)grantees.elementAt(j);
>                       String grantable = owner.equals(grantee) ? "YES" : "NO";
> !                     byte[][] tuple = new byte[8][];
>                       tuple[0] = null;
>                       tuple[1] = schemaName;
>                       tuple[2] = tableName;
> ***************
> *** 2567,2573 ****
>                   for (int j=0; j<grantees.size(); j++) {
>                       String grantee = (String)grantees.elementAt(j);
>                       String grantable = owner.equals(grantee) ? "YES" : "NO";
> !                     byte[][] tuple = new byte[7][0];
>                       tuple[0] = null;
>                       tuple[1] = schema;
>                       tuple[2] = table;
> --- 2572,2578 ----
>                   for (int j=0; j<grantees.size(); j++) {
>                       String grantee = (String)grantees.elementAt(j);
>                       String grantable = owner.equals(grantee) ? "YES" : "NO";
> !                     byte[][] tuple = new byte[7][];
>                       tuple[0] = null;
>                       tuple[1] = schema;
>                       tuple[2] = table;
> ***************
> *** 2819,2825 ****
>           f[6] = new Field(connection, "DECIMAL_DIGITS", iInt2Oid, 2);
>           f[7] = new Field(connection, "PSEUDO_COLUMN", iInt2Oid, 2);
>
> !         byte tuple[][] = new byte[8][0];
>
>           /* Postgresql does not have any column types that are
>            * automatically updated like some databases' timestamp type.
> --- 2824,2830 ----
>           f[6] = new Field(connection, "DECIMAL_DIGITS", iInt2Oid, 2);
>           f[7] = new Field(connection, "PSEUDO_COLUMN", iInt2Oid, 2);
>
> !         byte tuple[][] = new byte[8][];
>
>           /* Postgresql does not have any column types that are
>            * automatically updated like some databases' timestamp type.
>
>
> ------------------------------------------------------------------------
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 5: Have you checked our extensive FAQ?
>
> http://www.postgresql.org/users-lounge/docs/faq.html