From: Bruce Momjian Date: Mon, 10 Sep 2001 14:55:08 +0000 (+0000) Subject: On Fri, 07 Sep 2001 01:34:46 -0400, Tom Lane wrote: X-Git-Tag: REL7_2_BETA1~449 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6b50f9af333a2795b82dd3331df55c7e703f1bea;p=postgresql On Fri, 07 Sep 2001 01:34:46 -0400, Tom Lane wrote: >there is still an unpatched reference to pg_description in >getColumns(), in both jdbc1 and jdbc2. This was introduced by Jeroen's patch (see http://fts.postgresql.org/db/mw/msg.html?mid=1032468). Attached is a patch that returns getColumns() to using "select obj_description()" instead of direct access to pg_description, as per the request by Tom. I've incorporated Jeroen's fix to left outer join with pg_attrdef instead of inner join, so getColumns() also returns columns without a default value. I have, however, not included Jeroen's attempt to combine multiple queries into one huge multi-join query for better performance, because: 1) I don't know how to do that using obj_description() instead of direct access to pg_description 2) I don't think a performance improvement (if any) in this method is very important Because of the outer join, getColumns() will only work with a backend >= 7.1. Since the conditional coding for 7.1/7.2 and jdbc1/jdbc2 is already giving me headaches I didn't pursue a pre-7.1 solution. Regards, Ren? Pijlman --- diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/DatabaseMetaData.java b/src/interfaces/jdbc/org/postgresql/jdbc1/DatabaseMetaData.java index 986df4ed73..5ee83af8e4 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc1/DatabaseMetaData.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc1/DatabaseMetaData.java @@ -13,7 +13,7 @@ import org.postgresql.util.PSQLException; /** * This class provides information about the database as a whole. * - * $Id: DatabaseMetaData.java,v 1.31 2001/09/06 12:53:15 momjian Exp $ + * $Id: DatabaseMetaData.java,v 1.32 2001/09/10 14:55:08 momjian Exp $ * *

Many of the methods here return lists of information in ResultSets. You * can use the normal ResultSet methods such as getString and getInt to @@ -1895,19 +1895,21 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData */ public java.sql.ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { + // the field descriptors for the new ResultSet + Field f[] = new Field[18]; + java.sql.ResultSet r; // ResultSet for the SQL query that we need to do 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(connection, "TABLE_CAT", iVarcharOid, 32); - f[ 1] = new Field(connection, "TABLE_SCHEM", iVarcharOid, 32); - f[ 2] = new Field(connection, "TABLE_NAME", iVarcharOid, 32); - f[ 3] = new Field(connection, "COLUMN_NAME", iVarcharOid, 32); - f[ 4] = new Field(connection, "DATA_TYPE", iInt2Oid, 2); - f[ 5] = new Field(connection, "TYPE_NAME", iVarcharOid, 32); - f[ 6] = new Field(connection, "COLUMN_SIZE", iInt4Oid, 4); - f[ 7] = new Field(connection, "BUFFER_LENGTH", iVarcharOid, 32); - f[ 8] = new Field(connection, "DECIMAL_DIGITS", iInt4Oid, 4); - f[ 9] = new Field(connection, "NUM_PREC_RADIX", iInt4Oid, 4); + + f[0] = new Field(connection, "TABLE_CAT", iVarcharOid, 32); + f[1] = new Field(connection, "TABLE_SCHEM", iVarcharOid, 32); + f[2] = new Field(connection, "TABLE_NAME", iVarcharOid, 32); + f[3] = new Field(connection, "COLUMN_NAME", iVarcharOid, 32); + f[4] = new Field(connection, "DATA_TYPE", iInt2Oid, 2); + f[5] = new Field(connection, "TYPE_NAME", iVarcharOid, 32); + f[6] = new Field(connection, "COLUMN_SIZE", iInt4Oid, 4); + f[7] = new Field(connection, "BUFFER_LENGTH", iVarcharOid, 32); + f[8] = new Field(connection, "DECIMAL_DIGITS", iInt4Oid, 4); + f[9] = new Field(connection, "NUM_PREC_RADIX", iInt4Oid, 4); f[10] = new Field(connection, "NULLABLE", iInt4Oid, 4); f[11] = new Field(connection, "REMARKS", iVarcharOid, 32); f[12] = new Field(connection, "COLUMN_DEF", iVarcharOid, 32); @@ -1917,105 +1919,93 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData f[16] = new Field(connection, "ORDINAL_POSITION", iInt4Oid,4); f[17] = new Field(connection, "IS_NULLABLE", iVarcharOid, 32); - StringBuffer sql = new StringBuffer(512); - - sql.append("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, " + - " t.typname, " + - " e.description " + - "from" + - " (" + - " (pg_class c inner join pg_attribute a on" + - " (" + - " a.attrelid=c.oid"); - - if ((tableNamePattern != null) && ! tableNamePattern.equals("%")) { - sql.append(" and c.relname like \'" + tableNamePattern + "\'"); - } + // Added by Stefan Andreasen + // If the pattern are null then set them to % + if (tableNamePattern == null) tableNamePattern="%"; + if (columnNamePattern == null) columnNamePattern="%"; - if ((columnNamePattern != null) && ! columnNamePattern.equals("%")) { - sql.append(" and a.attname like \'" + 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 inner join pg_attribute a " + + "on (c.oid=a.attrelid) ) " + + "left outer join pg_attrdef d " + + "on (c.oid=d.adrelid and d.adnum=a.attnum) " + + "where " + + "c.relname like '"+tableNamePattern.toLowerCase()+"' and " + + "a.attname like '"+columnNamePattern.toLowerCase()+"' and " + + "a.attnum>0 " + + "order by c.relname,a.attnum"; + + r = connection.ExecSQL(query); - sql.append( - " and a.attnum > 0" + - " )" + - " ) inner join pg_type t on" + - " (" + - " t.oid = a.atttypid" + - " )" + - " )" + - " left outer join pg_attrdef d on" + - " (" + - " c.oid = d.adrelid" + - " and a.attnum = d.adnum" + - " )" + - " left outer join pg_description e on" + - " (" + - " e.objoid = a.attrelid"); - - if (connection.haveMinimumServerVersion("7.2")) { - sql.append( - " and e.objsubid = a.attnum" + - " and e.classoid = (select oid from pg_class where relname = \'pg_class\')"); - } + while(r.next()) { + byte[][] tuple = new byte[18][0]; - sql.append( - " ) " + - "order by" + - " c.relname, a.attnum"); - - java.sql.ResultSet r = connection.ExecSQL(sql.toString()); - while (r.next()) { - byte[][] tuple = new byte[18][0]; - - String nullFlag = r.getString(6); - String typname = r.getString(10); - - tuple[0] = "".getBytes(); // Catalog name - tuple[1] = "".getBytes(); // Schema name - tuple[2] = r.getBytes(2); // Table name - tuple[3] = r.getBytes(3); // Column name - tuple[4] = Integer.toString(connection.getSQLType(typname)).getBytes(); // Data type - tuple[5] = typname.getBytes(); // Type name - - // Column size - // Looking at the psql source, - // I think the length of a varchar as specified when the table was created - // should be extracted from atttypmod which contains this length + sizeof(int32) - if (typname.equals("bpchar") || typname.equals("varchar")) { - int atttypmod = r.getInt(8); - tuple[6] = Integer.toString(atttypmod != -1 ? atttypmod - VARHDRSZ : 0).getBytes(); - } else { - tuple[6] = r.getBytes(7); - } - - tuple[7] = null; // Buffer length - tuple[8] = "0".getBytes(); // Decimal Digits - how to get this? - tuple[9] = "10".getBytes(); // Num Prec Radix - assume decimal - tuple[10] = Integer.toString(nullFlag.equals("f") ? - java.sql.DatabaseMetaData.columnNullable : - java.sql.DatabaseMetaData.columnNoNulls).getBytes(); // Nullable - tuple[11] = r.getBytes(11); // Description (if any) - tuple[12] = r.getBytes(9); // Column default - tuple[13] = null; // sql data type (unused) - tuple[14] = null; // sql datetime sub (unused) - tuple[15] = tuple[6]; // char octet length - tuple[16] = r.getBytes(5); // ordinal position - tuple[17] = (nullFlag.equals("f") ? "YES" : "NO").getBytes(); // Is nullable - - v.addElement(tuple); - } - r.close(); + // 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 + tuple[1] = "".getBytes(); // Schema name + tuple[2] = r.getBytes(2); // Table name + tuple[3] = r.getBytes(3); // Column name + + dr = connection.ExecSQL("select typname from pg_type where oid = "+r.getString(4)); + dr.next(); + String typname=dr.getString(1); + dr.close(); + tuple[4] = Integer.toString(connection.getSQLType(typname)).getBytes(); // Data type + tuple[5] = typname.getBytes(); // Type name + + // Column size + // Looking at the psql source, + // I think the length of a varchar as specified when the table was created + // should be extracted from atttypmod which contains this length + sizeof(int32) + if (typname.equals("bpchar") || typname.equals("varchar")) { + int atttypmod = r.getInt(8); + tuple[6] = Integer.toString(atttypmod != -1 ? atttypmod - VARHDRSZ : 0).getBytes(); + } else + tuple[6] = r.getBytes(7); + + tuple[7] = null; // Buffer length + + tuple[8] = "0".getBytes(); // Decimal Digits - how to get this? + tuple[9] = "10".getBytes(); // Num Prec Radix - assume decimal + + // tuple[10] is below + // tuple[11] is above + + tuple[12] = r.getBytes(9); // column default + + tuple[13] = null; // sql data type (unused) + tuple[14] = null; // sql datetime sub (unused) + + tuple[15] = tuple[6]; // char octet length + + tuple[16] = r.getBytes(5); // ordinal position + + String nullFlag = r.getString(6); + tuple[10] = Integer.toString(nullFlag.equals("f")?java.sql.DatabaseMetaData.columnNullable:java.sql.DatabaseMetaData.columnNoNulls).getBytes(); // Nullable + tuple[17] = (nullFlag.equals("f")?"YES":"NO").getBytes(); // is nullable + + v.addElement(tuple); + } + r.close(); return new ResultSet(connection, f, v, "OK", 1); } diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/DatabaseMetaData.java b/src/interfaces/jdbc/org/postgresql/jdbc2/DatabaseMetaData.java index 4d39f87dae..8ff2a3f6b4 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc2/DatabaseMetaData.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/DatabaseMetaData.java @@ -13,7 +13,7 @@ import org.postgresql.util.PSQLException; /** * This class provides information about the database as a whole. * - * $Id: DatabaseMetaData.java,v 1.35 2001/09/06 12:53:15 momjian Exp $ + * $Id: DatabaseMetaData.java,v 1.36 2001/09/10 14:55:08 momjian Exp $ * *

Many of the methods here return lists of information in ResultSets. You * can use the normal ResultSet methods such as getString and getInt to @@ -1895,19 +1895,21 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData */ public java.sql.ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { + // the field descriptors for the new ResultSet + Field f[] = new Field[18]; + java.sql.ResultSet r; // ResultSet for the SQL query that we need to do 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(connection, "TABLE_CAT", iVarcharOid, 32); - f[ 1] = new Field(connection, "TABLE_SCHEM", iVarcharOid, 32); - f[ 2] = new Field(connection, "TABLE_NAME", iVarcharOid, 32); - f[ 3] = new Field(connection, "COLUMN_NAME", iVarcharOid, 32); - f[ 4] = new Field(connection, "DATA_TYPE", iInt2Oid, 2); - f[ 5] = new Field(connection, "TYPE_NAME", iVarcharOid, 32); - f[ 6] = new Field(connection, "COLUMN_SIZE", iInt4Oid, 4); - f[ 7] = new Field(connection, "BUFFER_LENGTH", iVarcharOid, 32); - f[ 8] = new Field(connection, "DECIMAL_DIGITS", iInt4Oid, 4); - f[ 9] = new Field(connection, "NUM_PREC_RADIX", iInt4Oid, 4); + + f[0] = new Field(connection, "TABLE_CAT", iVarcharOid, 32); + f[1] = new Field(connection, "TABLE_SCHEM", iVarcharOid, 32); + f[2] = new Field(connection, "TABLE_NAME", iVarcharOid, 32); + f[3] = new Field(connection, "COLUMN_NAME", iVarcharOid, 32); + f[4] = new Field(connection, "DATA_TYPE", iInt2Oid, 2); + f[5] = new Field(connection, "TYPE_NAME", iVarcharOid, 32); + f[6] = new Field(connection, "COLUMN_SIZE", iInt4Oid, 4); + f[7] = new Field(connection, "BUFFER_LENGTH", iVarcharOid, 32); + f[8] = new Field(connection, "DECIMAL_DIGITS", iInt4Oid, 4); + f[9] = new Field(connection, "NUM_PREC_RADIX", iInt4Oid, 4); f[10] = new Field(connection, "NULLABLE", iInt4Oid, 4); f[11] = new Field(connection, "REMARKS", iVarcharOid, 32); f[12] = new Field(connection, "COLUMN_DEF", iVarcharOid, 32); @@ -1917,105 +1919,93 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData f[16] = new Field(connection, "ORDINAL_POSITION", iInt4Oid,4); f[17] = new Field(connection, "IS_NULLABLE", iVarcharOid, 32); - StringBuffer sql = new StringBuffer(512); - - sql.append("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, " + - " t.typname, " + - " e.description " + - "from" + - " (" + - " (pg_class c inner join pg_attribute a on" + - " (" + - " a.attrelid=c.oid"); - - if ((tableNamePattern != null) && ! tableNamePattern.equals("%")) { - sql.append(" and c.relname like \'" + tableNamePattern + "\'"); - } + // Added by Stefan Andreasen + // If the pattern are null then set them to % + if (tableNamePattern == null) tableNamePattern="%"; + if (columnNamePattern == null) columnNamePattern="%"; - if ((columnNamePattern != null) && ! columnNamePattern.equals("%")) { - sql.append(" and a.attname like \'" + 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 inner join pg_attribute a " + + "on (c.oid=a.attrelid) ) " + + "left outer join pg_attrdef d " + + "on (c.oid=d.adrelid and d.adnum=a.attnum) " + + "where " + + "c.relname like '"+tableNamePattern.toLowerCase()+"' and " + + "a.attname like '"+columnNamePattern.toLowerCase()+"' and " + + "a.attnum>0 " + + "order by c.relname,a.attnum"; + + r = connection.ExecSQL(query); - sql.append( - " and a.attnum > 0" + - " )" + - " ) inner join pg_type t on" + - " (" + - " t.oid = a.atttypid" + - " )" + - " )" + - " left outer join pg_attrdef d on" + - " (" + - " c.oid = d.adrelid" + - " and a.attnum = d.adnum" + - " )" + - " left outer join pg_description e on" + - " (" + - " e.objoid = a.attrelid"); - - if (connection.haveMinimumServerVersion("7.2")) { - sql.append( - " and e.objsubid = a.attnum" + - " and e.classoid = (select oid from pg_class where relname = \'pg_class\')"); - } + while(r.next()) { + byte[][] tuple = new byte[18][0]; - sql.append( - " ) " + - "order by" + - " c.relname, a.attnum"); - - java.sql.ResultSet r = connection.ExecSQL(sql.toString()); - while (r.next()) { - byte[][] tuple = new byte[18][0]; - - String nullFlag = r.getString(6); - String typname = r.getString(10); - - tuple[0] = "".getBytes(); // Catalog name - tuple[1] = "".getBytes(); // Schema name - tuple[2] = r.getBytes(2); // Table name - tuple[3] = r.getBytes(3); // Column name - tuple[4] = Integer.toString(connection.getSQLType(typname)).getBytes(); // Data type - tuple[5] = typname.getBytes(); // Type name - - // Column size - // Looking at the psql source, - // I think the length of a varchar as specified when the table was created - // should be extracted from atttypmod which contains this length + sizeof(int32) - if (typname.equals("bpchar") || typname.equals("varchar")) { - int atttypmod = r.getInt(8); - tuple[6] = Integer.toString(atttypmod != -1 ? atttypmod - VARHDRSZ : 0).getBytes(); - } else { - tuple[6] = r.getBytes(7); - } - - tuple[7] = null; // Buffer length - tuple[8] = "0".getBytes(); // Decimal Digits - how to get this? - tuple[9] = "10".getBytes(); // Num Prec Radix - assume decimal - tuple[10] = Integer.toString(nullFlag.equals("f") ? - java.sql.DatabaseMetaData.columnNullable : - java.sql.DatabaseMetaData.columnNoNulls).getBytes(); // Nullable - tuple[11] = r.getBytes(11); // Description (if any) - tuple[12] = r.getBytes(9); // Column default - tuple[13] = null; // sql data type (unused) - tuple[14] = null; // sql datetime sub (unused) - tuple[15] = tuple[6]; // char octet length - tuple[16] = r.getBytes(5); // ordinal position - tuple[17] = (nullFlag.equals("f") ? "YES" : "NO").getBytes(); // Is nullable - - v.addElement(tuple); - } - r.close(); + // 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 + tuple[1] = "".getBytes(); // Schema name + tuple[2] = r.getBytes(2); // Table name + tuple[3] = r.getBytes(3); // Column name + + dr = connection.ExecSQL("select typname from pg_type where oid = "+r.getString(4)); + dr.next(); + String typname=dr.getString(1); + dr.close(); + tuple[4] = Integer.toString(connection.getSQLType(typname)).getBytes(); // Data type + tuple[5] = typname.getBytes(); // Type name + + // Column size + // Looking at the psql source, + // I think the length of a varchar as specified when the table was created + // should be extracted from atttypmod which contains this length + sizeof(int32) + if (typname.equals("bpchar") || typname.equals("varchar")) { + int atttypmod = r.getInt(8); + tuple[6] = Integer.toString(atttypmod != -1 ? atttypmod - VARHDRSZ : 0).getBytes(); + } else + tuple[6] = r.getBytes(7); + + tuple[7] = null; // Buffer length + + tuple[8] = "0".getBytes(); // Decimal Digits - how to get this? + tuple[9] = "10".getBytes(); // Num Prec Radix - assume decimal + + // tuple[10] is below + // tuple[11] is above + + tuple[12] = r.getBytes(9); // column default + + tuple[13] = null; // sql data type (unused) + tuple[14] = null; // sql datetime sub (unused) + + tuple[15] = tuple[6]; // char octet length + + tuple[16] = r.getBytes(5); // ordinal position + + String nullFlag = r.getString(6); + tuple[10] = Integer.toString(nullFlag.equals("f")?java.sql.DatabaseMetaData.columnNullable:java.sql.DatabaseMetaData.columnNoNulls).getBytes(); // Nullable + tuple[17] = (nullFlag.equals("f")?"YES":"NO").getBytes(); // is nullable + + v.addElement(tuple); + } + r.close(); return new ResultSet(connection, f, v, "OK", 1); }