Third phase of restructuring to add jdbc3 support.
authorBarry Lind
Thu, 25 Jul 2002 22:45:28 +0000 (22:45 +0000)
committerBarry Lind
Thu, 25 Jul 2002 22:45:28 +0000 (22:45 +0000)
 Modified Files:
  jdbc/org/postgresql/jdbc1/AbstractJdbc1Connection.java
  jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java
  jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java
  jdbc/org/postgresql/jdbc1/DatabaseMetaData.java
  jdbc/org/postgresql/jdbc1/Jdbc1Connection.java
  jdbc/org/postgresql/jdbc1/Jdbc1ResultSet.java
  jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java
  jdbc/org/postgresql/jdbc2/AbstractJdbc2Statement.java
  jdbc/org/postgresql/jdbc2/Array.java
  jdbc/org/postgresql/jdbc2/DatabaseMetaData.java
  jdbc/org/postgresql/jdbc2/Jdbc2Connection.java
  jdbc/org/postgresql/jdbc2/Jdbc2ResultSet.java
 Added Files:
  jdbc/org/postgresql/jdbc1/Jdbc1CallableStatement.java
  jdbc/org/postgresql/jdbc2/Jdbc2CallableStatement.java
 Removed Files:
  jdbc/org/postgresql/jdbc1/CallableStatement.java
  jdbc/org/postgresql/jdbc2/CallableStatement.java
  jdbc/org/postgresql/jdbc2/UpdateableResultSet.java

17 files changed:
src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Connection.java
src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java
src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java
src/interfaces/jdbc/org/postgresql/jdbc1/CallableStatement.java [deleted file]
src/interfaces/jdbc/org/postgresql/jdbc1/DatabaseMetaData.java
src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1CallableStatement.java [new file with mode: 0644]
src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1Connection.java
src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1ResultSet.java
src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java
src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2Statement.java
src/interfaces/jdbc/org/postgresql/jdbc2/Array.java
src/interfaces/jdbc/org/postgresql/jdbc2/CallableStatement.java [deleted file]
src/interfaces/jdbc/org/postgresql/jdbc2/DatabaseMetaData.java
src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2CallableStatement.java [new file with mode: 0644]
src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Connection.java
src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2ResultSet.java
src/interfaces/jdbc/org/postgresql/jdbc2/UpdateableResultSet.java [deleted file]

index 98aa33e5c916e5fed394c05618fa608314ccf1a3..f6d3807bb9acfbbf279a5ef83bb1637fd552c0aa 100644 (file)
@@ -13,7 +13,7 @@ import org.postgresql.largeobject.LargeObjectManager;
 import org.postgresql.util.*;
 
 
-/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Connection.java,v 1.1 2002/07/23 03:59:55 barry Exp $
+/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Connection.java,v 1.2 2002/07/25 22:45:27 barry Exp $
  * This class defines methods of the jdbc1 specification.  This class is
  * extended by org.postgresql.jdbc2.AbstractJdbc2Connection which adds the jdbc2
  * methods.  The real Connection class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Connection
@@ -359,8 +359,7 @@ public abstract class AbstractJdbc1Connection implements org.postgresql.PGConnec
         // are common to all implementations (JDBC1 or 2), they are placed here.
         // This should make it easy to maintain the two specifications.
 
-//BJL TODO this method shouldn't need to take a Connection since this can be used.
-        public abstract java.sql.ResultSet getResultSet(java.sql.Statement stat, 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, long insertOID, boolean binaryCursor) throws SQLException;
 
         /*
          * This adds a warning to the warning chain.
index 5aa4f90298a07ab1153a3fee44934309f686f41e..3bb278a8e9d8168e744a697795355a2451634994 100644 (file)
@@ -13,15 +13,15 @@ import org.postgresql.largeobject.*;
 import org.postgresql.util.PGbytea;
 import org.postgresql.util.PSQLException;
 
-/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1ResultSet.java,v 1.1 2002/07/23 03:59:55 barry Exp $
+/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1ResultSet.java,v 1.2 2002/07/25 22:45:27 barry Exp $
  * This class defines methods of the jdbc1 specification.  This class is
  * 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
 {
-
    protected Vector rows;          // The results
+        protected Statement statement;
    protected Field fields[];       // The field descriptions
    protected String status;        // Status of the result
    protected boolean binaryCursor = false; // is the data binary or Strings
@@ -33,7 +33,7 @@ public abstract class AbstractJdbc1ResultSet
    protected SQLWarning warnings = null;   // The warning chain
    protected boolean wasNullFlag = false;  // the flag for wasNull()
 
-   //  We can chain multiple resultSets together - this points to
+   // We can chain multiple resultSets together - this points to
    // next resultSet in the chain.
    protected ResultSet next = null;
 
@@ -41,9 +41,10 @@ public abstract class AbstractJdbc1ResultSet
    public byte[][] rowBuffer=null;
 
 
-   public AbstractJdbc1ResultSet(org.postgresql.PGConnection conn, 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;
        this.fields = fields;
        this.rows = tuples;
        this.status = status;
@@ -116,7 +117,7 @@ public abstract class AbstractJdbc1ResultSet
                throw new PSQLException("postgresql.res.badbyte", s);
            }
        }
-       return 0;       // SQL NULL
+       return 0; // SQL NULL
    }
 
    public short getShort(int columnIndex) throws SQLException
@@ -134,7 +135,7 @@ public abstract class AbstractJdbc1ResultSet
                throw new PSQLException("postgresql.res.badshort", s);
            }
        }
-       return 0;       // SQL NULL
+       return 0; // SQL NULL
    }
 
    public int getInt(int columnIndex) throws SQLException
index 6b06cc873e0e3bd36375a0575d1ecb58698783ec..96a50efa8fa5e8e76dee9df416e2640bf8c79b82 100644 (file)
@@ -8,7 +8,7 @@ import java.util.Vector;
 import org.postgresql.largeobject.*;
 import org.postgresql.util.*;
 
-/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.2 2002/07/24 22:08:39 barry Exp $
+/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.3 2002/07/25 22:45:27 barry Exp $
  * This class defines methods of the jdbc1 specification.  This class is
  * extended by org.postgresql.jdbc2.AbstractJdbc2Statement which adds the jdbc2
  * methods.  The real Statement class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Statement
@@ -47,6 +47,20 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
    protected String[] templateStrings;
    protected String[] inStrings;
 
+   //Used by the callablestatement style methods
+   private static final String JDBC_SYNTAX = "{[? =] call  ([? [,?]*]) }";
+   private static final String RESULT_COLUMN = "result";
+   private String originalSql = "";
+   private boolean isFunction;
+   // functionReturnType contains the user supplied value to check
+   // testReturn contains a modified version to make it easier to 
+   // check the getXXX methods..
+   private int functionReturnType;
+   private int testReturn;
+   // returnTypeSet is true when a proper call to registerOutParameter has been made
+   private boolean returnTypeSet;
+   protected Object callResult;
+
 
 
    public AbstractJdbc1Statement (AbstractJdbc1Connection connection)
@@ -62,6 +76,10 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
    }
 
    protected void parseSqlStmt () throws SQLException {
+       if (this instanceof CallableStatement) {
+                modifyJdbcCall();
+       }
+
        Vector v = new Vector();
        boolean inQuotes = false;
        int lastParmEnd = 0, i;
@@ -179,7 +197,23 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
        // New in 7.1, pass Statement so that ExecSQL can customise to it
        result = ((AbstractJdbc1Connection)connection).ExecSQL(sql, (java.sql.Statement)this);
 
-       return (result != null && ((AbstractJdbc1ResultSet)result).reallyResultSet());
+                //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) 
+               throw new PSQLException ("postgresql.call.wrongrtntype",
+                                        new Object[]{
+                   "java.sql.Types=" + columnType, "java.sql.Types="+functionReturnType }); 
+               result.close ();
+                        return true;
+       } else {
+               return (result != null && ((AbstractJdbc1ResultSet)result).reallyResultSet());
+       }
    }
 
    /*
@@ -233,6 +267,8 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
    {
        if (result == null)
            return -1;
+                if (isFunction)
+               return 1;
        if (((AbstractJdbc1ResultSet)result).reallyResultSet())
            return -1;
        return ((AbstractJdbc1ResultSet)result).getResultCount();
@@ -253,14 +289,6 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
 
 
 
-
-
-
-
-
-
-
-
    /*
     * Returns the status message from the current Result.

     * This is used internally by the driver.
@@ -1214,6 +1242,291 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
            setSerialize(parameterIndex, connection.storeObject(x), x.getClass().getName() );
    }
 
+   /*
+    * Before executing a stored procedure call you must explicitly
+    * call registerOutParameter to register the java.sql.Type of each
+    * out parameter.
+    *
+    * 

Note: When reading the value of an out parameter, you must use

+    * the getXXX method whose Java type XXX corresponds to the
+    * parameter's registered SQL type.
+    *
+    * ONLY 1 RETURN PARAMETER if {?= call ..} syntax is used
+    *
+    * @param parameterIndex the first parameter is 1, the second is 2,...
+    * @param sqlType SQL type code defined by java.sql.Types; for
+    * parameters of type Numeric or Decimal use the version of
+    * registerOutParameter that accepts a scale value
+    * @exception SQLException if a database-access error occurs.
+    */
+   public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException
+       {
+           if (parameterIndex != 1)
+               throw new PSQLException ("postgresql.call.noinout");
+           if (!isFunction)
+               throw new PSQLException ("postgresql.call.procasfunc", originalSql);
+           
+           // functionReturnType contains the user supplied value to check
+           // testReturn contains a modified version to make it easier to 
+           // check the getXXX methods..
+           functionReturnType = sqlType;
+           testReturn = sqlType;
+           if (functionReturnType == Types.CHAR || 
+               functionReturnType == Types.LONGVARCHAR)
+               testReturn = Types.VARCHAR;
+           else if (functionReturnType == Types.FLOAT)
+               testReturn = Types.REAL; // changes to streamline later error checking
+           returnTypeSet = true;
+       }
+
+   /*
+    * You must also specify the scale for numeric/decimal types:
+    *
+    * 

Note: When reading the value of an out parameter, you must use

+    * the getXXX method whose Java type XXX corresponds to the
+    * parameter's registered SQL type.
+    *
+    * @param parameterIndex the first parameter is 1, the second is 2,...
+    * @param sqlType use either java.sql.Type.NUMERIC or java.sql.Type.DECIMAL
+    * @param scale a value greater than or equal to zero representing the
+    * desired number of digits to the right of the decimal point
+    * @exception SQLException if a database-access error occurs.
+    */
+   public void registerOutParameter(int parameterIndex, int sqlType,
+                                    int scale) throws SQLException
+       {
+           registerOutParameter (parameterIndex, sqlType); // ignore for now..
+       }
+
+   /*
+    * An OUT parameter may have the value of SQL NULL; wasNull
+    * reports whether the last value read has this special value.
+    *
+    * 

Note: You must first call getXXX on a parameter to read its

+    * value and then call wasNull() to see if the value was SQL NULL.
+    * @return true if the last parameter read was SQL NULL
+    * @exception SQLException if a database-access error occurs.
+    */
+   public boolean wasNull() throws SQLException
+   {
+       // check to see if the last access threw an exception
+       return (callResult == null);
+   }
+
+   /*
+    * Get the value of a CHAR, VARCHAR, or LONGVARCHAR parameter as a
+    * Java String.
+    *
+    * @param parameterIndex the first parameter is 1, the second is 2,...
+    * @return the parameter value; if the value is SQL NULL, the result is null
+    * @exception SQLException if a database-access error occurs.
+    */
+   public String getString(int parameterIndex) throws SQLException
+   {
+       checkIndex (parameterIndex, Types.VARCHAR, "String");
+       return (String)callResult;
+   }
+
+
+   /*
+    * Get the value of a BIT parameter as a Java boolean.
+    *
+    * @param parameterIndex the first parameter is 1, the second is 2,...
+    * @return the parameter value; if the value is SQL NULL, the result is false
+    * @exception SQLException if a database-access error occurs.
+    */
+   public boolean getBoolean(int parameterIndex) throws SQLException
+   {
+       checkIndex (parameterIndex, Types.BIT, "Boolean");
+       if (callResult == null) return false;
+       return ((Boolean)callResult).booleanValue ();
+   }
+
+   /*
+    * Get the value of a TINYINT parameter as a Java byte.
+    *
+    * @param parameterIndex the first parameter is 1, the second is 2,...
+    * @return the parameter value; if the value is SQL NULL, the result is 0
+    * @exception SQLException if a database-access error occurs.
+    */
+   public byte getByte(int parameterIndex) throws SQLException
+   {
+       checkIndex (parameterIndex, Types.TINYINT, "Byte");
+       if (callResult == null) return 0;
+       return (byte)((Integer)callResult).intValue ();
+   }
+
+   /*
+    * Get the value of a SMALLINT parameter as a Java short.
+    *
+    * @param parameterIndex the first parameter is 1, the second is 2,...
+    * @return the parameter value; if the value is SQL NULL, the result is 0
+    * @exception SQLException if a database-access error occurs.
+    */
+   public short getShort(int parameterIndex) throws SQLException
+   {
+       checkIndex (parameterIndex, Types.SMALLINT, "Short");
+       if (callResult == null) return 0;
+       return (short)((Integer)callResult).intValue ();
+   }
+       
+
+   /*
+    * Get the value of an INTEGER parameter as a Java int.
+    *
+    * @param parameterIndex the first parameter is 1, the second is 2,...
+    * @return the parameter value; if the value is SQL NULL, the result is 0
+    * @exception SQLException if a database-access error occurs.
+    */
+   public int getInt(int parameterIndex) throws SQLException
+   {
+       checkIndex (parameterIndex, Types.INTEGER, "Int");
+       if (callResult == null) return 0;
+       return ((Integer)callResult).intValue ();
+   }
+
+   /*
+    * Get the value of a BIGINT parameter as a Java long.
+    *
+    * @param parameterIndex the first parameter is 1, the second is 2,...
+    * @return the parameter value; if the value is SQL NULL, the result is 0
+    * @exception SQLException if a database-access error occurs.
+    */
+   public long getLong(int parameterIndex) throws SQLException
+   {
+       checkIndex (parameterIndex, Types.BIGINT, "Long");
+       if (callResult == null) return 0;
+       return ((Long)callResult).longValue ();
+   }
+
+   /*
+    * Get the value of a FLOAT parameter as a Java float.
+    *
+    * @param parameterIndex the first parameter is 1, the second is 2,...
+    * @return the parameter value; if the value is SQL NULL, the result is 0
+    * @exception SQLException if a database-access error occurs.
+    */
+   public float getFloat(int parameterIndex) throws SQLException
+   {
+       checkIndex (parameterIndex, Types.REAL, "Float");
+       if (callResult == null) return 0;
+       return ((Float)callResult).floatValue ();
+   }
+
+   /*
+    * Get the value of a DOUBLE parameter as a Java double.
+    *
+    * @param parameterIndex the first parameter is 1, the second is 2,...
+    * @return the parameter value; if the value is SQL NULL, the result is 0
+    * @exception SQLException if a database-access error occurs.
+    */
+   public double getDouble(int parameterIndex) throws SQLException
+   {
+       checkIndex (parameterIndex, Types.DOUBLE, "Double");
+       if (callResult == null) return 0;
+       return ((Double)callResult).doubleValue ();
+   }
+
+   /*
+    * Get the value of a NUMERIC parameter as a java.math.BigDecimal
+    * object.
+    *
+    * @param parameterIndex the first parameter is 1, the second is 2,...
+    * @param scale a value greater than or equal to zero representing the
+    * desired number of digits to the right of the decimal point
+    * @return the parameter value; if the value is SQL NULL, the result is null
+    * @exception SQLException if a database-access error occurs.
+    * @deprecated in Java2.0
+    */
+   public BigDecimal getBigDecimal(int parameterIndex, int scale)
+   throws SQLException
+   {
+       checkIndex (parameterIndex, Types.NUMERIC, "BigDecimal");
+       return ((BigDecimal)callResult);
+   }
+
+   /*
+    * Get the value of a SQL BINARY or VARBINARY parameter as a Java
+    * byte[]
+    *
+    * @param parameterIndex the first parameter is 1, the second is 2,...
+    * @return the parameter value; if the value is SQL NULL, the result is null
+    * @exception SQLException if a database-access error occurs.
+    */
+   public byte[] getBytes(int parameterIndex) throws SQLException
+   {
+       checkIndex (parameterIndex, Types.VARBINARY, "Bytes");
+       return ((byte [])callResult);
+   }
+
+
+   /*
+    * Get the value of a SQL DATE parameter as a java.sql.Date object
+    *
+    * @param parameterIndex the first parameter is 1, the second is 2,...
+    * @return the parameter value; if the value is SQL NULL, the result is null
+    * @exception SQLException if a database-access error occurs.
+    */
+   public java.sql.Date getDate(int parameterIndex) throws SQLException
+   {
+       checkIndex (parameterIndex, Types.DATE, "Date");
+       return (java.sql.Date)callResult;
+   }
+
+   /*
+    * Get the value of a SQL TIME parameter as a java.sql.Time object.
+    *
+    * @param parameterIndex the first parameter is 1, the second is 2,...
+    * @return the parameter value; if the value is SQL NULL, the result is null
+    * @exception SQLException if a database-access error occurs.
+    */
+   public java.sql.Time getTime(int parameterIndex) throws SQLException
+   {
+       checkIndex (parameterIndex, Types.TIME, "Time");
+       return (java.sql.Time)callResult;
+   }
+
+   /*
+    * Get the value of a SQL TIMESTAMP parameter as a java.sql.Timestamp object.
+    *
+    * @param parameterIndex the first parameter is 1, the second is 2,...
+    * @return the parameter value; if the value is SQL NULL, the result is null
+    * @exception SQLException if a database-access error occurs.
+    */
+   public java.sql.Timestamp getTimestamp(int parameterIndex)
+   throws SQLException
+   {
+       checkIndex (parameterIndex, Types.TIMESTAMP, "Timestamp");
+       return (java.sql.Timestamp)callResult;
+   }
+
+   // getObject returns a Java object for the parameter.
+   // See the JDBC spec's "Dynamic Programming" chapter for details.
+   /*
+    * Get the value of a parameter as a Java object.
+    *
+    * 

This method returns a Java object whose type coresponds to the

+    * SQL type that was registered for this parameter using
+    * registerOutParameter.
+    *
+    * 

Note that this method may be used to read datatabase-specific,

+    * abstract data types. This is done by specifying a targetSqlType
+    * of java.sql.types.OTHER, which allows the driver to return a
+    * database-specific Java type.
+    *
+    * 

See the JDBC spec's "Dynamic Programming" chapter for details.

+    *
+    * @param parameterIndex the first parameter is 1, the second is 2,...
+    * @return A java.lang.Object holding the OUT parameter value.
+    * @exception SQLException if a database-access error occurs.
+    */
+   public Object getObject(int parameterIndex)
+   throws SQLException
+   {
+       checkIndex (parameterIndex);        
+       return callResult;
+   }
+
    /*
     * Returns the SQL statement with the current template values
     * substituted.
@@ -1253,6 +1566,8 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
    {
        if (paramIndex < 1 || paramIndex > inStrings.length)
            throw new PSQLException("postgresql.prep.range");
+       if (paramIndex == 1 && isFunction) // need to registerOut instead
+           throw new PSQLException ("postgresql.call.funcover");             
        inStrings[paramIndex - 1] = s;
    }
 
@@ -1267,6 +1582,13 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
        sbuf.setLength(0);
        int i;
 
+       if (isFunction && !returnTypeSet)
+           throw new PSQLException("postgresql.call.noreturntype");
+       if (isFunction) { // set entry 1 to dummy entry..
+           inStrings[0] = ""; // dummy entry which ensured that no one overrode
+           // and calls to setXXX (2,..) really went to first arg in a function call..
+       }
+
        for (i = 0 ; i < inStrings.length ; ++i)
        {
            if (inStrings[i] == null)
@@ -1299,5 +1621,67 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
        set(parameterIndex, Long.toString(x) + "::" + tablename );
    }
 
+   /** 
+    * this method will turn a string of the form
+    * {? = call  (?, [?,..]) }
+    * into the PostgreSQL format which is 
+    * select  (?, [?, ...]) as result
+    * 
+    */
+   private void modifyJdbcCall() throws SQLException {
+       // syntax checking is not complete only a few basics :(
+       originalSql = sql; // save for error msgs..
+       int index = sql.indexOf ("="); // is implied func or proc?
+       boolean isValid = true;
+       if (index != -1) {
+           isFunction = true;
+           isValid = sql.indexOf ("?") < index; // ? before =          
+       }
+       sql = sql.trim ();
+       if (sql.startsWith ("{") && sql.endsWith ("}")) {
+           sql = sql.substring (1, sql.length() -1);
+       } else isValid = false;
+       index = sql.indexOf ("call"); 
+       if (index == -1 || !isValid)
+           throw new PSQLException ("postgresql.call.malformed", 
+                                    new Object[]{sql, JDBC_SYNTAX});
+       sql = sql.replace ('{', ' '); // replace these characters
+       sql = sql.replace ('}', ' ');
+       sql = sql.replace (';', ' ');
+       
+       // this removes the 'call' string and also puts a hidden '?'
+       // at the front of the line for functions, this will
+       // allow the registerOutParameter to work correctly
+                // because in the source sql there was one more ? for the return
+                // value that is not needed by the postgres syntax.  But to make 
+                // sure that the parameter numbers are the same as in the original
+                // sql we add a dummy parameter in this case
+       sql = (isFunction ? "?" : "") + sql.substring (index + 4);
+       
+       sql = "select " + sql + " as " + RESULT_COLUMN + ";";     
+   }
+
+   /** 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});
+   }
+   /** 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
+    */
+   private void checkIndex (int parameterIndex) throws SQLException {
+       if (!isFunction)
+           throw new PSQLException("postgresql.call.noreturntype");
+       if (parameterIndex != 1)
+           throw new PSQLException("postgresql.call.noinout");
+   }
+       
 
 }
diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/CallableStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc1/CallableStatement.java
deleted file mode 100644 (file)
index dab157f..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-package org.postgresql.jdbc1;
-
-// IMPORTANT NOTE: This file implements the JDBC 1 version of the driver.
-// If you make any modifications to this file, you must make sure that the
-// changes are also made (if relevent) to the related JDBC 2 class in the
-// org.postgresql.jdbc2 package.
-
-import java.sql.*;
-import java.math.*;
-
-/*
- * CallableStatement is used to execute SQL stored procedures.
- *
- * 

JDBC provides a stored procedure SQL escape that allows stored

- * procedures to be called in a standard way for all RDBMS's. This escape
- * syntax has one form that includes a result parameter and one that does
- * not. If used, the result parameter must be registered as an OUT
- * parameter. The other parameters may be used for input, output or both.
- * Parameters are refered to sequentially, by number. The first parameter
- * is 1.
- *
- * {?= call [,, ...]}
- * {call [,, ...]}
- *
- *
- * 

IN parameter values are set using the set methods inherited from

- * PreparedStatement. The type of all OUT parameters must be registered
- * prior to executing the stored procedure; their values are retrieved
- * after execution via the get methods provided here.
- *
- * 

A Callable statement may return a ResultSet or multiple ResultSets.

- * Multiple ResultSets are handled using operations inherited from
- * Statement.
- *
- * 

For maximum portability, a call's ResultSets and update counts should 

- * be processed prior to getting the values of output parameters.
- *
- * @see Connection#prepareCall
- * @see ResultSet
- */
-
-public class CallableStatement extends Jdbc1PreparedStatement implements java.sql.CallableStatement
-{
-   /*
-    * @exception SQLException on failure
-    */
-   CallableStatement(Jdbc1Connection c, String q) throws SQLException
-   {
-       super(c, q);
-   }
-
-   /*
-    * Before executing a stored procedure call you must explicitly
-    * call registerOutParameter to register the java.sql.Type of each
-    * out parameter.
-    *
-    * 

Note: When reading the value of an out parameter, you must use

-    * the getXXX method whose Java type XXX corresponds to the
-    * parameter's registered SQL type.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @param sqlType SQL type code defined by java.sql.Types; for
-    * parameters of type Numeric or Decimal use the version of
-    * registerOutParameter that accepts a scale value
-    * @exception SQLException if a database-access error occurs.
-    */
-   public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException
-       {}
-
-   /*
-    * You must also specify the scale for numeric/decimal types:
-    *
-    * 

Note: When reading the value of an out parameter, you must use

-    * the getXXX method whose Java type XXX corresponds to the
-    * parameter's registered SQL type.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @param sqlType use either java.sql.Type.NUMERIC or java.sql.Type.DECIMAL
-    * @param scale a value greater than or equal to zero representing the
-    * desired number of digits to the right of the decimal point
-    * @exception SQLException if a database-access error occurs.
-    */
-   public void registerOutParameter(int parameterIndex, int sqlType,
-                                    int scale) throws SQLException
-       {}
-
-   // Old api?
-   //public boolean isNull(int parameterIndex) throws SQLException {
-   //return true;
-   //}
-
-   /*
-    * An OUT parameter may have the value of SQL NULL; wasNull
-    * reports whether the last value read has this special value.
-    *
-    * 

Note: You must first call getXXX on a parameter to read its

-    * value and then call wasNull() to see if the value was SQL NULL.
-    * @return true if the last parameter read was SQL NULL
-    * @exception SQLException if a database-access error occurs.
-    */
-   public boolean wasNull() throws SQLException
-   {
-       // check to see if the last access threw an exception
-       return false; // fake it for now
-   }
-
-   // Old api?
-   //public String getChar(int parameterIndex) throws SQLException {
-   //return null;
-   //}
-
-   /*
-    * Get the value of a CHAR, VARCHAR, or LONGVARCHAR parameter as a
-    * Java String.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is null
-    * @exception SQLException if a database-access error occurs.
-    */
-   public String getString(int parameterIndex) throws SQLException
-   {
-       return null;
-   }
-   //public String getVarChar(int parameterIndex) throws SQLException {
-   //   return null;
-   //}
-
-   //public String getLongVarChar(int parameterIndex) throws SQLException {
-   //return null;
-   //}
-
-   /*
-    * Get the value of a BIT parameter as a Java boolean.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is false
-    * @exception SQLException if a database-access error occurs.
-    */
-   public boolean getBoolean(int parameterIndex) throws SQLException
-   {
-       return false;
-   }
-
-   /*
-    * Get the value of a TINYINT parameter as a Java byte.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is 0
-    * @exception SQLException if a database-access error occurs.
-    */
-   public byte getByte(int parameterIndex) throws SQLException
-   {
-       return 0;
-   }
-
-   /*
-    * Get the value of a SMALLINT parameter as a Java short.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is 0
-    * @exception SQLException if a database-access error occurs.
-    */
-   public short getShort(int parameterIndex) throws SQLException
-   {
-       return 0;
-   }
-
-   /*
-    * Get the value of an INTEGER parameter as a Java int.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is 0
-    * @exception SQLException if a database-access error occurs.
-    */
-   public int getInt(int parameterIndex) throws SQLException
-   {
-       return 0;
-   }
-
-   /*
-    * Get the value of a BIGINT parameter as a Java long.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is 0
-    * @exception SQLException if a database-access error occurs.
-    */
-   public long getLong(int parameterIndex) throws SQLException
-   {
-       return 0;
-   }
-
-   /*
-    * Get the value of a FLOAT parameter as a Java float.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is 0
-    * @exception SQLException if a database-access error occurs.
-    */
-   public float getFloat(int parameterIndex) throws SQLException
-   {
-       return (float) 0.0;
-   }
-
-   /*
-    * Get the value of a DOUBLE parameter as a Java double.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is 0
-    * @exception SQLException if a database-access error occurs.
-    */
-   public double getDouble(int parameterIndex) throws SQLException
-   {
-       return 0.0;
-   }
-
-   /*
-    * Get the value of a NUMERIC parameter as a java.math.BigDecimal
-    * object.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @param scale a value greater than or equal to zero representing the
-    * desired number of digits to the right of the decimal point
-    * @return the parameter value; if the value is SQL NULL, the result is null
-    * @exception SQLException if a database-access error occurs.
-    */
-   public BigDecimal getBigDecimal(int parameterIndex, int scale)
-   throws SQLException
-   {
-       return null;
-   }
-
-   /*
-    * Get the value of a SQL BINARY or VARBINARY parameter as a Java
-    * byte[]
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is null
-    * @exception SQLException if a database-access error occurs.
-    */
-   public byte[] getBytes(int parameterIndex) throws SQLException
-   {
-       return null;
-   }
-
-   // New API (JPM) (getLongVarBinary)
-   //public byte[] getBinaryStream(int parameterIndex) throws SQLException {
-   //return null;
-   //}
-
-   /*
-    * Get the value of a SQL DATE parameter as a java.sql.Date object
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is null
-    * @exception SQLException if a database-access error occurs.
-    */
-   public java.sql.Date getDate(int parameterIndex) throws SQLException
-   {
-       return null;
-   }
-
-   /*
-    * Get the value of a SQL TIME parameter as a java.sql.Time object.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is null
-    * @exception SQLException if a database-access error occurs.
-    */
-   public java.sql.Time getTime(int parameterIndex) throws SQLException
-   {
-       return null;
-   }
-
-   /*
-    * Get the value of a SQL TIMESTAMP parameter as a java.sql.Timestamp object.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is null
-    * @exception SQLException if a database-access error occurs.
-    */
-   public java.sql.Timestamp getTimestamp(int parameterIndex)
-   throws SQLException
-   {
-       return null;
-   }
-
-   //----------------------------------------------------------------------
-   // Advanced features:
-
-   // You can obtain a ParameterMetaData object to get information
-   // about the parameters to this CallableStatement.
-   //public DatabaseMetaData getMetaData() {
-   //return null;
-   //}
-
-   // getObject returns a Java object for the parameter.
-   // See the JDBC spec's "Dynamic Programming" chapter for details.
-   /*
-    * Get the value of a parameter as a Java object.
-    *
-    * 

This method returns a Java object whose type coresponds to the

-    * SQL type that was registered for this parameter using
-    * registerOutParameter.
-    *
-    * 

Note that this method may be used to read datatabase-specific,

-    * abstract data types. This is done by specifying a targetSqlType
-    * of java.sql.types.OTHER, which allows the driver to return a
-    * database-specific Java type.
-    *
-    * 

See the JDBC spec's "Dynamic Programming" chapter for details.

-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return A java.lang.Object holding the OUT parameter value.
-    * @exception SQLException if a database-access error occurs.
-    */
-   public Object getObject(int parameterIndex)
-   throws SQLException
-   {
-       return null;
-   }
-}
-
index 747ee1f1ea4f2209350fe4fa292f5a9dfa9374ae..bf81f78874d2f5823951bb3bf6ffba33e811013e 100644 (file)
@@ -13,7 +13,7 @@ import org.postgresql.util.PSQLException;
 /*
  * This class provides information about the database as a whole.
  *
- * $Id: DatabaseMetaData.java,v 1.48 2002/07/23 03:59:55 barry Exp $
+ * $Id: DatabaseMetaData.java,v 1.49 2002/07/25 22:45:28 barry 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
@@ -1549,7 +1549,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
 
            v.addElement(tuple);
        }
-       return new Jdbc1ResultSet(connection, f, v, "OK", 1);
+       return connection.getResultSet(null, f, v, "OK", 1);
    }
 
    /*
@@ -1627,7 +1627,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
 
        // add query loop here
 
-       return new Jdbc1ResultSet(connection, f, v, "OK", 1);
+       return connection.getResultSet(null, f, v, "OK", 1);
    }
 
    /*
@@ -1762,7 +1762,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
            v.addElement(tuple);
        }
        r.close();
-       return new Jdbc1ResultSet(connection, f, v, "OK", 1);
+       return connection.getResultSet(null, f, v, "OK", 1);
    }
 
    // This array contains the valid values for the types argument
@@ -1809,7 +1809,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
        f[0] = new Field(connection, "TABLE_SCHEM", iVarcharOid, 32);
        tuple[0] = "".getBytes();
        v.addElement(tuple);
-       return new Jdbc1ResultSet(connection, f, v, "OK", 1);
+       return connection.getResultSet(null, f, v, "OK", 1);
    }
 
    /*
@@ -1854,7 +1854,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
            tuple[0] = getTableTypes[i][0].getBytes();
            v.addElement(tuple);
        }
-       return new Jdbc1ResultSet(connection, f, v, "OK", 1);
+       return connection.getResultSet(null, f, v, "OK", 1);
    }
 
    /*
@@ -2050,7 +2050,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
        }
        r.close();
 
-       return new Jdbc1ResultSet(connection, f, v, "OK", 1);
+       return connection.getResultSet(null, f, v, "OK", 1);
    }
 
    /*
@@ -2113,7 +2113,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
            //v.addElement(tuple);
        }
 
-       return new Jdbc1ResultSet(connection, f, v, "OK", 1);
+       return connection.getResultSet(null, f, v, "OK", 1);
    }
 
    /*
@@ -2203,7 +2203,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
        f[6] = new Field(connection, "DECIMAL_DIGITS", iInt2Oid, 2);
        f[7] = new Field(connection, "PSEUDO_COLUMN", iInt2Oid, 2);
 
-       return new Jdbc1ResultSet(connection, f, v, "OK", 1);
+       return connection.getResultSet(null, f, v, "OK", 1);
    }
 
    /*
@@ -2413,7 +2413,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
            while (hasMore);
        }
 
-       return new Jdbc1ResultSet(connection, f, tuples, "OK", 1);
+       return connection.getResultSet(null, f, tuples, "OK", 1);
    }
 
    /*
@@ -2692,7 +2692,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
                v.addElement(tuple);
            }
            rs.close();
-           return new Jdbc1ResultSet(connection, f, v, "OK", 1);
+           return connection.getResultSet(null, f, v, "OK", 1);
        }
 
        throw new PSQLException("postgresql.metadata.unavailable");
@@ -2832,7 +2832,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
            }
        }
 
-       return new Jdbc1ResultSet(connection, f, v, "OK", 1);
+       return connection.getResultSet(null, f, v, "OK", 1);
    }
 
 }
diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1CallableStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1CallableStatement.java
new file mode 100644 (file)
index 0000000..7cd6910
--- /dev/null
@@ -0,0 +1,14 @@
+package org.postgresql.jdbc1;
+
+
+import java.sql.*;
+
+public class Jdbc1CallableStatement extends AbstractJdbc1Statement implements java.sql.CallableStatement
+{
+
+   public Jdbc1CallableStatement(Jdbc1Connection connection, String sql) throws SQLException
+   {
+       super(connection, sql);
+   }
+}
+
index 249a41049b6ed2c3f86e043da65fbbf18cb9fa5c..b67b07fde9387124c74ba9041d6801553d05e354 100644 (file)
@@ -6,7 +6,7 @@ import java.sql.*;
 import org.postgresql.Field;
 import org.postgresql.util.PSQLException;
 
-/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/Jdbc1Connection.java,v 1.2 2002/07/24 22:08:40 barry Exp $
+/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/Jdbc1Connection.java,v 1.3 2002/07/25 22:45:28 barry Exp $
  * This class implements the java.sql.Connection interface for JDBC1.
  * However most of the implementation is really done in 
  * org.postgresql.jdbc1.AbstractJdbc1Connection
@@ -24,10 +24,9 @@ public class Jdbc1Connection extends org.postgresql.jdbc1.AbstractJdbc1Connectio
        return new org.postgresql.jdbc1.Jdbc1PreparedStatement(this, sql);
    }
 
-//BJL TODO - merge callable statement logic from jdbc2 to jdbc1
    public java.sql.CallableStatement prepareCall(String sql) throws SQLException
    {
-       throw new PSQLException("postgresql.con.call");
+       return new org.postgresql.jdbc1.Jdbc1CallableStatement(this, sql);
    }
 
    public java.sql.DatabaseMetaData getMetaData() throws SQLException
@@ -39,7 +38,12 @@ public class Jdbc1Connection extends org.postgresql.jdbc1.AbstractJdbc1Connectio
 
    public java.sql.ResultSet getResultSet(java.sql.Statement stat, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException
    {
-       return new Jdbc1ResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor);
+       return new Jdbc1ResultSet(this, stat, fields, tuples, status, updateCount, insertOID, binaryCursor);
+   }
+
+   public java.sql.ResultSet getResultSet(java.sql.Statement stat, Field[] fields, Vector tuples, String status, int updateCount) throws SQLException
+   {
+       return new Jdbc1ResultSet(this, stat, fields, tuples, status, updateCount, 0, false);
    }
 
 }
index a959fef9d392539880ac74dd33e0db4d4b1fe08f..57850569ec893cc40fa3eb60cee03631ec31e123 100644 (file)
@@ -5,7 +5,7 @@ import java.sql.*;
 import java.util.Vector;
 import org.postgresql.Field;
 
-/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/Jdbc1ResultSet.java,v 1.1 2002/07/23 03:59:55 barry Exp $
+/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/Jdbc1ResultSet.java,v 1.2 2002/07/25 22:45:28 barry Exp $
  * This class implements the java.sql.ResultSet interface for JDBC1.
  * However most of the implementation is really done in 
  * org.postgresql.jdbc1.AbstractJdbc1ResultSet
@@ -13,14 +13,9 @@ import org.postgresql.Field;
 public class Jdbc1ResultSet extends org.postgresql.jdbc1.AbstractJdbc1ResultSet implements java.sql.ResultSet
 {
 
-   public Jdbc1ResultSet(Jdbc1Connection conn, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor)
+   public Jdbc1ResultSet(Jdbc1Connection conn, Statement statement, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor)
    {
-       super(conn, fields, tuples, status, updateCount, insertOID, binaryCursor);
-   }
-
-   public Jdbc1ResultSet(Jdbc1Connection conn, Field[] fields, Vector tuples, String status, int updateCount)
-   {
-       super(conn, fields, tuples, status, updateCount, 0, false);
+       super(conn, statement, fields, tuples, status, updateCount, insertOID, binaryCursor);
    }
 
    public java.sql.ResultSetMetaData getMetaData() throws SQLException
index d2c5ee07607a39dd84f1fa141f0f5f77d81a54f2..1a6379bf59279fb2d19ae84c2e09c8b030452f99 100644 (file)
@@ -6,747 +6,1348 @@ import java.io.*;
 import java.sql.*;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
-import java.util.Vector;
+import java.util.*;
+import org.postgresql.Driver;
 import org.postgresql.Field;
 import org.postgresql.core.Encoding;
 import org.postgresql.largeobject.*;
 import org.postgresql.util.PGbytea;
 import org.postgresql.util.PSQLException;
 
-/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2ResultSet.java,v 1.2 2002/07/24 22:08:42 barry Exp $
+
+/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2ResultSet.java,v 1.3 2002/07/25 22:45:28 barry Exp $
  * This class defines methods of the jdbc2 specification.  This class extends
  * org.postgresql.jdbc1.AbstractJdbc1ResultSet which provides the jdbc1
  * methods.  The real Statement class (for jdbc2) is org.postgresql.jdbc2.Jdbc2ResultSet
  */
-public class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.AbstractJdbc1ResultSet
-{
-   protected Statement statement;
-
-   protected String sqlQuery=null;
-
-   public AbstractJdbc2ResultSet(org.postgresql.PGConnection conn, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor)
-   {
-       super(conn, fields, tuples, status, updateCount, insertOID, binaryCursor);
-   }
-
-   public java.net.URL getURL(int columnIndex) throws SQLException
-   {
-       return null;
-   }
-
-   public java.net.URL getURL(String columnName) throws SQLException
-   {
-       return null;
-   }
-
-   /*
-    * Get the value of a column in the current row as a Java object
-    *
-    * 

This method will return the value of the given column as a

-    * Java object.  The type of the Java object will be the default
-    * Java Object type corresponding to the column's SQL type, following
-    * the mapping specified in the JDBC specification.
-    *
-    * 

This method may also be used to read database specific abstract

-    * data types.
-    *
-    * @param columnIndex the first column is 1, the second is 2...
-    * @return a Object holding the column value
-    * @exception SQLException if a database access error occurs
-    */
-   public Object getObject(int columnIndex) throws SQLException
-   {
-       Field field;
-
-       checkResultSet( columnIndex );
-
-       wasNullFlag = (this_row[columnIndex - 1] == null);
-       if (wasNullFlag)
-           return null;
-
-       field = fields[columnIndex - 1];
-
-       // some fields can be null, mainly from those returned by MetaData methods
-       if (field == null)
-       {
-           wasNullFlag = true;
-           return null;
-       }
-
-       switch (field.getSQLType())
-       {
-           case Types.BIT:
-               return getBoolean(columnIndex) ? Boolean.TRUE : Boolean.FALSE;
-           case Types.SMALLINT:
-               return new Short(getShort(columnIndex));
-           case Types.INTEGER:
-               return new Integer(getInt(columnIndex));
-           case Types.BIGINT:
-               return new Long(getLong(columnIndex));
-           case Types.NUMERIC:
-               return getBigDecimal
-                      (columnIndex, (field.getMod() == -1) ? -1 : ((field.getMod() - 4) & 0xffff));
-           case Types.REAL:
-               return new Float(getFloat(columnIndex));
-           case Types.DOUBLE:
-               return new Double(getDouble(columnIndex));
-           case Types.CHAR:
-           case Types.VARCHAR:
-               return getString(columnIndex);
-           case Types.DATE:
-               return getDate(columnIndex);
-           case Types.TIME:
-               return getTime(columnIndex);
-           case Types.TIMESTAMP:
-               return getTimestamp(columnIndex);
-           case Types.BINARY:
-           case Types.VARBINARY:
-               return getBytes(columnIndex);
-           case Types.ARRAY:
-               return getArray(columnIndex);
-           default:
-               String type = field.getPGType();
-               // if the backend doesn't know the type then coerce to String
-               if (type.equals("unknown"))
-               {
-                   return getString(columnIndex);
-               }
-               else
-               {
-                   return connection.getObject(field.getPGType(), getString(columnIndex));
-               }
-       }
-   }
-
-   public boolean absolute(int index) throws SQLException
-   {
-       // index is 1-based, but internally we use 0-based indices
-       int internalIndex;
-
-       if (index == 0)
-           throw new SQLException("Cannot move to index of 0");
-
-       final int rows_size = rows.size();
-
-       //if index<0, count from the end of the result set, but check
-       //to be sure that it is not beyond the first index
-       if (index < 0)
-       {
-           if (index >= -rows_size)
-               internalIndex = rows_size + index;
-           else
-           {
-               beforeFirst();
-               return false;
-           }
-       }
-       else
-       {
-           //must be the case that index>0,
-           //find the correct place, assuming that
-           //the index is not too large
-           if (index <= rows_size)
-               internalIndex = index - 1;
-           else
-           {
-               afterLast();
-               return false;
-           }
-       }
-
-       current_row = internalIndex;
-       this_row = (byte [][])rows.elementAt(internalIndex);
-       return true;
-   }
-
-   public void afterLast() throws SQLException
-   {
-       final int rows_size = rows.size();
-       if (rows_size > 0)
-           current_row = rows_size;
-   }
-
-   public void beforeFirst() throws SQLException
-   {
-       if (rows.size() > 0)
-           current_row = -1;
-   }
-
-   public void cancelRowUpdates() throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-   }
-
-   public void deleteRow() throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-   }
-
-   public boolean first() throws SQLException
-   {
-       if (rows.size() <= 0)
-           return false;
-
-       current_row = 0;
-       this_row = (byte [][])rows.elementAt(current_row);
-
-       rowBuffer=new byte[this_row.length][];
-       System.arraycopy(this_row,0,rowBuffer,0,this_row.length);
-
-       return true;
-   }
-
-   public java.sql.Array getArray(String colName) throws SQLException
-   {
-       return getArray(findColumn(colName));
-   }
-
-   public java.sql.Array getArray(int i) throws SQLException
-   {
-       wasNullFlag = (this_row[i - 1] == null);
-       if (wasNullFlag)
-           return null;
-
-       if (i < 1 || i > fields.length)
-           throw new PSQLException("postgresql.res.colrange");
-       return (java.sql.Array) new org.postgresql.jdbc2.Array( connection, i, fields[i - 1], (java.sql.ResultSet)this );
-   }
-
-   public java.math.BigDecimal getBigDecimal(int columnIndex) throws SQLException
-   {
-       return getBigDecimal(columnIndex, -1);
-   }
-
-   public java.math.BigDecimal getBigDecimal(String columnName) throws SQLException
-   {
-       return getBigDecimal(findColumn(columnName));
-   }
-
-   public Blob getBlob(String columnName) throws SQLException
-   {
-       return getBlob(findColumn(columnName));
-   }
-
-   public Blob getBlob(int i) throws SQLException
-   {
-       return new org.postgresql.largeobject.PGblob(connection, getInt(i));
-   }
-
-   public java.io.Reader getCharacterStream(String columnName) throws SQLException
-   {
-       return getCharacterStream(findColumn(columnName));
-   }
-
-   public java.io.Reader getCharacterStream(int i) throws SQLException
-   {
-       checkResultSet( i );
-       wasNullFlag = (this_row[i - 1] == null);
-       if (wasNullFlag)
-           return null;
-
-       if (((AbstractJdbc2Connection)connection).haveMinimumCompatibleVersion("7.2"))
-       {
-           //Version 7.2 supports AsciiStream for all the PG text types
-           //As the spec/javadoc for this method indicate this is to be used for
-           //large text values (i.e. LONGVARCHAR)  PG doesn't have a separate
-           //long string datatype, but with toast the text datatype is capable of
-           //handling very large values.  Thus the implementation ends up calling
-           //getString() since there is no current way to stream the value from the server
-           return new CharArrayReader(getString(i).toCharArray());
-       }
-       else
-       {
-           // In 7.1 Handle as BLOBS so return the LargeObject input stream
-           Encoding encoding = connection.getEncoding();
-           InputStream input = getBinaryStream(i);
-           return encoding.getDecodingReader(input);
-       }
-   }
-
-   public Clob getClob(String columnName) throws SQLException
-   {
-       return getClob(findColumn(columnName));
-   }
-
-   public Clob getClob(int i) throws SQLException
-   {
-       return new org.postgresql.largeobject.PGclob(connection, getInt(i));
-   }
-
-   public int getConcurrency() throws SQLException
-   {
-       // The standard ResultSet class will now return
-       // CONCUR_READ_ONLY. A sub-class will overide this if the query was
-       // updateable.
-       return java.sql.ResultSet.CONCUR_READ_ONLY;
-   }
-
-   public java.sql.Date getDate(int i, java.util.Calendar cal) throws SQLException
-   {
-       // If I read the specs, this should use cal only if we don't
-       // store the timezone, and if we do, then act just like getDate()?
-       // for now...
-       return getDate(i);
-   }
-
-   public Time getTime(int i, java.util.Calendar cal) throws SQLException
-   {
-       // If I read the specs, this should use cal only if we don't
-       // store the timezone, and if we do, then act just like getTime()?
-       // for now...
-       return getTime(i);
-   }
-
-   public Timestamp getTimestamp(int i, java.util.Calendar cal) throws SQLException
-   {
-       // If I read the specs, this should use cal only if we don't
-       // store the timezone, and if we do, then act just like getDate()?
-       // for now...
-       return getTimestamp(i);
-   }
-
-   public java.sql.Date getDate(String c, java.util.Calendar cal) throws SQLException
-   {
-       return getDate(findColumn(c), cal);
-   }
-
-   public Time getTime(String c, java.util.Calendar cal) throws SQLException
-   {
-       return getTime(findColumn(c), cal);
-   }
-
-   public Timestamp getTimestamp(String c, java.util.Calendar cal) throws SQLException
-   {
-       return getTimestamp(findColumn(c), cal);
-   }
-
-   public int getFetchDirection() throws SQLException
-   {
-       //PostgreSQL normally sends rows first->last
-       return java.sql.ResultSet.FETCH_FORWARD;
-   }
-
-   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
-       return rows.size();
-   }
-
-   public Object getObject(String columnName, java.util.Map map) throws SQLException
-   {
-       return getObject(findColumn(columnName), map);
-   }
-
-   /*
-    * This checks against map for the type of column i, and if found returns
-    * an object based on that mapping. The class must implement the SQLData
-    * interface.
-    */
-   public Object getObject(int i, java.util.Map map) throws SQLException
-   {
-       throw org.postgresql.Driver.notImplemented();
-   }
-
-   public Ref getRef(String columnName) throws SQLException
-   {
-       return getRef(findColumn(columnName));
-   }
-
-   public Ref getRef(int i) throws SQLException
-   {
-       //The backend doesn't yet have SQL3 REF types
-       throw new PSQLException("postgresql.psqlnotimp");
-   }
-
-   public int getRow() throws SQLException
-   {
-       final int rows_size = rows.size();
-
-       if (current_row < 0 || current_row >= rows_size)
-           return 0;
-
-       return current_row + 1;
-   }
-
-   // This one needs some thought, as not all ResultSets come from a statement
-   public Statement getStatement() throws SQLException
-   {
-       return statement;
-   }
-
-   public int getType() throws SQLException
-   {
-       // This implementation allows scrolling but is not able to
-       // see any changes. Sub-classes may overide this to return a more
-       // meaningful result.
-       return java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE;
-   }
-
-   public void insertRow() throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-   }
-
-   public boolean isAfterLast() throws SQLException
-   {
-       final int rows_size = rows.size();
-       return (current_row >= rows_size && rows_size > 0);
-   }
-
-   public boolean isBeforeFirst() throws SQLException
-   {
-       return (current_row < 0 && rows.size() > 0);
-   }
-
-   public boolean isFirst() throws SQLException
-   {
-       return (current_row == 0 && rows.size() >= 0);
-   }
-
-   public boolean isLast() throws SQLException
-   {
-       final int rows_size = rows.size();
-       return (current_row == rows_size - 1 && rows_size > 0);
-   }
-
-   public boolean last() throws SQLException
-   {
-       final int rows_size = rows.size();
-       if (rows_size <= 0)
-           return false;
-
-       current_row = rows_size - 1;
-       this_row = (byte [][])rows.elementAt(current_row);
-
-       rowBuffer=new byte[this_row.length][];
-       System.arraycopy(this_row,0,rowBuffer,0,this_row.length);
-
-       return true;
-   }
-
-   public void moveToCurrentRow() throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-   }
-
-   public void moveToInsertRow() throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-   }
-
-   public boolean previous() throws SQLException
-   {
-       if (--current_row < 0)
-           return false;
-       this_row = (byte [][])rows.elementAt(current_row);
-       System.arraycopy(this_row,0,rowBuffer,0,this_row.length);
-       return true;
-   }
-
-   public void refreshRow() throws SQLException
-   {
-       throw new PSQLException("postgresql.notsensitive");
-   }
-
-   public boolean relative(int rows) throws SQLException
-   {
-       //have to add 1 since absolute expects a 1-based index
-       return absolute(current_row + 1 + rows);
-   }
-
-   public boolean rowDeleted() throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-       return false; // javac complains about not returning a value!
-   }
-
-   public boolean rowInserted() throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-       return false; // javac complains about not returning a value!
-   }
-
-   public boolean rowUpdated() throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-       return false; // javac complains about not returning a value!
-   }
-
-   public void setFetchDirection(int direction) throws SQLException
-   {
-       throw new PSQLException("postgresql.psqlnotimp");
-   }
-
-   public void setFetchSize(int rows) throws SQLException
-   {
-       // Sub-classes should implement this as part of their cursor support
-       throw org.postgresql.Driver.notImplemented();
-   }
-
-   public void updateAsciiStream(int columnIndex,
-                                 java.io.InputStream x,
-                                 int length
-                                ) throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-   }
-
-   public void updateAsciiStream(String columnName,
-                                 java.io.InputStream x,
-                                 int length
-                                ) throws SQLException
-   {
-       updateAsciiStream(findColumn(columnName), x, length);
-   }
-
-   public void updateBigDecimal(int columnIndex,
-                                java.math.BigDecimal x
-                               ) throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-   }
-
-   public void updateBigDecimal(String columnName,
-                                java.math.BigDecimal x
-                               ) throws SQLException
-   {
-       updateBigDecimal(findColumn(columnName), x);
-   }
-
-   public void updateBinaryStream(int columnIndex,
-                                  java.io.InputStream x,
-                                  int length
-                                 ) throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-   }
-
-   public void updateBinaryStream(String columnName,
-                                  java.io.InputStream x,
-                                  int length
-                                 ) throws SQLException
-   {
-       updateBinaryStream(findColumn(columnName), x, length);
-   }
-
-   public void updateBoolean(int columnIndex, boolean x) throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-   }
-
-   public void updateBoolean(String columnName, boolean x) throws SQLException
-   {
-       updateBoolean(findColumn(columnName), x);
-   }
-
-   public void updateByte(int columnIndex, byte x) throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-   }
-
-   public void updateByte(String columnName, byte x) throws SQLException
-   {
-       updateByte(findColumn(columnName), x);
-   }
-
-   public void updateBytes(String columnName, byte[] x) throws SQLException
-   {
-       updateBytes(findColumn(columnName), x);
-   }
-
-   public void updateBytes(int columnIndex, byte[] x) throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-   }
-
-   public void updateCharacterStream(int columnIndex,
-                                     java.io.Reader x,
-                                     int length
-                                    ) throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-   }
-
-   public void updateCharacterStream(String columnName,
-                                     java.io.Reader x,
-                                     int length
-                                    ) throws SQLException
-   {
-       updateCharacterStream(findColumn(columnName), x, length);
-   }
-
-   public void updateDate(int columnIndex, java.sql.Date x) throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-   }
-
-   public void updateDate(String columnName, java.sql.Date x) throws SQLException
-   {
-       updateDate(findColumn(columnName), x);
-   }
-
-   public void updateDouble(int columnIndex, double x) throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-   }
-
-   public void updateDouble(String columnName, double x) throws SQLException
-   {
-       updateDouble(findColumn(columnName), x);
-   }
-
-   public void updateFloat(int columnIndex, float x) throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-   }
-
-   public void updateFloat(String columnName, float x) throws SQLException
-   {
-       updateFloat(findColumn(columnName), x);
-   }
-
-   public void updateInt(int columnIndex, int x) throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-   }
-
-   public void updateInt(String columnName, int x) throws SQLException
-   {
-       updateInt(findColumn(columnName), x);
-   }
-
-       public void updateLong(int columnIndex, long x) throws SQLException
-       {
-           // only sub-classes implement CONCUR_UPDATEABLE
-           notUpdateable();
-       }
-
-       public void updateLong(String columnName, long x) throws SQLException
-       {
-           updateLong(findColumn(columnName), x);
-       }
-
-       public void updateNull(int columnIndex) throws SQLException
-       {
-           // only sub-classes implement CONCUR_UPDATEABLE
-           notUpdateable();
-       }
-
-   public void updateNull(String columnName) throws SQLException
-   {
-       updateNull(findColumn(columnName));
-   }
-
-   public void updateObject(int columnIndex, Object x) throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-   }
-
-   public void updateObject(String columnName, Object x) throws SQLException
-   {
-       updateObject(findColumn(columnName), x);
-   }
-
-   public void updateObject(int columnIndex, Object x, int scale) throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-   }
-
-   public void updateObject(String columnName, Object x, int scale) throws SQLException
-   {
-       updateObject(findColumn(columnName), x, scale);
-   }
-
-   public void updateRow() throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-   }
-
-   public void updateShort(int columnIndex, short x) throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-   }
-
-   public void updateShort(String columnName, short x) throws SQLException
-   {
-       updateShort(findColumn(columnName), x);
-   }
-
-   public void updateString(int columnIndex, String x) throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-   }
-
-   public void updateString(String columnName, String x) throws SQLException
-   {
-       updateString(findColumn(columnName), x);
-   }
-
-   public void updateTime(int columnIndex, Time x) throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-   }
-
-   public void updateTime(String columnName, Time x) throws SQLException
-   {
-       updateTime(findColumn(columnName), x);
-   }
-
-   public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException
-   {
-       // only sub-classes implement CONCUR_UPDATEABLE
-       notUpdateable();
-   }
-
-   public void updateTimestamp(String columnName, Timestamp x) throws SQLException
-   {
-       updateTimestamp(findColumn(columnName), x);
-   }
-
-   // helper method. Throws an SQLException when an update is not possible
-   public void notUpdateable() throws SQLException
-   {
-       throw new PSQLException("postgresql.noupdate");
-   }
-
-   /*
-    * It's used currently by getStatement() but may also with the new core
-    * package.
-    */
-   public void setStatement(Statement statement)
-   {
-       this.statement = statement;
-   }
-
-   public void setSQLQuery(String sqlQuery) {
-       this.sqlQuery=sqlQuery;
-   }
+public class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.AbstractJdbc1ResultSet {
+  protected String sqlQuery = null;
+
+  //needed for updateable result set support
+  protected boolean updateable = false;
+  protected boolean doingUpdates = false;
+  protected boolean onInsertRow = false;
+  protected Hashtable updateValues = new Hashtable();
+  private boolean usingOID = false;   // are we using the OID for the primary key?
+  private Vector primaryKeys;    // list of primary keys
+  private int numKeys = 0;
+  private boolean singleTable = false;
+  protected String tableName = null;
+  protected PreparedStatement updateStatement = null;
+  protected PreparedStatement insertStatement = null;
+  protected PreparedStatement deleteStatement = null;
+  private PreparedStatement selectStatement = null;
+
+
+
+  public AbstractJdbc2ResultSet(org.postgresql.PGConnection conn, Statement statement, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) {
+    super (conn, statement, fields, tuples, status, updateCount, insertOID, binaryCursor);
+  }
+
+  public java.net.URL getURL(int columnIndex) throws SQLException {
+    return null;
+  }
+
+
+  public java.net.URL getURL(String columnName) throws SQLException {
+    return null;
+  }
+
+
+  /*
+   * Get the value of a column in the current row as a Java object
+   *
+   * 

This method will return the value of the given column as a

+   * Java object.  The type of the Java object will be the default
+   * Java Object type corresponding to the column's SQL type, following
+   * the mapping specified in the JDBC specification.
+   *
+   * 

This method may also be used to read database specific abstract

+   * data types.
+   *
+   * @param columnIndex the first column is 1, the second is 2...
+   * @return a Object holding the column value
+   * @exception SQLException if a database access error occurs
+   */
+  public Object getObject(int columnIndex) throws SQLException {
+    Field field;
+
+    checkResultSet( columnIndex );
+
+    wasNullFlag = (this_row[columnIndex - 1] == null);
+    if (wasNullFlag)
+      return null;
+
+    field = fields[columnIndex - 1];
+
+    // some fields can be null, mainly from those returned by MetaData methods
+    if (field == null) {
+      wasNullFlag = true;
+      return null;
+    }
+
+    switch (field.getSQLType()) {
+    case Types.BIT:
+      return getBoolean(columnIndex) ? Boolean.TRUE : Boolean.FALSE;
+
+    case Types.SMALLINT:
+      return new Short(getShort(columnIndex));
+
+    case Types.INTEGER:
+      return new Integer(getInt(columnIndex));
+
+    case Types.BIGINT:
+      return new Long(getLong(columnIndex));
+
+    case Types.NUMERIC:
+      return getBigDecimal
+        (columnIndex, (field.getMod() == -1) ? -1 : ((field.getMod() - 4) & 0xffff));
+
+    case Types.REAL:
+      return new Float(getFloat(columnIndex));
+
+    case Types.DOUBLE:
+      return new Double(getDouble(columnIndex));
+
+    case Types.CHAR:
+    case Types.VARCHAR:
+      return getString(columnIndex);
+
+    case Types.DATE:
+      return getDate(columnIndex);
+
+    case Types.TIME:
+      return getTime(columnIndex);
+
+    case Types.TIMESTAMP:
+      return getTimestamp(columnIndex);
+
+    case Types.BINARY:
+    case Types.VARBINARY:
+      return getBytes(columnIndex);
+
+    case Types.ARRAY:
+      return getArray(columnIndex);
+
+    default:
+      String type = field.getPGType();
+      // if the backend doesn't know the type then coerce to String
+      if (type.equals("unknown")) {
+        return getString(columnIndex);
+      }
+      else {
+        return connection.getObject(field.getPGType(), getString(columnIndex));
+      }
+    }
+  }
+
+
+  public boolean absolute(int index) throws SQLException {
+    // index is 1-based, but internally we use 0-based indices
+    int internalIndex;
+
+    if (index == 0)
+      throw new SQLException("Cannot move to index of 0");
+
+    final int rows_size = rows.size();
+
+    //if index<0, count from the end of the result set, but check
+    //to be sure that it is not beyond the first index
+    if (index < 0) {
+      if (index >= -rows_size)
+        internalIndex = rows_size + index;
+      else {
+        beforeFirst();
+        return false;
+      }
+    }
+    else {
+      //must be the case that index>0,
+      //find the correct place, assuming that
+      //the index is not too large
+      if (index <= rows_size)
+        internalIndex = index - 1;
+      else {
+        afterLast();
+        return false;
+      }
+    }
+
+    current_row = internalIndex;
+    this_row = (byte[][]) rows.elementAt(internalIndex);
+    return true;
+  }
+
+
+  public void afterLast() throws SQLException {
+    final int rows_size = rows.size();
+    if (rows_size > 0)
+      current_row = rows_size;
+  }
+
+
+  public void beforeFirst() throws SQLException {
+    if (rows.size() > 0)
+      current_row = -1;
+  }
+
+
+  public boolean first() throws SQLException {
+    if (rows.size() <= 0)
+      return false;
+
+    current_row = 0;
+    this_row = (byte[][]) rows.elementAt(current_row);
+
+    rowBuffer = new byte[this_row.length][];
+    System.arraycopy(this_row, 0, rowBuffer, 0, this_row.length);
+
+    return true;
+  }
+
+
+  public java.sql.Array getArray(String colName) throws SQLException {
+    return getArray(findColumn(colName));
+  }
+
+
+  public java.sql.Array getArray(int i) throws SQLException {
+    wasNullFlag = (this_row[i - 1] == null);
+    if (wasNullFlag)
+      return null;
+
+    if (i < 1 || i > fields.length)
+      throw new PSQLException("postgresql.res.colrange");
+    return (java.sql.Array) new org.postgresql.jdbc2.Array( connection, i, fields[i - 1], (java.sql.ResultSet) this );
+  }
+
+
+  public java.math.BigDecimal getBigDecimal(int columnIndex) throws SQLException {
+    return getBigDecimal(columnIndex, -1);
+  }
+
+
+  public java.math.BigDecimal getBigDecimal(String columnName) throws SQLException {
+    return getBigDecimal(findColumn(columnName));
+  }
+
+
+  public Blob getBlob(String columnName) throws SQLException {
+    return getBlob(findColumn(columnName));
+  }
+
+
+  public Blob getBlob(int i) throws SQLException {
+    return new org.postgresql.largeobject.PGblob(connection, getInt(i));
+  }
+
+
+  public java.io.Reader getCharacterStream(String columnName) throws SQLException {
+    return getCharacterStream(findColumn(columnName));
+  }
+
+
+  public java.io.Reader getCharacterStream(int i) throws SQLException {
+    checkResultSet( i );
+    wasNullFlag = (this_row[i - 1] == null);
+    if (wasNullFlag)
+      return null;
+
+    if (((AbstractJdbc2Connection) connection).haveMinimumCompatibleVersion("7.2")) {
+      //Version 7.2 supports AsciiStream for all the PG text types
+      //As the spec/javadoc for this method indicate this is to be used for
+      //large text values (i.e. LONGVARCHAR)   PG doesn't have a separate
+      //long string datatype, but with toast the text datatype is capable of
+      //handling very large values.  Thus the implementation ends up calling
+      //getString() since there is no current way to stream the value from the server
+      return new CharArrayReader(getString(i).toCharArray());
+    }
+    else {
+      // In 7.1 Handle as BLOBS so return the LargeObject input stream
+      Encoding encoding = connection.getEncoding();
+      InputStream input = getBinaryStream(i);
+      return encoding.getDecodingReader(input);
+    }
+  }
+
+
+  public Clob getClob(String columnName) throws SQLException {
+    return getClob(findColumn(columnName));
+  }
+
+
+  public Clob getClob(int i) throws SQLException {
+    return new org.postgresql.largeobject.PGclob(connection, getInt(i));
+  }
+
+
+  public int getConcurrency() throws SQLException {
+    if (statement == null)
+      return java.sql.ResultSet.CONCUR_READ_ONLY;
+    return statement.getResultSetConcurrency();
+  }
+
+
+  public java.sql.Date getDate(int i, java.util.Calendar cal) throws SQLException {
+    // If I read the specs, this should use cal only if we don't
+    // store the timezone, and if we do, then act just like getDate()?
+    // for now...
+    return getDate(i);
+  }
+
+
+  public Time getTime(int i, java.util.Calendar cal) throws SQLException {
+    // If I read the specs, this should use cal only if we don't
+    // store the timezone, and if we do, then act just like getTime()?
+    // for now...
+    return getTime(i);
+  }
+
+
+  public Timestamp getTimestamp(int i, java.util.Calendar cal) throws SQLException {
+    // If I read the specs, this should use cal only if we don't
+    // store the timezone, and if we do, then act just like getDate()?
+    // for now...
+    return getTimestamp(i);
+  }
+
+
+  public java.sql.Date getDate(String c, java.util.Calendar cal) throws SQLException {
+    return getDate(findColumn(c), cal);
+  }
+
+
+  public Time getTime(String c, java.util.Calendar cal) throws SQLException {
+    return getTime(findColumn(c), cal);
+  }
+
+
+  public Timestamp getTimestamp(String c, java.util.Calendar cal) throws SQLException {
+    return getTimestamp(findColumn(c), cal);
+  }
+
+
+  public int getFetchDirection() throws SQLException {
+    //PostgreSQL normally sends rows first->last
+    return java.sql.ResultSet.FETCH_FORWARD;
+  }
+
+
+  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
+    return rows.size();
+  }
+
+
+  public Object getObject(String columnName, java.util.Map map) throws SQLException {
+    return getObject(findColumn(columnName), map);
+  }
+
+
+  /*
+   * This checks against map for the type of column i, and if found returns
+   * an object based on that mapping. The class must implement the SQLData
+   * interface.
+   */
+  public Object getObject(int i, java.util.Map map) throws SQLException {
+    throw org.postgresql.Driver.notImplemented();
+  }
+
+
+  public Ref getRef(String columnName) throws SQLException {
+    return getRef(findColumn(columnName));
+  }
+
+
+  public Ref getRef(int i) throws SQLException {
+    //The backend doesn't yet have SQL3 REF types
+    throw new PSQLException("postgresql.psqlnotimp");
+  }
+
+
+  public int getRow() throws SQLException {
+    final int rows_size = rows.size();
+
+    if (current_row < 0 || current_row >= rows_size)
+      return 0;
+
+    return current_row + 1;
+  }
+
+
+  // This one needs some thought, as not all ResultSets come from a statement
+  public Statement getStatement() throws SQLException {
+    return statement;
+  }
+
+
+  public int getType() throws SQLException {
+    // This implementation allows scrolling but is not able to
+    // see any changes. Sub-classes may overide this to return a more
+    // meaningful result.
+    return java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE;
+  }
+
+
+  public boolean isAfterLast() throws SQLException {
+    final int rows_size = rows.size();
+    return (current_row >= rows_size && rows_size > 0);
+  }
+
+
+  public boolean isBeforeFirst() throws SQLException {
+    return (current_row < 0 && rows.size() > 0);
+  }
+
+
+  public boolean isFirst() throws SQLException {
+    return (current_row == 0 && rows.size() >= 0);
+  }
+
+
+  public boolean isLast() throws SQLException {
+    final int rows_size = rows.size();
+    return (current_row == rows_size - 1 && rows_size > 0);
+  }
+
+
+  public boolean last() throws SQLException {
+    final int rows_size = rows.size();
+    if (rows_size <= 0)
+      return false;
+
+    current_row = rows_size - 1;
+    this_row = (byte[][]) rows.elementAt(current_row);
+
+    rowBuffer = new byte[this_row.length][];
+    System.arraycopy(this_row, 0, rowBuffer, 0, this_row.length);
+
+    return true;
+  }
+
+
+  public boolean previous() throws SQLException {
+    if (--current_row < 0)
+      return false;
+    this_row = (byte[][]) rows.elementAt(current_row);
+    System.arraycopy(this_row, 0, rowBuffer, 0, this_row.length);
+    return true;
+  }
+
+
+  public boolean relative(int rows) throws SQLException {
+    //have to add 1 since absolute expects a 1-based index
+    return absolute(current_row + 1 + rows);
+  }
+
+
+  public void setFetchDirection(int direction) throws SQLException {
+    throw new PSQLException("postgresql.psqlnotimp");
+  }
+
+
+  public void setFetchSize(int rows) throws SQLException {
+    // Sub-classes should implement this as part of their cursor support
+    throw org.postgresql.Driver.notImplemented();
+  }
+
+
+  public synchronized void cancelRowUpdates() throws SQLException {
+    if (doingUpdates) {
+      doingUpdates = false;
+
+      clearRowBuffer();
+    }
+  }
+
+
+  public synchronized void deleteRow() throws SQLException {
+    if ( !isUpdateable() ) {
+      throw new PSQLException( "postgresql.updateable.notupdateable" );
+    }
+
+    if (onInsertRow) {
+      throw new PSQLException( "postgresql.updateable.oninsertrow" );
+    }
+
+    if (rows.size() == 0) {
+      throw new PSQLException( "postgresql.updateable.emptydelete" );
+    }
+    if (isBeforeFirst()) {
+      throw new PSQLException( "postgresql.updateable.beforestartdelete" );
+    }
+    if (isAfterLast()) {
+      throw new PSQLException( "postgresql.updateable.afterlastdelete" );
+    }
+
+
+    int numKeys = primaryKeys.size();
+    if ( deleteStatement == null ) {
+
+
+      StringBuffer deleteSQL = new StringBuffer("DELETE FROM " ).append(tableName).append(" where " );
+
+      for ( int i = 0; i < numKeys; i++ ) {
+        deleteSQL.append( ((PrimaryKey) primaryKeys.get(i)).name ).append( " = ? " );
+        if ( i < numKeys - 1 ) {
+          deleteSQL.append( " and " );
+        }
+      }
+
+      deleteStatement = ((java.sql.Connection) connection).prepareStatement(deleteSQL.toString());
+    }
+    deleteStatement.clearParameters();
+
+    for ( int i = 0; i < numKeys; i++ ) {
+      deleteStatement.setObject(i + 1, ((PrimaryKey) primaryKeys.get(i)).getValue());
+    }
+
+
+    deleteStatement.executeUpdate();
+
+    rows.removeElementAt(current_row);
+  }
+
+
+  public synchronized void insertRow() throws SQLException {
+    if ( !isUpdateable() ) {
+      throw new PSQLException( "postgresql.updateable.notupdateable" );
+    }
+
+    if (!onInsertRow) {
+      throw new PSQLException( "postgresql.updateable.notoninsertrow" );
+    }
+    else {
+
+      // loop through the keys in the insertTable and create the sql statement
+      // we have to create the sql every time since the user could insert different
+      // columns each time
+
+      StringBuffer insertSQL = new StringBuffer("INSERT INTO ").append(tableName).append(" (");
+      StringBuffer paramSQL = new StringBuffer(") values (" );
+
+      Enumeration columnNames = updateValues.keys();
+      int numColumns = updateValues.size();
+
+      for ( int i = 0; columnNames.hasMoreElements(); i++ ) {
+        String columnName = (String) columnNames.nextElement();
+
+        insertSQL.append( columnName );
+        if ( i < numColumns - 1 ) {
+          insertSQL.append(", ");
+          paramSQL.append("?,");
+        }
+        else {
+          paramSQL.append("?)");
+        }
+
+      }
+
+      insertSQL.append(paramSQL.toString());
+      insertStatement = ((java.sql.Connection) connection).prepareStatement(insertSQL.toString());
+
+      Enumeration keys = updateValues.keys();
+
+      for ( int i = 1; keys.hasMoreElements(); i++) {
+        String key = (String) keys.nextElement();
+        insertStatement.setObject(i, updateValues.get( key ) );
+      }
+
+      insertStatement.executeUpdate();
+
+      if ( usingOID ) {
+        // we have to get the last inserted OID and put it in the resultset
+
+        long insertedOID = ((AbstractJdbc2Statement) insertStatement).getLastOID();
+
+        updateValues.put("oid", new Long(insertedOID) );
+
+      }
+
+      // update the underlying row to the new inserted data
+      updateRowBuffer();
+
+      rows.addElement(rowBuffer);
+
+      // we should now reflect the current data in this_row
+      // that way getXXX will get the newly inserted data
+      this_row = rowBuffer;
+
+      // need to clear this in case of another insert
+      clearRowBuffer();
+
+
+    }
+  }
+
+
+  public synchronized void moveToCurrentRow() throws SQLException {
+    if (!updateable) {
+      throw new PSQLException( "postgresql.updateable.notupdateable" );
+    }
+
+    this_row = (byte[][]) rows.elementAt(current_row);
+
+    rowBuffer = new byte[this_row.length][];
+    System.arraycopy(this_row, 0, rowBuffer, 0, this_row.length);
+
+    onInsertRow = false;
+    doingUpdates = false;
+  }
+
+
+  public synchronized void  moveToInsertRow() throws SQLException {
+    if (!updateable) {
+      throw new PSQLException( "postgresql.updateable.notupdateable" );
+    }
+
+    if (insertStatement != null) {
+      insertStatement = null;
+    }
+
+
+    // make sure the underlying data is null
+    clearRowBuffer();
+
+    onInsertRow = true;
+    doingUpdates = false;
+
+  }
+
+
+  private synchronized void clearRowBuffer() throws SQLException {
+    // rowBuffer is the temporary storage for the row
+    rowBuffer = new byte[fields.length][];
+
+    // clear the updateValues hashTable for the next set of updates
+    updateValues.clear();
+
+  }
+
+
+  public boolean rowDeleted() throws SQLException {
+    // only sub-classes implement CONCURuPDATEABLE
+    throw Driver.notImplemented();
+  }
+
+
+  public boolean rowInserted() throws SQLException {
+    // only sub-classes implement CONCURuPDATEABLE
+    throw Driver.notImplemented();
+  }
+
+
+  public boolean rowUpdated() throws SQLException {
+    // only sub-classes implement CONCURuPDATEABLE
+    throw Driver.notImplemented();
+  }
+
+
+  public synchronized void updateAsciiStream(int columnIndex,
+    java.io.InputStream x,
+    int length
+  ) throws SQLException {
+
+    if ( !isUpdateable() ) {
+      throw new PSQLException( "postgresql.updateable.notupdateable" );
+    }
+
+    byte[] theData = null;
+
+    try {
+      x.read(theData, 0, length);
+    }
+    catch (NullPointerException ex ) {
+      throw new PSQLException("postgresql.updateable.inputstream");
+    }
+    catch (IOException ie) {
+      throw new PSQLException("postgresql.updateable.ioerror" + ie);
+    }
+
+    doingUpdates = !onInsertRow;
+
+    updateValues.put( fields[columnIndex - 1].getName(), theData );
+
+  }
+
+
+  public synchronized void updateBigDecimal(int columnIndex,
+    java.math.BigDecimal x )
+  throws SQLException {
+
+    if ( !isUpdateable() ) {
+      throw new PSQLException( "postgresql.updateable.notupdateable" );
+    }
+
+    doingUpdates = !onInsertRow;
+    updateValues.put( fields[columnIndex - 1].getName(), x );
+
+  }
+
+
+  public synchronized void updateBinaryStream(int columnIndex,
+    java.io.InputStream x,
+    int length
+  ) throws SQLException {
+
+    if ( !isUpdateable() ) {
+      throw new PSQLException( "postgresql.updateable.notupdateable" );
+    }
+
+    byte[] theData = null;
+
+    try {
+      x.read(theData, 0, length);
+
+    }
+    catch ( NullPointerException ex ) {
+      throw new PSQLException("postgresql.updateable.inputstream");
+    }
+    catch (IOException ie) {
+      throw new PSQLException("postgresql.updateable.ioerror" + ie);
+    }
+
+    doingUpdates = !onInsertRow;
+
+    updateValues.put( fields[columnIndex - 1].getName(), theData );
+
+  }
+
+
+  public synchronized void updateBoolean(int columnIndex, boolean x) throws SQLException {
+
+    if ( !isUpdateable() ) {
+      throw new PSQLException( "postgresql.updateable.notupdateable" );
+    }
+
+    if ( Driver.logDebug ) Driver.debug("updating boolean " + fields[columnIndex - 1].getName() + "=" + x);
+
+    doingUpdates = !onInsertRow;
+    updateValues.put( fields[columnIndex - 1].getName(), new Boolean(x) );
+
+  }
+
+
+  public synchronized void updateByte(int columnIndex, byte x) throws SQLException {
+    if ( !isUpdateable() ) {
+      throw new PSQLException( "postgresql.updateable.notupdateable" );
+    }
+
+    doingUpdates = true;
+    updateValues.put( fields[columnIndex - 1].getName(), String.valueOf(x) );
+  }
+
+
+  public synchronized void updateBytes(int columnIndex, byte[] x) throws SQLException {
+
+    if ( !isUpdateable() ) {
+      throw new PSQLException( "postgresql.updateable.notupdateable" );
+    }
+
+    doingUpdates = !onInsertRow;
+    updateValues.put( fields[columnIndex - 1].getName(), x );
+
+  }
+
+
+  public synchronized void updateCharacterStream(int columnIndex,
+    java.io.Reader x,
+    int length
+  ) throws SQLException {
+
+    if ( !isUpdateable() ) {
+      throw new PSQLException( "postgresql.updateable.notupdateable" );
+    }
+
+    char[] theData = null;
+
+    try {
+      x.read(theData, 0, length);
+
+    }
+    catch (NullPointerException ex) {
+      throw new PSQLException("postgresql.updateable.inputstream");
+    }
+    catch (IOException ie) {
+      throw new PSQLException("postgresql.updateable.ioerror" + ie);
+    }
+
+    doingUpdates = !onInsertRow;
+    updateValues.put( fields[columnIndex - 1].getName(), theData);
+
+  }
+
+
+  public synchronized void updateDate(int columnIndex, java.sql.Date x) throws SQLException {
+
+    if ( !isUpdateable() ) {
+      throw new PSQLException( "postgresql.updateable.notupdateable" );
+    }
+
+    doingUpdates = !onInsertRow;
+    updateValues.put( fields[columnIndex - 1].getName(), x );
+  }
+
+
+  public synchronized void updateDouble(int columnIndex, double x) throws SQLException {
+    if ( !isUpdateable() ) {
+      throw new PSQLException( "postgresql.updateable.notupdateable" );
+    }
+
+    if ( Driver.logDebug ) Driver.debug("updating double " + fields[columnIndex - 1].getName() + "=" + x);
+
+    doingUpdates = !onInsertRow;
+    updateValues.put( fields[columnIndex - 1].getName(), new Double(x) );
+
+  }
+
+
+  public synchronized void updateFloat(int columnIndex, float x) throws SQLException {
+    if ( !isUpdateable() ) {
+      throw new PSQLException( "postgresql.updateable.notupdateable" );
+    }
+
+    if ( Driver.logDebug ) Driver.debug("updating float " + fields[columnIndex - 1].getName() + "=" + x);
+
+    doingUpdates = !onInsertRow;
+
+    updateValues.put( fields[columnIndex - 1].getName(), new Float(x) );
+
+  }
+
+
+  public synchronized void updateInt(int columnIndex, int x) throws SQLException {
+    if ( !isUpdateable() ) {
+      throw new PSQLException( "postgresql.updateable.notupdateable" );
+    }
+
+    if ( Driver.logDebug ) Driver.debug("updating int " + fields[columnIndex - 1].getName() + "=" + x);
+
+    doingUpdates = !onInsertRow;
+    updateValues.put( fields[columnIndex - 1].getName(), new Integer(x) );
+
+  }
+
+
+  public synchronized void updateLong(int columnIndex, long x) throws SQLException {
+    if ( !isUpdateable() ) {
+      throw new PSQLException( "postgresql.updateable.notupdateable" );
+    }
+
+    if ( Driver.logDebug ) Driver.debug("updating long " + fields[columnIndex - 1].getName() + "=" + x);
+
+    doingUpdates = !onInsertRow;
+    updateValues.put( fields[columnIndex - 1].getName(), new Long(x) );
+
+  }
+
+
+  public synchronized void updateNull(int columnIndex) throws SQLException {
+    if ( !isUpdateable() ) {
+      throw new PSQLException( "postgresql.updateable.notupdateable" );
+    }
+
+    doingUpdates = !onInsertRow;
+    updateValues.put( fields[columnIndex - 1].getName(), null);
+
+
+  }
+
+
+  public synchronized void updateObject(int columnIndex, Object x) throws SQLException {
+    if ( !isUpdateable() ) {
+      throw new PSQLException( "postgresql.updateable.notupdateable" );
+    }
+
+    if ( Driver.logDebug ) Driver.debug("updating object " + fields[columnIndex - 1].getName() + " = " + x);
+
+    doingUpdates = !onInsertRow;
+    updateValues.put( fields[columnIndex - 1].getName(), x );
+  }
+
+
+  public synchronized void updateObject(int columnIndex, Object x, int scale) throws SQLException {
+    if ( !isUpdateable() ) {
+      throw new PSQLException( "postgresql.updateable.notupdateable" );
+    }
+
+    this.updateObject(columnIndex, x);
+
+  }
+
+
+  public void refreshRow() throws SQLException {
+    if ( !isUpdateable() ) {
+      throw new PSQLException( "postgresql.updateable.notupdateable" );
+    }
+
+    try {
+      StringBuffer selectSQL = new StringBuffer( "select ");
+
+      final int numColumns = java.lang.reflect.Array.getLength(fields);
+
+      for (int i = 0; i < numColumns; i++ ) {
+
+        selectSQL.append( fields[i].getName() );
+
+        if ( i < numColumns - 1 ) {
+
+          selectSQL.append(", ");
+        }
+
+      }
+      selectSQL.append(" from " ).append(tableName).append(" where ");
+
+      int numKeys = primaryKeys.size();
+
+      for ( int i = 0; i < numKeys; i++ ) {
+
+        PrimaryKey primaryKey = ((PrimaryKey) primaryKeys.get(i));
+        selectSQL.append(primaryKey.name).append("= ?");
+
+        if ( i < numKeys - 1 ) {
+          selectSQL.append(" and ");
+        }
+      }
+      if ( Driver.logDebug ) Driver.debug("selecting " + selectSQL.toString());
+      selectStatement = ((java.sql.Connection) connection).prepareStatement(selectSQL.toString());
+
+
+      for ( int j = 0, i = 1; j < numKeys; j++, i++) {
+        selectStatement.setObject( i, ((PrimaryKey) primaryKeys.get(j)).getValue() );
+      }
+
+      Jdbc2ResultSet rs = (Jdbc2ResultSet) selectStatement.executeQuery();
+
+      if ( rs.first() ) {
+        rowBuffer = rs.rowBuffer;
+      }
+
+      rows.setElementAt( rowBuffer, current_row );
+      if ( Driver.logDebug ) Driver.debug("done updates");
+
+      rs.close();
+      selectStatement.close();
+      selectStatement = null;
+
+    }
+    catch (Exception e) {
+      if ( Driver.logDebug ) Driver.debug(e.getClass().getName() + e);
+      throw new SQLException( e.getMessage() );
+    }
+
+  }
+
+
+  public synchronized void updateRow() throws SQLException {
+    if ( !isUpdateable() ) {
+      throw new PSQLException( "postgresql.updateable.notupdateable" );
+    }
+
+    if (doingUpdates) {
+
+      try {
+
+        StringBuffer updateSQL = new StringBuffer("UPDATE " + tableName + " SET  ");
+
+        int numColumns = updateValues.size();
+        Enumeration columns = updateValues.keys();
+
+        for (int i = 0; columns.hasMoreElements(); i++ ) {
+
+          String column = (String) columns.nextElement();
+          updateSQL.append( column + "= ?");
+
+          if ( i < numColumns - 1 ) {
+
+            updateSQL.append(", ");
+          }
+
+        }
+        updateSQL.append( " WHERE " );
+
+        int numKeys = primaryKeys.size();
+
+        for ( int i = 0; i < numKeys; i++ ) {
+
+          PrimaryKey primaryKey = ((PrimaryKey) primaryKeys.get(i));
+          updateSQL.append(primaryKey.name).append("= ?");
+
+          if ( i < numKeys - 1 ) {
+            updateSQL.append(" and ");
+          }
+        }
+        if ( Driver.logDebug ) Driver.debug("updating " + updateSQL.toString());
+        updateStatement = ((java.sql.Connection) connection).prepareStatement(updateSQL.toString());
+
+        int i = 0;
+        Iterator iterator = updateValues.values().iterator();
+        for (; iterator.hasNext(); i++) {
+          updateStatement.setObject( i + 1, iterator.next() );
+
+        }
+        for ( int j = 0; j < numKeys; j++, i++) {
+          updateStatement.setObject( i + 1, ((PrimaryKey) primaryKeys.get(j)).getValue() );
+        }
+
+        updateStatement.executeUpdate();
+        updateStatement.close();
+
+        updateStatement = null;
+        updateRowBuffer();
+
+
+        if ( Driver.logDebug ) Driver.debug("copying data");
+        System.arraycopy(rowBuffer, 0, this_row, 0, rowBuffer.length);
+
+        rows.setElementAt( rowBuffer, current_row );
+        if ( Driver.logDebug ) Driver.debug("done updates");
+
+        doingUpdates = false;
+      }
+      catch (Exception e) {
+        if ( Driver.logDebug ) Driver.debug(e.getClass().getName() + e);
+        throw new SQLException( e.getMessage() );
+      }
+
+    }
+
+  }
+
+
+  public synchronized void updateShort(int columnIndex, short x) throws SQLException {
+    if ( Driver.logDebug ) Driver.debug("in update Short " + fields[columnIndex - 1].getName() + " = " + x);
+
+
+    doingUpdates = !onInsertRow;
+    updateValues.put( fields[columnIndex - 1].getName(), new Short(x) );
+
+  }
+
+
+  public synchronized void updateString(int columnIndex, String x) throws SQLException {
+    if ( Driver.logDebug ) Driver.debug("in update String " + fields[columnIndex - 1].getName() + " = " + x);
+
+    doingUpdates = !onInsertRow;
+    updateValues.put( fields[columnIndex - 1].getName(), x );
+
+  }
+
+
+  public synchronized void updateTime(int columnIndex, Time x) throws SQLException {
+    if ( Driver.logDebug ) Driver.debug("in update Time " + fields[columnIndex - 1].getName() + " = " + x);
+
+
+    doingUpdates = !onInsertRow;
+    updateValues.put( fields[columnIndex - 1].getName(), x );
+
+  }
+
+
+  public synchronized void updateTimestamp(int columnIndex, Timestamp x) throws SQLException {
+    if ( Driver.logDebug ) Driver.debug("updating Timestamp " + fields[columnIndex - 1].getName() + " = " + x);
+
+    doingUpdates = !onInsertRow;
+    updateValues.put( fields[columnIndex - 1].getName(), x );
+
+
+  }
+
+
+  public synchronized void updateNull(String columnName) throws SQLException {
+    updateNull(findColumn(columnName));
+  }
+
+
+  public synchronized void updateBoolean(String columnName, boolean x) throws SQLException {
+    updateBoolean(findColumn(columnName), x);
+  }
+
+
+  public synchronized void updateByte(String columnName, byte x) throws SQLException {
+    updateByte(findColumn(columnName), x);
+  }
+
+
+  public synchronized void updateShort(String columnName, short x) throws SQLException {
+    updateShort(findColumn(columnName), x);
+  }
+
+
+  public synchronized void updateInt(String columnName, int x) throws SQLException {
+    updateInt(findColumn(columnName), x);
+  }
+
+
+  public synchronized void updateLong(String columnName, long x) throws SQLException {
+    updateLong(findColumn(columnName), x);
+  }
+
+
+  public synchronized void updateFloat(String columnName, float x) throws SQLException {
+    updateFloat(findColumn(columnName), x);
+  }
+
+
+  public synchronized void updateDouble(String columnName, double x) throws SQLException {
+    updateDouble(findColumn(columnName), x);
+  }
+
+
+  public synchronized void updateBigDecimal(String columnName, BigDecimal x)
+  throws SQLException {
+    updateBigDecimal(findColumn(columnName), x);
+  }
+
+
+  public synchronized void updateString(String columnName, String x) throws SQLException {
+    updateString(findColumn(columnName), x);
+  }
+
+
+  public synchronized void updateBytes(String columnName, byte x[]) throws SQLException {
+    updateBytes(findColumn(columnName), x);
+  }
+
+
+  public synchronized void updateDate(String columnName, java.sql.Date x)
+  throws SQLException {
+    updateDate(findColumn(columnName), x);
+  }
+
+
+  public synchronized void updateTime(String columnName, java.sql.Time x)
+  throws SQLException {
+    updateTime(findColumn(columnName), x);
+  }
+
+
+  public synchronized void updateTimestamp(String columnName, java.sql.Timestamp x)
+  throws SQLException {
+    updateTimestamp(findColumn(columnName), x);
+  }
+
+
+  public synchronized void updateAsciiStream(
+    String columnName,
+    java.io.InputStream x,
+    int length)
+  throws SQLException {
+    updateAsciiStream(findColumn(columnName), x, length);
+  }
+
+
+  public synchronized void updateBinaryStream(
+    String columnName,
+    java.io.InputStream x,
+    int length)
+  throws SQLException {
+    updateBinaryStream(findColumn(columnName), x, length);
+  }
+
+
+  public synchronized void updateCharacterStream(
+    String columnName,
+    java.io.Reader reader,
+    int length)
+  throws SQLException {
+    updateCharacterStream(findColumn(columnName), reader, length);
+  }
+
+
+  public synchronized void updateObject(String columnName, Object x, int scale)
+  throws SQLException {
+    updateObject(findColumn(columnName), x);
+  }
+
+
+  public synchronized void updateObject(String columnName, Object x) throws SQLException {
+    updateObject(findColumn(columnName), x);
+  }
+
+
+  private int _findColumn( String columnName ) {
+    int i;
+
+    final int flen = fields.length;
+    for (i = 0; i < flen; ++i) {
+      if (fields[i].getName().equalsIgnoreCase(columnName)) {
+        return (i + 1);
+      }
+    }
+    return -1;
+  }
+
+
+  /**
+   * Is this ResultSet updateable?
+   */
+
+  boolean isUpdateable() throws SQLException {
+
+    if (updateable) return true;
+
+    if ( Driver.logDebug ) Driver.debug("checking if rs is updateable");
+
+    parseQuery();
+
+    if ( singleTable == false ) {
+      if ( Driver.logDebug ) Driver.debug("not a single table");
+      return false;
+    }
+
+    if ( Driver.logDebug ) Driver.debug("getting primary keys");
+
+    //
+    // Contains the primary key?
+    //
+
+    primaryKeys = new Vector();
+
+    // this is not stricty jdbc spec, but it will make things much faster if used
+    // the user has to select oid, * from table and then we will just use oid
+
+
+    usingOID = false;
+    int oidIndex = _findColumn( "oid" );
+    int i = 0;
+
+
+    // if we find the oid then just use it
+
+    if ( oidIndex > 0 ) {
+      i++;
+      primaryKeys.add( new PrimaryKey( oidIndex, "oid" ) );
+      usingOID = true;
+    }
+    else {
+      // otherwise go and get the primary keys and create a hashtable of keys
+      java.sql.ResultSet rs  = ((java.sql.Connection) connection).getMetaData().getPrimaryKeys("", "", tableName);
+
+
+      for (; rs.next(); i++ ) {
+        String columnName = rs.getString(4);    // get the columnName
+
+        int index = findColumn( columnName );
+
+        if ( index > 0 ) {
+          primaryKeys.add( new PrimaryKey(index, columnName ) ); // get the primary key information
+        }
+      }
+
+      rs.close();
+    }
+
+    numKeys = primaryKeys.size();
+
+    if ( Driver.logDebug ) Driver.debug( "no of keys=" + i );
+
+    if ( i < 1 ) {
+      throw new SQLException("No Primary Keys");
+    }
+
+    updateable = primaryKeys.size() > 0;
+
+    if ( Driver.logDebug ) Driver.debug( "checking primary key " + updateable );
+
+    return updateable;
+  }
+
+
+  public void parseQuery() {
+    StringTokenizer st = new StringTokenizer(sqlQuery, " \r\t");
+    boolean tableFound = false, tablesChecked = false;
+    String name = "";
+
+    singleTable = true;
+
+    while ( !tableFound && !tablesChecked && st.hasMoreTokens() ) {
+      name = st.nextToken();
+      if ( !tableFound ) {
+        if (name.toLowerCase().equals("from")) {
+          tableName = st.nextToken();
+          tableFound = true;
+        }
+      }
+      else {
+        tablesChecked = true;
+        // if the very next token is , then there are multiple tables
+        singleTable =  !name.equalsIgnoreCase(",");
+      }
+    }
+  }
+
+
+  private void updateRowBuffer() throws SQLException {
+
+    Enumeration columns = updateValues.keys();
+
+    while ( columns.hasMoreElements() ) {
+      String columnName = (String) columns.nextElement();
+      int columnIndex = _findColumn( columnName ) - 1;
+
+      switch ( connection.getSQLType( fields[columnIndex].getPGType() ) ) {
+
+      case Types.DECIMAL:
+      case Types.BIGINT:
+      case Types.DOUBLE:
+      case Types.BIT:
+      case Types.VARCHAR:
+      case Types.DATE:
+      case Types.TIME:
+      case Types.TIMESTAMP:
+      case Types.SMALLINT:
+      case Types.FLOAT:
+      case Types.INTEGER:
+      case Types.CHAR:
+      case Types.NUMERIC:
+      case Types.REAL:
+      case Types.TINYINT:
+
+        try {
+          rowBuffer[columnIndex] = String.valueOf( updateValues.get( columnName ) ).getBytes(connection.getEncoding().name() );
+        }
+        catch ( UnsupportedEncodingException ex) {
+          throw new SQLException("Unsupported Encoding " + connection.getEncoding().name());
+        }
+
+      case Types.NULL:
+        continue;
+
+      default:
+        rowBuffer[columnIndex] = (byte[]) updateValues.get( columnName );
+      }
+
+    }
+  }
+
+
+  public void setStatement(Statement statement) {
+    this.statement = statement;
+  }
+
+
+  public void setSQLQuery(String sqlQuery) {
+    this.sqlQuery = sqlQuery;
+  }
+
+
+  private class PrimaryKey {
+    int index;              // where in the result set is this primaryKey
+    String name;            // what is the columnName of this primary Key
+
+    PrimaryKey( int index, String name) {
+      this.index = index;
+      this.name = name;
+    }
+    Object getValue() throws SQLException {
+      return getObject(index);
+    }
+  };
+
+
+
 }
 
index 47c2c77983153637d94df8a2c0e5f714de6fcc81..d8d16985ad10b9a786c4b2af7c14e0acd06ec864 100644 (file)
@@ -2,12 +2,13 @@ package org.postgresql.jdbc2;
 
 
 import java.io.*;
+import java.math.*;
 import java.sql.*;
 import java.util.Vector;
 import org.postgresql.largeobject.*;
 import org.postgresql.util.PSQLException;
 
-/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2Statement.java,v 1.2 2002/07/24 22:08:42 barry Exp $
+/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2Statement.java,v 1.3 2002/07/25 22:45:28 barry Exp $
  * This class defines methods of the jdbc2 specification.  This class extends
  * org.postgresql.jdbc1.AbstractJdbc1Statement which provides the jdbc1
  * methods.  The real Statement class (for jdbc2) is org.postgresql.jdbc2.Jdbc2Statement
@@ -46,7 +47,7 @@ public abstract class AbstractJdbc2Statement extends org.postgresql.jdbc1.Abstra
    {
            boolean l_return = super.execute(sql);
                 //Now do the jdbc2 specific stuff
-       //required for ResultSet.getStatement() to work
+       //required for ResultSet.getStatement() to work and updateable resultsets
        ((AbstractJdbc2ResultSet)result).setStatement((Statement)this);
 
        // Added this so that the Updateable resultset knows the query that gave this
@@ -331,4 +332,60 @@ public abstract class AbstractJdbc2Statement extends org.postgresql.jdbc1.Abstra
            setTimestamp(i, new java.sql.Timestamp(cal.getTime().getTime()));
        }
    }
+
+   // ** JDBC 2 Extensions for CallableStatement**
+
+   public java.sql.Array getArray(int i) throws SQLException
+   {
+       throw org.postgresql.Driver.notImplemented();
+   }
+
+   public java.math.BigDecimal getBigDecimal(int parameterIndex) throws SQLException
+   {
+       checkIndex (parameterIndex, Types.NUMERIC, "BigDecimal");
+       return ((BigDecimal)callResult);
+   }
+
+   public Blob getBlob(int i) throws SQLException
+   {
+       throw org.postgresql.Driver.notImplemented();
+   }
+
+   public Clob getClob(int i) throws SQLException
+   {
+       throw org.postgresql.Driver.notImplemented();
+   }
+
+   public Object getObject(int i, java.util.Map map) throws SQLException
+   {
+       throw org.postgresql.Driver.notImplemented();
+   }
+
+   public Ref getRef(int i) throws SQLException
+   {
+       throw org.postgresql.Driver.notImplemented();
+   }
+
+   public java.sql.Date getDate(int i, java.util.Calendar cal) throws SQLException
+   {
+       throw org.postgresql.Driver.notImplemented();
+   }
+
+   public Time getTime(int i, java.util.Calendar cal) throws SQLException
+   {
+       throw org.postgresql.Driver.notImplemented();
+   }
+
+   public Timestamp getTimestamp(int i, java.util.Calendar cal) throws SQLException
+   {
+       throw org.postgresql.Driver.notImplemented();
+   }
+
+   // no custom types allowed yet..
+   public void registerOutParameter(int parameterIndex, int sqlType, String typeName) throws SQLException
+   {
+       throw org.postgresql.Driver.notImplemented();
+   }
+
+
 }
index 2105802d66a17fa1e77efeedf3c828bda5c7f1db..99cbf0ea8ce6b405e3b9c4cd15d4c1b315923cff 100644 (file)
@@ -340,7 +340,7 @@ public class Array implements java.sql.Array
            default:
                throw org.postgresql.Driver.notImplemented();
        }
-       return new Jdbc2ResultSet((org.postgresql.jdbc2.Jdbc2Connection)conn, fields, rows, "OK", 1 );
+       return ((Jdbc2Connection)conn).getResultSet(null, fields, rows, "OK", 1 );
    }
 
    public String toString()
diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/CallableStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc2/CallableStatement.java
deleted file mode 100644 (file)
index 51dd9b2..0000000
+++ /dev/null
@@ -1,604 +0,0 @@
-package org.postgresql.jdbc2;
-
-// IMPORTANT NOTE: This file implements the JDBC 2 version of the driver.
-// If you make any modifications to this file, you must make sure that the
-// changes are also made (if relevent) to the related JDBC 1 class in the
-// org.postgresql.jdbc1 package.
-
-import java.sql.*;
-import java.math.*;
-import org.postgresql.util.*;
-/*
- * CallableStatement is used to execute SQL stored procedures.
- *
- * 

JDBC provides a stored procedure SQL escape that allows stored

- * procedures to be called in a standard way for all RDBMS's. This escape
- * syntax has one form that includes a result parameter and one that does
- * not. If used, the result parameter must be registered as an OUT
- * parameter. The other parameters may be used for input, output or both.
- * Parameters are refered to sequentially, by number. The first parameter
- * is 1.
- *
- * {?= call [,, ...]}
- * {call [,, ...]}
- *
- *
- * 

IN parameter values are set using the set methods inherited from

- * PreparedStatement. The type of all OUT parameters must be registered
- * prior to executing the stored procedure; their values are retrieved
- * after execution via the get methods provided here.
- *
- * 

A Callable statement may return a ResultSet or multiple ResultSets.

- * Multiple ResultSets are handled using operations inherited from
- * Statement.
- *
- * 

For maximum portability, a call's ResultSets and update counts should

- * be processed prior to getting the values of output parameters.
- *
- * @see Connection#prepareCall
- * @see ResultSet
- * @author Paul Bethe (implementer)
- */
-
-public class CallableStatement extends org.postgresql.jdbc2.Jdbc2PreparedStatement implements java.sql.CallableStatement
-{
-   /*
-    * @exception SQLException on failure
-    */
-   public CallableStatement(Jdbc2Connection c, String q) throws SQLException
-   {
-       super(c, q); // don't parse yet..
-   }
-
-
-   /**
-    * allows this class to tweak the standard JDBC call !see Usage
-    * -> and replace with the pgsql function syntax
-    * ie. select  as RESULT;
-    */
-
-   protected void parseSqlStmt () throws SQLException {
-       modifyJdbcCall ();
-       super.parseSqlStmt ();
-   }
-   /** 
-    * this method will turn a string of the form
-    * {? = call  (?, [?,..]) }
-    * into the PostgreSQL format which is 
-    * select  (?, [?, ...]) as result
-    * 
-    */
-   private void modifyJdbcCall () throws SQLException {
-       // syntax checking is not complete only a few basics :(
-       originalSql = sql; // save for error msgs..
-       int index = sql.indexOf ("="); // is implied func or proc?
-       boolean isValid = true;
-       if (index != -1) {
-           isFunction = true;
-           isValid = sql.indexOf ("?") < index; // ? before =          
-       }
-       sql = sql.trim ();
-       if (sql.startsWith ("{") && sql.endsWith ("}")) {
-           sql = sql.substring (1, sql.length() -1);
-       } else isValid = false;
-       index = sql.indexOf ("call"); 
-       if (index == -1 || !isValid)
-           throw new PSQLException ("postgresql.call.malformed", 
-                                    new Object[]{sql, JDBC_SYNTAX});
-       sql = sql.replace ('{', ' '); // replace these characters
-       sql = sql.replace ('}', ' ');
-       sql = sql.replace (';', ' ');
-       
-       // this removes the 'call' string and also puts a hidden '?'
-       // at the front of the line for functions, this will
-       // allow the registerOutParameter to work correctly
-                // because in the source sql there was one more ? for the return
-                // value that is not needed by the postgres syntax.  But to make 
-                // sure that the parameter numbers are the same as in the original
-                // sql we add a dummy parameter in this case
-       sql = (isFunction ? "?" : "") + sql.substring (index + 4);
-       
-       sql = "select " + sql + " as " + RESULT_COLUMN + ";";     
-   }
-
-   // internals 
-   static final String JDBC_SYNTAX = "{[? =] call  ([? [,?]*]) }";
-   static final String RESULT_COLUMN = "result";
-   String originalSql = "";
-   boolean isFunction;
-   // functionReturnType contains the user supplied value to check
-   // testReturn contains a modified version to make it easier to 
-   // check the getXXX methods..
-   int functionReturnType;
-   int testReturn;
-   // returnTypeSet is true when a proper call to registerOutParameter has been made
-   boolean returnTypeSet;
-   Object result;
-
-   /*
-    * Before executing a stored procedure call you must explicitly
-    * call registerOutParameter to register the java.sql.Type of each
-    * out parameter.
-    *
-    * 

Note: When reading the value of an out parameter, you must use

-    * the getXXX method whose Java type XXX corresponds to the
-    * parameter's registered SQL type.
-    *
-    * ONLY 1 RETURN PARAMETER if {?= call ..} syntax is used
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @param sqlType SQL type code defined by java.sql.Types; for
-    * parameters of type Numeric or Decimal use the version of
-    * registerOutParameter that accepts a scale value
-    * @exception SQLException if a database-access error occurs.
-    */
-   public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException
-       {
-           if (parameterIndex != 1)
-               throw new PSQLException ("postgresql.call.noinout");
-           if (!isFunction)
-               throw new PSQLException ("postgresql.call.procasfunc", originalSql);
-           
-           // functionReturnType contains the user supplied value to check
-           // testReturn contains a modified version to make it easier to 
-           // check the getXXX methods..
-           functionReturnType = sqlType;
-           testReturn = sqlType;
-           if (functionReturnType == Types.CHAR || 
-               functionReturnType == Types.LONGVARCHAR)
-               testReturn = Types.VARCHAR;
-           else if (functionReturnType == Types.FLOAT)
-               testReturn = Types.REAL; // changes to streamline later error checking
-           returnTypeSet = true;
-       }
-
-   /**
-    * allow calls to execute update
-    * @return 1 if succesful call otherwise 0
-    */
-   public int executeUpdate() throws SQLException
-   {
-       java.sql.ResultSet rs = super.executeQuery (compileQuery());    
-       if (isFunction) {
-           if (!rs.next ())
-               throw new PSQLException ("postgresql.call.noreturnval");
-           result = rs.getObject(1);
-           int columnType = rs.getMetaData().getColumnType(1);
-           if (columnType != functionReturnType) 
-               throw new PSQLException ("postgresql.call.wrongrtntype",
-                                        new Object[]{
-                   getSqlTypeName (columnType), getSqlTypeName (functionReturnType) }); 
-       }
-       rs.close ();
-       return 1;
-   }
-
-
-   /**
-    * allow calls to execute update
-    * @return true if succesful
-    */
-   public boolean execute() throws SQLException
-   {
-       return (executeUpdate() == 1);
-   }
-
-   /*
-    * You must also specify the scale for numeric/decimal types:
-    *
-    * 

Note: When reading the value of an out parameter, you must use

-    * the getXXX method whose Java type XXX corresponds to the
-    * parameter's registered SQL type.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @param sqlType use either java.sql.Type.NUMERIC or java.sql.Type.DECIMAL
-    * @param scale a value greater than or equal to zero representing the
-    * desired number of digits to the right of the decimal point
-    * @exception SQLException if a database-access error occurs.
-    */
-   public void registerOutParameter(int parameterIndex, int sqlType,
-                                    int scale) throws SQLException
-       {
-           registerOutParameter (parameterIndex, sqlType); // ignore for now..
-       }
-
-   /*
-    * override this method to check for set @ 1 when declared function..
-    *
-    * @param paramIndex the index into the inString
-    * @param s a string to be stored
-    * @exception SQLException if something goes wrong
-    */
-   protected void set(int paramIndex, String s) throws SQLException
-   {
-       if (paramIndex == 1 && isFunction) // need to registerOut instead
-           throw new PSQLException ("postgresql.call.funcover");
-       super.set (paramIndex, s); // else set as usual..
-   }
-
-       /*
-    * Helper - this compiles the SQL query from the various parameters
-    * This is identical to toString() except it throws an exception if a
-    * parameter is unused.
-    */
-   protected synchronized String compileQuery()
-   throws SQLException
-   {
-       if (isFunction && !returnTypeSet)
-           throw new PSQLException("postgresql.call.noreturntype");
-       if (isFunction) { // set entry 1 to dummy entry..
-           inStrings[0] = ""; // dummy entry which ensured that no one overrode
-           // and calls to setXXX (2,..) really went to first arg in a function call..
-       }
-       return super.compileQuery ();
-   }
-
-   /*
-    * An OUT parameter may have the value of SQL NULL; wasNull
-    * reports whether the last value read has this special value.
-    *
-    * 

Note: You must first call getXXX on a parameter to read its

-    * value and then call wasNull() to see if the value was SQL NULL.
-    * @return true if the last parameter read was SQL NULL
-    * @exception SQLException if a database-access error occurs.
-    */
-   public boolean wasNull() throws SQLException
-   {
-       // check to see if the last access threw an exception
-       return (result == null);
-   }
-
-   /*
-    * Get the value of a CHAR, VARCHAR, or LONGVARCHAR parameter as a
-    * Java String.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is null
-    * @exception SQLException if a database-access error occurs.
-    */
-   public String getString(int parameterIndex) throws SQLException
-   {
-       checkIndex (parameterIndex, Types.VARCHAR, "String");
-       return (String)result;
-   }
-   //public String getVarChar(int parameterIndex) throws SQLException {
-   //   return null;
-   //}
-
-   //public String getLongVarChar(int parameterIndex) throws SQLException {
-   //return null;
-   //}
-
-   /*
-    * Get the value of a BIT parameter as a Java boolean.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is false
-    * @exception SQLException if a database-access error occurs.
-    */
-   public boolean getBoolean(int parameterIndex) throws SQLException
-   {
-       checkIndex (parameterIndex, Types.BIT, "Boolean");
-       if (result == null) return false;
-       return ((Boolean)result).booleanValue ();
-   }
-
-   /*
-    * Get the value of a TINYINT parameter as a Java byte.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is 0
-    * @exception SQLException if a database-access error occurs.
-    */
-   public byte getByte(int parameterIndex) throws SQLException
-   {
-       checkIndex (parameterIndex, Types.TINYINT, "Byte");
-       if (result == null) return 0;
-       return (byte)((Integer)result).intValue ();
-   }
-
-   /*
-    * Get the value of a SMALLINT parameter as a Java short.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is 0
-    * @exception SQLException if a database-access error occurs.
-    */
-   public short getShort(int parameterIndex) throws SQLException
-   {
-       checkIndex (parameterIndex, Types.SMALLINT, "Short");
-       if (result == null) return 0;
-       return (short)((Integer)result).intValue ();
-   }
-       
-
-   /*
-    * Get the value of an INTEGER parameter as a Java int.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is 0
-    * @exception SQLException if a database-access error occurs.
-    */
-   public int getInt(int parameterIndex) throws SQLException
-   {
-       checkIndex (parameterIndex, Types.INTEGER, "Int");
-       if (result == null) return 0;
-       return ((Integer)result).intValue ();
-   }
-
-   /*
-    * Get the value of a BIGINT parameter as a Java long.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is 0
-    * @exception SQLException if a database-access error occurs.
-    */
-   public long getLong(int parameterIndex) throws SQLException
-   {
-       checkIndex (parameterIndex, Types.BIGINT, "Long");
-       if (result == null) return 0;
-       return ((Long)result).longValue ();
-   }
-
-   /*
-    * Get the value of a FLOAT parameter as a Java float.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is 0
-    * @exception SQLException if a database-access error occurs.
-    */
-   public float getFloat(int parameterIndex) throws SQLException
-   {
-       checkIndex (parameterIndex, Types.REAL, "Float");
-       if (result == null) return 0;
-       return ((Float)result).floatValue ();
-   }
-
-   /*
-    * Get the value of a DOUBLE parameter as a Java double.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is 0
-    * @exception SQLException if a database-access error occurs.
-    */
-   public double getDouble(int parameterIndex) throws SQLException
-   {
-       checkIndex (parameterIndex, Types.DOUBLE, "Double");
-       if (result == null) return 0;
-       return ((Double)result).doubleValue ();
-   }
-
-   /*
-    * Get the value of a NUMERIC parameter as a java.math.BigDecimal
-    * object.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @param scale a value greater than or equal to zero representing the
-    * desired number of digits to the right of the decimal point
-    * @return the parameter value; if the value is SQL NULL, the result is null
-    * @exception SQLException if a database-access error occurs.
-    * @deprecated in Java2.0
-    */
-   public BigDecimal getBigDecimal(int parameterIndex, int scale)
-   throws SQLException
-   {
-       checkIndex (parameterIndex, Types.NUMERIC, "BigDecimal");
-       return ((BigDecimal)result);
-   }
-
-   /*
-    * Get the value of a SQL BINARY or VARBINARY parameter as a Java
-    * byte[]
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is null
-    * @exception SQLException if a database-access error occurs.
-    */
-   public byte[] getBytes(int parameterIndex) throws SQLException
-   {
-       checkIndex (parameterIndex, Types.VARBINARY, "Bytes");
-       return ((byte [])result);
-   }
-
-   // New API (JPM) (getLongVarBinary)
-   //public byte[] getBinaryStream(int parameterIndex) throws SQLException {
-   //return null;
-   //}
-
-   /*
-    * Get the value of a SQL DATE parameter as a java.sql.Date object
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is null
-    * @exception SQLException if a database-access error occurs.
-    */
-   public java.sql.Date getDate(int parameterIndex) throws SQLException
-   {
-       checkIndex (parameterIndex, Types.DATE, "Date");
-       return (java.sql.Date)result;
-   }
-
-   /*
-    * Get the value of a SQL TIME parameter as a java.sql.Time object.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is null
-    * @exception SQLException if a database-access error occurs.
-    */
-   public java.sql.Time getTime(int parameterIndex) throws SQLException
-   {
-       checkIndex (parameterIndex, Types.TIME, "Time");
-       return (java.sql.Time)result;
-   }
-
-   /*
-    * Get the value of a SQL TIMESTAMP parameter as a java.sql.Timestamp object.
-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return the parameter value; if the value is SQL NULL, the result is null
-    * @exception SQLException if a database-access error occurs.
-    */
-   public java.sql.Timestamp getTimestamp(int parameterIndex)
-   throws SQLException
-   {
-       checkIndex (parameterIndex, Types.TIMESTAMP, "Timestamp");
-       return (java.sql.Timestamp)result;
-   }
-
-   //----------------------------------------------------------------------
-   // Advanced features:
-
-   // You can obtain a ParameterMetaData object to get information
-   // about the parameters to this CallableStatement.
-   //public DatabaseMetaData getMetaData() {
-   //return null;
-   //}
-
-   // getObject returns a Java object for the parameter.
-   // See the JDBC spec's "Dynamic Programming" chapter for details.
-   /*
-    * Get the value of a parameter as a Java object.
-    *
-    * 

This method returns a Java object whose type coresponds to the

-    * SQL type that was registered for this parameter using
-    * registerOutParameter.
-    *
-    * 

Note that this method may be used to read datatabase-specific,

-    * abstract data types. This is done by specifying a targetSqlType
-    * of java.sql.types.OTHER, which allows the driver to return a
-    * database-specific Java type.
-    *
-    * 

See the JDBC spec's "Dynamic Programming" chapter for details.

-    *
-    * @param parameterIndex the first parameter is 1, the second is 2,...
-    * @return A java.lang.Object holding the OUT parameter value.
-    * @exception SQLException if a database-access error occurs.
-    */
-   public Object getObject(int parameterIndex)
-   throws SQLException
-   {
-       checkIndex (parameterIndex);        
-       return result;
-   }
-
-   // ** JDBC 2 Extensions **
-
-   public java.sql.Array getArray(int i) throws SQLException
-   {
-       throw org.postgresql.Driver.notImplemented();
-   }
-
-   public java.math.BigDecimal getBigDecimal(int parameterIndex) throws SQLException
-   {
-       checkIndex (parameterIndex, Types.NUMERIC, "BigDecimal");
-       return ((BigDecimal)result);
-   }
-
-   public Blob getBlob(int i) throws SQLException
-   {
-       throw org.postgresql.Driver.notImplemented();
-   }
-
-   public Clob getClob(int i) throws SQLException
-   {
-       throw org.postgresql.Driver.notImplemented();
-   }
-
-   public Object getObject(int i, java.util.Map map) throws SQLException
-   {
-       throw org.postgresql.Driver.notImplemented();
-   }
-
-   public Ref getRef(int i) throws SQLException
-   {
-       throw org.postgresql.Driver.notImplemented();
-   }
-
-   public java.sql.Date getDate(int i, java.util.Calendar cal) throws SQLException
-   {
-       throw org.postgresql.Driver.notImplemented();
-   }
-
-   public Time getTime(int i, java.util.Calendar cal) throws SQLException
-   {
-       throw org.postgresql.Driver.notImplemented();
-   }
-
-   public Timestamp getTimestamp(int i, java.util.Calendar cal) throws SQLException
-   {
-       throw org.postgresql.Driver.notImplemented();
-   }
-
-   // no custom types allowed yet..
-   public void registerOutParameter(int parameterIndex, int sqlType, String typeName) throws SQLException
-   {
-       throw org.postgresql.Driver.notImplemented();
-   }
-
-
-
-   /** helperfunction for the getXXX calls to check isFunction and index == 1
-    */
-   private void checkIndex (int parameterIndex, int type, String getName) 
-       throws SQLException {
-       checkIndex (parameterIndex);
-       if (type != this.testReturn) 
-           throw new PSQLException("postgresql.call.wrongget",
-                                   new Object[]{getSqlTypeName (testReturn),
-                                                    getName,
-                                                    getSqlTypeName (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
-    */
-   private void checkIndex (int parameterIndex) throws SQLException {
-       if (!isFunction)
-           throw new PSQLException("postgresql.call.noreturntype");
-       if (parameterIndex != 1)
-           throw new PSQLException("postgresql.call.noinout");
-   }
-       
-   /** helper function for creating msg with type names
-    * @param sqlType a java.sql.Types.XX constant
-    * @return String which is the name of the constant..
-    */
-   private static String getSqlTypeName (int sqlType) {
-       switch (sqlType)
-           {
-           case Types.BIT:
-               return "BIT";
-           case Types.SMALLINT:
-               return "SMALLINT";
-           case Types.INTEGER:
-               return "INTEGER";
-           case Types.BIGINT:
-               return "BIGINT";
-           case Types.NUMERIC:
-               return "NUMERIC";
-           case Types.REAL:
-               return "REAL";
-           case Types.DOUBLE:
-               return "DOUBLE";
-           case Types.FLOAT:
-               return "FLOAT";
-           case Types.CHAR:
-               return "CHAR";
-           case Types.VARCHAR:
-               return "VARCHAR";
-           case Types.DATE:
-               return "DATE";
-           case Types.TIME:
-               return "TIME";
-           case Types.TIMESTAMP:
-               return "TIMESTAMP";
-           case Types.BINARY:
-               return "BINARY";
-           case Types.VARBINARY:
-               return "VARBINARY";
-           default:
-               return "UNKNOWN";
-           }
-   }
-}
-
index 77415d051d428a0732626fef15ac2d8481691b9d..a1c8e22737b24d2a05f8aa5ed4b196682ac8e3d2 100644 (file)
@@ -15,7 +15,7 @@ import org.postgresql.util.PSQLException;
 /*
  * This class provides information about the database as a whole.
  *
- * $Id: DatabaseMetaData.java,v 1.59 2002/07/23 03:59:55 barry Exp $
+ * $Id: DatabaseMetaData.java,v 1.60 2002/07/25 22:45:28 barry 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
@@ -1653,7 +1653,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
 
            v.addElement(tuple);
        }
-       return new Jdbc2ResultSet(connection, f, v, "OK", 1);
+       return connection.getResultSet(null, f, v, "OK", 1);
    }
 
    /*
@@ -1731,7 +1731,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
 
        // add query loop here
 
-       return new Jdbc2ResultSet(connection, f, v, "OK", 1);
+       return connection.getResultSet(null, f, v, "OK", 1);
    }
 
    /*
@@ -1866,7 +1866,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
            v.addElement(tuple);
        }
        r.close();
-       return new Jdbc2ResultSet(connection, f, v, "OK", 1);
+       return connection.getResultSet(null, f, v, "OK", 1);
    }
 
    // This array contains the valid values for the types argument
@@ -1913,7 +1913,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
        f[0] = new Field(connection, "TABLE_SCHEM", iVarcharOid, 32);
        tuple[0] = "".getBytes();
        v.addElement(tuple);
-       return new Jdbc2ResultSet(connection, f, v, "OK", 1);
+       return connection.getResultSet(null, f, v, "OK", 1);
    }
 
    /*
@@ -1958,7 +1958,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
            tuple[0] = getTableTypes[i][0].getBytes();
            v.addElement(tuple);
        }
-       return new Jdbc2ResultSet(connection, f, v, "OK", 1);
+       return connection.getResultSet(null, f, v, "OK", 1);
    }
 
    /*
@@ -2154,7 +2154,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
        }
        r.close();
 
-       return new Jdbc2ResultSet(connection, f, v, "OK", 1);
+       return connection.getResultSet(null, f, v, "OK", 1);
    }
 
    /*
@@ -2218,7 +2218,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
            //v.addElement(tuple);
        }
 
-       return new Jdbc2ResultSet(connection, f, v, "OK", 1);
+       return connection.getResultSet(null, f, v, "OK", 1);
    }
 
    /*
@@ -2281,7 +2281,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
            //v.addElement(tuple);
        }
 
-       return new Jdbc2ResultSet(connection, f, v, "OK", 1);
+       return connection.getResultSet(null, f, v, "OK", 1);
    }
 
    /*
@@ -2337,7 +2337,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
        f[6] = new Field(connection, "DECIMAL_DIGITS", iInt2Oid, 2);
        f[7] = new Field(connection, "PSEUDO_COLUMN", iInt2Oid, 2);
 
-       return new Jdbc2ResultSet(connection, f, v, "OK", 1);
+       return connection.getResultSet(null, f, v, "OK", 1);
    }
 
    /*
@@ -2680,7 +2680,7 @@ WHERE
       tuples.addElement(tuple);
     }
 
-    return new Jdbc2ResultSet(connection, f, tuples, "OK", 1);
+    return connection.getResultSet(null, f, tuples, "OK", 1);
    }
 
    /*
@@ -2959,7 +2959,7 @@ WHERE
                v.addElement(tuple);
            }
            rs.close();
-           return new Jdbc2ResultSet(connection, f, v, "OK", 1);
+           return connection.getResultSet(null, f, v, "OK", 1);
        }
 
        throw new PSQLException("postgresql.metadata.unavailable");
@@ -3097,7 +3097,7 @@ WHERE
            }
        }
 
-       return new Jdbc2ResultSet(connection, f, v, "OK", 1);
+       return connection.getResultSet(null, f, v, "OK", 1);
    }
 
 
diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2CallableStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2CallableStatement.java
new file mode 100644 (file)
index 0000000..c8bc1b7
--- /dev/null
@@ -0,0 +1,15 @@
+package org.postgresql.jdbc2;
+
+
+import java.sql.*;
+
+public class Jdbc2CallableStatement extends AbstractJdbc2Statement implements java.sql.CallableStatement
+{
+
+   public Jdbc2CallableStatement(Jdbc2Connection connection, String sql) throws SQLException
+   {
+       super(connection, sql);
+   }
+
+}
+
index 787b14e62af6485d84fb46c398b9327521f26420..b512355260c2520d641e58160aaed72f1bc29a11 100644 (file)
@@ -3,9 +3,10 @@ package org.postgresql.jdbc2;
 
 import java.sql.*;
 import java.util.Vector;
+import java.util.Hashtable;
 import org.postgresql.Field;
 
-/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/Jdbc2Connection.java,v 1.2 2002/07/24 22:08:42 barry Exp $
+/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/Jdbc2Connection.java,v 1.3 2002/07/25 22:45:28 barry Exp $
  * This class implements the java.sql.Connection interface for JDBC2.
  * However most of the implementation is really done in 
  * org.postgresql.jdbc2.AbstractJdbc2Connection or one of it's parents
@@ -32,7 +33,7 @@ public class Jdbc2Connection extends org.postgresql.jdbc2.AbstractJdbc2Connectio
 
         public java.sql.CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
         {
-       org.postgresql.jdbc2.CallableStatement s = new org.postgresql.jdbc2.CallableStatement(this,sql);
+       Jdbc2CallableStatement s = new org.postgresql.jdbc2.Jdbc2CallableStatement(this,sql);
        s.setResultSetType(resultSetType);
            s.setResultSetConcurrency(resultSetConcurrency);
            return s;
@@ -45,15 +46,14 @@ public class Jdbc2Connection extends org.postgresql.jdbc2.AbstractJdbc2Connectio
                 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
+        public java.sql.ResultSet getResultSet(Statement statement, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException
         {
-                if (stat != null)
-                {
-                        if (stat.getResultSetConcurrency() == java.sql.ResultSet.CONCUR_UPDATABLE)
-                          return new org.postgresql.jdbc2.UpdateableResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor);
-                }
+                return new Jdbc2ResultSet(this, statement, fields, tuples, status, updateCount, insertOID, binaryCursor);
+        }
 
-                return new Jdbc2ResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor);
+        public java.sql.ResultSet getResultSet(Statement statement, Field[] fields, Vector tuples, String status, int updateCount) throws SQLException
+        {
+                return new Jdbc2ResultSet(this, statement, fields, tuples, status, updateCount, 0, false);
         }
 
 
index 7200cf549ad586ddfc49d5a518e06482a7949d26..e2c6ad7eea28bf375030e4354a3106dc9bcaaf28 100644 (file)
@@ -5,7 +5,7 @@ import java.sql.*;
 import java.util.Vector;
 import org.postgresql.Field;
 
-/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/Jdbc2ResultSet.java,v 1.1 2002/07/23 03:59:55 barry Exp $
+/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/Jdbc2ResultSet.java,v 1.2 2002/07/25 22:45:28 barry Exp $
  * This class implements the java.sql.ResultSet interface for JDBC2.
  * However most of the implementation is really done in 
  * org.postgresql.jdbc2.AbstractJdbc2ResultSet or one of it's parents
@@ -13,14 +13,9 @@ import org.postgresql.Field;
 public class Jdbc2ResultSet extends org.postgresql.jdbc2.AbstractJdbc2ResultSet implements java.sql.ResultSet
 {
 
-   public Jdbc2ResultSet(Jdbc2Connection conn, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor)
+   public Jdbc2ResultSet(Jdbc2Connection conn, Statement statement, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor)
    {
-       super(conn, fields, tuples, status, updateCount, insertOID, binaryCursor);
-   }
-
-   public Jdbc2ResultSet(Jdbc2Connection conn, Field[] fields, Vector tuples, String status, int updateCount)
-   {
-       super(conn, fields, tuples, status, updateCount, 0, false);
+       super(conn, statement, fields, tuples, status, updateCount, insertOID, binaryCursor);
    }
 
    public java.sql.ResultSetMetaData getMetaData() throws SQLException
diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/UpdateableResultSet.java b/src/interfaces/jdbc/org/postgresql/jdbc2/UpdateableResultSet.java
deleted file mode 100644 (file)
index 6f6f67d..0000000
+++ /dev/null
@@ -1,1389 +0,0 @@
-package org.postgresql.jdbc2;
-
-// IMPORTANT NOTE: This is the begining of supporting updateable ResultSets.
-//
-// This is because here we should be updateable, so any unimplemented methods
-// must say so.
-//
-// Also you'll notice that the String columnName based calls are not present.
-// They are not required as they are in the super class.
-//
-
-import java.lang.*;
-import java.io.*;
-import java.math.*;
-import java.text.*;
-import java.util.*;
-import java.sql.*;
-import org.postgresql.Field;
-import org.postgresql.largeobject.*;
-import org.postgresql.util.*;
-import org.postgresql.Driver;
-
-/*
- * @see ResultSet
- * @see ResultSetMetaData
- * @see java.sql.ResultSet
- */
-public class UpdateableResultSet extends org.postgresql.jdbc2.Jdbc2ResultSet
-{
-
-
-  class PrimaryKey
-  {
-    int index;              // where in the result set is this primaryKey
-    String name;            // what is the columnName of this primary Key
-
-    PrimaryKey( int index, String name)
-    {
-      this.index = index;
-      this.name = name;
-    }
-    Object getValue() throws SQLException
-    {
-      return getObject(index);
-    }
-  };
-
-  private boolean usingOID = false;   // are we using the OID for the primary key?
-
-  private Vector primaryKeys;    // list of primary keys
-
-  private int numKeys = 0;
-
-  private boolean singleTable = false;
-
-   protected String tableName = null;
-
-   /**
-    * PreparedStatement used to delete data
-    */
-
-   protected java.sql.PreparedStatement updateStatement = null;
-
-   /**
-    * PreparedStatement used to insert data
-    */
-
-   protected java.sql.PreparedStatement insertStatement = null;
-
-   /**
-    * PreparedStatement used to delete data
-    */
-
-   protected java.sql.PreparedStatement deleteStatement = null;
-
-
-  /**
-   * PreparedStatement used to refresh data
-   */
-  private java.sql.PreparedStatement selectStatement = null;
-
-
-   /**
-    * Is this result set updateable?
-    */
-
-   protected boolean updateable = false;
-
-   /**
-    * Are we in the middle of doing updates to the current row?
-    */
-
-   protected boolean doingUpdates = false;
-
-
-   /**
-    * Are we on the insert row?
-    */
-
-   protected boolean onInsertRow = false;
-
-
-   protected Hashtable updateValues = new Hashtable();
-
-   // The Row Buffer will be used to cache updated rows..then we shall sync this with the rows vector
-
-
-   /*
-    * Create a new ResultSet - Note that we create ResultSets to
-    * represent the results of everything.
-    *
-    * @param fields an array of Field objects (basically, the
-    *  ResultSet MetaData)
-    * @param tuples Vector of the actual data
-    * @param status the status string returned from the back end
-    * @param updateCount the number of rows affected by the operation
-    * @param cursor the positioned update/delete cursor name
-    */
-   public UpdateableResultSet(Jdbc2Connection conn, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor)
-   {
-       super(conn, fields, tuples, status, updateCount, insertOID, binaryCursor);
-   }
-
-  /**
-   *
-   * @throws SQLException
-   */
-   public synchronized void cancelRowUpdates() throws SQLException
-  {
-       if (doingUpdates)
-    {
-           doingUpdates = false;
-
-           clearRowBuffer();
-       }
-   }
-
-  /**
-   *
-   * @throws SQLException
-   */
-   public synchronized void deleteRow() throws SQLException
-  {
-       if ( !isUpdateable() )
-    {
-           throw new PSQLException( "postgresql.updateable.notupdateable" );
-       }
-
-       if (onInsertRow)
-    {
-           throw new PSQLException( "postgresql.updateable.oninsertrow" );
-       }
-
-    if (rows.size() == 0)
-    {
-      throw new PSQLException( "postgresql.updateable.emptydelete" );
-    }
-    if (isBeforeFirst())
-    {
-      throw new PSQLException( "postgresql.updateable.beforestartdelete" );
-    }
-    if (isAfterLast())
-    {
-      throw new PSQLException( "postgresql.updateable.afterlastdelete" );
-    }
-
-
-    int numKeys = primaryKeys.size();
-    if ( deleteStatement == null )
-    {
-
-
-      StringBuffer deleteSQL= new StringBuffer("DELETE FROM " ).append(tableName).append(" where " );
-
-      for ( int i=0; i < numKeys ; i++ )
-      {
-        deleteSQL.append( ((PrimaryKey)primaryKeys.get(i)).name ).append( " = ? " );
-        if ( i < numKeys-1 )
-        {
-          deleteSQL.append( " and " );
-        }
-      }
-
-      deleteStatement = ((java.sql.Connection)connection).prepareStatement(deleteSQL.toString());
-    }
-    deleteStatement.clearParameters();
-
-    for ( int i =0; i < numKeys; i++ )
-    {
-      deleteStatement.setObject(i+1, ((PrimaryKey)primaryKeys.get(i)).getValue());
-    }
-
-
-    deleteStatement.executeUpdate();
-
-    rows.removeElementAt(current_row);
-  }
-
-
-  /**
-   *
-   * @return
-   * @throws SQLException
-   */
-   public int getConcurrency() throws SQLException
-   {
-       // New in 7.1 - The updateable ResultSet class will now return
-       // CONCURuPDATEABLE.
-       return CONCUR_UPDATABLE;
-   }
-
-  /**
-   *
-   * @throws SQLException
-   */
-
-   public synchronized void insertRow() throws SQLException
-  {
-       if ( !isUpdateable() )
-    {
-           throw new PSQLException( "postgresql.updateable.notupdateable" );
-       }
-
-       if (!onInsertRow)
-    {
-           throw new PSQLException( "postgresql.updateable.notoninsertrow" );
-       }
-       else
-    {
-
-      // loop through the keys in the insertTable and create the sql statement
-      // we have to create the sql every time since the user could insert different
-      // columns each time
-
-      StringBuffer insertSQL=new StringBuffer("INSERT INTO ").append(tableName).append(" (");
-      StringBuffer paramSQL = new StringBuffer(") values (" );
-
-      Enumeration columnNames = updateValues.keys();
-      int numColumns = updateValues.size();
-
-      for ( int i=0; columnNames.hasMoreElements() ; i++ )
-      {
-        String columnName = (String)columnNames.nextElement();
-
-        insertSQL.append( columnName );
-        if ( i < numColumns - 1 )
-        {
-          insertSQL.append(", ");
-          paramSQL.append("?,");
-        }
-        else
-        {
-          paramSQL.append("?)");
-        }
-
-      }
-
-      insertSQL.append(paramSQL.toString());
-      insertStatement = ((java.sql.Connection)connection).prepareStatement(insertSQL.toString());
-
-      Enumeration keys = updateValues.keys();
-
-      for( int i=1; keys.hasMoreElements() ; i++)
-      {
-        String key = (String)keys.nextElement();
-        insertStatement.setObject(i, updateValues.get( key ) );
-      }
-
-      insertStatement.executeUpdate();
-
-      if ( usingOID )
-      {
-        // we have to get the last inserted OID and put it in the resultset
-
-        long insertedOID = ((AbstractJdbc2Statement)insertStatement).getLastOID();
-
-        updateValues.put("oid", new Long(insertedOID) );
-
-      }
-
-      // update the underlying row to the new inserted data
-      updateRowBuffer();
-
-           rows.addElement(rowBuffer);
-
-         // we should now reflect the current data in this_row
-      // that way getXXX will get the newly inserted data
-      this_row = rowBuffer;
-
-      // need to clear this in case of another insert
-      clearRowBuffer();
-
-
-       }
-   }
-
-
-  /**
-   *
-   * @throws SQLException
-   */
-
-   public synchronized void moveToCurrentRow() throws SQLException
-   {
-       this_row = (byte [][])rows.elementAt(current_row);
-
-       rowBuffer=new byte[this_row.length][];
-       System.arraycopy(this_row,0,rowBuffer,0,this_row.length);
-
-    onInsertRow = false;
-    doingUpdates = false;
-   }
-
-  /**
-   *
-   * @throws SQLException
-   */
-   public synchronized void  moveToInsertRow() throws SQLException
-   {
-       // only sub-classes implement CONCURuPDATEABLE
-       if (!updateable)
-    {
-           throw new PSQLException( "postgresql.updateable.notupdateable" );
-       }
-
-       if (insertStatement != null)
-    {
-      insertStatement = null;
-       }
-
-
-    // make sure the underlying data is null
-    clearRowBuffer();
-
-       onInsertRow = true;
-       doingUpdates = false;
-
-   }
-
-  /**
-   *
-   * @throws SQLException
-   */
-   private synchronized void clearRowBuffer() throws SQLException
-  {
-    // rowBuffer is the temporary storage for the row
-       rowBuffer=new byte[fields.length][];
-
-    // clear the updateValues hashTable for the next set of updates
-    updateValues.clear();
-
-   }
-
-
-  /**
-   *
-   * @return
-   * @throws SQLException
-   */
-   public boolean rowDeleted() throws SQLException
-   {
-       // only sub-classes implement CONCURuPDATEABLE
-       throw Driver.notImplemented();
-   }
-
-  /**
-   *
-   * @return
-   * @throws SQLException
-   */
-   public boolean rowInserted() throws SQLException
-   {
-       // only sub-classes implement CONCURuPDATEABLE
-       throw Driver.notImplemented();
-   }
-
-  /**
-   *
-   * @return
-   * @throws SQLException
-   */
-   public boolean rowUpdated() throws SQLException
-   {
-       // only sub-classes implement CONCURuPDATEABLE
-       throw Driver.notImplemented();
-   }
-
-  /**
-   *
-   * @param columnIndex
-   * @param x
-   * @param length
-   * @throws SQLException
-   */
-   public synchronized void updateAsciiStream(int columnIndex,
-                                 java.io.InputStream x,
-                                 int length
-                                ) throws SQLException
-   {
-
-       byte[] theData=null;
-
-       try
-    {
-           x.read(theData,0,length);
-       }
-    catch (NullPointerException ex )
-    {
-      throw new PSQLException("postgresql.updateable.inputstream");
-    }
-       catch (IOException ie)
-    {
-           throw new PSQLException("postgresql.updateable.ioerror" + ie);
-       }
-
-    doingUpdates = !onInsertRow;
-
-    updateValues.put( fields[columnIndex-1].getName(), theData );
-
-   }
-
-  /**
-   *
-   * @param columnIndex
-   * @param x
-   * @throws SQLException
-   */
-   public synchronized void updateBigDecimal(int columnIndex,
-                                           java.math.BigDecimal x )
-                                                                throws SQLException
-   {
-
-    doingUpdates = !onInsertRow;
-    updateValues.put( fields[columnIndex-1].getName(), x );
-
-   }
-
-  /**
-   *
-   * @param columnIndex
-   * @param x
-   * @param length
-   * @throws SQLException
-   */
-   public synchronized void updateBinaryStream(int columnIndex,
-                                               java.io.InputStream x,
-                                               int length
-                                              ) throws SQLException
-   {
-
-
-       byte[] theData=null;
-
-       try {
-           x.read(theData,0,length);
-
-       }
-    catch( NullPointerException ex )
-    {
-      throw new PSQLException("postgresql.updateable.inputstream");
-    }
-       catch (IOException ie)
-    {
-           throw new PSQLException("postgresql.updateable.ioerror" + ie);
-       }
-
-    doingUpdates = !onInsertRow;
-
-    updateValues.put( fields[columnIndex-1].getName(), theData );
-
-   }
-
-  /**
-   *
-   * @param columnIndex
-   * @param x
-   * @throws SQLException
-   */
-   public synchronized void updateBoolean(int columnIndex, boolean x) throws SQLException
-   {
-
-       if ( Driver.logDebug ) Driver.debug("updating boolean "+fields[columnIndex-1].getName()+"="+x);
-
-    doingUpdates = !onInsertRow;
-     updateValues.put( fields[columnIndex-1].getName(), new Boolean(x) );
-
-   }
-
-  /**
-   *
-   * @param columnIndex
-   * @param x
-   * @throws SQLException
-   */
-   public synchronized void updateByte(int columnIndex, byte x) throws SQLException
-   {
-
-    doingUpdates = true;
-    updateValues.put( fields[columnIndex-1].getName(), String.valueOf(x) );
-   }
-
-  /**
-   *
-   * @param columnIndex
-   * @param x
-   * @throws SQLException
-   */
-   public synchronized void updateBytes(int columnIndex, byte[] x) throws SQLException
-   {
-
-    doingUpdates = !onInsertRow;
-       updateValues.put( fields[columnIndex-1].getName(), x );
-
-   }
-
-  /**
-   *
-   * @param columnIndex
-   * @param x
-   * @param length
-   * @throws SQLException
-   */
-   public synchronized void updateCharacterStream(int columnIndex,
-                                                  java.io.Reader x,
-                                                  int length
-                                                 ) throws SQLException
-   {
-
-
-       char[] theData=null;
-
-       try
-    {
-           x.read(theData,0,length);
-
-       }
-    catch (NullPointerException ex)
-    {
-      throw new PSQLException("postgresql.updateable.inputstream");
-    }
-       catch (IOException ie)
-    {
-           throw new PSQLException("postgresql.updateable.ioerror" + ie);
-       }
-
-    doingUpdates = !onInsertRow;
-    updateValues.put( fields[columnIndex-1].getName(), theData);
-
-   }
-
-   public synchronized void updateDate(int columnIndex, java.sql.Date x) throws SQLException
-   {
-
-    doingUpdates = !onInsertRow;
-       updateValues.put( fields[columnIndex-1].getName(), x );
-   }
-
-   public synchronized void updateDouble(int columnIndex, double x) throws SQLException
-   {
-       if ( Driver.logDebug ) Driver.debug("updating double "+fields[columnIndex-1].getName()+"="+x);
-
-    doingUpdates = !onInsertRow;
-    updateValues.put( fields[columnIndex-1].getName(), new Double(x) );
-
-   }
-
-   public synchronized void updateFloat(int columnIndex, float x) throws SQLException
-   {
-       if ( Driver.logDebug ) Driver.debug("updating float "+fields[columnIndex-1].getName()+"="+x);
-
-    doingUpdates = !onInsertRow;
-
-       updateValues.put( fields[columnIndex-1].getName(), new Float(x) );
-
-   }
-
-   public synchronized void updateInt(int columnIndex, int x) throws SQLException
-   {
-       if ( Driver.logDebug ) Driver.debug("updating int "+fields[columnIndex-1].getName()+"="+x);
-
-    doingUpdates = !onInsertRow;
-    updateValues.put( fields[columnIndex-1].getName(), new Integer(x) );
-
-   }
-
-   public synchronized void updateLong(int columnIndex, long x) throws SQLException
-   {
-       if ( Driver.logDebug ) Driver.debug("updating long "+fields[columnIndex-1].getName()+"="+x);
-
-    doingUpdates = !onInsertRow;
-    updateValues.put( fields[columnIndex-1].getName(), new Long(x) );
-
-   }
-
-   public synchronized void updateNull(int columnIndex) throws SQLException
-   {
-
-    doingUpdates = !onInsertRow;
-    updateValues.put( fields[columnIndex-1].getName(), null);
-
-
-   }
-
-   public synchronized void updateObject(int columnIndex, Object x) throws SQLException
-   {
-
-
-       if ( Driver.logDebug ) Driver.debug("updating object " + fields[columnIndex-1].getName() + " = " + x);
-
-    doingUpdates = !onInsertRow;
-    updateValues.put( fields[columnIndex-1].getName(), x );
-   }
-
-   public synchronized void updateObject(int columnIndex, Object x, int scale) throws SQLException
-   {
-
-    this.updateObject(columnIndex, x);
-
-   }
-
-
-  public void refreshRow() throws SQLException
-  {
-       if ( !isUpdateable() )
-    {
-           throw new PSQLException( "postgresql.updateable.notupdateable" );
-       }
-
-    try
-    {
-      StringBuffer selectSQL = new StringBuffer( "select ");
-
-      final int numColumns = java.lang.reflect.Array.getLength(fields);
-
-      for (int i=0; i < numColumns ; i++ )
-      {
-
-        selectSQL.append( fields[i].getName() );
-
-        if ( i < numColumns - 1 )
-        {
-
-          selectSQL.append(", ");
-        }
-
-      }
-      selectSQL.append(" from " ).append(tableName).append(" where ");
-
-      int numKeys = primaryKeys.size();
-
-      for ( int i = 0; i < numKeys; i++ )
-      {
-
-        PrimaryKey primaryKey = ((PrimaryKey)primaryKeys.get(i));
-        selectSQL.append(primaryKey.name).append("= ?");
-
-        if ( i < numKeys -1 )
-        {
-          selectSQL.append(" and ");
-        }
-      }
-      if ( Driver.logDebug ) Driver.debug("selecting "+ selectSQL.toString());
-      selectStatement = ((java.sql.Connection)connection).prepareStatement(selectSQL.toString());
-
-
-      for( int j=0, i=1; j < numKeys; j++, i++)
-      {
-        selectStatement.setObject( i, ((PrimaryKey)primaryKeys.get(j)).getValue() );
-      }
-
-      Jdbc2ResultSet rs = (Jdbc2ResultSet) selectStatement.executeQuery();
-
-      if( rs.first() )
-      {
-        rowBuffer = rs.rowBuffer;
-      }
-
-      rows.setElementAt( rowBuffer, current_row );
-      if ( Driver.logDebug ) Driver.debug("done updates");
-
-      rs.close();
-      selectStatement.close();
-      selectStatement = null;
-
-    }
-    catch (Exception e)
-    {
-      if ( Driver.logDebug ) Driver.debug(e.getClass().getName()+e);
-      throw new SQLException( e.getMessage() );
-    }
-
-  }
-  /**
-   *
-   * @throws SQLException
-   */
-   public synchronized void updateRow() throws SQLException
-  {
-       if ( !isUpdateable() )
-    {
-           throw new PSQLException( "postgresql.updateable.notupdateable" );
-       }
-
-       if (doingUpdates)
-    {
-
-           try
-      {
-
-        StringBuffer updateSQL=new StringBuffer("UPDATE "+tableName+" SET  ");
-
-        int numColumns = updateValues.size();
-        Enumeration columns = updateValues.keys();
-
-        for (int i=0; columns.hasMoreElements() ; i++ )
-        {
-
-          String column = (String)columns.nextElement();
-          updateSQL.append( column + "= ?");
-
-          if ( i < numColumns - 1 )
-          {
-
-            updateSQL.append(", ");
-          }
-
-        }
-        updateSQL.append( " WHERE " );
-
-        int numKeys = primaryKeys.size();
-
-        for ( int i = 0; i < numKeys; i++ )
-        {
-
-          PrimaryKey primaryKey = ((PrimaryKey)primaryKeys.get(i));
-          updateSQL.append(primaryKey.name).append("= ?");
-
-          if ( i < numKeys -1 )
-          {
-            updateSQL.append(" and ");
-          }
-        }
-        if ( Driver.logDebug ) Driver.debug("updating "+updateSQL.toString());
-        updateStatement = ((java.sql.Connection)connection).prepareStatement(updateSQL.toString());
-
-        int i = 0;
-        Iterator iterator = updateValues.values().iterator();
-        for (; iterator.hasNext(); i++)
-        {
-          updateStatement.setObject( i+1, iterator.next() );
-
-        }
-        for( int j=0; j < numKeys; j++, i++)
-        {
-          updateStatement.setObject( i+1, ((PrimaryKey)primaryKeys.get(j)).getValue() );
-        }
-
-        updateStatement.executeUpdate();
-        updateStatement.close();
-
-        updateStatement = null;
-        updateRowBuffer();
-
-
-               if ( Driver.logDebug ) Driver.debug("copying data");
-               System.arraycopy(rowBuffer,0,this_row,0,rowBuffer.length);
-
-               rows.setElementAt( rowBuffer, current_row );
-        if ( Driver.logDebug ) Driver.debug("done updates");
-
-             doingUpdates = false;
-           }
-           catch(Exception e)
-      {
-               if ( Driver.logDebug ) Driver.debug(e.getClass().getName()+e);
-        throw new SQLException( e.getMessage() );
-           }
-
-       }
-
-   }
-
-   public synchronized void updateShort(int columnIndex, short x) throws SQLException
-   {
-       if ( Driver.logDebug ) Driver.debug("in update Short "+fields[columnIndex-1].getName()+" = "+x);
-
-
-    doingUpdates = !onInsertRow;
-    updateValues.put( fields[columnIndex-1].getName(), new Short(x) );
-
-   }
-
-   public synchronized void updateString(int columnIndex, String x) throws SQLException
-   {
-       if ( Driver.logDebug ) Driver.debug("in update String "+fields[columnIndex-1].getName()+" = "+x);
-
-    doingUpdates = !onInsertRow;
-    updateValues.put( fields[columnIndex-1].getName(), x );
-
-   }
-
-   public synchronized void updateTime(int columnIndex, Time x) throws SQLException
-   {
-       if ( Driver.logDebug ) Driver.debug("in update Time "+fields[columnIndex-1].getName()+" = "+x);
-
-
-    doingUpdates = !onInsertRow;
-    updateValues.put( fields[columnIndex-1].getName(), x );
-
-   }
-
-   public synchronized void updateTimestamp(int columnIndex, Timestamp x) throws SQLException
-   {
-       if ( Driver.logDebug ) Driver.debug("updating Timestamp "+fields[columnIndex-1].getName()+" = "+x);
-
-    doingUpdates = !onInsertRow;
-    updateValues.put( fields[columnIndex-1].getName(), x );
-
-
-   }
-
-   public synchronized void updateNull(String columnName) throws SQLException
-  {
-       updateNull(findColumn(columnName));
-   }
-
-   /**
-    * JDBC 2.0
-    *
-    * Update a column with a boolean value.
-    *
-    * The updateXXX() methods are used to update column values in the
-    * current row, or the insert row.  The updateXXX() methods do not
-    * update the underlying database, instead the updateRow() or insertRow()
-    * methods are called to update the database.
-    *
-    * @param columnName the name of the column
-    * @param x the new column value
-    * @exception SQLException if a database-access error occurs
-    */
-
-   public synchronized void updateBoolean(String columnName, boolean x) throws SQLException
-  {
-       updateBoolean(findColumn(columnName), x);
-   }
-
-   /**
-    * JDBC 2.0
-    *
-    * Update a column with a byte value.
-    *
-    * The updateXXX() methods are used to update column values in the
-    * current row, or the insert row.  The updateXXX() methods do not
-    * update the underlying database, instead the updateRow() or insertRow()
-    * methods are called to update the database.
-    *
-    * @param columnName the name of the column
-    * @param x the new column value
-    * @exception SQLException if a database-access error occurs
-    */
-
-   public synchronized void updateByte(String columnName, byte x) throws SQLException
-  {
-       updateByte(findColumn(columnName), x);
-   }
-
-   /**
-    * JDBC 2.0
-    *
-    * Update a column with a short value.
-    *
-    * The updateXXX() methods are used to update column values in the
-    * current row, or the insert row.  The updateXXX() methods do not
-    * update the underlying database, instead the updateRow() or insertRow()
-    * methods are called to update the database.
-    *
-    * @param columnName the name of the column
-    * @param x the new column value
-    * @exception SQLException if a database-access error occurs
-    */
-
-   public synchronized void updateShort(String columnName, short x) throws SQLException
-  {
-       updateShort(findColumn(columnName), x);
-   }
-
-   /**
-    * JDBC 2.0
-    *
-    * Update a column with an integer value.
-    *
-    * The updateXXX() methods are used to update column values in the
-    * current row, or the insert row.  The updateXXX() methods do not
-    * update the underlying database, instead the updateRow() or insertRow()
-    * methods are called to update the database.
-    *
-    * @param columnName the name of the column
-    * @param x the new column value
-    * @exception SQLException if a database-access error occurs
-    */
-
-   public synchronized void updateInt(String columnName, int x) throws SQLException
-  {
-       updateInt(findColumn(columnName), x);
-   }
-
-   /**
-    * JDBC 2.0
-    *
-    * Update a column with a long value.
-    *
-    * The updateXXX() methods are used to update column values in the
-    * current row, or the insert row.  The updateXXX() methods do not
-    * update the underlying database, instead the updateRow() or insertRow()
-    * methods are called to update the database.
-    *
-    * @param columnName the name of the column
-    * @param x the new column value
-    * @exception SQLException if a database-access error occurs
-    */
-
-   public synchronized void updateLong(String columnName, long x) throws SQLException
-  {
-       updateLong(findColumn(columnName), x);
-   }
-
-   /**
-    * JDBC 2.0
-    *
-    * Update a column with a float value.
-    *
-    * The updateXXX() methods are used to update column values in the
-    * current row, or the insert row.  The updateXXX() methods do not
-    * update the underlying database, instead the updateRow() or insertRow()
-    * methods are called to update the database.
-    *
-    * @param columnName the name of the column
-    * @param x the new column value
-    * @exception SQLException if a database-access error occurs
-    */
-
-   public synchronized void updateFloat(String columnName, float x) throws SQLException
-  {
-       updateFloat(findColumn(columnName), x);
-   }
-
-   /**
-    * JDBC 2.0
-    *
-    * Update a column with a double value.
-    *
-    * The updateXXX() methods are used to update column values in the
-    * current row, or the insert row.  The updateXXX() methods do not
-    * update the underlying database, instead the updateRow() or insertRow()
-    * methods are called to update the database.
-    *
-    * @param columnName the name of the column
-    * @param x the new column value
-    * @exception SQLException if a database-access error occurs
-    */
-
-   public synchronized void updateDouble(String columnName, double x) throws SQLException
-  {
-       updateDouble(findColumn(columnName), x);
-   }
-
-   /**
-    * JDBC 2.0
-    *
-    * Update a column with a BigDecimal value.
-    *
-    * The updateXXX() methods are used to update column values in the
-    * current row, or the insert row.  The updateXXX() methods do not
-    * update the underlying database, instead the updateRow() or insertRow()
-    * methods are called to update the database.
-    *
-    * @param columnName the name of the column
-    * @param x the new column value
-    * @exception SQLException if a database-access error occurs
-    */
-
-   public synchronized void updateBigDecimal(String columnName, BigDecimal x)
-                                                                  throws SQLException
-  {
-       updateBigDecimal(findColumn(columnName), x);
-   }
-
-   /**
-    * JDBC 2.0
-    *
-    * Update a column with a String value.
-    *
-    * The updateXXX() methods are used to update column values in the
-    * current row, or the insert row.  The updateXXX() methods do not
-    * update the underlying database, instead the updateRow() or insertRow()
-    * methods are called to update the database.
-    *
-    * @param columnName the name of the column
-    * @param x the new column value
-    * @exception SQLException if a database-access error occurs
-    */
-
-   public synchronized void updateString(String columnName, String x) throws SQLException
-  {
-       updateString(findColumn(columnName), x);
-   }
-
-   /**
-    * JDBC 2.0
-    *
-    * Update a column with a byte array value.
-    *
-    * The updateXXX() methods are used to update column values in the
-    * current row, or the insert row.  The updateXXX() methods do not
-    * update the underlying database, instead the updateRow() or insertRow()
-    * methods are called to update the database.
-    *
-    * @param columnName the name of the column
-    * @param x the new column value
-    * @exception SQLException if a database-access error occurs
-    */
-
-   public synchronized void updateBytes(String columnName, byte x[]) throws SQLException
-  {
-       updateBytes(findColumn(columnName), x);
-   }
-
-   /**
-    * JDBC 2.0
-    *
-    * Update a column with a Date value.
-    *
-    * The updateXXX() methods are used to update column values in the
-    * current row, or the insert row.  The updateXXX() methods do not
-    * update the underlying database, instead the updateRow() or insertRow()
-    * methods are called to update the database.
-    *
-    * @param columnName the name of the column
-    * @param x the new column value
-    * @exception SQLException if a database-access error occurs
-    */
-
-   public synchronized void updateDate(String columnName, java.sql.Date x)
-                                                                          throws SQLException
-  {
-       updateDate(findColumn(columnName), x);
-   }
-
-   /**
-    * JDBC 2.0
-    *
-    * Update a column with a Time value.
-    *
-    * The updateXXX() methods are used to update column values in the
-    * current row, or the insert row.  The updateXXX() methods do not
-    * update the underlying database, instead the updateRow() or insertRow()
-    * methods are called to update the database.
-    *
-    * @param columnName the name of the column
-    * @param x the new column value
-    * @exception SQLException if a database-access error occurs
-    */
-
-   public synchronized void updateTime(String columnName, java.sql.Time x)
-                                                                          throws SQLException
-  {
-       updateTime(findColumn(columnName), x);
-   }
-
-   /**
-    * JDBC 2.0
-    *
-    * Update a column with a Timestamp value.
-    *
-    * The updateXXX() methods are used to update column values in the
-    * current row, or the insert row.  The updateXXX() methods do not
-    * update the underlying database, instead the updateRow() or insertRow()
-    * methods are called to update the database.
-    *
-    * @param columnName the name of the column
-    * @param x the new column value
-    * @exception SQLException if a database-access error occurs
-    */
-
-   public synchronized void updateTimestamp(String columnName, java.sql.Timestamp x)
-                                                                                 throws SQLException
-  {
-       updateTimestamp(findColumn(columnName), x);
-   }
-
-   /**
-    * JDBC 2.0
-    *
-    * Update a column with an ascii stream value.
-    *
-    * The updateXXX() methods are used to update column values in the
-    * current row, or the insert row.  The updateXXX() methods do not
-    * update the underlying database, instead the updateRow() or insertRow()
-    * methods are called to update the database.
-    *
-    * @param columnName the name of the column
-    * @param x the new column value
-    * @param length of the stream
-    * @exception SQLException if a database-access error occurs
-    */
-
-   public synchronized void updateAsciiStream(
-                                              String columnName,
-                                              java.io.InputStream x,
-                                              int length)
-                                              throws SQLException
-  {
-       updateAsciiStream(findColumn(columnName), x, length);
-   }
-
-   /**
-    * JDBC 2.0
-    *
-    * Update a column with a binary stream value.
-    *
-    * The updateXXX() methods are used to update column values in the
-    * current row, or the insert row.  The updateXXX() methods do not
-    * update the underlying database, instead the updateRow() or insertRow()
-    * methods are called to update the database.
-    *
-    * @param columnName the name of the column
-    * @param x the new column value
-    * @param length of the stream
-    * @exception SQLException if a database-access error occurs
-    */
-
-   public synchronized void updateBinaryStream(
-                                              String columnName,
-                                              java.io.InputStream x,
-                                              int length)
-                                              throws SQLException
-  {
-       updateBinaryStream(findColumn(columnName), x, length);
-   }
-
-   /**
-    * JDBC 2.0
-    *
-    * Update a column with a character stream value.
-    *
-    * The updateXXX() methods are used to update column values in the
-    * current row, or the insert row.  The updateXXX() methods do not
-    * update the underlying database, instead the updateRow() or insertRow()
-    * methods are called to update the database.
-    *
-    * @param columnName the name of the column
-    * @param x the new column value
-    * @param length of the stream
-    * @exception SQLException if a database-access error occurs
-    */
-
-   public synchronized void updateCharacterStream(
-                                                  String columnName,
-                                                  java.io.Reader reader,
-                                                  int length)
-                                                  throws SQLException
-  {
-       updateCharacterStream(findColumn(columnName), reader,length);
-   }
-
-   /**
-    * JDBC 2.0
-    *
-    * Update a column with an Object value.
-    *
-    * The updateXXX() methods are used to update column values in the
-    * current row, or the insert row.  The updateXXX() methods do not
-    * update the underlying database, instead the updateRow() or insertRow()
-    * methods are called to update the database.
-    *
-    * @param columnName the name of the column
-    * @param x the new column value
-    * @param scale For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types
-    *  this is the number of digits after the decimal.  For all other
-    *  types this value will be ignored.
-    * @exception SQLException if a database-access error occurs
-    */
-
-   public synchronized void updateObject(String columnName, Object x, int scale)
-                                                                     throws SQLException
-  {
-       updateObject(findColumn(columnName), x);
-   }
-
-   /**
-    * JDBC 2.0
-    *
-    * Update a column with an Object value.
-    *
-    * The updateXXX() methods are used to update column values in the
-    * current row, or the insert row.  The updateXXX() methods do not
-    * update the underlying database, instead the updateRow() or insertRow()
-    * methods are called to update the database.
-    *
-    * @param columnName the name of the column
-    * @param x the new column value
-    * @exception SQLException if a database-access error occurs
-    */
-
-   public synchronized void updateObject(String columnName, Object x) throws SQLException
-  {
-       updateObject(findColumn(columnName), x);
-   }
-
-
-
-  private int _findColumn( String columnName )
-  {
-       int i;
-
-       final int flen = fields.length;
-       for (i = 0 ; i < flen; ++i)
-    {
-           if (fields[i].getName().equalsIgnoreCase(columnName))
-      {
-               return (i + 1);
-      }
-    }
-    return -1;
-   }
-
-
-   /**
-    * Is this ResultSet updateable?
-    */
-
-   boolean isUpdateable() throws SQLException
-  {
-
-    if (updateable) return true;
-
-    if ( Driver.logDebug ) Driver.debug("checking if rs is updateable");
-
-    parseQuery();
-
-    if ( singleTable == false )
-    {
-         if ( Driver.logDebug ) Driver.debug("not a single table");
-      return false;
-    }
-
-       if ( Driver.logDebug ) Driver.debug("getting primary keys");
-
-       //
-       // Contains the primary key?
-       //
-
-       primaryKeys = new Vector();
-
-    // this is not stricty jdbc spec, but it will make things much faster if used
-    // the user has to select oid, * from table and then we will just use oid
-
-
-    usingOID = false;
-    int oidIndex = _findColumn( "oid" );
-    int i = 0;
-
-
-    // if we find the oid then just use it
-
-    if ( oidIndex > 0 )
-    {
-      i++;
-      primaryKeys.add( new PrimaryKey( oidIndex, "oid" ) );
-      usingOID = true;
-    }
-    else
-    {
-      // otherwise go and get the primary keys and create a hashtable of keys
-      java.sql.ResultSet rs  = ((java.sql.Connection)connection).getMetaData().getPrimaryKeys("","",tableName);
-
-
-      for( ; rs.next(); i++ )
-      {
-        String columnName = rs.getString(4);    // get the columnName
-
-        int index = findColumn( columnName );
-
-        if ( index > 0 )
-        {
-          primaryKeys.add( new PrimaryKey(index, columnName ) ); // get the primary key information
-        }
-      }
-
-      rs.close();
-    }
-
-    numKeys = primaryKeys.size();
-
-    if ( Driver.logDebug ) Driver.debug( "no of keys=" + i );
-
-    if ( i < 1 )
-    {
-           throw new SQLException("No Primary Keys");
-       }
-
-       updateable = primaryKeys.size() > 0;
-
-       if ( Driver.logDebug ) Driver.debug( "checking primary key " + updateable );
-
-       return updateable;
-   }
-
-
-  /**
-   *
-   */
-   public void parseQuery()
-  {
-       StringTokenizer st=new StringTokenizer(sqlQuery," \r\t");
-       boolean tableFound=false, tablesChecked = false;
-       String name="";
-
-    singleTable = true;
-
-    while ( !tableFound && !tablesChecked && st.hasMoreTokens() )
-    {
-           name=st.nextToken();
-      if ( !tableFound )
-      {
-        if (name.toLowerCase().equals("from"))
-        {
-          tableName=st.nextToken();
-          tableFound=true;
-        }
-      }
-      else
-      {
-        tablesChecked = true;
-        // if the very next token is , then there are multiple tables
-        singleTable =  !name.equalsIgnoreCase(",");
-      }
-       }
-   }
-
-
-  private void updateRowBuffer() throws SQLException
-  {
-
-    Enumeration columns = updateValues.keys();
-
-    while( columns.hasMoreElements() )
-    {
-      String columnName = (String)columns.nextElement();
-      int columnIndex = _findColumn( columnName ) - 1;
-
-      switch ( connection.getSQLType( fields[columnIndex].getPGType() ) )
-      {
-
-        case Types.DECIMAL:
-        case Types.BIGINT:
-        case Types.DOUBLE:
-        case Types.BIT:
-        case Types.VARCHAR:
-        case Types.DATE:
-        case Types.TIME:
-        case Types.TIMESTAMP:
-        case Types.SMALLINT:
-        case Types.FLOAT:
-        case Types.INTEGER:
-        case Types.CHAR:
-        case Types.NUMERIC:
-        case Types.REAL:
-        case Types.TINYINT:
-
-          try
-          {
-            rowBuffer[columnIndex] = String.valueOf( updateValues.get( columnName ) ).getBytes(connection.getEncoding().name() );
-          }
-          catch ( UnsupportedEncodingException ex)
-          {
-            throw new SQLException("Unsupported Encoding "+connection.getEncoding().name());
-          }
-        case Types.NULL:
-          continue;
-        default:
-          rowBuffer[columnIndex] = (byte [])updateValues.get( columnName );
-      }
-
-    }
-  }
-
-}
-