diff -rcN -xCVS src/interfaces/jdbc/org/postgresql/core/BaseStatement.java src/interfaces/rsmdjdbc/org/postgresql/core/BaseStatement.java *** src/interfaces/jdbc/org/postgresql/core/BaseStatement.java Sat Nov 29 11:52:09 2003 --- src/interfaces/rsmdjdbc/org/postgresql/core/BaseStatement.java Tue Dec 30 01:12:46 2003 *************** *** 18,23 **** --- 18,25 ---- public interface BaseStatement extends org.postgresql.PGStatement { + public BaseResultSet createDriverResultSet(Field[] fields, Vector tuples) throws SQLException; + public BaseResultSet createResultSet(Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException; public PGRefCursorResultSet createRefCursorResultSet(String cursorName) throws SQLException; diff -rcN -xCVS src/interfaces/jdbc/org/postgresql/core/Field.java src/interfaces/rsmdjdbc/org/postgresql/core/Field.java *** src/interfaces/jdbc/org/postgresql/core/Field.java Sat Nov 29 11:52:09 2003 --- src/interfaces/rsmdjdbc/org/postgresql/core/Field.java Tue Dec 30 01:41:53 2003 *************** *** 13,18 **** --- 13,19 ---- package org.postgresql.core; import java.sql.*; + import org.postgresql.core.BaseConnection; /* *************** *** 22,28 **** private int length; // Internal Length of this field private int oid; // OID of the type private int mod; // type modifier of this field ! private String name; // Name of this field private BaseConnection conn; // Connection Instantation --- 23,36 ---- private int length; // Internal Length of this field private int oid; // OID of the type private int mod; // type modifier of this field ! private String name; // Name of this field (the column label) ! private int tableOid; // OID of table ( zero if no table ) ! private int positionInTable; ! private boolean fromServer; // Did this field come from a query? ! ! // cache-fields ! private Integer nullable; ! private String columnName; private BaseConnection conn; // Connection Instantation *************** *** 37,47 **** */ public Field(BaseConnection conn, String name, int oid, int length, int mod) { ! this.conn = conn; ! this.name = name; ! this.oid = oid; ! this.length = length; ! this.mod = mod; } /* --- 45,51 ---- */ public Field(BaseConnection conn, String name, int oid, int length, int mod) { ! this(conn, name, oid, length, mod, 0, 0); } /* *************** *** 58,63 **** --- 62,89 ---- } /* + * Construct a field based on the information fed to it. + * + * @param conn the connection this field came from + * @param name the name of the field + * @param oid the OID of the field + * @param length the length of the field + * @param tableOid the OID of the columns' table + * @param positionInTable the position of column in the table (first column is 1, second column is 2, etc...) + */ + public Field(BaseConnection conn, String name, int oid, int length, int mod, int tableOid, int positionInTable) + { + this.conn = conn; + this.name = name; + this.oid = oid; + this.length = length; + this.mod = mod; + this.tableOid = tableOid; + this.positionInTable = positionInTable; + this.fromServer = true; + } + + /* * @return the oid of this Field's data type */ public int getOID() *************** *** 101,109 **** } /* ! * We also need to get the java.sql.types type. * ! * @return the int representation of the java.sql.types type of this field * @exception SQLException if a database access error occurs */ public int getSQLType() throws SQLException --- 127,135 ---- } /* ! * We also need to get the java.sql.Types type. * ! * @return the int representation of the java.sql.Types type of this field * @exception SQLException if a database access error occurs */ public int getSQLType() throws SQLException *************** *** 111,114 **** --- 137,243 ---- return conn.getSQLType(oid); } + /** + * Specify if this field was created from a server query + * or the driver manually creating a ResultSet. + */ + public void setFromServer(boolean fromServer) + { + this.fromServer = fromServer; + } + + /* + * @return the columns' table oid, zero if no oid available + */ + public int getTableOid() + { + return tableOid; + } + + /* + * @return instantiated connection + */ + public BaseConnection getConn() + { + return conn; + } + + public int getPositionInTable() + { + return positionInTable; + } + + public int getNullable() throws SQLException + { + if (nullable != null) + { + return nullable.intValue(); + } + if (tableOid == 0) + { + nullable = new Integer(ResultSetMetaData.columnNullableUnknown); + return nullable.intValue(); + } + Connection con = (Connection) conn; + ResultSet res = null; + PreparedStatement ps = null; + try + { + ps = con.prepareStatement("SELECT attnotnull FROM pg_catalog.pg_attribute WHERE attrelid = ? AND attnum = ?;"); + ps.setInt(1, tableOid); + ps.setInt(2, positionInTable); + res = ps.executeQuery(); + int nullResult = ResultSetMetaData.columnNullableUnknown; + if (res.next()) + { + nullResult = res.getBoolean(1) ? ResultSetMetaData.columnNoNulls : ResultSetMetaData.columnNullable; + } + nullable = new Integer(nullResult); + return nullResult; + } finally + { + if (res != null) + res.close(); + if (ps != null) + ps.close(); + } + } + + public String getColumnName() throws SQLException + { + if (conn.getPGProtocolVersionMajor() < 3 || !fromServer) { + return name; + } + if (columnName != null) + { + return columnName; + } + if (tableOid == 0) + { + return columnName = ""; + } + Connection con = (Connection) conn; + ResultSet res = null; + PreparedStatement ps = null; + try + { + ps = con.prepareStatement("SELECT attname FROM pg_catalog.pg_attribute WHERE attrelid = ? AND attnum = ?"); + ps.setInt(1, tableOid); + ps.setInt(2, positionInTable); + res = ps.executeQuery(); + String columnName = ""; + if (res.next()) + { + columnName = res.getString(1); + } + return columnName; + } finally + { + if (res != null) + res.close(); + if (ps != null) + ps.close(); + } + } + } diff -rcN -xCVS src/interfaces/jdbc/org/postgresql/core/QueryExecutor.java src/interfaces/rsmdjdbc/org/postgresql/core/QueryExecutor.java *** src/interfaces/jdbc/org/postgresql/core/QueryExecutor.java Sat Nov 29 11:52:09 2003 --- src/interfaces/rsmdjdbc/org/postgresql/core/QueryExecutor.java Tue Dec 30 01:43:41 2003 *************** *** 468,474 **** private void receiveFieldsV3() throws SQLException { //TODO: use the msgSize - //TODO: use the tableOid, and tablePosition if (fields != null) throw new PSQLException("postgresql.con.multres", PSQLState.CONNECTION_FAILURE); int l_msgSize = pgStream.ReceiveIntegerR(4); --- 468,473 ---- *************** *** 477,491 **** for (int i = 0; i < fields.length; i++) { ! String typeName = pgStream.ReceiveString(connection.getEncoding()); int tableOid = pgStream.ReceiveIntegerR(4); ! int tablePosition = pgStream.ReceiveIntegerR(2); int typeOid = pgStream.ReceiveIntegerR(4); int typeLength = pgStream.ReceiveIntegerR(2); int typeModifier = pgStream.ReceiveIntegerR(4); int formatType = pgStream.ReceiveIntegerR(2); ! //TODO: use the extra values coming back ! fields[i] = new Field(connection, typeName, typeOid, typeLength, typeModifier); } } /* --- 476,489 ---- for (int i = 0; i < fields.length; i++) { ! String columnLabel = pgStream.ReceiveString(connection.getEncoding()); int tableOid = pgStream.ReceiveIntegerR(4); ! short positionInTable = (short)pgStream.ReceiveIntegerR(2); int typeOid = pgStream.ReceiveIntegerR(4); int typeLength = pgStream.ReceiveIntegerR(2); int typeModifier = pgStream.ReceiveIntegerR(4); int formatType = pgStream.ReceiveIntegerR(2); ! fields[i] = new Field(connection, columnLabel, typeOid, typeLength, typeModifier, tableOid, positionInTable); } } /* *************** *** 501,511 **** for (int i = 0; i < fields.length; i++) { ! String typeName = pgStream.ReceiveString(connection.getEncoding()); int typeOid = pgStream.ReceiveIntegerR(4); int typeLength = pgStream.ReceiveIntegerR(2); int typeModifier = pgStream.ReceiveIntegerR(4); ! fields[i] = new Field(connection, typeName, typeOid, typeLength, typeModifier); } } } --- 499,509 ---- for (int i = 0; i < fields.length; i++) { ! String columnLabel = pgStream.ReceiveString(connection.getEncoding()); int typeOid = pgStream.ReceiveIntegerR(4); int typeLength = pgStream.ReceiveIntegerR(2); int typeModifier = pgStream.ReceiveIntegerR(4); ! fields[i] = new Field(connection, columnLabel, typeOid, typeLength, typeModifier); } } } diff -rcN -xCVS src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java src/interfaces/rsmdjdbc/org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java *** src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java Fri Dec 12 10:27:51 2003 --- src/interfaces/rsmdjdbc/org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java Tue Dec 30 01:18:03 2003 *************** *** 1926,1932 **** } rs.close(); ! return (ResultSet) ((BaseStatement)connection.createStatement()).createResultSet(f, v, "OK", 1, 0, false); } /* --- 1926,1932 ---- } rs.close(); ! return (ResultSet) ((BaseStatement)connection.createStatement()).createDriverResultSet(f, v); } /* *************** *** 2218,2224 **** v.addElement(tuple); } ! return (ResultSet) ((BaseStatement)connection.createStatement()).createResultSet(f, v, "OK", 1, 0, false); } /* --- 2218,2224 ---- v.addElement(tuple); } ! return (ResultSet) ((BaseStatement)connection.createStatement()).createDriverResultSet(f, v); } /* *************** *** 2392,2398 **** } rs.close(); ! return (ResultSet) ((BaseStatement)connection.createStatement()).createResultSet(f, v, "OK", 1, 0, false); } /* --- 2392,2398 ---- } rs.close(); ! return (ResultSet) ((BaseStatement)connection.createStatement()).createDriverResultSet(f, v); } /* *************** *** 2505,2511 **** } rs.close(); ! return (ResultSet) ((BaseStatement)connection.createStatement()).createResultSet(f, v, "OK", 1, 0, false); } /* --- 2505,2511 ---- } rs.close(); ! return (ResultSet) ((BaseStatement)connection.createStatement()).createDriverResultSet(f, v); } /* *************** *** 2607,2613 **** } rs.close(); ! return (ResultSet) ((BaseStatement)connection.createStatement()).createResultSet(f, v, "OK", 1, 0, false); } private static void sortStringArray(String s[]) { --- 2607,2613 ---- } rs.close(); ! return (ResultSet) ((BaseStatement)connection.createStatement()).createDriverResultSet(f, v); } private static void sortStringArray(String s[]) { *************** *** 2805,2811 **** v.addElement(tuple); } ! return (ResultSet) ((BaseStatement)connection.createStatement()).createResultSet(f, v, "OK", 1, 0, false); } /* --- 2805,2811 ---- v.addElement(tuple); } ! return (ResultSet) ((BaseStatement)connection.createStatement()).createDriverResultSet(f, v); } /* *************** *** 2875,2881 **** /* Perhaps we should check that the given * catalog.schema.table actually exists. -KJ */ ! return (ResultSet) ((BaseStatement)connection.createStatement()).createResultSet(f, v, "OK", 1, 0, false); } /* --- 2875,2881 ---- /* Perhaps we should check that the given * catalog.schema.table actually exists. -KJ */ ! return (ResultSet) ((BaseStatement)connection.createStatement()).createDriverResultSet(f, v); } /* *************** *** 3249,3255 **** tuples.addElement(tuple); } ! return (ResultSet) ((BaseStatement)connection.createStatement()).createResultSet(f, tuples, "OK", 1, 0, false); } /* --- 3249,3255 ---- tuples.addElement(tuple); } ! return (ResultSet) ((BaseStatement)connection.createStatement()).createDriverResultSet(f, tuples); } /* *************** *** 3534,3540 **** } rs.close(); ! return (ResultSet) ((BaseStatement)connection.createStatement()).createResultSet(f, v, "OK", 1, 0, false); } /* --- 3534,3540 ---- } rs.close(); ! return (ResultSet) ((BaseStatement)connection.createStatement()).createDriverResultSet(f, v); } /* diff -rcN -xCVS src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSetMetaData.java src/interfaces/rsmdjdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSetMetaData.java *** src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSetMetaData.java Fri Sep 12 21:02:15 2003 --- src/interfaces/rsmdjdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSetMetaData.java Tue Dec 30 01:45:12 2003 *************** *** 4,19 **** import org.postgresql.core.Field; import org.postgresql.util.PSQLException; import org.postgresql.util.PSQLState; ! import java.sql.SQLException; ! import java.sql.Types; ! import java.util.Vector; public abstract class AbstractJdbc1ResultSetMetaData { - protected Vector rows; protected Field[] fields; /* * Initialise for a result with a tuple set and * a field descriptor set --- 4,21 ---- import org.postgresql.core.Field; import org.postgresql.util.PSQLException; import org.postgresql.util.PSQLState; ! ! import java.sql.*; ! import java.util.*; public abstract class AbstractJdbc1ResultSetMetaData { protected Vector rows; protected Field[] fields; + private Hashtable tableNameCache; + private Hashtable schemaNameCache; + /* * Initialise for a result with a tuple set and * a field descriptor set *************** *** 131,143 **** */ public int isNullable(int column) throws SQLException { ! /* ! * TODO This needs a real implementation, taking into account columns ! * defined with NOT NULL or PRIMARY KEY, CHECK constraints, views, ! * functions etc. ! */ ! return java.sql.ResultSetMetaData.columnNullableUnknown; ! } /* * Is the column a signed number? In PostgreSQL, all numbers --- 133,141 ---- */ public int isNullable(int column) throws SQLException { ! Field field = getField(column); ! return field.getNullable(); ! } /* * Is the column a signed number? In PostgreSQL, all numbers *************** *** 225,240 **** } /* - * What is the suggested column title for use in printouts and - * displays? We suggest the ColumnName! - * * @param column the first column is 1, the second is 2, etc. * @return the column label * @exception SQLException if a database access error occurs */ public String getColumnLabel(int column) throws SQLException { ! return getColumnName(column); } /* --- 223,238 ---- } /* * @param column the first column is 1, the second is 2, etc. * @return the column label * @exception SQLException if a database access error occurs */ public String getColumnLabel(int column) throws SQLException { ! Field f = getField(column); ! if (f != null) ! return f.getName(); ! return "field" + column; } /* *************** *** 246,270 **** */ public String getColumnName(int column) throws SQLException { ! Field f = getField(column); ! if (f != null) ! return f.getName(); ! return "field" + column; } /* - * What is a column's table's schema? This relies on us knowing - * the table name....which I don't know how to do as yet. The - * JDBC specification allows us to return "" if this is not - * applicable. - * * @param column the first column is 1, the second is 2... ! * @return the Schema * @exception SQLException if a database access error occurs */ public String getSchemaName(int column) throws SQLException { ! return ""; } /* --- 244,300 ---- */ public String getColumnName(int column) throws SQLException { ! Field field = getField(column); ! return field.getColumnName(); } /* * @param column the first column is 1, the second is 2... ! * @return the Schema Name * @exception SQLException if a database access error occurs */ public String getSchemaName(int column) throws SQLException { ! Field field = getField(column); ! if (field.getTableOid() == 0) ! { ! return ""; ! } ! Integer tableOid = new Integer(field.getTableOid()); ! if (schemaNameCache == null) ! { ! schemaNameCache = new Hashtable(); ! } ! String schemaName = (String) schemaNameCache.get(tableOid); ! if (schemaName != null) ! { ! return schemaName; ! } else ! { ! java.sql.Connection con = (java.sql.Connection) field.getConn(); ! ResultSet res = null; ! PreparedStatement ps = null; ! try ! { ! String sql = "SELECT n.nspname FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n WHERE n.oid = c.relnamespace AND c.oid = ?;"; ! ps = con.prepareStatement(sql); ! ps.setInt(1, tableOid.intValue()); ! res = ps.executeQuery(); ! schemaName = ""; ! if (res.next()) ! { ! schemaName = res.getString(1); ! } ! schemaNameCache.put(tableOid, schemaName); ! return schemaName; ! } finally ! { ! if (res != null) ! res.close(); ! if (ps != null) ! ps.close(); ! } ! } } /* *************** *** 341,357 **** } /* - * Whats a column's table's name? How do I find this out? Both - * getSchemaName() and getCatalogName() rely on knowing the table - * Name, so we need this before we can work on them. - * * @param column the first column is 1, the second is 2... * @return column name, or "" if not applicable * @exception SQLException if a database access error occurs */ public String getTableName(int column) throws SQLException { ! return ""; } /* --- 371,421 ---- } /* * @param column the first column is 1, the second is 2... * @return column name, or "" if not applicable * @exception SQLException if a database access error occurs */ public String getTableName(int column) throws SQLException { ! Field field = getField(column); ! if (field.getTableOid() == 0) ! { ! return ""; ! } ! Integer tableOid = new Integer(field.getTableOid()); ! if (tableNameCache == null) ! { ! tableNameCache = new Hashtable(); ! } ! String tableName = (String) tableNameCache.get(tableOid); ! if (tableName != null) ! { ! return tableName; ! } else ! { ! java.sql.Connection con = (java.sql.Connection) field.getConn(); ! ResultSet res = null; ! PreparedStatement ps = null; ! try ! { ! ps = con.prepareStatement("SELECT relname FROM pg_catalog.pg_class WHERE oid = ?"); ! ps.setInt(1, tableOid.intValue()); ! res = ps.executeQuery(); ! tableName = ""; ! if (res.next()) ! { ! tableName = res.getString(1); ! } ! tableNameCache.put(tableOid, tableName); ! return tableName; ! } finally ! { ! if (res != null) ! res.close(); ! if (ps != null) ! ps.close(); ! } ! } } /* diff -rcN -xCVS src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java src/interfaces/rsmdjdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java *** src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java Fri Dec 12 10:36:19 2003 --- src/interfaces/rsmdjdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java Tue Dec 30 01:21:28 2003 *************** *** 108,113 **** --- 108,121 ---- protected Object callResult; protected int maxfieldSize = 0; + public BaseResultSet createDriverResultSet(Field[] fields, Vector tuples) throws SQLException + { + for (int i=0; i