Attached is the patch requested by Tom Lane (see below). It includes two changes in the JDBC driver: 1) When connected to a backend >= 7.2: use obj_description() and col_description() instead of direct access to pg_description. 2) In DatabaseMetaData.getTables()/getColumns()/getProcedures(): when there is no comment on the object, return null in the REMARKS column of the ResultSet, instead of the default string "no remarks". Change 2 first appeared as a side-effect of change 1, but it is actually more compliant with the JDBC spec: "String object containing an explanatory comment on the table/column/procedure, which may be null". The default string "no remarks" was strictly speaking incorrect, as it could not be distinguished from a real user comment "no remarks". So I removed the default string completely. Change 2 might break existing code that doesn't follow the JDBC spec and isn't prepared to handle a null in the REMARKS column of getTables()/getColumns()/getProcedures. Patch tested with jdbc2 against both a 7.1 and a CVS tip backend. I did not have a jdbc1 environment to build and test with, but since the touched code is identical in jdbc1 and jdbc2 I don't foresee any problems. Regards, René Pijlman On Fri, 10 Aug 2001 16:08:50 -0400, Tom Lane wrote: >Would some JDBC hacker develop a patch for the following issue? The >change is just barely large enough that I don't want to commit untested >code for it --- but not having a Java development environment at hand, >I can't test the updated code. > >The problem is in DatabaseMetaData.java (same code in both jdbc1 and >jdbc2, looks like). It does direct access to pg_description that isn't >right anymore. In getTables, instead of > > java.sql.ResultSet dr = connection.ExecSQL("select description from >pg_description where objoid="+r.getInt(2)); > >it should be > > java.sql.ResultSet dr = connection.ExecSQL("select >obj_description("+r.getInt(2)+",'pg_class')"); > >In getColumns, the change is a little more involved, because >pg_attribute doesn't have an OID column anymore. The initial query >can't fetch a.oid, but should fetch a.attrelid instead, and then the >pg_description query should become > > java.sql.ResultSet dr = connection.ExecSQL("select >col_description("+r.getInt(1)+","+r.getInt(5)+")"); > >(col_description takes the table OID and the column's attnum). > >The reason this is more than a 3-line change is that it should be done >either the old way or the new way depending on whether server version >= >7.2 or not, for backwards-compatibility of the driver. > >It's possible there are other similar changes needed that I missed in a >quick lookover. > >So, would some enterprising person fix the JDBC code to work with CVS >tip, and submit a patch? > > thanks, tom lane > >---------------------------(end of broadcast)--------------------------- >TIP 3: if posting/reading through Usenet, please send an appropriate >subscribe-nomail command to [EMAIL PROTECTED] so that your >message can get through to the mailing list cleanly Regards, René Pijlman
Index: src/interfaces/jdbc/org/postgresql/jdbc1/DatabaseMetaData.java =================================================================== RCS file: /home/projects/pgsql/cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/DatabaseMetaData.java,v retrieving revision 1.24 diff -c -r1.24 DatabaseMetaData.java *** src/interfaces/jdbc/org/postgresql/jdbc1/DatabaseMetaData.java 2001/08/04 19:32:04 1.24 --- src/interfaces/jdbc/org/postgresql/jdbc1/DatabaseMetaData.java 2001/08/13 17:31:51 *************** *** 43,52 **** static final int iInt4Oid = 23; // OID for int4 static final int VARHDRSZ = 4; // length for int4 - // This is a default value for remarks - private static final byte defaultRemarks[]="no remarks".getBytes(); - - public DatabaseMetaData(Connection conn) { this.connection = conn; --- 43,48 ---- *************** *** 1517,1524 **** java.sql.ResultSet r; // ResultSet for the SQL query that we need to do Vector v = new Vector(); // The new ResultSet tuple stuff - byte remarks[] = defaultRemarks; - f[0] = new Field(connection, "PROCEDURE_CAT", iVarcharOid, 32); f[1] = new Field(connection, "PROCEDURE_SCHEM", iVarcharOid, 32); f[2] = new Field(connection, "PROCEDURE_NAME", iVarcharOid, 32); --- 1513,1518 ---- *************** *** 1540,1546 **** tuple[1] = null; // Schema name tuple[2] = r.getBytes(1); // Procedure name tuple[3] = tuple[4] = tuple[5] = null; // Reserved ! tuple[6] = remarks; // Remarks if (r.getBoolean(2)) tuple[7] = Integer.toString(java.sql.DatabaseMetaData.procedureReturnsResult).getBytes(); --- 1534,1540 ---- tuple[1] = null; // Schema name tuple[2] = r.getBytes(1); // Procedure name tuple[3] = tuple[4] = tuple[5] = null; // Reserved ! tuple[6] = null; // Remarks if (r.getBoolean(2)) tuple[7] = Integer.toString(java.sql.DatabaseMetaData.procedureReturnsResult).getBytes(); *************** *** 1684,1689 **** --- 1678,1684 ---- // Now form the query StringBuffer sql = new StringBuffer("select relname,oid,relkind from pg_class where ("); + boolean notFirst=false; for(int i=0;i<types.length;i++) { for(int j=0;j<getTableTypes.length;j++) *************** *** 1704,1722 **** // Now run the query r = connection.ExecSQL(sql.toString()); - byte remarks[]; - while (r.next()) { byte[][] tuple = new byte[5][0]; // Fetch the description for the table (if any) ! java.sql.ResultSet dr = connection.ExecSQL("select description from pg_description where objoid="+r.getInt(2)); if(((org.postgresql.ResultSet)dr).getTupleCount()==1) { dr.next(); remarks = dr.getBytes(1); ! } else ! remarks = defaultRemarks; dr.close(); String relKind; --- 1699,1722 ---- // Now run the query r = connection.ExecSQL(sql.toString()); while (r.next()) { byte[][] tuple = new byte[5][0]; // Fetch the description for the table (if any) ! String getDescriptionStatement = ! connection.haveMinimumServerVersion("7.2") ? ! "select obj_description("+r.getInt(2)+",'pg_class')" : ! "select description from pg_description where objoid=" + r.getInt(2); ! ! java.sql.ResultSet dr = connection.ExecSQL(getDescriptionStatement); ! ! byte remarks[] = null; ! if(((org.postgresql.ResultSet)dr).getTupleCount()==1) { dr.next(); remarks = dr.getBytes(1); ! } dr.close(); String relKind; *************** *** 1919,1940 **** if (columnNamePattern == null) columnNamePattern="%"; // Now form the query ! // Modified by Stefan Andreasen <[EMAIL PROTECTED]> ! r = connection.ExecSQL("select a.oid,c.relname,a.attname,a.atttypid,a.attnum,a.attnotnull,a.attlen,a.atttypmod,d.adsrc from pg_class c,pg_attribute a,pg_attrdef d where a.attrelid=c.oid and c.relname like '"+tableNamePattern.toLowerCase()+"' and a.attname like '"+columnNamePattern.toLowerCase()+"' and a.attnum>0 and c.oid=d.adrelid and d.adnum=a.attnum order by c.relname,a.attnum"); ! byte remarks[]; while(r.next()) { byte[][] tuple = new byte[18][0]; // Fetch the description for the table (if any) ! java.sql.ResultSet dr = connection.ExecSQL("select description from pg_description where objoid="+r.getInt(1)); if(((org.postgresql.ResultSet)dr).getTupleCount()==1) { dr.next(); tuple[11] = dr.getBytes(1); } else ! tuple[11] = defaultRemarks; ! dr.close(); tuple[0] = "".getBytes(); // Catalog name --- 1919,1953 ---- if (columnNamePattern == null) columnNamePattern="%"; // Now form the query ! String query = ! "select " + ! (connection.haveMinimumServerVersion("7.2") ? "a.attrelid" : "a.oid") + ! ",c.relname,a.attname,a.atttypid," + ! "a.attnum,a.attnotnull,a.attlen,a.atttypmod,d.adsrc from pg_class c," + ! "pg_attribute a,pg_attrdef d where a.attrelid=c.oid and " + ! "c.relname like '"+tableNamePattern.toLowerCase()+"' and " + ! "a.attname like '"+columnNamePattern.toLowerCase()+"' and " + ! "a.attnum>0 and c.oid=d.adrelid and d.adnum=a.attnum " + ! "order by c.relname,a.attnum"; ! r = connection.ExecSQL(query); while(r.next()) { byte[][] tuple = new byte[18][0]; // Fetch the description for the table (if any) ! String getDescriptionStatement = ! connection.haveMinimumServerVersion("7.2") ? ! "select col_description(" + r.getInt(1) + "," + r.getInt(5) + ")" : ! "select description from pg_description where objoid=" + r.getInt(1); ! ! java.sql.ResultSet dr = connection.ExecSQL(getDescriptionStatement); ! if(((org.postgresql.ResultSet)dr).getTupleCount()==1) { dr.next(); tuple[11] = dr.getBytes(1); } else ! tuple[11] = null; dr.close(); tuple[0] = "".getBytes(); // Catalog name *************** *** 1985,1991 **** r.close(); return new ResultSet(connection, f, v, "OK", 1); } - /** * Get a description of the access rights for a table's columns. * --- 1998,2003 ---- Index: src/interfaces/jdbc/org/postgresql/jdbc2/DatabaseMetaData.java =================================================================== RCS file: /home/projects/pgsql/cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/DatabaseMetaData.java,v retrieving revision 1.27 diff -c -r1.27 DatabaseMetaData.java *** src/interfaces/jdbc/org/postgresql/jdbc2/DatabaseMetaData.java 2001/08/04 19:32:04 1.27 --- src/interfaces/jdbc/org/postgresql/jdbc2/DatabaseMetaData.java 2001/08/13 17:31:51 *************** *** 43,52 **** static final int iInt4Oid = 23; // OID for int4 static final int VARHDRSZ = 4; // length for int4 - // This is a default value for remarks - private static final byte defaultRemarks[]="no remarks".getBytes(); - - public DatabaseMetaData(Connection conn) { this.connection = conn; --- 43,48 ---- *************** *** 1517,1524 **** java.sql.ResultSet r; // ResultSet for the SQL query that we need to do Vector v = new Vector(); // The new ResultSet tuple stuff - byte remarks[] = defaultRemarks; - f[0] = new Field(connection, "PROCEDURE_CAT", iVarcharOid, 32); f[1] = new Field(connection, "PROCEDURE_SCHEM", iVarcharOid, 32); f[2] = new Field(connection, "PROCEDURE_NAME", iVarcharOid, 32); --- 1513,1518 ---- *************** *** 1540,1546 **** tuple[1] = null; // Schema name tuple[2] = r.getBytes(1); // Procedure name tuple[3] = tuple[4] = tuple[5] = null; // Reserved ! tuple[6] = remarks; // Remarks if (r.getBoolean(2)) tuple[7] = Integer.toString(java.sql.DatabaseMetaData.procedureReturnsResult).getBytes(); --- 1534,1540 ---- tuple[1] = null; // Schema name tuple[2] = r.getBytes(1); // Procedure name tuple[3] = tuple[4] = tuple[5] = null; // Reserved ! tuple[6] = null; if (r.getBoolean(2)) tuple[7] = Integer.toString(java.sql.DatabaseMetaData.procedureReturnsResult).getBytes(); *************** *** 1684,1689 **** --- 1678,1684 ---- // Now form the query StringBuffer sql = new StringBuffer("select relname,oid,relkind from pg_class where ("); + boolean notFirst=false; for(int i=0;i<types.length;i++) { for(int j=0;j<getTableTypes.length;j++) *************** *** 1704,1722 **** // Now run the query r = connection.ExecSQL(sql.toString()); - byte remarks[]; - while (r.next()) { byte[][] tuple = new byte[5][0]; // Fetch the description for the table (if any) ! java.sql.ResultSet dr = connection.ExecSQL("select description from pg_description where objoid="+r.getInt(2)); if(((org.postgresql.ResultSet)dr).getTupleCount()==1) { dr.next(); remarks = dr.getBytes(1); ! } else ! remarks = defaultRemarks; dr.close(); String relKind; --- 1699,1722 ---- // Now run the query r = connection.ExecSQL(sql.toString()); while (r.next()) { byte[][] tuple = new byte[5][0]; // Fetch the description for the table (if any) ! String getDescriptionStatement = ! connection.haveMinimumServerVersion("7.2") ? ! "select obj_description("+r.getInt(2)+",'pg_class')" : ! "select description from pg_description where objoid=" + r.getInt(2); ! ! java.sql.ResultSet dr = connection.ExecSQL(getDescriptionStatement); ! ! byte remarks[] = null; ! if(((org.postgresql.ResultSet)dr).getTupleCount()==1) { dr.next(); remarks = dr.getBytes(1); ! } dr.close(); String relKind; *************** *** 1919,1940 **** if (columnNamePattern == null) columnNamePattern="%"; // Now form the query ! // Modified by Stefan Andreasen <[EMAIL PROTECTED]> ! r = connection.ExecSQL("select a.oid,c.relname,a.attname,a.atttypid,a.attnum,a.attnotnull,a.attlen,a.atttypmod,d.adsrc from pg_class c,pg_attribute a,pg_attrdef d where a.attrelid=c.oid and c.relname like '"+tableNamePattern.toLowerCase()+"' and a.attname like '"+columnNamePattern.toLowerCase()+"' and a.attnum>0 and c.oid=d.adrelid and d.adnum=a.attnum order by c.relname,a.attnum"); ! byte remarks[]; while(r.next()) { byte[][] tuple = new byte[18][0]; // Fetch the description for the table (if any) ! java.sql.ResultSet dr = connection.ExecSQL("select description from pg_description where objoid="+r.getInt(1)); if(((org.postgresql.ResultSet)dr).getTupleCount()==1) { dr.next(); tuple[11] = dr.getBytes(1); } else ! tuple[11] = defaultRemarks; ! dr.close(); tuple[0] = "".getBytes(); // Catalog name --- 1919,1953 ---- if (columnNamePattern == null) columnNamePattern="%"; // Now form the query ! String query = ! "select " + ! (connection.haveMinimumServerVersion("7.2") ? "a.attrelid" : "a.oid") + ! ",c.relname,a.attname,a.atttypid," + ! "a.attnum,a.attnotnull,a.attlen,a.atttypmod,d.adsrc from pg_class c," + ! "pg_attribute a,pg_attrdef d where a.attrelid=c.oid and " + ! "c.relname like '"+tableNamePattern.toLowerCase()+"' and " + ! "a.attname like '"+columnNamePattern.toLowerCase()+"' and " + ! "a.attnum>0 and c.oid=d.adrelid and d.adnum=a.attnum " + ! "order by c.relname,a.attnum"; ! r = connection.ExecSQL(query); while(r.next()) { byte[][] tuple = new byte[18][0]; // Fetch the description for the table (if any) ! String getDescriptionStatement = ! connection.haveMinimumServerVersion("7.2") ? ! "select col_description(" + r.getInt(1) + "," + r.getInt(5) + ")" : ! "select description from pg_description where objoid=" + r.getInt(1); ! ! java.sql.ResultSet dr = connection.ExecSQL(getDescriptionStatement); ! if(((org.postgresql.ResultSet)dr).getTupleCount()==1) { dr.next(); tuple[11] = dr.getBytes(1); } else ! tuple[11] = null; dr.close(); tuple[0] = "".getBytes(); // Catalog name
---------------------------(end of broadcast)--------------------------- TIP 3: if posting/reading through Usenet, please send an appropriate subscribe-nomail command to [EMAIL PROTECTED] so that your message can get through to the mailing list cleanly