Re: Missing fields in getColumns() result - Mailing list pgsql-jdbc

From Christian Schröder
Subject Re: Missing fields in getColumns() result
Date
Msg-id 476EEC20.8020902@deriva.de
Whole thread Raw
In response to Missing fields in getColumns() result  (Christian Schröder <cs@deriva.de>)
Responses Re: Missing fields in getColumns() result  (Christian Schröder <cs@deriva.de>)
Re: Missing fields in getColumns() result  (Kris Jurka <books@ejurka.com>)
List pgsql-jdbc
Hi list,
by now I have found two threads in the archive about this issue:

http://archives.postgresql.org/pgsql-jdbc/2006-06/msg00038.php
http://archives.postgresql.org/pgsql-jdbc/2004-12/msg00008.php

I have also seen the following entry in the "Todo" section on the driver
homepage: "[JDBC3] The JDBC 3 DatabaseMetaData methods sometimes return
additional information. Currently we only return JDBC 2 data for these
methods."

So the problem doesn't seem to be solved yet. I have implemented a patch
that specifically adds the "SOURCE_DATA_TYPE" field to the result of
"getColumns()". The other missing fields are added, but always have a
"null" value. I had to do changes to both the
AbstractJdbc2DatabaseMetaData and the AbstractJdbc3DatabaseMetaData
class, but I hope that I didn't break the JDBC 2 code. The test cases
completed without errors.

It would be great if you could have a look at my proposed patch and
decide if you will include it into the CVS repository.

Regards,
    Christian

--
Deriva GmbH                         Tel.: +49 551 489500-42
Financial IT and Consulting         Fax:  +49 551 489500-91
Hans-Böckler-Straße 2                  http://www.deriva.de
D-37079 Göttingen

Deriva CA Certificate: http://www.deriva.de/deriva-ca.cer



Index: org/postgresql/jdbc2/AbstractJdbc2DatabaseMetaData.java
===================================================================
RCS file: /cvsroot/jdbc/pgjdbc/org/postgresql/jdbc2/AbstractJdbc2DatabaseMetaData.java,v
retrieving revision 1.42
diff -c -r1.42 AbstractJdbc2DatabaseMetaData.java
*** org/postgresql/jdbc2/AbstractJdbc2DatabaseMetaData.java    2 Dec 2007 06:48:43 -0000    1.42
--- org/postgresql/jdbc2/AbstractJdbc2DatabaseMetaData.java    23 Dec 2007 23:12:41 -0000
***************
*** 2202,2280 ****

          return (ResultSet) ((BaseStatement)createMetaDataStatement()).createDriverResultSet(f, v);
      }
!
!     /*
!      * Get a description of table columns available in a catalog.
!      *
!      * <P>Only column descriptions matching the catalog, schema, table
!      * and column name criteria are returned.  They are ordered by
!      * TABLE_SCHEM, TABLE_NAME and ORDINAL_POSITION.
!      *
!      * <P>Each column description has the following columns:
!      * <OL>
!      * <LI><B>TABLE_CAT</B> String => table catalog (may be null)
!      * <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
!      * <LI><B>TABLE_NAME</B> String => table name
!      * <LI><B>COLUMN_NAME</B> String => column name
!      * <LI><B>DATA_TYPE</B> short => SQL type from java.sql.Types
!      * <LI><B>TYPE_NAME</B> String => Data source dependent type name
!      * <LI><B>COLUMN_SIZE</B> int => column size. For char or date
!      *  types this is the maximum number of characters, for numeric or
!      *  decimal types this is precision.
!      * <LI><B>BUFFER_LENGTH</B> is not used.
!      * <LI><B>DECIMAL_DIGITS</B> int => the number of fractional digits
!      * <LI><B>NUM_PREC_RADIX</B> int => Radix (typically either 10 or 2)
!      * <LI><B>NULLABLE</B> int => is NULL allowed?
!      *  <UL>
!      *  <LI> columnNoNulls - might not allow NULL values
!      *  <LI> columnNullable - definitely allows NULL values
!      *  <LI> columnNullableUnknown - nullability unknown
!      *  </UL>
!      * <LI><B>REMARKS</B> String => comment describing column (may be null)
!      * <LI><B>COLUMN_DEF</B> String => default value (may be null)
!      * <LI><B>SQL_DATA_TYPE</B> int => unused
!      * <LI><B>SQL_DATETIME_SUB</B> int => unused
!      * <LI><B>CHAR_OCTET_LENGTH</B> int => for char types the
!      *   maximum number of bytes in the column
!      * <LI><B>ORDINAL_POSITION</B> int => index of column in table
!      *  (starting at 1)
!      * <LI><B>IS_NULLABLE</B> String => "NO" means column definitely
!      *  does not allow NULL values; "YES" means the column might
!      *  allow NULL values. An empty string means nobody knows.
!      * </OL>
!      *
!      * @param catalog a catalog name; "" retrieves those without a catalog
!      * @param schemaPattern a schema name pattern; "" retrieves those
!      * without a schema
!      * @param tableNamePattern a table name pattern
!      * @param columnNamePattern a column name pattern
!      * @return ResultSet each row is a column description
!      * @see #getSearchStringEscape
!      */
!     public java.sql.ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String
columnNamePattern)throws SQLException 
!     {
!         Vector v = new Vector();  // The new ResultSet tuple stuff
!         Field f[] = new Field[18];  // The field descriptors for the new ResultSet
!
!         f[0] = new Field("TABLE_CAT", Oid.VARCHAR);
!         f[1] = new Field("TABLE_SCHEM", Oid.VARCHAR);
!         f[2] = new Field("TABLE_NAME", Oid.VARCHAR);
!         f[3] = new Field("COLUMN_NAME", Oid.VARCHAR);
!         f[4] = new Field("DATA_TYPE", Oid.INT2);
!         f[5] = new Field("TYPE_NAME", Oid.VARCHAR);
!         f[6] = new Field("COLUMN_SIZE", Oid.INT4);
!         f[7] = new Field("BUFFER_LENGTH", Oid.VARCHAR);
!         f[8] = new Field("DECIMAL_DIGITS", Oid.INT4);
!         f[9] = new Field("NUM_PREC_RADIX", Oid.INT4);
!         f[10] = new Field("NULLABLE", Oid.INT4);
!         f[11] = new Field("REMARKS", Oid.VARCHAR);
!         f[12] = new Field("COLUMN_DEF", Oid.VARCHAR);
!         f[13] = new Field("SQL_DATA_TYPE", Oid.INT4);
!         f[14] = new Field("SQL_DATETIME_SUB", Oid.INT4);
!         f[15] = new Field("CHAR_OCTET_LENGTH", Oid.VARCHAR);
!         f[16] = new Field("ORDINAL_POSITION", Oid.INT4);
!         f[17] = new Field("IS_NULLABLE", Oid.VARCHAR);
!
          String sql;
          if (connection.haveMinimumServerVersion("7.3"))
          {
--- 2202,2233 ----

          return (ResultSet) ((BaseStatement)createMetaDataStatement()).createDriverResultSet(f, v);
      }
!
!     protected Vector getColumnsFieldDef() {
!         Vector f = new Vector();
!         f.addElement(new Field("TABLE_CAT", Oid.VARCHAR));
!         f.addElement(new Field("TABLE_SCHEM", Oid.VARCHAR));
!         f.addElement(new Field("TABLE_NAME", Oid.VARCHAR));
!         f.addElement(new Field("COLUMN_NAME", Oid.VARCHAR));
!         f.addElement(new Field("DATA_TYPE", Oid.INT2));
!         f.addElement(new Field("TYPE_NAME", Oid.VARCHAR));
!         f.addElement(new Field("COLUMN_SIZE", Oid.INT4));
!         f.addElement(new Field("BUFFER_LENGTH", Oid.VARCHAR));
!         f.addElement(new Field("DECIMAL_DIGITS", Oid.INT4));
!         f.addElement(new Field("NUM_PREC_RADIX", Oid.INT4));
!         f.addElement(new Field("NULLABLE", Oid.INT4));
!         f.addElement(new Field("REMARKS", Oid.VARCHAR));
!         f.addElement(new Field("COLUMN_DEF", Oid.VARCHAR));
!         f.addElement(new Field("SQL_DATA_TYPE", Oid.INT4));
!         f.addElement(new Field("SQL_DATETIME_SUB", Oid.INT4));
!         f.addElement(new Field("CHAR_OCTET_LENGTH", Oid.VARCHAR));
!         f.addElement(new Field("ORDINAL_POSITION", Oid.INT4));
!         f.addElement(new Field("IS_NULLABLE", Oid.VARCHAR));
!         return f;
!     }
!
!     protected Vector getColumnsValues(Field[] f, String catalog, String schemaPattern, String tableNamePattern,
StringcolumnNamePattern) throws SQLException { 
!         Vector v = new Vector();
          String sql;
          if (connection.haveMinimumServerVersion("7.3"))
          {
***************
*** 2332,2338 ****
          ResultSet rs = connection.createStatement().executeQuery(sql);
          while (rs.next())
          {
!             byte[][] tuple = new byte[18][];
              int typeOid = (int)rs.getLong("atttypid");
              int typeMod = rs.getInt("atttypmod");

--- 2285,2291 ----
          ResultSet rs = connection.createStatement().executeQuery(sql);
          while (rs.next())
          {
!             byte[][] tuple = new byte[f.length][];
              int typeOid = (int)rs.getLong("atttypid");
              int typeMod = rs.getInt("atttypmod");

***************
*** 2392,2397 ****
--- 2345,2406 ----
          }
          rs.close();

+         return v;
+     }
+
+     /*
+      * Get a description of table columns available in a catalog.
+      *
+      * <P>Only column descriptions matching the catalog, schema, table
+      * and column name criteria are returned.  They are ordered by
+      * TABLE_SCHEM, TABLE_NAME and ORDINAL_POSITION.
+      *
+      * <P>Each column description has the following columns:
+      * <OL>
+      * <LI><B>TABLE_CAT</B> String => table catalog (may be null)
+      * <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
+      * <LI><B>TABLE_NAME</B> String => table name
+      * <LI><B>COLUMN_NAME</B> String => column name
+      * <LI><B>DATA_TYPE</B> short => SQL type from java.sql.Types
+      * <LI><B>TYPE_NAME</B> String => Data source dependent type name
+      * <LI><B>COLUMN_SIZE</B> int => column size. For char or date
+      *  types this is the maximum number of characters, for numeric or
+      *  decimal types this is precision.
+      * <LI><B>BUFFER_LENGTH</B> is not used.
+      * <LI><B>DECIMAL_DIGITS</B> int => the number of fractional digits
+      * <LI><B>NUM_PREC_RADIX</B> int => Radix (typically either 10 or 2)
+      * <LI><B>NULLABLE</B> int => is NULL allowed?
+      *  <UL>
+      *  <LI> columnNoNulls - might not allow NULL values
+      *  <LI> columnNullable - definitely allows NULL values
+      *  <LI> columnNullableUnknown - nullability unknown
+      *  </UL>
+      * <LI><B>REMARKS</B> String => comment describing column (may be null)
+      * <LI><B>COLUMN_DEF</B> String => default value (may be null)
+      * <LI><B>SQL_DATA_TYPE</B> int => unused
+      * <LI><B>SQL_DATETIME_SUB</B> int => unused
+      * <LI><B>CHAR_OCTET_LENGTH</B> int => for char types the
+      *   maximum number of bytes in the column
+      * <LI><B>ORDINAL_POSITION</B> int => index of column in table
+      *  (starting at 1)
+      * <LI><B>IS_NULLABLE</B> String => "NO" means column definitely
+      *  does not allow NULL values; "YES" means the column might
+      *  allow NULL values. An empty string means nobody knows.
+      * </OL>
+      *
+      * @param catalog a catalog name; "" retrieves those without a catalog
+      * @param schemaPattern a schema name pattern; "" retrieves those
+      * without a schema
+      * @param tableNamePattern a table name pattern
+      * @param columnNamePattern a column name pattern
+      * @return ResultSet each row is a column description
+      * @see #getSearchStringEscape
+      */
+     public java.sql.ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String
columnNamePattern)throws SQLException 
+     {
+         Field[] f = (Field[]) getColumnsFieldDef().toArray(new Field[0]);   // The field descriptors for the new
ResultSet
+         Vector v = getColumnsValues(f, catalog, schemaPattern, tableNamePattern, columnNamePattern);    // The new
ResultSettuple stuff 
+
          return (ResultSet) ((BaseStatement)createMetaDataStatement()).createDriverResultSet(f, v);
      }

Index: org/postgresql/jdbc3/AbstractJdbc3DatabaseMetaData.java
===================================================================
RCS file: /cvsroot/jdbc/pgjdbc/org/postgresql/jdbc3/AbstractJdbc3DatabaseMetaData.java,v
retrieving revision 1.11
diff -c -r1.11 AbstractJdbc3DatabaseMetaData.java
*** org/postgresql/jdbc3/AbstractJdbc3DatabaseMetaData.java    15 Feb 2005 08:56:26 -0000    1.11
--- org/postgresql/jdbc3/AbstractJdbc3DatabaseMetaData.java    23 Dec 2007 23:12:41 -0000
***************
*** 3,9 ****
  * Copyright (c) 2004-2005, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
! *   $PostgreSQL: pgjdbc/org/postgresql/jdbc3/AbstractJdbc3DatabaseMetaData.java,v 1.11 2005/02/15 08:56:26 jurka Exp
$
  *
  *-------------------------------------------------------------------------
  */
--- 3,9 ----
  * Copyright (c) 2004-2005, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
! *   $PostgreSQL: pgjdbc/org/postgresql/jdbc3/AbstractJdbc3DatabaseMetaData.java,v 1.10 2005/01/11 08:25:46 jurka Exp
$
  *
  *-------------------------------------------------------------------------
  */
***************
*** 11,16 ****
--- 11,19 ----


  import java.sql.*;
+ import java.util.Vector;
+ import org.postgresql.core.Field;
+ import org.postgresql.core.Oid;

  public abstract class AbstractJdbc3DatabaseMetaData extends org.postgresql.jdbc2.AbstractJdbc2DatabaseMetaData
  {
***************
*** 366,370 ****
      {
          return false;
      }
!
  }
--- 369,432 ----
      {
          return false;
      }
!
!     protected Vector getColumnsFieldDef() {
!         Vector f = super.getColumnsFieldDef();
!         f.add(new Field("SCOPE_CATLOG", Oid.VARCHAR));
!         f.add(new Field("SCOPE_SCHEMA", Oid.VARCHAR));
!         f.add(new Field("SCOPE_TABLE", Oid.VARCHAR));
!         f.add(new Field("SOURCE_DATA_TYPE", Oid.INT2));
!         return f;
!     }
!
!     protected Vector getColumnsValues(Field[] f, String catalog, String schemaPattern, String tableNamePattern,
StringcolumnNamePattern) throws SQLException { 
!         Vector v = super.getColumnsValues(f, catalog, schemaPattern, tableNamePattern, columnNamePattern);
!         String sql;
!         if (connection.haveMinimumServerVersion("7.3")) {
!             sql = "SELECT t.typbasetype" +
!                   " FROM pg_catalog.pg_namespace n " +
!                   " JOIN pg_catalog.pg_class c ON (c.relnamespace = n.oid) " +
!                   " JOIN pg_catalog.pg_attribute a ON (a.attrelid = c.oid) " +
!                   " JOIN pg_catalog.pg_type t ON (a.atttypid = t.oid) " +
!                   " WHERE a.attnum > 0 AND NOT a.attisdropped ";
!             if (schemaPattern != null && !"".equals(schemaPattern)) {
!                 sql += " AND n.nspname LIKE '" + escapeQuotes(schemaPattern) + "' ";
!             }
!             if (tableNamePattern != null && !"".equals(tableNamePattern))
!             {
!                 sql += " AND c.relname LIKE '" + escapeQuotes(tableNamePattern) + "' ";
!             }
!             if (columnNamePattern != null && !"".equals(columnNamePattern))
!             {
!                 sql += " AND a.attname LIKE '" + escapeQuotes(columnNamePattern) + "' ";
!             }
!             sql += " ORDER BY nspname,relname,attnum ";
!             ResultSet rs = connection.createStatement().executeQuery(sql);
!             int i = 0;
!             while (rs.next()) {
!                 int baseTypeOid = (int) rs.getLong("typbasetype");
!
!                 byte[][] tuple = (byte[][]) v.get(i++);
!                 tuple[18] = null;   // SCOPE_CATLOG
!                 tuple[19] = null;   // SCOPE_SCHEMA
!                 tuple[20] = null;   // SCOPE_TABLE
!                 tuple[21] = baseTypeOid == 0 ? null :
connection.encodeString(Integer.toString(connection.getSQLType(baseTypeOid)));
!                     // SOURCE_DATA_TYPE
!             }
!             rs.close();
!         }
!         else {
!             // Domains have been added in PostgreSQL 7.3 so we can simply leave the
!             // additional fields null if we have an older server.
!             for (int i = 0; i < v.size(); i++) {
!                 byte[][] tuple = (byte[][]) v.get(i);
!                 tuple[18] = null;   // SCOPE_CATLOG
!                 tuple[19] = null;   // SCOPE_SCHEMA
!                 tuple[20] = null;   // SCOPE_TABLE
!                 tuple[21] = null;   // SOURCE_DATA_TYPE
!             }
!         }
!         return v;
!     }
!
  }

pgsql-jdbc by date:

Previous
From: Oliver Jowett
Date:
Subject: Re: TypeInfoCache
Next
From: Andrew Lazarus
Date:
Subject: Re: concat returns null