Index: org/postgresql/PGConnection.java =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/PGConnection.java,v retrieving revision 1.3 diff -u -r1.3 PGConnection.java --- org/postgresql/PGConnection.java 2002/09/06 21:23:05 1.3 +++ org/postgresql/PGConnection.java 2002/12/11 14:13:31 @@ -14,6 +14,12 @@ */ public interface PGConnection { + + /* Specify the method which all connections must provide. + */ + public void openConnection (String host, int port, Properties props, + String database, String url, Driver driver) throws SQLException; + /* * Get the character encoding to use for this connection. */ @@ -77,5 +83,21 @@ public PGNotification[] getNotifications(); + + + // Added by Nic. + + /** Create a result set for the specified statement. + * This is the factory method provided by the various + * version specific implementations of the JDBC connection + * classes. + */ + public java.sql.ResultSet createResultSet (java.sql.Statement statement); + + /** Create a result set wrapepd around an existing cursor. + */ + public PGRefCursorResultSet createRefCursorResultSet (java.sql.Statement statement, String cursorHandle) throws SQLException; } + + Index: org/postgresql/PGRefCursorResultSet.java =================================================================== RCS file: PGRefCursorResultSet.java diff -N PGRefCursorResultSet.java --- /dev/null Wed Dec 11 09:09:00 2002 +++ PGRefCursorResultSet.java Wed Dec 11 09:13:31 2002 @@ -0,0 +1,15 @@ +package org.postgresql; + + +import java.util.Vector; + + +/** PG base rep of a ref cursor based Res Set. + */ +public interface PGRefCursorResultSet +{ + + // return the name of the cursor. + public String getRefCursor (); + +} Index: org/postgresql/PGResultSet.java =================================================================== RCS file: PGResultSet.java diff -N PGResultSet.java --- /dev/null Wed Dec 11 09:09:00 2002 +++ PGResultSet.java Wed Dec 11 09:13:31 2002 @@ -0,0 +1,16 @@ +package org.postgresql; + + +import java.util.Vector; + + +/** PG base rep of a Res Set. + */ +public interface PGResultSet +{ + + /** The init method is what is used to put the data into a ResultSet. + */ + public void init (Field[] fields, Vector tuples, String status, + int update_count, long insert_oid, boolean binaryCursor); +} Index: org/postgresql/core/QueryExecutor.java =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/core/QueryExecutor.java,v retrieving revision 1.16.2.1 diff -u -r1.16.2.1 QueryExecutor.java --- org/postgresql/core/QueryExecutor.java 2002/11/14 05:54:39 1.16.2.1 +++ org/postgresql/core/QueryExecutor.java 2002/12/11 14:13:32 @@ -18,13 +18,57 @@ public class QueryExecutor { + /** nic version - statically sets up the QE correctly. + */ + public static void execute (String[] p_sqlFrags, + Object[] p_binds, + java.sql.Statement statement, + java.sql.ResultSet rs, + PG_Stream pg_stream, + java.sql.Connection con) + throws SQLException + { + QueryExecutor qe = new QueryExecutor(); + // I think this should be a PGConnection and we should move + // everything we need for that from AbstractJdbc1... into PGConnection. + qe.connection = (org.postgresql.jdbc1.AbstractJdbc1Connection)con; + qe.m_sqlFrags = p_sqlFrags; + qe.m_binds = p_binds; + qe.statement = statement; + // Nic says: connection should wrap pg_stream. + qe.pg_stream = pg_stream; + if (statement != null) + qe.maxRows = statement.getMaxRows(); + else + qe.maxRows = 0; + // The result set. + qe.rs = rs; + qe.execute(); + } + + // This is the result set used to wrap the results. + // The type of this is whatever is passed into the static above. + private java.sql.ResultSet rs; + + // cons for the static above. + private QueryExecutor () + { + } + + - private final String[] m_sqlFrags; - private final Object[] m_binds; - private final java.sql.Statement statement; - private final PG_Stream pg_stream; - private final org.postgresql.jdbc1.AbstractJdbc1Connection connection; + /*** pre-nic implementation ***/ + + + /// Nic has removed the final from ALL of these (to facilitate static method). + private String[] m_sqlFrags; + private Object[] m_binds; + private java.sql.Statement statement; + private PG_Stream pg_stream; + private org.postgresql.jdbc1.AbstractJdbc1Connection connection; + + public QueryExecutor(String[] p_sqlFrags, Object[] p_binds, java.sql.Statement statement, PG_Stream pg_stream, @@ -33,7 +77,7 @@ { this.m_sqlFrags = p_sqlFrags; this.m_binds = p_binds; - this.statement = statement; + this.statement = statement; this.pg_stream = pg_stream; this.connection = (org.postgresql.jdbc1.AbstractJdbc1Connection)connection; @@ -43,6 +87,7 @@ maxRows = 0; } + private Field[] fields = null; private Vector tuples = new Vector(); private boolean binaryCursor = false; @@ -51,8 +96,10 @@ private long insert_oid = 0; private int maxRows; + /* * Execute a query on the backend. + * */ public java.sql.ResultSet execute() throws SQLException { @@ -129,8 +176,13 @@ // did we get an error during this query? if ( errorMessage != null ) throw new SQLException( errorMessage.toString() ); + - return connection.getResultSet(statement, fields, tuples, status, update_count, insert_oid, binaryCursor); + // Nic changes. + PGResultSet resSet = ((PGResultSet)rs); + // System.out.println(getClass().getName() + " resSet=" + resSet); + resSet.init(fields, tuples, status, update_count, insert_oid, binaryCursor); + return rs; } } @@ -145,10 +197,17 @@ for (int i = 0 ; i < m_binds.length ; ++i) { if (m_binds[i] == null) - throw new PSQLException("postgresql.prep.param", new Integer(i + 1)); + throw new PSQLException("postgresql.prep.param (" + i + ")", new Integer(i + 1)); + + // System.out.println("QE send(" + m_sqlFrags[i] + ")"); + // System.out.println("QE send(" + m_binds[i].toString() + ")"); + pg_stream.Send(connection.getEncoding().encode(m_sqlFrags[i])); pg_stream.Send(connection.getEncoding().encode(m_binds[i].toString())); } + + // System.out.println("QE send(" + m_sqlFrags[m_binds.length] + ")"); + pg_stream.Send(connection.getEncoding().encode(m_sqlFrags[m_binds.length])); pg_stream.SendChar(0); pg_stream.flush(); Index: org/postgresql/jdbc1/AbstractJdbc1Connection.java =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Connection.java,v retrieving revision 1.12.2.1 diff -u -r1.12.2.1 AbstractJdbc1Connection.java --- org/postgresql/jdbc1/AbstractJdbc1Connection.java 2002/11/14 05:54:39 1.12.2.1 +++ org/postgresql/jdbc1/AbstractJdbc1Connection.java 2002/12/11 14:13:33 @@ -23,7 +23,7 @@ { // This is the network stream associated with this connection public PG_Stream pg_stream; - + protected String PG_HOST; protected int PG_PORT; protected String PG_USER; @@ -84,7 +84,6 @@ public abstract java.sql.Statement createStatement() throws SQLException; - /* * This method actually opens the connection. It is called by Driver. * @@ -350,9 +349,10 @@ // Set datestyle and fetch db encoding in a single call, to avoid making // more than one round trip to the backend during connection startup. - java.sql.ResultSet resultSet = - ExecSQL("set datestyle to 'ISO'; select version(), " + encodingQuery + ";"); + java.sql.ResultSet resultSet + = doQuery("set datestyle to 'ISO'; select version(), " + encodingQuery + ";"); + if (! resultSet.next()) { throw new PSQLException("postgresql.con.failed", "failed getting backend encoding"); @@ -373,7 +373,7 @@ if (haveMinimumServerVersion("7.3")) { java.sql.ResultSet acRset = - ExecSQL("set client_encoding = 'UNICODE'; show autocommit"); + doQuery("set client_encoding = 'UNICODE'; show autocommit"); //set encoding to be unicode encoding = Encoding.getEncoding("UNICODE", null); @@ -388,7 +388,7 @@ //to make the setting permanent if (acRset.getString(1).equals("off")) { - ExecSQL("set autocommit = on; commit;"); + doQuery("set autocommit = on; commit;"); } } @@ -409,14 +409,7 @@ return this_driver; } - // These methods used to be in the main Connection implementation. As they - // are common to all implementations (JDBC1 or 2), they are placed here. - // This should make it easy to maintain the two specifications. - - public abstract java.sql.ResultSet getResultSet(Statement statement, org.postgresql.Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException; - public abstract java.sql.ResultSet getResultSet(Statement statement, org.postgresql.Field[] fields, Vector tuples, String status, int updateCount) throws SQLException; - /* * This adds a warning to the warning chain. * @param msg message to add @@ -445,66 +438,40 @@ //} } - /* - * Send a query to the backend. Returns one of the ResultSet - * objects. - * - * Note: there does not seem to be any method currently - * in existance to return the update count. - * - * @param sql the SQL statement to be executed - * @return a ResultSet holding the results - * @exception SQLException if a database error occurs + /** Simple query execution. */ - public java.sql.ResultSet ExecSQL(String sql) throws SQLException + public java.sql.ResultSet doQuery (String s) throws SQLException { - return ExecSQL(sql, null); + final Object[] nullarr = new Object[0]; + java.sql.Statement stat = createStatement(); + java.sql.ResultSet rs = createResultSet(stat); + execSQL(new String[] { s }, nullarr, stat, rs); + return rs; } - /* - * Send a query to the backend. Returns one of the ResultSet - * objects. + /** Advanced query execution. * - * Note: there does not seem to be any method currently - * in existance to return the update count. - * - * @param sql the SQL statement to be executed - * @param stat The Statement associated with this query (may be null) - * @return a ResultSet holding the results - * @exception SQLException if a database error occurs - */ - public java.sql.ResultSet ExecSQL(String sql, java.sql.Statement stat) throws SQLException - { - if (isClosed()) - { - throw new PSQLException("postgresql.con.closed"); - } - return new QueryExecutor(new String[] {sql}, EMPTY_OBJECT_ARRAY, stat, pg_stream, (java.sql.Connection)this).execute(); - } - private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; - - /* - * Send a query to the backend. Returns one of the ResultSet - * objects. - * - * Note: there does not seem to be any method currently - * in existance to return the update count. - * * @param p_sqlFragmentss the SQL statement parts to be executed * @param p_binds the SQL bind values - * @param stat The Statement associated with this query (may be null) - * @return a ResultSet holding the results + * @param stat the statement associated with this query. + * @param rs the ResultSet which will be initied for the results. * @exception SQLException if a database error occurs */ - public java.sql.ResultSet ExecSQL(String[] p_sqlFragments, Object[] p_binds, java.sql.Statement stat) throws SQLException - { - if (isClosed()) - { - throw new PSQLException("postgresql.con.closed"); - } - return new QueryExecutor(p_sqlFragments, p_binds, stat, pg_stream, (java.sql.Connection)this).execute(); + public void execSQL(String[] p_sqlFragments, + Object[] p_binds, + java.sql.Statement stat, + java.sql.ResultSet rs) + throws SQLException + { + QueryExecutor.execute(p_sqlFragments, + p_binds, + stat, + rs, + pg_stream, + (java.sql.Connection)this); } + /* * In SQL, a result table can be retrieved through a cursor that * is named. The current row of a result can be updated or deleted @@ -939,27 +906,27 @@ //We do the select to ensure a transaction is in process //before we do the commit to avoid warning messages //from issuing a commit without a transaction in process - ExecSQL("select 1; commit; set autocommit = on;"); + doQuery("select 1; commit; set autocommit = on;"); } else { - ExecSQL("end"); + doQuery("end"); } } else { if (haveMinimumServerVersion("7.3")) { - ExecSQL("set autocommit = off; " + getIsolationLevelSQL()); + doQuery("set autocommit = off; " + getIsolationLevelSQL()); } else if (haveMinimumServerVersion("7.1")) { - ExecSQL("begin;" + getIsolationLevelSQL()); + doQuery("begin;" + getIsolationLevelSQL()); } else { - ExecSQL("begin"); - ExecSQL(getIsolationLevelSQL()); + doQuery("begin"); + doQuery(getIsolationLevelSQL()); } } this.autoCommit = autoCommit; @@ -993,17 +960,17 @@ return ; if (haveMinimumServerVersion("7.3")) { - ExecSQL("commit; " + getIsolationLevelSQL()); + doQuery("commit; " + getIsolationLevelSQL()); } else if (haveMinimumServerVersion("7.1")) { - ExecSQL("commit;begin;" + getIsolationLevelSQL()); + doQuery("commit;begin;" + getIsolationLevelSQL()); } else { - ExecSQL("commit"); - ExecSQL("begin"); - ExecSQL(getIsolationLevelSQL()); + doQuery("commit"); + doQuery("begin"); + doQuery(getIsolationLevelSQL()); } } @@ -1024,17 +991,17 @@ //we don't automatically start a transaction //but let the server functionality automatically start //one when the first statement is executed - ExecSQL("rollback; " + getIsolationLevelSQL()); + doQuery("rollback; " + getIsolationLevelSQL()); } else if (haveMinimumServerVersion("7.1")) { - ExecSQL("rollback; begin;" + getIsolationLevelSQL()); + doQuery("rollback; begin;" + getIsolationLevelSQL()); } else { - ExecSQL("rollback"); - ExecSQL("begin"); - ExecSQL(getIsolationLevelSQL()); + doQuery("rollback"); + doQuery("begin"); + doQuery(getIsolationLevelSQL()); } } @@ -1049,14 +1016,14 @@ String sql = "show transaction isolation level"; String level = null; if (haveMinimumServerVersion("7.3")) { - ResultSet rs = ExecSQL(sql); + ResultSet rs = doQuery(sql); if (rs.next()) { level = rs.getString(1); } rs.close(); } else { clearWarnings(); - ExecSQL(sql); + doQuery(sql); SQLWarning warning = getWarnings(); if (warning != null) { @@ -1121,7 +1088,7 @@ new Integer(isolationLevel)); } } - ExecSQL(isolationLevelSQL); + doQuery(isolationLevelSQL); } /* @@ -1264,7 +1231,7 @@ } else { sql = "SELECT typname FROM pg_type WHERE oid = " +oid; } - ResultSet result = ExecSQL(sql); + ResultSet result = doQuery(sql); if (((AbstractJdbc1ResultSet)result).getColumnCount() != 1 || ((AbstractJdbc1ResultSet)result).getTupleCount() != 1) { throw new PSQLException("postgresql.unexpected"); } @@ -1305,7 +1272,7 @@ } else { sql = "SELECT oid FROM pg_type WHERE typname='" + typeName + "'"; } - ResultSet result = ExecSQL(sql); + ResultSet result = doQuery(sql); if (((AbstractJdbc1ResultSet)result).getColumnCount() != 1 || ((AbstractJdbc1ResultSet)result).getTupleCount() != 1) throw new PSQLException("postgresql.unexpected"); result.next(); @@ -1413,21 +1380,21 @@ * Tip: keep these grouped together by the Types. value */ private static final int jdbc1Typei[] = { - Types.SMALLINT, - Types.INTEGER, Types.INTEGER, - Types.BIGINT, - Types.DOUBLE, Types.DOUBLE, - Types.NUMERIC, - Types.REAL, - Types.DOUBLE, - Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, - Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, - Types.BINARY, - Types.BIT, - Types.DATE, - Types.TIME, - Types.TIMESTAMP, Types.TIMESTAMP, Types.TIMESTAMP - }; + Types.SMALLINT, + Types.INTEGER, Types.INTEGER, + Types.BIGINT, + Types.DOUBLE, Types.DOUBLE, + Types.NUMERIC, + Types.REAL, + Types.DOUBLE, + Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.BINARY, + Types.BIT, + Types.DATE, + Types.TIME, + Types.TIMESTAMP, Types.TIMESTAMP, Types.TIMESTAMP + }; //Methods to support postgres notifications public void addNotification(org.postgresql.PGNotification p_notification) Index: org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java,v retrieving revision 1.10.2.2 diff -u -r1.10.2.2 AbstractJdbc1DatabaseMetaData.java --- org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java 2002/12/05 01:09:58 1.10.2.2 +++ org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java 2002/12/11 14:13:37 @@ -1913,7 +1913,9 @@ } rs.close(); - return connection.getResultSet(null, f, v, "OK", 1); + java.sql.ResultSet retRs = connection.createResultSet(connection.createStatement()); + ((AbstractJdbc1ResultSet)retRs).init(f, v, "OK", 1, 0, false); + return retRs; } /* @@ -2199,7 +2201,10 @@ tuple[0] = types[i].getBytes(); v.addElement(tuple); } - return connection.getResultSet(null, f, v, "OK", 1); + + java.sql.ResultSet retRs = connection.createResultSet(connection.createStatement()); + ((AbstractJdbc1ResultSet)retRs).init(f, v, "OK", 1, 0, false); + return retRs; } /* @@ -2366,7 +2371,9 @@ } rs.close(); - return connection.getResultSet(null, f, v, "OK", 1); + java.sql.ResultSet retRs = connection.createResultSet(connection.createStatement()); + ((AbstractJdbc1ResultSet)retRs).init(f, v, "OK", 1, 0, false); + return retRs; } /* @@ -2478,7 +2485,10 @@ } } rs.close(); - return connection.getResultSet(null, f, v, "OK", 1); + + java.sql.ResultSet retRs = connection.createResultSet(connection.createStatement()); + ((AbstractJdbc1ResultSet)retRs).init(f, v, "OK", 1, 0, false); + return retRs; } /* @@ -2580,7 +2590,9 @@ } rs.close(); - return connection.getResultSet(null, f, v, "OK", 1); + java.sql.ResultSet retRs = connection.createResultSet(connection.createStatement()); + ((AbstractJdbc1ResultSet)retRs).init(f, v, "OK", 1, 0, false); + return retRs; } private static void sortStringArray(String s[]) { @@ -2773,7 +2785,10 @@ tuple[7] = Integer.toString(java.sql.DatabaseMetaData.bestRowNotPseudo).getBytes(); v.addElement(tuple); } - return connection.getResultSet(null, f, v, "OK", 1); + + java.sql.ResultSet retRs = connection.createResultSet(connection.createStatement()); + ((AbstractJdbc1ResultSet)retRs).init(f, v, "OK", 1, 0, false); + return retRs; } /* @@ -2843,7 +2858,9 @@ /* Perhaps we should check that the given * catalog.schema.table actually exists. -KJ */ - return connection.getResultSet(null, f, v, "OK", 1); + java.sql.ResultSet retRs = connection.createResultSet(connection.createStatement()); + ((AbstractJdbc1ResultSet)retRs).init(f, v, "OK", 1, 0, false); + return retRs; } /* @@ -3193,7 +3210,9 @@ tuples.addElement(tuple); } - return connection.getResultSet(null, f, tuples, "OK", 1); + java.sql.ResultSet retRs = connection.createResultSet(connection.createStatement()); + ((AbstractJdbc1ResultSet)retRs).init(f, tuples, "OK", 1, 0, false); + return retRs; } /* @@ -3478,7 +3497,10 @@ v.addElement(tuple); } rs.close(); - return connection.getResultSet(null, f, v, "OK", 1); + + java.sql.ResultSet retRs = connection.createResultSet(connection.createStatement()); + ((AbstractJdbc1ResultSet)retRs).init(f, v, "OK", 1, 0, false); + return retRs; } /* Index: org/postgresql/jdbc1/AbstractJdbc1ResultSet.java =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java,v retrieving revision 1.7 diff -u -r1.7 AbstractJdbc1ResultSet.java --- org/postgresql/jdbc1/AbstractJdbc1ResultSet.java 2002/10/19 22:10:36 1.7 +++ org/postgresql/jdbc1/AbstractJdbc1ResultSet.java 2002/12/11 14:13:38 @@ -18,7 +18,7 @@ * extended by org.postgresql.jdbc2.AbstractJdbc2ResultSet which adds the jdbc2 * methods. The real ResultSet class (for jdbc1) is org.postgresql.jdbc1.Jdbc1ResultSet */ -public abstract class AbstractJdbc1ResultSet +public abstract class AbstractJdbc1ResultSet implements org.postgresql.PGResultSet { protected Vector rows; // The results @@ -42,7 +42,13 @@ public byte[][] rowBuffer = null; - public AbstractJdbc1ResultSet(org.postgresql.PGConnection conn, Statement statement, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) + public AbstractJdbc1ResultSet(org.postgresql.PGConnection conn, + Statement statement, + Field[] fields, + Vector tuples, + String status, + int updateCount, + long insertOID, boolean binaryCursor) { this.connection = conn; this.statement = statement; @@ -50,20 +56,72 @@ this.rows = tuples; this.status = status; this.updateCount = updateCount; + + System.out.println(getClass().getName() + " updateCount = " + updateCount); + + this.insertOID = insertOID; + this.this_row = null; + this.current_row = -1; + this.binaryCursor = binaryCursor; + } + + + /*** nic constructor: called by superclass which is called from Jdbc1Connection.createResultSet ***/ + public AbstractJdbc1ResultSet(org.postgresql.PGConnection conn, + Statement statement) + { + this.connection = conn; + this.statement = statement; + } + + /*** nic initializer. ***/ + public void init (Field[] fields, Vector tuples, String status, + int updateCount, long insertOID, boolean binaryCursor) + { + this.fields = fields; + // on a reinit the size of this indicates how many we pulled + // back. If it's 0 then the res set has ended. + this.rows = tuples; + this.status = status; + this.updateCount = updateCount; this.insertOID = insertOID; this.this_row = null; this.current_row = -1; this.binaryCursor = binaryCursor; } + + + // This slightly altered by nic. public boolean next() throws SQLException { if (rows == null) throw new PSQLException("postgresql.con.closed"); if (++current_row >= rows.size()) - return false; + { + int fetchSize = ((AbstractJdbc1Statement)statement).fetchSize; + // Must be false if we weren't batching. + if (fetchSize == 0) + return false; + // Use the ref to the statement to get + // the details we need to do another cursor + // query - it will use reinit() to repopulate this + // with the right data. + String[] sql = new String[1]; + String[] binds = new String[0]; + // Is this the correct query??? + String cursorName = ((AbstractJdbc1Statement)statement).m_statementName; + sql[0] = "FETCH FORWARD " + fetchSize + " FROM " + cursorName + " ;"; + ((AbstractJdbc1Connection)connection).execSQL(sql, binds, statement, (java.sql.ResultSet)this); + + // Test the new rows array. + if (rows.size() == 0) + return false; + // Otherwise reset the counter and let it go on... + current_row = 0; + } this_row = (byte [][])rows.elementAt(current_row); @@ -501,6 +559,13 @@ if (type.equals("unknown")) { return getString(columnIndex); + } + else if (type.equals("refcursor")) + { + // We must return a ResultSet with the results packaged. + // We should probably check that auto commit is turned off. + String cursorName = getString(columnIndex); + return connection.createRefCursorResultSet(statement, cursorName); } else { Index: org/postgresql/jdbc1/AbstractJdbc1Statement.java =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java,v retrieving revision 1.12.2.2 diff -u -r1.12.2.2 AbstractJdbc1Statement.java --- org/postgresql/jdbc1/AbstractJdbc1Statement.java 2002/11/20 07:54:27 1.12.2.2 +++ org/postgresql/jdbc1/AbstractJdbc1Statement.java 2002/12/11 14:13:40 @@ -25,6 +25,9 @@ /** Maximum number of rows to return, 0 = unlimited */ protected int maxrows = 0; + /** Number of rows to get in a batch. */ + protected int fetchSize = 0; + /** Timeout (in seconds) for a query (not used) */ protected int timeout = 0; @@ -47,8 +50,10 @@ private String[] m_origSqlFragments; private String[] m_executeSqlFragments; protected Object[] m_binds = new Object[0]; + protected String[] m_bindTypes = new String[0]; - private String m_statementName = null; + protected String m_statementName = null; + private boolean m_useServerPrepare = false; private static int m_preparedCount = 1; @@ -117,7 +122,7 @@ } - + /* * Execute a SQL statement that retruns a single ResultSet * @@ -132,11 +137,21 @@ m_binds = new Object[0]; //If we have already created a server prepared statement, we need //to deallocate the existing one - if (m_statementName != null) { - ((AbstractJdbc1Connection)connection).ExecSQL("DEALLOCATE " + m_statementName); - m_statementName = null; - m_origSqlFragments = null; - m_executeSqlFragments = null; + if (m_statementName != null) + { + try + { + ((AbstractJdbc1Connection)connection).doQuery("DEALLOCATE " + m_statementName); + } + catch (Exception e) + { + } + finally + { + m_statementName = null; + m_origSqlFragments = null; + m_executeSqlFragments = null; + } } return executeQuery(); } @@ -150,7 +165,11 @@ */ public java.sql.ResultSet executeQuery() throws SQLException { - this.execute(); + if (fetchSize > 0) + this.nic_execute(); + else + this.execute(); + while (result != null && !((AbstractJdbc1ResultSet)result).reallyResultSet()) result = ((AbstractJdbc1ResultSet)result).getNext(); if (result == null) @@ -175,7 +194,7 @@ //If we have already created a server prepared statement, we need //to deallocate the existing one if (m_statementName != null) { - ((AbstractJdbc1Connection)connection).ExecSQL("DEALLOCATE " + m_statementName); + ((AbstractJdbc1Connection)connection).doQuery("DEALLOCATE " + m_statementName); m_statementName = null; m_origSqlFragments = null; m_executeSqlFragments = null; @@ -219,7 +238,7 @@ //If we have already created a server prepared statement, we need //to deallocate the existing one if (m_statementName != null) { - ((AbstractJdbc1Connection)connection).ExecSQL("DEALLOCATE " + m_statementName); + ((AbstractJdbc1Connection)connection).doQuery("DEALLOCATE " + m_statementName); m_statementName = null; m_origSqlFragments = null; m_executeSqlFragments = null; @@ -317,7 +336,9 @@ } // New in 7.1, pass Statement so that ExecSQL can customise to it - result = ((AbstractJdbc1Connection)connection).ExecSQL(m_sqlFragments, m_binds, (java.sql.Statement)this); + result = ((AbstractJdbc1Connection)connection).createResultSet((java.sql.Statement)this); + ((AbstractJdbc1Connection)connection).execSQL(m_sqlFragments, m_binds, + (java.sql.Statement)this, result); //If we are executing a callable statement function set the return data if (isFunction) @@ -341,6 +362,104 @@ } } + /** version of execute which converts the query to a cursor. + */ + public boolean nic_execute() throws SQLException + { + if (isFunction && !returnTypeSet) + throw new PSQLException("postgresql.call.noreturntype"); + if (isFunction) + { // set entry 1 to dummy entry.. + m_binds[0] = ""; // dummy entry which ensured that no one overrode + m_bindTypes[0] = PG_TEXT; + // and calls to setXXX (2,..) really went to first arg in a function call.. + } + + // New in 7.1, if we have a previous resultset then force it to close + // This brings us nearer to compliance, and helps memory management. + // Internal stuff will call ExecSQL directly, bypassing this. + if (result != null) + { + java.sql.ResultSet rs = getResultSet(); + if (rs != null) + rs.close(); + } + + // I've pretty much ignored server prepared statements... can declare and prepare be + // used together? + // It's trivial to change this: you just have to resolve this issue + // of how to work out whether there's a function call. If there isn't then the first + // element of the array must be the bit that you extend to become the cursor + // decleration. + // The last thing that can go wrong is when the user supplies a cursor statement + // directly: the translation takes no account of that. I think we should just look + // for declare and stop the translation if we find it. + + // The first thing to do is transform the statement text into the cursor form. + String[] origSqlFragments = m_sqlFragments; + m_sqlFragments = new String[origSqlFragments.length]; + System.arraycopy(origSqlFragments, 0, m_sqlFragments, 0, origSqlFragments.length); + // Pinch the prepared count for our own nefarious purposes. + m_statementName = "JDBC_CURS_" + m_preparedCount++; + // The static bit to prepend to all querys. + String cursDecl = "BEGIN; DECLARE " + m_statementName + " CURSOR FOR "; + String endCurs = " FETCH FORWARD " + fetchSize + " FROM " + m_statementName + ";"; + + // Add the real query to the curs decleration. + // This is the bit that really makes the presumption about + // m_sqlFragments not being a function call. + if (m_sqlFragments.length < 1) + m_sqlFragments[0] = cursDecl + "SELECT NULL;"; + + else if (m_sqlFragments.length < 2) + { + if (m_sqlFragments[0].endsWith(";")) + m_sqlFragments[0] = cursDecl + m_sqlFragments[0] + endCurs; + else + m_sqlFragments[0] = cursDecl + m_sqlFragments[0] + ";" + endCurs; + } + else + { + m_sqlFragments[0] = cursDecl + m_sqlFragments[0]; + if (m_sqlFragments[m_sqlFragments.length - 1].endsWith(";")) + m_sqlFragments[m_sqlFragments.length - 1] += endCurs; + else + m_sqlFragments[m_sqlFragments.length - 1] += (";" + endCurs); + } + + // Make the call to the query executor. + AbstractJdbc1Connection execr = (AbstractJdbc1Connection)connection; + java.sql.Statement st = (java.sql.Statement)this; + result = (java.sql.ResultSet) execr.createResultSet(st); + execr.execSQL(m_sqlFragments, m_binds, st, result); + + //If we are executing a callable statement function set the return data + if (isFunction) + { + if (!((AbstractJdbc1ResultSet)result).reallyResultSet()) + throw new PSQLException("postgresql.call.noreturnval"); + if (!result.next ()) + throw new PSQLException ("postgresql.call.noreturnval"); + callResult = result.getObject(1); + int columnType = result.getMetaData().getColumnType(1); + if (columnType != functionReturnType) + { + Object[] arr = + { "java.sql.Types=" + columnType, + "java.sql.Types=" + functionReturnType + }; + throw new PSQLException ("postgresql.call.wrongrtntype",arr); + } + result.close (); + return true; + } + else + { + return (result != null && ((AbstractJdbc1ResultSet)result).reallyResultSet()); + } + } + + /* * setCursorName defines the SQL cursor name that will be used by * subsequent execute methods. This name can then be used in SQL @@ -593,7 +712,7 @@ // If using server prepared statements deallocate them if (m_useServerPrepare && m_statementName != null) { - ((AbstractJdbc1Connection)connection).ExecSQL("DEALLOCATE " + m_statementName); + ((AbstractJdbc1Connection)connection).doQuery("DEALLOCATE " + m_statementName); } // Disasociate it from us (For Garbage Collection) @@ -1690,7 +1809,7 @@ */ public byte[] getBytes(int parameterIndex) throws SQLException { - checkIndex (parameterIndex, Types.VARBINARY, "Bytes"); + checkIndex (parameterIndex, Types.VARBINARY, Types.BINARY, "Bytes"); return ((byte [])callResult); } @@ -1797,6 +1916,10 @@ */ protected void bind(int paramIndex, Object s, String type) throws SQLException { + // System.out.println("AbstractJdbc1Statement bind(" + // + paramIndex + ", " + // + s + ", " + // + type + ") + m_binds.length = " + m_binds.length); if (paramIndex < 1 || paramIndex > m_binds.length) throw new PSQLException("postgresql.prep.range"); if (paramIndex == 1 && isFunction) // need to registerOut instead @@ -1847,7 +1970,7 @@ String l_sql = p_sql; int index = l_sql.indexOf ("="); // is implied func or proc? boolean isValid = true; - if (index != -1) + if (index > -1) { isFunction = true; isValid = l_sql.indexOf ("?") < index; // ? before = @@ -1875,23 +1998,37 @@ // sure that the parameter numbers are the same as in the original // sql we add a dummy parameter in this case l_sql = (isFunction ? "?" : "") + l_sql.substring (index + 4); - l_sql = "select " + l_sql + " as " + RESULT_COLUMN + ";"; return l_sql; } /** helperfunction for the getXXX calls to check isFunction and index == 1 + * Compare BOTH type fields against the return type. */ + protected void checkIndex (int parameterIndex, int type1, int type2, String getName) + throws SQLException + { + checkIndex (parameterIndex); + if (type1 != this.testReturn && type2 != this.testReturn) + throw new PSQLException("postgresql.call.wrongget", + new Object[]{"java.sql.Types=" + testReturn, + getName, + "java.sql.Types=" + type1}); + } + + /** helperfunction for the getXXX calls to check isFunction and index == 1 + */ protected void checkIndex (int parameterIndex, int type, String getName) throws SQLException { checkIndex (parameterIndex); if (type != this.testReturn) throw new PSQLException("postgresql.call.wrongget", - new Object[]{"java.sql.Types=" + testReturn, - getName, - "java.sql.Types=" + type}); + new Object[]{"java.sql.Types=" + testReturn, + getName, + "java.sql.Types=" + type}); } + /** helperfunction for the getXXX calls to check isFunction and index == 1 * @param parameterIndex index of getXXX (index) * check to make sure is a function and index == 1 @@ -1912,7 +2049,7 @@ //If turning server prepared statements off deallocate statement //and reset statement name if (m_useServerPrepare != flag && !flag) - ((AbstractJdbc1Connection)connection).ExecSQL("DEALLOCATE " + m_statementName); + ((AbstractJdbc1Connection)connection).doQuery("DEALLOCATE " + m_statementName); m_statementName = null; m_useServerPrepare = flag; } else { Index: org/postgresql/jdbc1/Jdbc1Connection.java =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1Connection.java,v retrieving revision 1.5 diff -u -r1.5 Jdbc1Connection.java --- org/postgresql/jdbc1/Jdbc1Connection.java 2002/09/06 21:23:06 1.5 +++ org/postgresql/jdbc1/Jdbc1Connection.java 2002/12/11 14:13:40 @@ -36,16 +36,20 @@ return metadata; } - public java.sql.ResultSet getResultSet(java.sql.Statement stat, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException + + + // Methods for creating result sets + + public java.sql.ResultSet createResultSet (java.sql.Statement stat) throws SQLException { - return new Jdbc1ResultSet(this, stat, fields, tuples, status, updateCount, insertOID, binaryCursor); + // This needs doing. + return null; } - public java.sql.ResultSet getResultSet(java.sql.Statement stat, Field[] fields, Vector tuples, String status, int updateCount) throws SQLException + public PGRefCursorResultSet createRefCursorResultSet (java.sql.Statement stat, String cursorHandle) throws SQLException { - return new Jdbc1ResultSet(this, stat, fields, tuples, status, updateCount, 0, false); + return new Jdbc1RefCursorResultSet(stat, cursorHandle); } - } Index: org/postgresql/jdbc1/Jdbc1RefCursorResultSet.java =================================================================== RCS file: Jdbc1RefCursorResultSet.java diff -N Jdbc1RefCursorResultSet.java --- /dev/null Wed Dec 11 09:09:00 2002 +++ Jdbc1RefCursorResultSet.java Wed Dec 11 09:13:41 2002 @@ -0,0 +1,40 @@ +package org.postgresql.jdbc1; + + + +/** A real result set based on a ref cursor. + * + * @author Nic Ferrier + */ +public class Jdbc1RefCursorResultSet extends AbstractJdbc1ResultSet implements PGRefCursorResultSet +{ + + java.sql.Statement statement; + String refCursorHandle; + + // Indicates when the result set has activaly bound to the cursor. + boolean isInitialized = false; + + Jdbc1RefCursorResultSet(java.sql.Statement statement, String refCursorName) + { + this.statement = statement; + this.refCursorHandle = refCursorName; + } + + public String getRefCursor () + { + return refCursorHandle; + } + + public boolean next () throws SQLException + { + if (isInitialized) + return super.next(); + // Initialize this res set with the rows from the cursor. + String[] toExec = { "FETCH ALL IN \"" + refCursorHandle + "\";" }; + Jdbc1Connection execr = (Jdbc1Connection) statement.getConnection(); + execr.execSQL(toExec, new String[0], statement, this); + isInitialized = true; + return super.next(); + } +} Index: org/postgresql/jdbc1/Jdbc1Statement.java =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1Statement.java,v retrieving revision 1.3 diff -u -r1.3 Jdbc1Statement.java --- org/postgresql/jdbc1/Jdbc1Statement.java 2002/09/06 21:23:06 1.3 +++ org/postgresql/jdbc1/Jdbc1Statement.java 2002/12/11 14:13:41 @@ -16,4 +16,5 @@ super(c); } + } Index: org/postgresql/jdbc2/AbstractJdbc2Connection.java =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2Connection.java,v retrieving revision 1.2 diff -u -r1.2 AbstractJdbc2Connection.java --- org/postgresql/jdbc2/AbstractJdbc2Connection.java 2002/09/06 21:23:06 1.2 +++ org/postgresql/jdbc2/AbstractJdbc2Connection.java 2002/12/11 14:13:41 @@ -6,6 +6,7 @@ import java.sql.*; import org.postgresql.util.PSQLException; + /* $Header: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2Connection.java,v 1.2 2002/09/06 21:23:06 momjian Exp $ * This class defines methods of the jdbc2 specification. This class extends * org.postgresql.jdbc1.AbstractJdbc1Connection which provides the jdbc1 @@ -17,7 +18,7 @@ * The current type mappings */ protected java.util.Map typemap; - + public java.sql.Statement createStatement() throws SQLException { // The spec says default of TYPE_FORWARD_ONLY but everyone is used to Index: org/postgresql/jdbc2/AbstractJdbc2ResultSet.java =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java,v retrieving revision 1.10 diff -u -r1.10 AbstractJdbc2ResultSet.java --- org/postgresql/jdbc2/AbstractJdbc2ResultSet.java 2002/11/04 06:42:33 1.10 +++ org/postgresql/jdbc2/AbstractJdbc2ResultSet.java 2002/12/11 14:13:42 @@ -38,6 +38,11 @@ protected PreparedStatement deleteStatement = null; private PreparedStatement selectStatement = null; + + protected AbstractJdbc2ResultSet (org.postgresql.PGConnection conn, Statement statement) + { + super(conn, statement); + } public AbstractJdbc2ResultSet(org.postgresql.PGConnection conn, Statement statement, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) @@ -142,6 +147,13 @@ { return getString(columnIndex); } + else if (type.equals("refcursor")) + { + // We must return a ResultSet with the results packaged. + // We should probably check that auto commit is turned off. + String cursorName = getString(columnIndex); + return connection.createRefCursorResultSet(statement, cursorName); + } else { return connection.getObject(field.getPGType(), getString(columnIndex)); @@ -366,9 +378,7 @@ public int getFetchSize() throws SQLException { - // In this implementation we return the entire result set, so - // here return the number of rows we have. Sub-classes can return a proper - // value + // Returning the current batch size seems the right thing to do. return rows.size(); } @@ -754,7 +764,6 @@ } updateValue(columnIndex, theData); - } @@ -787,7 +796,6 @@ throw new PSQLException("postgresql.updateable.ioerror" + ie); } updateValue(columnIndex, theData); - } Index: org/postgresql/jdbc2/AbstractJdbc2Statement.java =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2Statement.java,v retrieving revision 1.8.2.2 diff -u -r1.8.2.2 AbstractJdbc2Statement.java --- org/postgresql/jdbc2/AbstractJdbc2Statement.java 2002/11/20 20:42:24 1.8.2.2 +++ org/postgresql/jdbc2/AbstractJdbc2Statement.java 2002/12/11 14:13:42 @@ -133,7 +133,7 @@ public int getFetchSize() throws SQLException { - return 0; + return super.fetchSize; } public int getResultSetConcurrency() throws SQLException @@ -148,12 +148,16 @@ public void setFetchDirection(int direction) throws SQLException { - throw org.postgresql.Driver.notImplemented(); + // I don't think this should happen, since it's a hint it should just + // fail quietly. + // throw org.postgresql.Driver.notImplemented(); } public void setFetchSize(int rows) throws SQLException { - throw org.postgresql.Driver.notImplemented(); + // if (super.fetchSize > 0 && rows == 0) + // throw new SQLException("you can't set fetch size to 0 during "); + super.fetchSize = rows; } public void setResultSetConcurrency(int value) throws SQLException Index: org/postgresql/jdbc2/Array.java =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc2/Array.java,v retrieving revision 1.18 diff -u -r1.18 Array.java --- org/postgresql/jdbc2/Array.java 2002/09/06 21:23:06 1.18 +++ org/postgresql/jdbc2/Array.java 2002/12/11 14:13:43 @@ -343,7 +343,10 @@ default: throw org.postgresql.Driver.notImplemented(); } - return ((AbstractJdbc2Connection)conn).getResultSet(null, fields, rows, "OK", 1 ); + java.sql.Statement stat = ((AbstractJdbc2Connection)conn).createStatement(); + java.sql.ResultSet retRs = ((AbstractJdbc2Connection)conn).createResultSet(stat); + ((AbstractJdbc2ResultSet)retRs).init(fields, rows, "OK", 1, 0, false); + return retRs; } public String toString() Index: org/postgresql/jdbc2/Jdbc2Connection.java =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Connection.java,v retrieving revision 1.5 diff -u -r1.5 Jdbc2Connection.java --- org/postgresql/jdbc2/Jdbc2Connection.java 2002/09/06 21:23:06 1.5 +++ org/postgresql/jdbc2/Jdbc2Connection.java 2002/12/11 14:13:43 @@ -6,6 +6,7 @@ import java.util.Hashtable; import org.postgresql.Field; + /* $Header: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Connection.java,v 1.5 2002/09/06 21:23:06 momjian Exp $ * This class implements the java.sql.Connection interface for JDBC2. * However most of the implementation is really done in @@ -45,17 +46,21 @@ metadata = new org.postgresql.jdbc2.Jdbc2DatabaseMetaData(this); return metadata; } + + - public java.sql.ResultSet getResultSet(Statement statement, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException + // Result set creation. + + /** new nic method **/ + public java.sql.ResultSet createResultSet (Statement statement) { - return new Jdbc2ResultSet(this, statement, fields, tuples, status, updateCount, insertOID, binaryCursor); + return new Jdbc2ResultSet(this, statement); } - public java.sql.ResultSet getResultSet(Statement statement, Field[] fields, Vector tuples, String status, int updateCount) throws SQLException + public org.postgresql.PGRefCursorResultSet createRefCursorResultSet (java.sql.Statement stat, String cursorHandle) throws SQLException { - return new Jdbc2ResultSet(this, statement, fields, tuples, status, updateCount, 0, false); + return new Jdbc2RefCursorResultSet(stat, cursorHandle); } - } Index: org/postgresql/jdbc2/Jdbc2RefCursorResultSet.java =================================================================== RCS file: Jdbc2RefCursorResultSet.java diff -N Jdbc2RefCursorResultSet.java --- /dev/null Wed Dec 11 09:09:00 2002 +++ Jdbc2RefCursorResultSet.java Wed Dec 11 09:13:43 2002 @@ -0,0 +1,41 @@ +package org.postgresql.jdbc2; + + +import org.postgresql.PGConnection; + + +/** A real result set based on a ref cursor. + * + * @author Nic Ferrier + */ +public class Jdbc2RefCursorResultSet extends Jdbc2ResultSet implements org.postgresql.PGRefCursorResultSet +{ + + String refCursorHandle; + + // Indicates when the result set has activaly bound to the cursor. + boolean isInitialized = false; + + Jdbc2RefCursorResultSet(java.sql.Statement statement, String refCursorName) throws java.sql.SQLException + { + super((PGConnection)statement.getConnection(), statement); + this.refCursorHandle = refCursorName; + } + + public String getRefCursor () + { + return refCursorHandle; + } + + public boolean next () throws java.sql.SQLException + { + if (isInitialized) + return super.next(); + // Initialize this res set with the rows from the cursor. + String[] toExec = { "FETCH ALL IN \"" + refCursorHandle + "\";" }; + Jdbc2Connection execr = (Jdbc2Connection) statement.getConnection(); + execr.execSQL(toExec, new String[0], statement, this); + isInitialized = true; + return super.next(); + } +} Index: org/postgresql/jdbc2/Jdbc2ResultSet.java =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2ResultSet.java,v retrieving revision 1.6 diff -u -r1.6 Jdbc2ResultSet.java --- org/postgresql/jdbc2/Jdbc2ResultSet.java 2002/09/11 05:38:45 1.6 +++ org/postgresql/jdbc2/Jdbc2ResultSet.java 2002/12/11 14:13:43 @@ -13,6 +13,12 @@ public class Jdbc2ResultSet extends org.postgresql.jdbc2.AbstractJdbc2ResultSet implements java.sql.ResultSet { + Jdbc2ResultSet (org.postgresql.PGConnection conn, Statement statement) + { + super (conn, statement); + } + + public Jdbc2ResultSet(Jdbc2Connection conn, Statement statement, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) { super(conn, statement, fields, tuples, status, updateCount, insertOID, binaryCursor); Index: org/postgresql/jdbc3/AbstractJdbc3ResultSet.java =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc3/AbstractJdbc3ResultSet.java,v retrieving revision 1.2 diff -u -r1.2 AbstractJdbc3ResultSet.java --- org/postgresql/jdbc3/AbstractJdbc3ResultSet.java 2002/09/06 21:23:06 1.2 +++ org/postgresql/jdbc3/AbstractJdbc3ResultSet.java 2002/12/11 14:13:43 @@ -12,6 +12,12 @@ public abstract class AbstractJdbc3ResultSet extends org.postgresql.jdbc2.AbstractJdbc2ResultSet { + protected AbstractJdbc3ResultSet (org.postgresql.PGConnection conn, Statement statement) + { + super(conn, statement); + } + + public AbstractJdbc3ResultSet(org.postgresql.PGConnection conn, Statement statement, org.postgresql.Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) { super (conn, statement, fields, tuples, status, updateCount, insertOID, binaryCursor); Index: org/postgresql/jdbc3/Jdbc3Connection.java =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc3/Jdbc3Connection.java,v retrieving revision 1.2 diff -u -r1.2 Jdbc3Connection.java --- org/postgresql/jdbc3/Jdbc3Connection.java 2002/09/06 21:23:06 1.2 +++ org/postgresql/jdbc3/Jdbc3Connection.java 2002/12/11 14:13:43 @@ -46,16 +46,18 @@ return metadata; } - public java.sql.ResultSet getResultSet(Statement statement, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException + + + /** new nic method **/ + public java.sql.ResultSet createResultSet (Statement statement) { - return new Jdbc3ResultSet(this, statement, fields, tuples, status, updateCount, insertOID, binaryCursor); + return new Jdbc3ResultSet(this, statement); } + - public java.sql.ResultSet getResultSet(Statement statement, Field[] fields, Vector tuples, String status, int updateCount) throws SQLException + public org.postgresql.PGRefCursorResultSet createRefCursorResultSet (java.sql.Statement statement, String cursorName) throws SQLException { - return new Jdbc3ResultSet(this, statement, fields, tuples, status, updateCount, 0, false); + return new Jdbc3RefCursorResultSet(statement, cursorName); } - + } - - Index: org/postgresql/jdbc3/Jdbc3RefCursorResultSet.java =================================================================== RCS file: Jdbc3RefCursorResultSet.java diff -N Jdbc3RefCursorResultSet.java --- /dev/null Wed Dec 11 09:09:00 2002 +++ Jdbc3RefCursorResultSet.java Wed Dec 11 09:13:43 2002 @@ -0,0 +1,41 @@ +package org.postgresql.jdbc3; + + +import org.postgresql.PGConnection; + + +/** A real result set based on a ref cursor. + * + * @author Nic Ferrier + */ +public class Jdbc3RefCursorResultSet extends Jdbc3ResultSet implements org.postgresql.PGRefCursorResultSet +{ + + String refCursorHandle; + + // Indicates when the result set has activaly bound to the cursor. + boolean isInitialized = false; + + Jdbc3RefCursorResultSet(java.sql.Statement statement, String refCursorName) throws java.sql.SQLException + { + super((PGConnection)statement.getConnection(), statement); + this.refCursorHandle = refCursorName; + } + + public String getRefCursor () + { + return refCursorHandle; + } + + public boolean next () throws java.sql.SQLException + { + if (isInitialized) + return super.next(); + // Initialize this res set with the rows from the cursor. + String[] toExec = { "FETCH ALL IN \"" + refCursorHandle + "\";" }; + Jdbc3Connection execr = (Jdbc3Connection) statement.getConnection(); + execr.execSQL(toExec, new String[0], statement, this); + isInitialized = true; + return super.next(); + } +} Index: org/postgresql/jdbc3/Jdbc3ResultSet.java =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc3/Jdbc3ResultSet.java,v retrieving revision 1.3 diff -u -r1.3 Jdbc3ResultSet.java --- org/postgresql/jdbc3/Jdbc3ResultSet.java 2002/09/11 05:38:45 1.3 +++ org/postgresql/jdbc3/Jdbc3ResultSet.java 2002/12/11 14:13:43 @@ -13,6 +13,13 @@ public class Jdbc3ResultSet extends org.postgresql.jdbc3.AbstractJdbc3ResultSet implements java.sql.ResultSet { + Jdbc3ResultSet (org.postgresql.PGConnection conn, Statement statement) + { + super (conn, statement); + } + + + public Jdbc3ResultSet(Jdbc3Connection conn, Statement statement, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) { super(conn, statement, fields, tuples, status, updateCount, insertOID, binaryCursor); Index: org/postgresql/util/Serialize.java =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/util/Serialize.java,v retrieving revision 1.14 diff -u -r1.14 Serialize.java --- org/postgresql/util/Serialize.java 2002/10/01 00:39:02 1.14 +++ org/postgresql/util/Serialize.java 2002/12/11 14:13:44 @@ -405,7 +405,7 @@ if (Driver.logDebug) Driver.debug("Serialize.store: " + sb.toString() ); - ResultSet rs = ((org.postgresql.jdbc1.AbstractJdbc1Connection)conn).ExecSQL(sb.toString()); + ResultSet rs = ((org.postgresql.jdbc1.AbstractJdbc1Connection)conn).doQuery(sb.toString()); // fetch the OID for returning if (update)