Second phase of restructuring to add jdbc3 support.
authorBarry Lind
Wed, 24 Jul 2002 22:08:45 +0000 (22:08 +0000)
committerBarry Lind
Wed, 24 Jul 2002 22:08:45 +0000 (22:08 +0000)
13 files changed:
src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java
src/interfaces/jdbc/org/postgresql/jdbc1/CallableStatement.java
src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1Connection.java
src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1PreparedStatement.java [new file with mode: 0644]
src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1Statement.java
src/interfaces/jdbc/org/postgresql/jdbc1/PreparedStatement.java [deleted file]
src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java
src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2Statement.java
src/interfaces/jdbc/org/postgresql/jdbc2/CallableStatement.java
src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Connection.java
src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2PreparedStatement.java [new file with mode: 0644]
src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Statement.java
src/interfaces/jdbc/org/postgresql/jdbc2/PreparedStatement.java [deleted file]

index 9c4d2b1cd9cbfe6105ad1bfac3783dbbca085192..6b06cc873e0e3bd36375a0575d1ecb58698783ec 100644 (file)
@@ -1,9 +1,14 @@
 package org.postgresql.jdbc1;
 
+import java.io.*;
+
+import java.math.BigDecimal;
 import java.sql.*;
-import org.postgresql.util.PSQLException;
+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.1 2002/07/23 03:59:55 barry Exp $
+/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.2 2002/07/24 22:08:39 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
@@ -34,6 +39,56 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
    private static final short BACKSLASH = 2;
    private static final short ESC_TIMEDATE = 3;
 
+   // Some performance caches
+   private StringBuffer sbuf = new StringBuffer();
+
+        //Used by the preparedstatement style methods
+   protected String sql;
+   protected String[] templateStrings;
+   protected String[] inStrings;
+
+
+
+   public AbstractJdbc1Statement (AbstractJdbc1Connection connection)
+   {
+       this.connection = connection;
+   }
+
+   public AbstractJdbc1Statement (AbstractJdbc1Connection connection, String sql) throws SQLException
+   {
+       this.sql = sql;
+       this.connection = connection;
+                parseSqlStmt();  // this allows Callable stmt to override
+   }
+
+   protected void parseSqlStmt () throws SQLException {
+       Vector v = new Vector();
+       boolean inQuotes = false;
+       int lastParmEnd = 0, i;
+
+       for (i = 0; i < sql.length(); ++i)
+       {
+           int c = sql.charAt(i);
+
+           if (c == '\'')
+               inQuotes = !inQuotes;
+           if (c == '?' && !inQuotes)
+           {
+               v.addElement(sql.substring (lastParmEnd, i));
+               lastParmEnd = i + 1;
+           }
+       }
+       v.addElement(sql.substring (lastParmEnd, sql.length()));
+
+       templateStrings = new String[v.size()];
+       inStrings = new String[v.size() - 1];
+       clearParameters();
+
+       for (i = 0 ; i < templateStrings.length; ++i)
+           templateStrings[i] = (String)v.elementAt(i);
+   }
+
+
    /*
     * Execute a SQL statement that retruns a single ResultSet
     *
@@ -51,6 +106,18 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
        return result;
    }
 
+   /*
+    * A Prepared SQL query is executed and its ResultSet is returned
+    *
+    * @return a ResultSet that contains the data produced by the
+    *       *  query - never null
+    * @exception SQLException if a database access error occurs
+    */
+   public java.sql.ResultSet executeQuery() throws SQLException
+   {
+       return executeQuery(compileQuery());
+   }
+
    /*
     * Execute a SQL INSERT, UPDATE or DELETE statement.  In addition
     * SQL statements that return nothing such as SQL DDL statements
@@ -68,6 +135,20 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
        return this.getUpdateCount();
    }
 
+   /*
+    * Execute a SQL INSERT, UPDATE or DELETE statement.  In addition,
+    * SQL statements that return nothing such as SQL DDL statements can
+    * be executed.
+    *
+    * @return either the row count for INSERT, UPDATE or DELETE; or
+    *       *  0 for SQL statements that return nothing.
+    * @exception SQLException if a database access error occurs
+    */
+   public int executeUpdate() throws SQLException
+   {
+       return executeUpdate(compileQuery());
+   }
+
    /*
     * Execute a SQL statement that may return multiple results. We
     * don't have to worry about this since we do not support multiple
@@ -101,6 +182,20 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
        return (result != null && ((AbstractJdbc1ResultSet)result).reallyResultSet());
    }
 
+   /*
+    * Some prepared statements return multiple results; the execute method
+    * handles these complex statements as well as the simpler form of
+    * statements handled by executeQuery and executeUpdate
+    *
+    * @return true if the next result is a ResultSet; false if it is an
+    *       *  update count or there are no more results
+    * @exception SQLException if a database access error occurs
+    */
+   public boolean execute() throws SQLException
+   {
+       return execute(compileQuery());
+   }
+
    /*
     * setCursorName defines the SQL cursor name that will be used by
     * subsequent execute methods.  This name can then be used in SQL
@@ -466,6 +561,743 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
        return ((AbstractJdbc1ResultSet)result).getLastOID();
    }
 
+   /*
+    * Set a parameter to SQL NULL
+    *
+    * 

Note: You must specify the parameters SQL type (although

+    * PostgreSQL ignores it)
+    *
+    * @param parameterIndex the first parameter is 1, etc...
+    * @param sqlType the SQL type code defined in java.sql.Types
+    * @exception SQLException if a database access error occurs
+    */
+   public void setNull(int parameterIndex, int sqlType) throws SQLException
+   {
+       set(parameterIndex, "null");
+   }
+
+   /*
+    * Set a parameter to a Java boolean value.  The driver converts this
+    * to a SQL BIT value when it sends it to the database.
+    *
+    * @param parameterIndex the first parameter is 1...
+    * @param x the parameter value
+    * @exception SQLException if a database access error occurs
+    */
+   public void setBoolean(int parameterIndex, boolean x) throws SQLException
+   {
+       set(parameterIndex, x ? "'t'" : "'f'");
+   }
+
+   /*
+    * Set a parameter to a Java byte value.  The driver converts this to
+    * a SQL TINYINT value when it sends it to the database.
+    *
+    * @param parameterIndex the first parameter is 1...
+    * @param x the parameter value
+    * @exception SQLException if a database access error occurs
+    */
+   public void setByte(int parameterIndex, byte x) throws SQLException
+   {
+       set(parameterIndex, Integer.toString(x));
+   }
+
+   /*
+    * Set a parameter to a Java short value.  The driver converts this
+    * to a SQL SMALLINT value when it sends it to the database.
+    *
+    * @param parameterIndex the first parameter is 1...
+    * @param x the parameter value
+    * @exception SQLException if a database access error occurs
+    */
+   public void setShort(int parameterIndex, short x) throws SQLException
+   {
+       set(parameterIndex, Integer.toString(x));
+   }
+
+   /*
+    * Set a parameter to a Java int value.  The driver converts this to
+    * a SQL INTEGER value when it sends it to the database.
+    *
+    * @param parameterIndex the first parameter is 1...
+    * @param x the parameter value
+    * @exception SQLException if a database access error occurs
+    */
+   public void setInt(int parameterIndex, int x) throws SQLException
+   {
+       set(parameterIndex, Integer.toString(x));
+   }
+
+   /*
+    * Set a parameter to a Java long value.  The driver converts this to
+    * a SQL BIGINT value when it sends it to the database.
+    *
+    * @param parameterIndex the first parameter is 1...
+    * @param x the parameter value
+    * @exception SQLException if a database access error occurs
+    */
+   public void setLong(int parameterIndex, long x) throws SQLException
+   {
+       set(parameterIndex, Long.toString(x));
+   }
+
+   /*
+    * Set a parameter to a Java float value.  The driver converts this
+    * to a SQL FLOAT value when it sends it to the database.
+    *
+    * @param parameterIndex the first parameter is 1...
+    * @param x the parameter value
+    * @exception SQLException if a database access error occurs
+    */
+   public void setFloat(int parameterIndex, float x) throws SQLException
+   {
+       set(parameterIndex, Float.toString(x));
+   }
+
+   /*
+    * Set a parameter to a Java double value.  The driver converts this
+    * to a SQL DOUBLE value when it sends it to the database
+    *
+    * @param parameterIndex the first parameter is 1...
+    * @param x the parameter value
+    * @exception SQLException if a database access error occurs
+    */
+   public void setDouble(int parameterIndex, double x) throws SQLException
+   {
+       set(parameterIndex, Double.toString(x));
+   }
+
+   /*
+    * Set a parameter to a java.lang.BigDecimal value.  The driver
+    * converts this to a SQL NUMERIC value when it sends it to the
+    * database.
+    *
+    * @param parameterIndex the first parameter is 1...
+    * @param x the parameter value
+    * @exception SQLException if a database access error occurs
+    */
+   public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException
+   {
+       if (x == null)
+           setNull(parameterIndex, Types.OTHER);
+       else
+       {
+           set(parameterIndex, x.toString());
+       }
+   }
+
+   /*
+    * Set a parameter to a Java String value.  The driver converts this
+    * to a SQL VARCHAR or LONGVARCHAR value (depending on the arguments
+    * size relative to the driver's limits on VARCHARs) when it sends it
+    * to the database.
+    *
+    * @param parameterIndex the first parameter is 1...
+    * @param x the parameter value
+    * @exception SQLException if a database access error occurs
+    */
+   public void setString(int parameterIndex, String x) throws SQLException
+   {
+       // if the passed string is null, then set this column to null
+       if (x == null)
+           setNull(parameterIndex, Types.OTHER);
+       else
+       {
+           // use the shared buffer object. Should never clash but this makes
+           // us thread safe!
+           synchronized (sbuf)
+           {
+               sbuf.setLength(0);
+               int i;
+
+               sbuf.append('\'');
+               for (i = 0 ; i < x.length() ; ++i)
+               {
+                   char c = x.charAt(i);
+                   if (c == '\\' || c == '\'')
+                       sbuf.append((char)'\\');
+                   sbuf.append(c);
+               }
+               sbuf.append('\'');
+               set(parameterIndex, sbuf.toString());
+           }
+       }
+   }
+
+   /*
+    * Set a parameter to a Java array of bytes.  The driver converts this
+    * to a SQL VARBINARY or LONGVARBINARY (depending on the argument's
+    * size relative to the driver's limits on VARBINARYs) when it sends
+    * it to the database.
+    *
+    * 

Implementation note:

+    * 
With org.postgresql, this creates a large object, and stores the
+    * objects oid in this column.
+    *
+    * @param parameterIndex the first parameter is 1...
+    * @param x the parameter value
+    * @exception SQLException if a database access error occurs
+    */
+   public void setBytes(int parameterIndex, byte x[]) throws SQLException
+   {
+       if (connection.haveMinimumCompatibleVersion("7.2"))
+       {
+           //Version 7.2 supports the bytea datatype for byte arrays
+           if (null == x)
+           {
+               setNull(parameterIndex, Types.OTHER);
+           }
+           else
+           {
+               setString(parameterIndex, PGbytea.toPGString(x));
+           }
+       }
+       else
+       {
+           //Version 7.1 and earlier support done as LargeObjects
+           LargeObjectManager lom = connection.getLargeObjectAPI();
+           int oid = lom.create();
+           LargeObject lob = lom.open(oid);
+           lob.write(x);
+           lob.close();
+           setInt(parameterIndex, oid);
+       }
+   }
+
+   /*
+    * Set a parameter to a java.sql.Date value.  The driver converts this
+    * to a SQL DATE value when it sends it to the database.
+    *
+    * @param parameterIndex the first parameter is 1...
+    * @param x the parameter value
+    * @exception SQLException if a database access error occurs
+    */
+   public void setDate(int parameterIndex, java.sql.Date x) throws SQLException
+   {
+       if (null == x)
+       {
+           setNull(parameterIndex, Types.OTHER);
+       }
+       else
+       {
+           set(parameterIndex, "'" + x.toString() + "'");
+       }
+   }
+
+   /*
+    * Set a parameter to a java.sql.Time value.  The driver converts
+    * this to a SQL TIME value when it sends it to the database.
+    *
+    * @param parameterIndex the first parameter is 1...));
+    * @param x the parameter value
+    * @exception SQLException if a database access error occurs
+    */
+   public void setTime(int parameterIndex, Time x) throws SQLException
+   {
+       if (null == x)
+       {
+           setNull(parameterIndex, Types.OTHER);
+       }
+       else
+       {
+           set(parameterIndex, "'" + x.toString() + "'");
+       }
+   }
+
+   /*
+    * Set a parameter to a java.sql.Timestamp value.  The driver converts
+    * this to a SQL TIMESTAMP value when it sends it to the database.
+    *
+    * @param parameterIndex the first parameter is 1...
+    * @param x the parameter value
+    * @exception SQLException if a database access error occurs
+    */
+   public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException
+   {
+       if (null == x)
+       {
+           setNull(parameterIndex, Types.OTHER);
+       }
+       else
+           {
+           // Use the shared StringBuffer
+           synchronized (sbuf)
+           {
+               sbuf.setLength(0);
+               sbuf.append("'");
+                                //format the timestamp
+                                //we do our own formating so that we can get a format
+                                //that works with both timestamp with time zone and
+                                //timestamp without time zone datatypes.
+                                //The format is '2002-01-01 23:59:59.123456-0130'
+                                //we need to include the local time and timezone offset
+                                //so that timestamp without time zone works correctly
+                       int l_year = x.getYear() + 1900;
+                                sbuf.append(l_year);
+                                sbuf.append('-');
+                       int l_month = x.getMonth() + 1;
+                                if (l_month < 10) sbuf.append('0');
+                                sbuf.append(l_month);
+                                sbuf.append('-');
+                       int l_day = x.getDate();
+                                if (l_day < 10) sbuf.append('0');
+                                sbuf.append(l_day);
+                                sbuf.append(' ');
+                       int l_hours = x.getHours();
+                                if (l_hours < 10) sbuf.append('0');
+                                sbuf.append(l_hours);
+                                sbuf.append(':');
+                       int l_minutes = x.getMinutes();
+                                if (l_minutes < 10) sbuf.append('0');
+                                sbuf.append(l_minutes);
+                                sbuf.append(':');
+                                int l_seconds = x.getSeconds();
+                                if (l_seconds < 10) sbuf.append('0');
+                                sbuf.append(l_seconds);
+                                // Make decimal from nanos.
+                                char[] l_decimal = {'0','0','0','0','0','0','0','0','0'};
+                                char[] l_nanos = Integer.toString(x.getNanos()).toCharArray();
+                                System.arraycopy(l_nanos, 0, l_decimal, l_decimal.length - l_nanos.length, l_nanos.length);
+                                sbuf.append('.');
+                                if (connection.haveMinimumServerVersion("7.2")) {
+                                  sbuf.append(l_decimal,0,6);
+                                } else {
+                                  // Because 7.1 include bug that "hh:mm:59.999" becomes "hh:mm:60.00".
+                                  sbuf.append(l_decimal,0,2);
+                                }
+                                //add timezone offset
+                                int l_offset = -(x.getTimezoneOffset());
+                                int l_houros = l_offset/60;
+                                if (l_houros >= 0) {
+                                  sbuf.append('+');
+                                } else {
+                                  sbuf.append('-');
+                                }
+                                if (l_houros > -10 && l_houros < 10) sbuf.append('0');
+                                if (l_houros >= 0) {
+                                  sbuf.append(l_houros);
+                                } else {
+                                  sbuf.append(-l_houros);
+                                }
+                                int l_minos = l_offset - (l_houros *60);
+                                if (l_minos != 0) {
+                                  if (l_minos < 10) sbuf.append('0');
+                                  sbuf.append(l_minos);
+                                }
+               sbuf.append("'");
+               set(parameterIndex, sbuf.toString());
+           }
+
+       }
+   }
+
+   /*
+    * When a very large ASCII value is input to a LONGVARCHAR parameter,
+    * it may be more practical to send it via a java.io.InputStream.
+    * JDBC will read the data from the stream as needed, until it reaches
+    * end-of-file.  The JDBC driver will do any necessary conversion from
+    * ASCII to the database char format.
+    *
+    * 

Note: This stream object can either be a standard Java

+    * stream object or your own subclass that implements the standard
+    * interface.
+    *
+    * @param parameterIndex the first parameter is 1...
+    * @param x the parameter value
+    * @param length the number of bytes in the stream
+    * @exception SQLException if a database access error occurs
+    */
+   public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException
+   {
+       if (connection.haveMinimumCompatibleVersion("7.2"))
+       {
+           //Version 7.2 supports AsciiStream for all PG text types (char, varchar, text)
+           //As the spec/javadoc for this method indicate this is to be used for
+           //large String values (i.e. LONGVARCHAR)  PG doesn't have a separate
+           //long varchar datatype, but with toast all text datatypes are capable of
+           //handling very large values.  Thus the implementation ends up calling
+           //setString() since there is no current way to stream the value to the server
+           try
+           {
+               InputStreamReader l_inStream = new InputStreamReader(x, "ASCII");
+               char[] l_chars = new char[length];
+               int l_charsRead = l_inStream.read(l_chars, 0, length);
+               setString(parameterIndex, new String(l_chars, 0, l_charsRead));
+           }
+           catch (UnsupportedEncodingException l_uee)
+           {
+               throw new PSQLException("postgresql.unusual", l_uee);
+           }
+           catch (IOException l_ioe)
+           {
+               throw new PSQLException("postgresql.unusual", l_ioe);
+           }
+       }
+       else
+       {
+           //Version 7.1 supported only LargeObjects by treating everything
+           //as binary data
+           setBinaryStream(parameterIndex, x, length);
+       }
+   }
+
+   /*
+    * When a very large Unicode value is input to a LONGVARCHAR parameter,
+    * it may be more practical to send it via a java.io.InputStream.
+    * JDBC will read the data from the stream as needed, until it reaches
+    * end-of-file.  The JDBC driver will do any necessary conversion from
+    * UNICODE to the database char format.
+    *
+    * 

Note: This stream object can either be a standard Java

+    * stream object or your own subclass that implements the standard
+    * interface.
+    *
+    * @param parameterIndex the first parameter is 1...
+    * @param x the parameter value
+    * @exception SQLException if a database access error occurs
+    */
+   public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException
+   {
+       if (connection.haveMinimumCompatibleVersion("7.2"))
+       {
+           //Version 7.2 supports AsciiStream for all PG text types (char, varchar, text)
+           //As the spec/javadoc for this method indicate this is to be used for
+           //large String values (i.e. LONGVARCHAR)  PG doesn't have a separate
+           //long varchar datatype, but with toast all text datatypes are capable of
+           //handling very large values.  Thus the implementation ends up calling
+           //setString() since there is no current way to stream the value to the server
+           try
+           {
+               InputStreamReader l_inStream = new InputStreamReader(x, "UTF-8");
+               char[] l_chars = new char[length];
+               int l_charsRead = l_inStream.read(l_chars, 0, length);
+               setString(parameterIndex, new String(l_chars, 0, l_charsRead));
+           }
+           catch (UnsupportedEncodingException l_uee)
+           {
+               throw new PSQLException("postgresql.unusual", l_uee);
+           }
+           catch (IOException l_ioe)
+           {
+               throw new PSQLException("postgresql.unusual", l_ioe);
+           }
+       }
+       else
+       {
+           //Version 7.1 supported only LargeObjects by treating everything
+           //as binary data
+           setBinaryStream(parameterIndex, x, length);
+       }
+   }
+
+   /*
+    * When a very large binary value is input to a LONGVARBINARY parameter,
+    * it may be more practical to send it via a java.io.InputStream.
+    * JDBC will read the data from the stream as needed, until it reaches
+    * end-of-file.
+    *
+    * 

Note: This stream object can either be a standard Java

+    * stream object or your own subclass that implements the standard
+    * interface.
+    *
+    * @param parameterIndex the first parameter is 1...
+    * @param x the parameter value
+    * @exception SQLException if a database access error occurs
+    */
+   public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException
+   {
+       if (connection.haveMinimumCompatibleVersion("7.2"))
+       {
+           //Version 7.2 supports BinaryStream for for the PG bytea type
+           //As the spec/javadoc for this method indicate this is to be used for
+           //large binary values (i.e. LONGVARBINARY)  PG doesn't have a separate
+           //long binary datatype, but with toast the bytea datatype is capable of
+           //handling very large values.  Thus the implementation ends up calling
+           //setBytes() since there is no current way to stream the value to the server
+           byte[] l_bytes = new byte[length];
+           int l_bytesRead;
+           try
+           {
+               l_bytesRead = x.read(l_bytes, 0, length);
+           }
+           catch (IOException l_ioe)
+           {
+               throw new PSQLException("postgresql.unusual", l_ioe);
+           }
+           if (l_bytesRead == length)
+           {
+               setBytes(parameterIndex, l_bytes);
+           }
+           else
+           {
+               //the stream contained less data than they said
+               byte[] l_bytes2 = new byte[l_bytesRead];
+               System.arraycopy(l_bytes, 0, l_bytes2, 0, l_bytesRead);
+               setBytes(parameterIndex, l_bytes2);
+           }
+       }
+       else
+       {
+           //Version 7.1 only supported streams for LargeObjects
+           //but the jdbc spec indicates that streams should be
+           //available for LONGVARBINARY instead
+           LargeObjectManager lom = connection.getLargeObjectAPI();
+           int oid = lom.create();
+           LargeObject lob = lom.open(oid);
+           OutputStream los = lob.getOutputStream();
+           try
+           {
+               // could be buffered, but then the OutputStream returned by LargeObject
+               // is buffered internally anyhow, so there would be no performance
+               // boost gained, if anything it would be worse!
+               int c = x.read();
+               int p = 0;
+               while (c > -1 && p < length)
+               {
+                   los.write(c);
+                   c = x.read();
+                   p++;
+               }
+               los.close();
+           }
+           catch (IOException se)
+           {
+               throw new PSQLException("postgresql.unusual", se);
+           }
+           // lob is closed by the stream so don't call lob.close()
+           setInt(parameterIndex, oid);
+       }
+   }
+
+
+   /*
+    * In general, parameter values remain in force for repeated used of a
+    * Statement.  Setting a parameter value automatically clears its
+    * previous value.  However, in coms cases, it is useful to immediately
+    * release the resources used by the current parameter values; this
+    * can be done by calling clearParameters
+    *
+    * @exception SQLException if a database access error occurs
+    */
+   public void clearParameters() throws SQLException
+   {
+       int i;
+
+       for (i = 0 ; i < inStrings.length ; i++)
+           inStrings[i] = null;
+   }
+
+   /*
+    * Set the value of a parameter using an object; use the java.lang
+    * equivalent objects for integral values.
+    *
+    * 

The given Java object will be converted to the targetSqlType before

+    * being sent to the database.
+    *
+    * 

note that this method may be used to pass database-specific

+    * abstract data types.  This is done by using a Driver-specific
+    * Java type and using a targetSqlType of java.sql.Types.OTHER
+    *
+    * @param parameterIndex the first parameter is 1...
+    * @param x the object containing the input parameter value
+    * @param targetSqlType The SQL type to be send to the database
+    * @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 void setObject(int parameterIndex, Object x, int targetSqlType, int scale) throws SQLException
+   {
+       if (x == null)
+       {
+           setNull(parameterIndex, Types.OTHER);
+           return;
+       }
+       switch (targetSqlType)
+       {
+           case Types.TINYINT:
+           case Types.SMALLINT:
+           case Types.INTEGER:
+           case Types.BIGINT:
+           case Types.REAL:
+           case Types.FLOAT:
+           case Types.DOUBLE:
+           case Types.DECIMAL:
+           case Types.NUMERIC:
+               if (x instanceof Boolean)
+                   set(parameterIndex, ((Boolean)x).booleanValue() ? "1" : "0");
+               else
+                   set(parameterIndex, x.toString());
+               break;
+           case Types.CHAR:
+           case Types.VARCHAR:
+           case Types.LONGVARCHAR:
+               setString(parameterIndex, x.toString());
+               break;
+           case Types.DATE:
+               setDate(parameterIndex, (java.sql.Date)x);
+               break;
+           case Types.TIME:
+               setTime(parameterIndex, (Time)x);
+               break;
+           case Types.TIMESTAMP:
+               setTimestamp(parameterIndex, (Timestamp)x);
+               break;
+           case Types.BIT:
+               if (x instanceof Boolean)
+               {
+                   set(parameterIndex, ((Boolean)x).booleanValue() ? "TRUE" : "FALSE");
+               }
+               else
+               {
+                   throw new PSQLException("postgresql.prep.type");
+               }
+               break;
+           case Types.BINARY:
+           case Types.VARBINARY:
+               setObject(parameterIndex, x);
+               break;
+           case Types.OTHER:
+               setString(parameterIndex, ((PGobject)x).getValue());
+               break;
+           default:
+               throw new PSQLException("postgresql.prep.type");
+       }
+   }
+
+   public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException
+   {
+       setObject(parameterIndex, x, targetSqlType, 0);
+   }
+
+   /*
+    * This stores an Object into a parameter.
+    * 

New for 6.4, if the object is not recognised, but it is

+    * Serializable, then the object is serialised using the
+    * org.postgresql.util.Serialize class.
+    */
+   public void setObject(int parameterIndex, Object x) throws SQLException
+   {
+       if (x == null)
+       {
+           setNull(parameterIndex, Types.OTHER);
+           return;
+       }
+       if (x instanceof String)
+           setString(parameterIndex, (String)x);
+       else if (x instanceof BigDecimal)
+           setBigDecimal(parameterIndex, (BigDecimal)x);
+       else if (x instanceof Short)
+           setShort(parameterIndex, ((Short)x).shortValue());
+       else if (x instanceof Integer)
+           setInt(parameterIndex, ((Integer)x).intValue());
+       else if (x instanceof Long)
+           setLong(parameterIndex, ((Long)x).longValue());
+       else if (x instanceof Float)
+           setFloat(parameterIndex, ((Float)x).floatValue());
+       else if (x instanceof Double)
+           setDouble(parameterIndex, ((Double)x).doubleValue());
+       else if (x instanceof byte[])
+           setBytes(parameterIndex, (byte[])x);
+       else if (x instanceof java.sql.Date)
+           setDate(parameterIndex, (java.sql.Date)x);
+       else if (x instanceof Time)
+           setTime(parameterIndex, (Time)x);
+       else if (x instanceof Timestamp)
+           setTimestamp(parameterIndex, (Timestamp)x);
+       else if (x instanceof Boolean)
+           setBoolean(parameterIndex, ((Boolean)x).booleanValue());
+       else if (x instanceof PGobject)
+           setString(parameterIndex, ((PGobject)x).getValue());
+       else
+           // Try to store java object in database
+           setSerialize(parameterIndex, connection.storeObject(x), x.getClass().getName() );
+   }
+
+   /*
+    * Returns the SQL statement with the current template values
+    * substituted.
+           * NB: This is identical to compileQuery() except instead of throwing
+           * SQLException if a parameter is null, it places ? instead.
+    */
+   public String toString()
+   {
+       synchronized (sbuf)
+       {
+           sbuf.setLength(0);
+           int i;
+
+           for (i = 0 ; i < inStrings.length ; ++i)
+           {
+               if (inStrings[i] == null)
+                   sbuf.append( '?' );
+               else
+                   sbuf.append (templateStrings[i]);
+               sbuf.append (inStrings[i]);
+           }
+           sbuf.append(templateStrings[inStrings.length]);
+           return sbuf.toString();
+       }
+   }
+
+   /*
+    * There are a lot of setXXX classes which all basically do
+    * the same thing.  We need a method which actually does the
+    * set for us.
+    *
+    * @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 || paramIndex > inStrings.length)
+           throw new PSQLException("postgresql.prep.range");
+       inStrings[paramIndex - 1] = s;
+   }
+
+   /*
+    * 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
+   {
+       sbuf.setLength(0);
+       int i;
+
+       for (i = 0 ; i < inStrings.length ; ++i)
+       {
+           if (inStrings[i] == null)
+               throw new PSQLException("postgresql.prep.param", new Integer(i + 1));
+           sbuf.append (templateStrings[i]).append (inStrings[i]);
+       }
+       sbuf.append(templateStrings[inStrings.length]);
+       return sbuf.toString();
+   }
+
+   /*
+    * Set a parameter to a tablerow-type oid reference.
+    *
+    * @param parameterIndex the first parameter is 1...
+    * @param x the oid of the object from org.postgresql.util.Serialize.store
+    * @param classname the classname of the java object x
+    * @exception SQLException if a database access error occurs
+    */
+   private void setSerialize(int parameterIndex, long x, String classname) throws SQLException
+   {
+       // converts . to _, toLowerCase, and ensures length<32
+       String tablename = Serialize.toPostgreSQL( classname );
+       DriverManager.println("setSerialize: setting " + x + "::" + tablename );
+
+       // OID reference to tablerow-type must be cast like:  ::
+       // Note that postgres support for tablerow data types is incomplete/broken.
+       // This cannot be just a plain OID because then there would be ambiguity
+       // between when you want the oid itself and when you want the object
+       // an oid references.
+       set(parameterIndex, Long.toString(x) + "::" + tablename );
+   }
 
 
 }
index 10e8c5f4171db2f1f73b8494d0b8f344abe95dfa..dab157f97b624a6dcc3fa59ad329b17b8b3ece79 100644 (file)
@@ -39,7 +39,7 @@ import java.math.*;
  * @see ResultSet
  */
 
-public class CallableStatement extends PreparedStatement implements java.sql.CallableStatement
+public class CallableStatement extends Jdbc1PreparedStatement implements java.sql.CallableStatement
 {
    /*
     * @exception SQLException on failure
index 55e527bd4908c6c6d033978c3e9f64efffcf6078..249a41049b6ed2c3f86e043da65fbbf18cb9fa5c 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.1 2002/07/23 03:59:55 barry Exp $
+/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/Jdbc1Connection.java,v 1.2 2002/07/24 22:08:40 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
@@ -21,7 +21,7 @@ public class Jdbc1Connection extends org.postgresql.jdbc1.AbstractJdbc1Connectio
 
    public java.sql.PreparedStatement prepareStatement(String sql) throws SQLException
    {
-       return new org.postgresql.jdbc1.PreparedStatement(this, sql);
+       return new org.postgresql.jdbc1.Jdbc1PreparedStatement(this, sql);
    }
 
 //BJL TODO - merge callable statement logic from jdbc2 to jdbc1
diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1PreparedStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1PreparedStatement.java
new file mode 100644 (file)
index 0000000..b065b57
--- /dev/null
@@ -0,0 +1,14 @@
+package org.postgresql.jdbc1;
+
+
+import java.sql.*;
+
+public class Jdbc1PreparedStatement extends AbstractJdbc1Statement implements PreparedStatement
+{
+
+   public Jdbc1PreparedStatement(Jdbc1Connection connection, String sql) throws SQLException
+   {
+       super(connection, sql);
+   }
+
+}
index bb073eae99871cdfaae4186c57815a14e14efaf9..f56841b3df8a0ff24b1f30d052a12f57eb765d33 100644 (file)
@@ -3,7 +3,7 @@ package org.postgresql.jdbc1;
 
 import java.sql.*;
 
-/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/Jdbc1Statement.java,v 1.1 2002/07/23 03:59:55 barry Exp $
+/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/Jdbc1Statement.java,v 1.2 2002/07/24 22:08:40 barry Exp $
  * This class implements the java.sql.Statement interface for JDBC1.
  * However most of the implementation is really done in 
  * org.postgresql.jdbc1.AbstractJdbc1Statement
@@ -13,7 +13,7 @@ public class Jdbc1Statement extends org.postgresql.jdbc1.AbstractJdbc1Statement
 
    public Jdbc1Statement (Jdbc1Connection c)
    {
-       connection = c;
+       super(c);
    }
 
 }
diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/PreparedStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc1/PreparedStatement.java
deleted file mode 100644 (file)
index 9ef9a42..0000000
+++ /dev/null
@@ -1,843 +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.io.*;
-import java.math.*;
-import java.sql.*;
-import java.text.*;
-import java.util.*;
-import org.postgresql.largeobject.*;
-import org.postgresql.util.*;
-
-/*
- * A SQL Statement is pre-compiled and stored in a PreparedStatement object.
- * This object can then be used to efficiently execute this statement multiple
- * times.
- *
- * 

Note: The setXXX methods for setting IN parameter values must

- * specify types that are compatible with the defined SQL type of the input
- * parameter.  For instance, if the IN parameter has SQL type Integer, then
- * setInt should be used.
- *
- * 

If arbitrary parameter type conversions are required, then the setObject

- * method should be used with a target SQL type.
- *
- * @see ResultSet
- * @see java.sql.PreparedStatement
- */
-public class PreparedStatement extends Jdbc1Statement implements java.sql.PreparedStatement
-{
-   String sql;
-   String[] templateStrings;
-   String[] inStrings;
-   Jdbc1Connection connection;
-
-   // Some performance caches
-   private StringBuffer sbuf = new StringBuffer();
-
-   /*
-    * Constructor for the PreparedStatement class.
-    * Split the SQL statement into segments - separated by the arguments.
-    * When we rebuild the thing with the arguments, we can substitute the
-    * args and join the whole thing together.
-    *
-    * @param conn the instanatiating connection
-    * @param sql the SQL statement with ? for IN markers
-    * @exception SQLException if something bad occurs
-    */
-   public PreparedStatement(Jdbc1Connection connection, String sql) throws SQLException
-   {
-       super(connection);
-
-       Vector v = new Vector();
-       boolean inQuotes = false;
-       int lastParmEnd = 0, i;
-
-       this.sql = sql;
-       this.connection = connection;
-       for (i = 0; i < sql.length(); ++i)
-       {
-           int c = sql.charAt(i);
-
-           if (c == '\'')
-               inQuotes = !inQuotes;
-           if (c == '?' && !inQuotes)
-           {
-               v.addElement(sql.substring (lastParmEnd, i));
-               lastParmEnd = i + 1;
-           }
-       }
-       v.addElement(sql.substring (lastParmEnd, sql.length()));
-
-       templateStrings = new String[v.size()];
-       inStrings = new String[v.size() - 1];
-       clearParameters();
-
-       for (i = 0 ; i < templateStrings.length; ++i)
-           templateStrings[i] = (String)v.elementAt(i);
-   }
-
-   /*
-    * A Prepared SQL query is executed and its ResultSet is returned
-    *
-    * @return a ResultSet that contains the data produced by the
-    *       *  query - never null
-    * @exception SQLException if a database access error occurs
-    */
-   public java.sql.ResultSet executeQuery() throws SQLException
-   {
-       StringBuffer s = new StringBuffer();
-       int i;
-
-       for (i = 0 ; i < inStrings.length ; ++i)
-       {
-           if (inStrings[i] == null)
-               throw new PSQLException("postgresql.prep.param", new Integer(i + 1));
-           s.append (templateStrings[i]);
-           s.append (inStrings[i]);
-       }
-       s.append(templateStrings[inStrings.length]);
-       return super.executeQuery(s.toString());    // in Statement class
-   }
-
-   /*
-    * Execute a SQL INSERT, UPDATE or DELETE statement.  In addition,
-    * SQL statements that return nothing such as SQL DDL statements can
-    * be executed.
-    *
-    * @return either the row count for INSERT, UPDATE or DELETE; or
-    *       *  0 for SQL statements that return nothing.
-    * @exception SQLException if a database access error occurs
-    */
-   public int executeUpdate() throws SQLException
-   {
-       StringBuffer s = new StringBuffer();
-       int i;
-
-       for (i = 0 ; i < inStrings.length ; ++i)
-       {
-           if (inStrings[i] == null)
-               throw new PSQLException("postgresql.prep.param", new Integer(i + 1));
-           s.append (templateStrings[i]);
-           s.append (inStrings[i]);
-       }
-       s.append(templateStrings[inStrings.length]);
-       return super.executeUpdate(s.toString());   // in Statement class
-   }
-
-   /*
-    * Set a parameter to SQL NULL
-    *
-    * 

Note: You must specify the parameters SQL type (although

-    * PostgreSQL ignores it)
-    *
-    * @param parameterIndex the first parameter is 1, etc...
-    * @param sqlType the SQL type code defined in java.sql.Types
-    * @exception SQLException if a database access error occurs
-    */
-   public void setNull(int parameterIndex, int sqlType) throws SQLException
-   {
-       set(parameterIndex, "null");
-   }
-
-   /*
-    * Set a parameter to a Java boolean value.  The driver converts this
-    * to a SQL BIT value when it sends it to the database.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setBoolean(int parameterIndex, boolean x) throws SQLException
-   {
-       set(parameterIndex, x ? "'t'" : "'f'");
-   }
-
-   /*
-    * Set a parameter to a Java byte value.  The driver converts this to
-    * a SQL TINYINT value when it sends it to the database.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setByte(int parameterIndex, byte x) throws SQLException
-   {
-       set(parameterIndex, Integer.toString(x));
-   }
-
-   /*
-    * Set a parameter to a Java short value.  The driver converts this
-    * to a SQL SMALLINT value when it sends it to the database.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setShort(int parameterIndex, short x) throws SQLException
-   {
-       set(parameterIndex, Integer.toString(x));
-   }
-
-   /*
-    * Set a parameter to a Java int value.  The driver converts this to
-    * a SQL INTEGER value when it sends it to the database.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setInt(int parameterIndex, int x) throws SQLException
-   {
-       set(parameterIndex, Integer.toString(x));
-   }
-
-   /*
-    * Set a parameter to a Java long value.  The driver converts this to
-    * a SQL BIGINT value when it sends it to the database.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setLong(int parameterIndex, long x) throws SQLException
-   {
-       set(parameterIndex, Long.toString(x));
-   }
-
-   /*
-    * Set a parameter to a Java float value.  The driver converts this
-    * to a SQL FLOAT value when it sends it to the database.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setFloat(int parameterIndex, float x) throws SQLException
-   {
-       set(parameterIndex, Float.toString(x));
-   }
-
-   /*
-    * Set a parameter to a Java double value.  The driver converts this
-    * to a SQL DOUBLE value when it sends it to the database
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setDouble(int parameterIndex, double x) throws SQLException
-   {
-       set(parameterIndex, Double.toString(x));
-   }
-
-   /*
-    * Set a parameter to a java.lang.BigDecimal value.  The driver
-    * converts this to a SQL NUMERIC value when it sends it to the
-    * database.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException
-   {
-       if (x == null)
-           setNull(parameterIndex, Types.OTHER);
-       else
-       {
-           set(parameterIndex, x.toString());
-       }
-   }
-
-   /*
-    * Set a parameter to a Java String value.  The driver converts this
-    * to a SQL VARCHAR or LONGVARCHAR value (depending on the arguments
-    * size relative to the driver's limits on VARCHARs) when it sends it
-    * to the database.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setString(int parameterIndex, String x) throws SQLException
-   {
-       // if the passed string is null, then set this column to null
-       if (x == null)
-           setNull(parameterIndex, Types.OTHER);
-       else
-       {
-           StringBuffer b = new StringBuffer();
-           int i;
-
-           b.append('\'');
-           for (i = 0 ; i < x.length() ; ++i)
-           {
-               char c = x.charAt(i);
-               if (c == '\\' || c == '\'')
-                   b.append((char)'\\');
-               b.append(c);
-           }
-           b.append('\'');
-           set(parameterIndex, b.toString());
-       }
-   }
-
-   /*
-    * Set a parameter to a Java array of bytes.  The driver converts this
-    * to a SQL VARBINARY or LONGVARBINARY (depending on the argument's
-    * size relative to the driver's limits on VARBINARYs) when it sends
-    * it to the database.
-    *
-    * 

Implementation note:

-    * 
With org.postgresql, this creates a large object, and stores the
-    * objects oid in this column.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setBytes(int parameterIndex, byte x[]) throws SQLException
-   {
-       if (connection.haveMinimumCompatibleVersion("7.2"))
-       {
-           //Version 7.2 supports the bytea datatype for byte arrays
-           if (null == x)
-           {
-               setNull(parameterIndex, Types.OTHER);
-           }
-           else
-           {
-               setString(parameterIndex, PGbytea.toPGString(x));
-           }
-       }
-       else
-       {
-           //Version 7.1 and earlier support done as LargeObjects
-           LargeObjectManager lom = connection.getLargeObjectAPI();
-           int oid = lom.create();
-           LargeObject lob = lom.open(oid);
-           lob.write(x);
-           lob.close();
-           setInt(parameterIndex, oid);
-       }
-   }
-
-   /*
-    * Set a parameter to a java.sql.Date value.  The driver converts this
-    * to a SQL DATE value when it sends it to the database.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setDate(int parameterIndex, java.sql.Date x) throws SQLException
-   {
-       if (null == x)
-       {
-           setNull(parameterIndex, Types.OTHER);
-       }
-       else
-       {
-           set(parameterIndex, "'" + x.toString() + "'");
-       }
-   }
-
-   /*
-    * Set a parameter to a java.sql.Time value.  The driver converts
-    * this to a SQL TIME value when it sends it to the database.
-    *
-    * @param parameterIndex the first parameter is 1...));
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setTime(int parameterIndex, Time x) throws SQLException
-   {
-       if (null == x)
-       {
-           setNull(parameterIndex, Types.OTHER);
-       }
-       else
-       {
-           set(parameterIndex, "'" + x.toString() + "'");
-       }
-   }
-
-   /*
-    * Set a parameter to a java.sql.Timestamp value.  The driver converts
-    * this to a SQL TIMESTAMP value when it sends it to the database.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException
-   {
-       if (null == x)
-       {
-           setNull(parameterIndex, Types.OTHER);
-       }
-       else
-           {
-           // Use the shared StringBuffer
-           synchronized (sbuf)
-           {
-               sbuf.setLength(0);
-               sbuf.append("'");
-                                //format the timestamp
-                                //we do our own formating so that we can get a format
-                                //that works with both timestamp with time zone and
-                                //timestamp without time zone datatypes.
-                                //The format is '2002-01-01 23:59:59.123456-0130'
-                                //we need to include the local time and timezone offset
-                                //so that timestamp without time zone works correctly
-                       int l_year = x.getYear() + 1900;
-                                sbuf.append(l_year);
-                                sbuf.append('-');
-                       int l_month = x.getMonth() + 1;
-                                if (l_month < 10) sbuf.append('0');
-                                sbuf.append(l_month);
-                                sbuf.append('-');
-                       int l_day = x.getDate();
-                                if (l_day < 10) sbuf.append('0');
-                                sbuf.append(l_day);
-                                sbuf.append(' ');
-                       int l_hours = x.getHours();
-                                if (l_hours < 10) sbuf.append('0');
-                                sbuf.append(l_hours);
-                                sbuf.append(':');
-                       int l_minutes = x.getMinutes();
-                                if (l_minutes < 10) sbuf.append('0');
-                                sbuf.append(l_minutes);
-                                sbuf.append(':');
-                                int l_seconds = x.getSeconds();
-                                if (l_seconds < 10) sbuf.append('0');
-                                sbuf.append(l_seconds);
-                                // Make decimal from nanos.
-                                char[] l_decimal = {'0','0','0','0','0','0','0','0','0'};
-                                char[] l_nanos = Integer.toString(x.getNanos()).toCharArray();
-                                System.arraycopy(l_nanos, 0, l_decimal, l_decimal.length - l_nanos.length, l_nanos.length);
-                                sbuf.append('.');
-                                if (connection.haveMinimumServerVersion("7.2")) {
-                                  sbuf.append(l_decimal,0,6);
-                                } else {
-                                  // Because 7.1 include bug that "hh:mm:59.999" becomes "hh:mm:60.00".
-                                  sbuf.append(l_decimal,0,2);
-                                }
-                                //add timezone offset
-                                int l_offset = -(x.getTimezoneOffset());
-                                int l_houros = l_offset/60;
-                                if (l_houros >= 0) {
-                                  sbuf.append('+');
-                                } else {
-                                  sbuf.append('-');
-                                }
-                                if (l_houros > -10 && l_houros < 10) sbuf.append('0');
-                                if (l_houros >= 0) {
-                                  sbuf.append(l_houros);
-                                } else {
-                                  sbuf.append(-l_houros);
-                                }
-                                int l_minos = l_offset - (l_houros *60);
-                                if (l_minos != 0) {
-                                  if (l_minos < 10) sbuf.append('0');
-                                  sbuf.append(l_minos);
-                                }
-               sbuf.append("'");
-               set(parameterIndex, sbuf.toString());
-           }
-
-       }
-   }
-
-   /*
-    * When a very large ASCII value is input to a LONGVARCHAR parameter,
-    * it may be more practical to send it via a java.io.InputStream.
-    * JDBC will read the data from the stream as needed, until it reaches
-    * end-of-file.  The JDBC driver will do any necessary conversion from
-    * ASCII to the database char format.
-    *
-    * 

Note: This stream object can either be a standard Java

-    * stream object or your own subclass that implements the standard
-    * interface.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @param length the number of bytes in the stream
-    * @exception SQLException if a database access error occurs
-    */
-   public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException
-   {
-       if (connection.haveMinimumCompatibleVersion("7.2"))
-       {
-           //Version 7.2 supports AsciiStream for all PG text types (char, varchar, text)
-           //As the spec/javadoc for this method indicate this is to be used for
-           //large String values (i.e. LONGVARCHAR)  PG doesn't have a separate
-           //long varchar datatype, but with toast all text datatypes are capable of
-           //handling very large values.  Thus the implementation ends up calling
-           //setString() since there is no current way to stream the value to the server
-           try
-           {
-               InputStreamReader l_inStream = new InputStreamReader(x, "ASCII");
-               char[] l_chars = new char[length];
-               int l_charsRead = l_inStream.read(l_chars, 0, length);
-               setString(parameterIndex, new String(l_chars, 0, l_charsRead));
-           }
-           catch (UnsupportedEncodingException l_uee)
-           {
-               throw new PSQLException("postgresql.unusual", l_uee);
-           }
-           catch (IOException l_ioe)
-           {
-               throw new PSQLException("postgresql.unusual", l_ioe);
-           }
-       }
-       else
-       {
-           //Version 7.1 supported only LargeObjects by treating everything
-           //as binary data
-           setBinaryStream(parameterIndex, x, length);
-       }
-   }
-
-   /*
-    * When a very large Unicode value is input to a LONGVARCHAR parameter,
-    * it may be more practical to send it via a java.io.InputStream.
-    * JDBC will read the data from the stream as needed, until it reaches
-    * end-of-file.  The JDBC driver will do any necessary conversion from
-    * UNICODE to the database char format.
-    *
-    * 

Note: This stream object can either be a standard Java

-    * stream object or your own subclass that implements the standard
-    * interface.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException
-   {
-       if (connection.haveMinimumCompatibleVersion("7.2"))
-       {
-           //Version 7.2 supports AsciiStream for all PG text types (char, varchar, text)
-           //As the spec/javadoc for this method indicate this is to be used for
-           //large String values (i.e. LONGVARCHAR)  PG doesn't have a separate
-           //long varchar datatype, but with toast all text datatypes are capable of
-           //handling very large values.  Thus the implementation ends up calling
-           //setString() since there is no current way to stream the value to the server
-           try
-           {
-               InputStreamReader l_inStream = new InputStreamReader(x, "UTF-8");
-               char[] l_chars = new char[length];
-               int l_charsRead = l_inStream.read(l_chars, 0, length);
-               setString(parameterIndex, new String(l_chars, 0, l_charsRead));
-           }
-           catch (UnsupportedEncodingException l_uee)
-           {
-               throw new PSQLException("postgresql.unusual", l_uee);
-           }
-           catch (IOException l_ioe)
-           {
-               throw new PSQLException("postgresql.unusual", l_ioe);
-           }
-       }
-       else
-       {
-           //Version 7.1 supported only LargeObjects by treating everything
-           //as binary data
-           setBinaryStream(parameterIndex, x, length);
-       }
-   }
-
-   /*
-    * When a very large binary value is input to a LONGVARBINARY parameter,
-    * it may be more practical to send it via a java.io.InputStream.
-    * JDBC will read the data from the stream as needed, until it reaches
-    * end-of-file.
-    *
-    * 

Note: This stream object can either be a standard Java

-    * stream object or your own subclass that implements the standard
-    * interface.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException
-   {
-       if (connection.haveMinimumCompatibleVersion("7.2"))
-       {
-           //Version 7.2 supports BinaryStream for for the PG bytea type
-           //As the spec/javadoc for this method indicate this is to be used for
-           //large binary values (i.e. LONGVARBINARY)  PG doesn't have a separate
-           //long binary datatype, but with toast the bytea datatype is capable of
-           //handling very large values.  Thus the implementation ends up calling
-           //setBytes() since there is no current way to stream the value to the server
-           byte[] l_bytes = new byte[length];
-           int l_bytesRead;
-           try
-           {
-               l_bytesRead = x.read(l_bytes, 0, length);
-           }
-           catch (IOException l_ioe)
-           {
-               throw new PSQLException("postgresql.unusual", l_ioe);
-           }
-           if (l_bytesRead == length)
-           {
-               setBytes(parameterIndex, l_bytes);
-           }
-           else
-           {
-               //the stream contained less data than they said
-               byte[] l_bytes2 = new byte[l_bytesRead];
-               System.arraycopy(l_bytes, 0, l_bytes2, 0, l_bytesRead);
-               setBytes(parameterIndex, l_bytes2);
-           }
-       }
-       else
-       {
-           //Version 7.1 only supported streams for LargeObjects
-           //but the jdbc spec indicates that streams should be
-           //available for LONGVARBINARY instead
-           LargeObjectManager lom = connection.getLargeObjectAPI();
-           int oid = lom.create();
-           LargeObject lob = lom.open(oid);
-           OutputStream los = lob.getOutputStream();
-           try
-           {
-               // could be buffered, but then the OutputStream returned by LargeObject
-               // is buffered internally anyhow, so there would be no performance
-               // boost gained, if anything it would be worse!
-               int c = x.read();
-               int p = 0;
-               while (c > -1 && p < length)
-               {
-                   los.write(c);
-                   c = x.read();
-                   p++;
-               }
-               los.close();
-           }
-           catch (IOException se)
-           {
-               throw new PSQLException("postgresql.unusual", se);
-           }
-           // lob is closed by the stream so don't call lob.close()
-           setInt(parameterIndex, oid);
-       }
-   }
-
-   /*
-    * In general, parameter values remain in force for repeated used of a
-    * Statement.  Setting a parameter value automatically clears its
-    * previous value.  However, in coms cases, it is useful to immediately
-    * release the resources used by the current parameter values; this
-    * can be done by calling clearParameters
-    *
-    * @exception SQLException if a database access error occurs
-    */
-   public void clearParameters() throws SQLException
-   {
-       int i;
-
-       for (i = 0 ; i < inStrings.length ; i++)
-           inStrings[i] = null;
-   }
-
-   /*
-    * Set the value of a parameter using an object; use the java.lang
-    * equivalent objects for integral values.
-    *
-    * 

The given Java object will be converted to the targetSqlType before

-    * being sent to the database.
-    *
-    * 

note that this method may be used to pass database-specific

-    * abstract data types.  This is done by using a Driver-specific
-    * Java type and using a targetSqlType of java.sql.Types.OTHER
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the object containing the input parameter value
-    * @param targetSqlType The SQL type to be send to the database
-    * @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 void setObject(int parameterIndex, Object x, int targetSqlType, int scale) throws SQLException
-   {
-       if (x == null)
-       {
-           setNull(parameterIndex, Types.OTHER);
-           return;
-       }
-       switch (targetSqlType)
-       {
-           case Types.TINYINT:
-           case Types.SMALLINT:
-           case Types.INTEGER:
-           case Types.BIGINT:
-           case Types.REAL:
-           case Types.FLOAT:
-           case Types.DOUBLE:
-           case Types.DECIMAL:
-           case Types.NUMERIC:
-               if (x instanceof Boolean)
-                   set(parameterIndex, ((Boolean)x).booleanValue() ? "1" : "0");
-               else
-                   set(parameterIndex, x.toString());
-               break;
-           case Types.CHAR:
-           case Types.VARCHAR:
-           case Types.LONGVARCHAR:
-               setString(parameterIndex, x.toString());
-               break;
-           case Types.DATE:
-               setDate(parameterIndex, (java.sql.Date)x);
-               break;
-           case Types.TIME:
-               setTime(parameterIndex, (Time)x);
-               break;
-           case Types.TIMESTAMP:
-               setTimestamp(parameterIndex, (Timestamp)x);
-               break;
-           case Types.BIT:
-               if (x instanceof Boolean)
-               {
-                   set(parameterIndex, ((Boolean)x).booleanValue() ? "TRUE" : "FALSE");
-               }
-               else
-               {
-                   throw new PSQLException("postgresql.prep.type");
-               }
-               break;
-           case Types.BINARY:
-           case Types.VARBINARY:
-               setObject(parameterIndex, x);
-               break;
-           case Types.OTHER:
-               setString(parameterIndex, ((PGobject)x).getValue());
-               break;
-           default:
-               throw new PSQLException("postgresql.prep.type");
-       }
-   }
-
-   public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException
-   {
-       setObject(parameterIndex, x, targetSqlType, 0);
-   }
-
-   /*
-    * This stores an Object into a parameter.
-    * 

New for 6.4, if the object is not recognised, but it is

-    * Serializable, then the object is serialised using the
-    * org.postgresql.util.Serialize class.
-    */
-   public void setObject(int parameterIndex, Object x) throws SQLException
-   {
-       if (x == null)
-       {
-           setNull(parameterIndex, Types.OTHER);
-           return;
-       }
-       if (x instanceof String)
-           setString(parameterIndex, (String)x);
-       else if (x instanceof BigDecimal)
-           setBigDecimal(parameterIndex, (BigDecimal)x);
-       else if (x instanceof Short)
-           setShort(parameterIndex, ((Short)x).shortValue());
-       else if (x instanceof Integer)
-           setInt(parameterIndex, ((Integer)x).intValue());
-       else if (x instanceof Long)
-           setLong(parameterIndex, ((Long)x).longValue());
-       else if (x instanceof Float)
-           setFloat(parameterIndex, ((Float)x).floatValue());
-       else if (x instanceof Double)
-           setDouble(parameterIndex, ((Double)x).doubleValue());
-       else if (x instanceof byte[])
-           setBytes(parameterIndex, (byte[])x);
-       else if (x instanceof java.sql.Date)
-           setDate(parameterIndex, (java.sql.Date)x);
-       else if (x instanceof Time)
-           setTime(parameterIndex, (Time)x);
-       else if (x instanceof Timestamp)
-           setTimestamp(parameterIndex, (Timestamp)x);
-       else if (x instanceof Boolean)
-           setBoolean(parameterIndex, ((Boolean)x).booleanValue());
-       else if (x instanceof PGobject)
-           setString(parameterIndex, ((PGobject)x).getValue());
-       else
-           setLong(parameterIndex, connection.storeObject(x));
-   }
-
-   /*
-    * Some prepared statements return multiple results; the execute method
-    * handles these complex statements as well as the simpler form of
-    * statements handled by executeQuery and executeUpdate
-    *
-    * @return true if the next result is a ResultSet; false if it is an
-    *       *  update count or there are no more results
-    * @exception SQLException if a database access error occurs
-    */
-   public boolean execute() throws SQLException
-   {
-       StringBuffer s = new StringBuffer();
-       int i;
-
-       for (i = 0 ; i < inStrings.length ; ++i)
-       {
-           if (inStrings[i] == null)
-               throw new PSQLException("postgresql.prep.param", new Integer(i + 1));
-           s.append (templateStrings[i]);
-           s.append (inStrings[i]);
-       }
-       s.append(templateStrings[inStrings.length]);
-       return super.execute(s.toString());     // in Statement class
-   }
-
-   /*
-    * Returns the SQL statement with the current template values
-    * substituted.
-    */
-   public String toString()
-   {
-       StringBuffer s = new StringBuffer();
-       int i;
-
-       for (i = 0 ; i < inStrings.length ; ++i)
-       {
-           if (inStrings[i] == null)
-               s.append( '?' );
-           else
-               s.append (templateStrings[i]);
-           s.append (inStrings[i]);
-       }
-       s.append(templateStrings[inStrings.length]);
-       return s.toString();
-   }
-
-   // **************************************************************
-   //  END OF PUBLIC INTERFACE
-   // **************************************************************
-
-   /*
-    * There are a lot of setXXX classes which all basically do
-    * the same thing.  We need a method which actually does the
-    * set for us.
-    *
-    * @param paramIndex the index into the inString
-    * @param s a string to be stored
-    * @exception SQLException if something goes wrong
-    */
-   private void set(int paramIndex, String s) throws SQLException
-   {
-       if (paramIndex < 1 || paramIndex > inStrings.length)
-           throw new PSQLException("postgresql.prep.range");
-       inStrings[paramIndex - 1] = s;
-   }
-}
index 50c5d942bbf63ce71e53e46d756bf8c681b6d123..d2c5ee07607a39dd84f1fa141f0f5f77d81a54f2 100644 (file)
@@ -13,14 +13,14 @@ 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.1 2002/07/23 03:59:55 barry Exp $
+/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2ResultSet.java,v 1.2 2002/07/24 22:08:42 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 Jdbc2Statement statement;
+   protected Statement statement;
 
    protected String sqlQuery=null;
 
@@ -373,7 +373,7 @@ public class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.AbstractJdbc1Re
    }
 
    // This one needs some thought, as not all ResultSets come from a statement
-   public java.sql.Statement getStatement() throws SQLException
+   public Statement getStatement() throws SQLException
    {
        return statement;
    }
@@ -740,7 +740,7 @@ public class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.AbstractJdbc1Re
     * It's used currently by getStatement() but may also with the new core
     * package.
     */
-   public void setStatement(Jdbc2Statement statement)
+   public void setStatement(Statement statement)
    {
        this.statement = statement;
    }
index 3d6f6553ced3fea5afba83d7e4c81cbbcabf5d1d..47c2c77983153637d94df8a2c0e5f714de6fcc81 100644 (file)
@@ -1,11 +1,13 @@
 package org.postgresql.jdbc2;
 
 
+import java.io.*;
 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.1 2002/07/23 03:59:55 barry Exp $
+/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2Statement.java,v 1.2 2002/07/24 22:08:42 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
@@ -17,6 +19,18 @@ public abstract class AbstractJdbc2Statement extends org.postgresql.jdbc1.Abstra
    protected int resultsettype;         // the resultset type to return
    protected int concurrency;       // is it updateable or not?
 
+   public AbstractJdbc2Statement (AbstractJdbc2Connection c)
+   {
+       super(c);
+       resultsettype = java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE;
+       concurrency = java.sql.ResultSet.CONCUR_READ_ONLY;
+   }
+
+   public AbstractJdbc2Statement(AbstractJdbc2Connection connection, String sql) throws SQLException
+   {
+       super(connection, sql);
+   }
+
    /*
     * Execute a SQL statement that may return multiple results. We
     * don't have to worry about this since we do not support multiple
@@ -31,10 +45,9 @@ public abstract class AbstractJdbc2Statement extends org.postgresql.jdbc1.Abstra
    public boolean execute(String sql) throws SQLException
    {
            boolean l_return = super.execute(sql);
-
                 //Now do the jdbc2 specific stuff
        //required for ResultSet.getStatement() to work
-       ((AbstractJdbc2ResultSet)result).setStatement((Jdbc2Statement)this);
+       ((AbstractJdbc2ResultSet)result).setStatement((Statement)this);
 
        // Added this so that the Updateable resultset knows the query that gave this
        ((AbstractJdbc2ResultSet)result).setSQLQuery(sql);
@@ -139,4 +152,183 @@ public abstract class AbstractJdbc2Statement extends org.postgresql.jdbc1.Abstra
        resultsettype = value;
    }
 
+   public void addBatch() throws SQLException
+   {
+       addBatch(compileQuery());
+   }
+
+   public java.sql.ResultSetMetaData getMetaData() throws SQLException
+   {
+       java.sql.ResultSet rs = getResultSet();
+       if (rs != null)
+           return rs.getMetaData();
+
+       // Does anyone really know what this method does?
+       return null;
+   }
+
+   public void setArray(int i, java.sql.Array x) throws SQLException
+   {
+       setString(i, x.toString());
+   }
+
+   public void setBlob(int i, Blob x) throws SQLException
+   {
+       InputStream l_inStream = x.getBinaryStream();
+       int l_length = (int) x.length();
+       LargeObjectManager lom = connection.getLargeObjectAPI();
+       int oid = lom.create();
+       LargeObject lob = lom.open(oid);
+       OutputStream los = lob.getOutputStream();
+       try
+       {
+           // could be buffered, but then the OutputStream returned by LargeObject
+           // is buffered internally anyhow, so there would be no performance
+           // boost gained, if anything it would be worse!
+           int c = l_inStream.read();
+           int p = 0;
+           while (c > -1 && p < l_length)
+           {
+               los.write(c);
+               c = l_inStream.read();
+               p++;
+           }
+           los.close();
+       }
+       catch (IOException se)
+       {
+           throw new PSQLException("postgresql.unusual", se);
+       }
+       // lob is closed by the stream so don't call lob.close()
+       setInt(i, oid);
+   }
+
+   public void setCharacterStream(int i, java.io.Reader x, int length) throws SQLException
+   {
+       if (connection.haveMinimumCompatibleVersion("7.2"))
+       {
+           //Version 7.2 supports CharacterStream for for 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 varchar datatype, but with toast all the text datatypes are capable of
+           //handling very large values.  Thus the implementation ends up calling
+           //setString() since there is no current way to stream the value to the server
+           char[] l_chars = new char[length];
+           int l_charsRead;
+           try
+           {
+               l_charsRead = x.read(l_chars, 0, length);
+           }
+           catch (IOException l_ioe)
+           {
+               throw new PSQLException("postgresql.unusual", l_ioe);
+           }
+           setString(i, new String(l_chars, 0, l_charsRead));
+       }
+       else
+       {
+           //Version 7.1 only supported streams for LargeObjects
+           //but the jdbc spec indicates that streams should be
+           //available for LONGVARCHAR instead
+           LargeObjectManager lom = connection.getLargeObjectAPI();
+           int oid = lom.create();
+           LargeObject lob = lom.open(oid);
+           OutputStream los = lob.getOutputStream();
+           try
+           {
+               // could be buffered, but then the OutputStream returned by LargeObject
+               // is buffered internally anyhow, so there would be no performance
+               // boost gained, if anything it would be worse!
+               int c = x.read();
+               int p = 0;
+               while (c > -1 && p < length)
+               {
+                   los.write(c);
+                   c = x.read();
+                   p++;
+               }
+               los.close();
+           }
+           catch (IOException se)
+           {
+               throw new PSQLException("postgresql.unusual", se);
+           }
+           // lob is closed by the stream so don't call lob.close()
+           setInt(i, oid);
+       }
+   }
+
+   public void setClob(int i, Clob x) throws SQLException
+   {
+       InputStream l_inStream = x.getAsciiStream();
+       int l_length = (int) x.length();
+       LargeObjectManager lom = connection.getLargeObjectAPI();
+       int oid = lom.create();
+       LargeObject lob = lom.open(oid);
+       OutputStream los = lob.getOutputStream();
+       try
+       {
+           // could be buffered, but then the OutputStream returned by LargeObject
+           // is buffered internally anyhow, so there would be no performance
+           // boost gained, if anything it would be worse!
+           int c = l_inStream.read();
+           int p = 0;
+           while (c > -1 && p < l_length)
+           {
+               los.write(c);
+               c = l_inStream.read();
+               p++;
+           }
+           los.close();
+       }
+       catch (IOException se)
+       {
+           throw new PSQLException("postgresql.unusual", se);
+       }
+       // lob is closed by the stream so don't call lob.close()
+       setInt(i, oid);
+   }
+
+   public void setNull(int i, int t, String s) throws SQLException
+   {
+       setNull(i, t);
+   }
+
+   public void setRef(int i, Ref x) throws SQLException
+   {
+       throw org.postgresql.Driver.notImplemented();
+   }
+
+   public void setDate(int i, java.sql.Date d, java.util.Calendar cal) throws SQLException
+   {
+       if (cal == null)
+           setDate(i, d);
+       else
+       {
+           cal.setTime(d);
+           setDate(i, new java.sql.Date(cal.getTime().getTime()));
+       }
+   }
+
+   public void setTime(int i, Time t, java.util.Calendar cal) throws SQLException
+   {
+       if (cal == null)
+           setTime(i, t);
+       else
+       {
+           cal.setTime(t);
+           setTime(i, new java.sql.Time(cal.getTime().getTime()));
+       }
+   }
+
+   public void setTimestamp(int i, Timestamp t, java.util.Calendar cal) throws SQLException
+   {
+       if (cal == null)
+           setTimestamp(i, t);
+       else
+       {
+           cal.setTime(t);
+           setTimestamp(i, new java.sql.Timestamp(cal.getTime().getTime()));
+       }
+   }
 }
index 9d37bf04bc50c42cacc133b394cb719e3a1f6289..51dd9b2c7f0138b26f65e0eda732e2b976d51441 100644 (file)
@@ -40,7 +40,7 @@ import org.postgresql.util.*;
  * @author Paul Bethe (implementer)
  */
 
-public class CallableStatement extends org.postgresql.jdbc2.PreparedStatement implements java.sql.CallableStatement
+public class CallableStatement extends org.postgresql.jdbc2.Jdbc2PreparedStatement implements java.sql.CallableStatement
 {
    /*
     * @exception SQLException on failure
index cfbb3486ec6f6d25dc6b0ca25110bedf73a6e65e..787b14e62af6485d84fb46c398b9327521f26420 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/Jdbc2Connection.java,v 1.1 2002/07/23 03:59:55 barry Exp $
+/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/Jdbc2Connection.java,v 1.2 2002/07/24 22:08:42 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
@@ -24,7 +24,7 @@ public class Jdbc2Connection extends org.postgresql.jdbc2.AbstractJdbc2Connectio
 
         public java.sql.PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
         {
-                org.postgresql.jdbc2.PreparedStatement s = new org.postgresql.jdbc2.PreparedStatement(this, sql);
+                Jdbc2PreparedStatement s = new Jdbc2PreparedStatement(this, sql);
                 s.setResultSetType(resultSetType);
                 s.setResultSetConcurrency(resultSetConcurrency);
                 return s;
diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2PreparedStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2PreparedStatement.java
new file mode 100644 (file)
index 0000000..0472007
--- /dev/null
@@ -0,0 +1,15 @@
+package org.postgresql.jdbc2;
+
+
+import java.sql.*;
+
+public class Jdbc2PreparedStatement extends AbstractJdbc2Statement implements java.sql.PreparedStatement
+{
+
+   public Jdbc2PreparedStatement(Jdbc2Connection connection, String sql) throws SQLException
+   {
+       super(connection, sql);
+   }
+
+}
+
index 31cec93821a4f8dde7b01b811a3d584c5e579246..4f63d10c14f485caa190501568b4812dcd533ca3 100644 (file)
@@ -3,7 +3,7 @@ package org.postgresql.jdbc2;
 
 import java.sql.*;
 
-/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/Jdbc2Statement.java,v 1.1 2002/07/23 03:59:55 barry Exp $
+/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/Jdbc2Statement.java,v 1.2 2002/07/24 22:08:43 barry Exp $
  * This class implements the java.sql.Statement interface for JDBC2.
  * However most of the implementation is really done in 
  * org.postgresql.jdbc2.AbstractJdbc2Statement or one of it's parents
@@ -13,9 +13,7 @@ public class Jdbc2Statement extends org.postgresql.jdbc2.AbstractJdbc2Statement
 
    public Jdbc2Statement (Jdbc2Connection c)
    {
-       connection = c;
-       resultsettype = java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE;
-       concurrency = java.sql.ResultSet.CONCUR_READ_ONLY;
+       super(c);
    }
 
 }
diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/PreparedStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc2/PreparedStatement.java
deleted file mode 100644 (file)
index 21aba8d..0000000
+++ /dev/null
@@ -1,1086 +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.io.*;
-import java.math.*;
-import java.sql.*;
-import java.text.*;
-import java.util.*;
-import org.postgresql.largeobject.*;
-import org.postgresql.util.*;
-
-/*
- * A SQL Statement is pre-compiled and stored in a PreparedStatement object.
- * This object can then be used to efficiently execute this statement multiple
- * times.
- *
- * 

Note: The setXXX methods for setting IN parameter values must

- * specify types that are compatible with the defined SQL type of the input
- * parameter.  For instance, if the IN parameter has SQL type Integer, then
- * setInt should be used.
- *
- * 

If arbitrary parameter type conversions are required, then the setObject

- * method should be used with a target SQL type.
- *
- * @see ResultSet
- * @see java.sql.PreparedStatement
- */
-public class PreparedStatement extends Jdbc2Statement implements java.sql.PreparedStatement
-{
-   String sql;
-   String[] templateStrings;
-   String[] inStrings;
-   Jdbc2Connection connection;
-
-   // Some performance caches
-   private StringBuffer sbuf = new StringBuffer();
-
-   /*
-    * Constructor for the PreparedStatement class.
-    * Split the SQL statement into segments - separated by the arguments.
-    * When we rebuild the thing with the arguments, we can substitute the
-    * args and join the whole thing together.
-    *
-    * @param conn the instanatiating connection
-    * @param sql the SQL statement with ? for IN markers
-    * @exception SQLException if something bad occurs
-    */
-   public PreparedStatement(Jdbc2Connection connection, String sql) throws SQLException
-   {
-       super(connection);
-
-       this.sql = sql;
-       this.connection = connection;
-       parseSqlStmt (); // this allows Callable stmt to override
-   }
-
-   protected void parseSqlStmt () throws SQLException {
-       Vector v = new Vector();
-       boolean inQuotes = false;
-       int lastParmEnd = 0, i;
-
-       for (i = 0; i < sql.length(); ++i)
-       {
-           int c = sql.charAt(i);
-
-           if (c == '\'')
-               inQuotes = !inQuotes;
-           if (c == '?' && !inQuotes)
-           {
-               v.addElement(sql.substring (lastParmEnd, i));
-               lastParmEnd = i + 1;
-           }
-       }
-       v.addElement(sql.substring (lastParmEnd, sql.length()));
-
-       templateStrings = new String[v.size()];
-       inStrings = new String[v.size() - 1];
-       clearParameters();
-
-       for (i = 0 ; i < templateStrings.length; ++i)
-           templateStrings[i] = (String)v.elementAt(i);
-   }
-
-   /*
-    * A Prepared SQL query is executed and its ResultSet is returned
-    *
-    * @return a ResultSet that contains the data produced by the
-           *             *         query - never null
-    * @exception SQLException if a database access error occurs
-    */
-   public java.sql.ResultSet executeQuery() throws SQLException
-   {
-       return super.executeQuery(compileQuery());  // in Statement class
-   }
-
-   /*
-    * Execute a SQL INSERT, UPDATE or DELETE statement.  In addition,
-    * SQL statements that return nothing such as SQL DDL statements can
-    * be executed.
-    *
-    * @return either the row count for INSERT, UPDATE or DELETE; or
-           *             *         0 for SQL statements that return nothing.
-    * @exception SQLException if a database access error occurs
-    */
-   public int executeUpdate() throws SQLException
-   {
-       return super.executeUpdate(compileQuery());     // in Statement class
-   }
-
-   /*
-    * 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
-   {
-       sbuf.setLength(0);
-       int i;
-
-       for (i = 0 ; i < inStrings.length ; ++i)
-       {
-           if (inStrings[i] == null)
-               throw new PSQLException("postgresql.prep.param", new Integer(i + 1));
-           sbuf.append (templateStrings[i]).append (inStrings[i]);
-       }
-       sbuf.append(templateStrings[inStrings.length]);
-       return sbuf.toString();
-   }
-
-   /*
-    * Set a parameter to SQL NULL
-    *
-    * 

Note: You must specify the parameters SQL type (although

-    * PostgreSQL ignores it)
-    *
-    * @param parameterIndex the first parameter is 1, etc...
-    * @param sqlType the SQL type code defined in java.sql.Types
-    * @exception SQLException if a database access error occurs
-    */
-   public void setNull(int parameterIndex, int sqlType) throws SQLException
-   {
-       set(parameterIndex, "null");
-   }
-
-   /*
-    * Set a parameter to a Java boolean value.  The driver converts this
-    * to a SQL BIT value when it sends it to the database.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setBoolean(int parameterIndex, boolean x) throws SQLException
-   {
-       set(parameterIndex, x ? "'t'" : "'f'");
-   }
-
-   /*
-    * Set a parameter to a Java byte value.  The driver converts this to
-    * a SQL TINYINT value when it sends it to the database.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setByte(int parameterIndex, byte x) throws SQLException
-   {
-       set(parameterIndex, Integer.toString(x));
-   }
-
-   /*
-    * Set a parameter to a Java short value.  The driver converts this
-    * to a SQL SMALLINT value when it sends it to the database.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setShort(int parameterIndex, short x) throws SQLException
-   {
-       set(parameterIndex, Integer.toString(x));
-   }
-
-   /*
-    * Set a parameter to a Java int value.  The driver converts this to
-    * a SQL INTEGER value when it sends it to the database.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setInt(int parameterIndex, int x) throws SQLException
-   {
-       set(parameterIndex, Integer.toString(x));
-   }
-
-   /*
-    * Set a parameter to a Java long value.  The driver converts this to
-    * a SQL BIGINT value when it sends it to the database.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setLong(int parameterIndex, long x) throws SQLException
-   {
-       set(parameterIndex, Long.toString(x));
-   }
-
-   /*
-    * Set a parameter to a Java float value.  The driver converts this
-    * to a SQL FLOAT value when it sends it to the database.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setFloat(int parameterIndex, float x) throws SQLException
-   {
-       set(parameterIndex, Float.toString(x));
-   }
-
-   /*
-    * Set a parameter to a Java double value.  The driver converts this
-    * to a SQL DOUBLE value when it sends it to the database
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setDouble(int parameterIndex, double x) throws SQLException
-   {
-       set(parameterIndex, Double.toString(x));
-   }
-
-   /*
-    * Set a parameter to a java.lang.BigDecimal value.  The driver
-    * converts this to a SQL NUMERIC value when it sends it to the
-    * database.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException
-   {
-       if (x == null) {
-       setNull(parameterIndex, Types.OTHER);
-            } else {
-       set(parameterIndex, x.toString());
-       }
-   }
-
-   /*
-    * Set a parameter to a Java String value.  The driver converts this
-    * to a SQL VARCHAR or LONGVARCHAR value (depending on the arguments
-    * size relative to the driver's limits on VARCHARs) when it sends it
-    * to the database.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setString(int parameterIndex, String x) throws SQLException
-   {
-       // if the passed string is null, then set this column to null
-       if (x == null)
-           setNull(parameterIndex, Types.OTHER);
-       else
-       {
-           // use the shared buffer object. Should never clash but this makes
-           // us thread safe!
-           synchronized (sbuf)
-           {
-               sbuf.setLength(0);
-               int i;
-
-               sbuf.append('\'');
-               for (i = 0 ; i < x.length() ; ++i)
-               {
-                   char c = x.charAt(i);
-                   if (c == '\\' || c == '\'')
-                       sbuf.append((char)'\\');
-                   sbuf.append(c);
-               }
-               sbuf.append('\'');
-               set(parameterIndex, sbuf.toString());
-           }
-       }
-   }
-
-   /*
-    * Set a parameter to a Java array of bytes.  The driver converts this
-    * to a SQL VARBINARY or LONGVARBINARY (depending on the argument's
-    * size relative to the driver's limits on VARBINARYs) when it sends
-    * it to the database.
-    *
-    * 

Implementation note:

-    * 
With org.postgresql, this creates a large object, and stores the
-    * objects oid in this column.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setBytes(int parameterIndex, byte x[]) throws SQLException
-   {
-       if (connection.haveMinimumCompatibleVersion("7.2"))
-       {
-           //Version 7.2 supports the bytea datatype for byte arrays
-           if (null == x)
-           {
-               setNull(parameterIndex, Types.OTHER);
-           }
-           else
-           {
-               setString(parameterIndex, PGbytea.toPGString(x));
-           }
-       }
-       else
-       {
-           //Version 7.1 and earlier support done as LargeObjects
-           LargeObjectManager lom = connection.getLargeObjectAPI();
-           int oid = lom.create();
-           LargeObject lob = lom.open(oid);
-           lob.write(x);
-           lob.close();
-           setInt(parameterIndex, oid);
-       }
-   }
-
-   /*
-    * Set a parameter to a java.sql.Date value.  The driver converts this
-    * to a SQL DATE value when it sends it to the database.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setDate(int parameterIndex, java.sql.Date x) throws SQLException
-   {
-       if (null == x)
-       {
-           setNull(parameterIndex, Types.OTHER);
-       }
-       else
-       {
-           set(parameterIndex, "'" + x.toString() + "'");
-       }
-   }
-
-   /*
-    * Set a parameter to a java.sql.Time value.  The driver converts
-    * this to a SQL TIME value when it sends it to the database.
-    *
-    * @param parameterIndex the first parameter is 1...));
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setTime(int parameterIndex, Time x) throws SQLException
-   {
-       if (null == x)
-       {
-           setNull(parameterIndex, Types.OTHER);
-       }
-       else
-       {
-           set(parameterIndex, "'" + x.toString() + "'");
-       }
-   }
-
-   /*
-    * Set a parameter to a java.sql.Timestamp value.  The driver converts
-    * this to a SQL TIMESTAMP value when it sends it to the database.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException
-   {
-       if (null == x)
-       {
-           setNull(parameterIndex, Types.OTHER);
-       }
-       else
-           {
-           // Use the shared StringBuffer
-           synchronized (sbuf)
-           {
-               sbuf.setLength(0);
-               sbuf.append("'");
-                                //format the timestamp
-                                //we do our own formating so that we can get a format
-                                //that works with both timestamp with time zone and
-                                //timestamp without time zone datatypes.
-                                //The format is '2002-01-01 23:59:59.123456-0130'
-                                //we need to include the local time and timezone offset
-                                //so that timestamp without time zone works correctly
-                       int l_year = x.getYear() + 1900;
-                                sbuf.append(l_year);
-                                sbuf.append('-');
-                       int l_month = x.getMonth() + 1;
-                                if (l_month < 10) sbuf.append('0');
-                                sbuf.append(l_month);
-                                sbuf.append('-');
-                       int l_day = x.getDate();
-                                if (l_day < 10) sbuf.append('0');
-                                sbuf.append(l_day);
-                                sbuf.append(' ');
-                       int l_hours = x.getHours();
-                                if (l_hours < 10) sbuf.append('0');
-                                sbuf.append(l_hours);
-                                sbuf.append(':');
-                       int l_minutes = x.getMinutes();
-                                if (l_minutes < 10) sbuf.append('0');
-                                sbuf.append(l_minutes);
-                                sbuf.append(':');
-                                int l_seconds = x.getSeconds();
-                                if (l_seconds < 10) sbuf.append('0');
-                                sbuf.append(l_seconds);
-                                // Make decimal from nanos.
-                                char[] l_decimal = {'0','0','0','0','0','0','0','0','0'};
-                                char[] l_nanos = Integer.toString(x.getNanos()).toCharArray();
-                                System.arraycopy(l_nanos, 0, l_decimal, l_decimal.length - l_nanos.length, l_nanos.length);
-                                sbuf.append('.');
-                                if (connection.haveMinimumServerVersion("7.2")) {
-                                  sbuf.append(l_decimal,0,6);
-                                } else {
-                                  // Because 7.1 include bug that "hh:mm:59.999" becomes "hh:mm:60.00".
-                                  sbuf.append(l_decimal,0,2);
-                                }
-                                //add timezone offset
-                                int l_offset = -(x.getTimezoneOffset());
-                                int l_houros = l_offset/60;
-                                if (l_houros >= 0) {
-                                  sbuf.append('+');
-                                } else {
-                                  sbuf.append('-');
-                                }
-                                if (l_houros > -10 && l_houros < 10) sbuf.append('0');
-                                if (l_houros >= 0) {
-                                  sbuf.append(l_houros);
-                                } else {
-                                  sbuf.append(-l_houros);
-                                }
-                                int l_minos = l_offset - (l_houros *60);
-                                if (l_minos != 0) {
-                                  if (l_minos < 10) sbuf.append('0');
-                                  sbuf.append(l_minos);
-                                }
-               sbuf.append("'");
-               set(parameterIndex, sbuf.toString());
-           }
-
-       }
-   }
-
-   /*
-    * When a very large ASCII value is input to a LONGVARCHAR parameter,
-    * it may be more practical to send it via a java.io.InputStream.
-    * JDBC will read the data from the stream as needed, until it reaches
-    * end-of-file.  The JDBC driver will do any necessary conversion from
-    * ASCII to the database char format.
-    *
-    * 

Note: This stream object can either be a standard Java

-    * stream object or your own subclass that implements the standard
-    * interface.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @param length the number of bytes in the stream
-    * @exception SQLException if a database access error occurs
-    */
-   public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException
-   {
-       if (connection.haveMinimumCompatibleVersion("7.2"))
-       {
-           //Version 7.2 supports AsciiStream for all PG text types (char, varchar, text)
-           //As the spec/javadoc for this method indicate this is to be used for
-           //large String values (i.e. LONGVARCHAR)  PG doesn't have a separate
-           //long varchar datatype, but with toast all text datatypes are capable of
-           //handling very large values.  Thus the implementation ends up calling
-           //setString() since there is no current way to stream the value to the server
-           try
-           {
-               InputStreamReader l_inStream = new InputStreamReader(x, "ASCII");
-               char[] l_chars = new char[length];
-               int l_charsRead = l_inStream.read(l_chars, 0, length);
-               setString(parameterIndex, new String(l_chars, 0, l_charsRead));
-           }
-           catch (UnsupportedEncodingException l_uee)
-           {
-               throw new PSQLException("postgresql.unusual", l_uee);
-           }
-           catch (IOException l_ioe)
-           {
-               throw new PSQLException("postgresql.unusual", l_ioe);
-           }
-       }
-       else
-       {
-           //Version 7.1 supported only LargeObjects by treating everything
-           //as binary data
-           setBinaryStream(parameterIndex, x, length);
-       }
-   }
-
-   /*
-    * When a very large Unicode value is input to a LONGVARCHAR parameter,
-    * it may be more practical to send it via a java.io.InputStream.
-    * JDBC will read the data from the stream as needed, until it reaches
-    * end-of-file.  The JDBC driver will do any necessary conversion from
-    * UNICODE to the database char format.
-    *
-    * ** DEPRECIATED IN JDBC 2 **
-    *
-    * 

Note: This stream object can either be a standard Java

-    * stream object or your own subclass that implements the standard
-    * interface.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    * @deprecated
-    */
-   public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException
-   {
-       if (connection.haveMinimumCompatibleVersion("7.2"))
-       {
-           //Version 7.2 supports AsciiStream for all PG text types (char, varchar, text)
-           //As the spec/javadoc for this method indicate this is to be used for
-           //large String values (i.e. LONGVARCHAR)  PG doesn't have a separate
-           //long varchar datatype, but with toast all text datatypes are capable of
-           //handling very large values.  Thus the implementation ends up calling
-           //setString() since there is no current way to stream the value to the server
-           try
-           {
-               InputStreamReader l_inStream = new InputStreamReader(x, "UTF-8");
-               char[] l_chars = new char[length];
-               int l_charsRead = l_inStream.read(l_chars, 0, length);
-               setString(parameterIndex, new String(l_chars, 0, l_charsRead));
-           }
-           catch (UnsupportedEncodingException l_uee)
-           {
-               throw new PSQLException("postgresql.unusual", l_uee);
-           }
-           catch (IOException l_ioe)
-           {
-               throw new PSQLException("postgresql.unusual", l_ioe);
-           }
-       }
-       else
-       {
-           //Version 7.1 supported only LargeObjects by treating everything
-           //as binary data
-           setBinaryStream(parameterIndex, x, length);
-       }
-   }
-
-   /*
-    * When a very large binary value is input to a LONGVARBINARY parameter,
-    * it may be more practical to send it via a java.io.InputStream.
-    * JDBC will read the data from the stream as needed, until it reaches
-    * end-of-file.
-    *
-    * 

Note: This stream object can either be a standard Java

-    * stream object or your own subclass that implements the standard
-    * interface.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the parameter value
-    * @exception SQLException if a database access error occurs
-    */
-   public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException
-   {
-       if (connection.haveMinimumCompatibleVersion("7.2"))
-       {
-           //Version 7.2 supports BinaryStream for for the PG bytea type
-           //As the spec/javadoc for this method indicate this is to be used for
-           //large binary values (i.e. LONGVARBINARY)  PG doesn't have a separate
-           //long binary datatype, but with toast the bytea datatype is capable of
-           //handling very large values.  Thus the implementation ends up calling
-           //setBytes() since there is no current way to stream the value to the server
-           byte[] l_bytes = new byte[length];
-           int l_bytesRead;
-           try
-           {
-               l_bytesRead = x.read(l_bytes, 0, length);
-           }
-           catch (IOException l_ioe)
-           {
-               throw new PSQLException("postgresql.unusual", l_ioe);
-           }
-           if (l_bytesRead == length)
-           {
-               setBytes(parameterIndex, l_bytes);
-           }
-           else
-           {
-               //the stream contained less data than they said
-               byte[] l_bytes2 = new byte[l_bytesRead];
-               System.arraycopy(l_bytes, 0, l_bytes2, 0, l_bytesRead);
-               setBytes(parameterIndex, l_bytes2);
-           }
-       }
-       else
-       {
-           //Version 7.1 only supported streams for LargeObjects
-           //but the jdbc spec indicates that streams should be
-           //available for LONGVARBINARY instead
-           LargeObjectManager lom = connection.getLargeObjectAPI();
-           int oid = lom.create();
-           LargeObject lob = lom.open(oid);
-           OutputStream los = lob.getOutputStream();
-           try
-           {
-               // could be buffered, but then the OutputStream returned by LargeObject
-               // is buffered internally anyhow, so there would be no performance
-               // boost gained, if anything it would be worse!
-               int c = x.read();
-               int p = 0;
-               while (c > -1 && p < length)
-               {
-                   los.write(c);
-                   c = x.read();
-                   p++;
-               }
-               los.close();
-           }
-           catch (IOException se)
-           {
-               throw new PSQLException("postgresql.unusual", se);
-           }
-           // lob is closed by the stream so don't call lob.close()
-           setInt(parameterIndex, oid);
-       }
-   }
-
-   /*
-    * In general, parameter values remain in force for repeated used of a
-    * Statement.  Setting a parameter value automatically clears its
-    * previous value.  However, in coms cases, it is useful to immediately
-    * release the resources used by the current parameter values; this
-    * can be done by calling clearParameters
-    *
-    * @exception SQLException if a database access error occurs
-    */
-   public void clearParameters() throws SQLException
-   {
-       int i;
-
-       for (i = 0 ; i < inStrings.length ; i++)
-           inStrings[i] = null;
-   }
-
-   /*
-    * Set the value of a parameter using an object; use the java.lang
-    * equivalent objects for integral values.
-    *
-    * 

The given Java object will be converted to the targetSqlType before

-    * being sent to the database.
-    *
-    * 

note that this method may be used to pass database-specific

-    * abstract data types.  This is done by using a Driver-specific
-    * Java type and using a targetSqlType of java.sql.Types.OTHER
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the object containing the input parameter value
-    * @param targetSqlType The SQL type to be send to the database
-    * @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 void setObject(int parameterIndex, Object x, int targetSqlType, int scale) throws SQLException
-   {
-       if (x == null)
-       {
-           setNull(parameterIndex, Types.OTHER);
-           return;
-       }
-       switch (targetSqlType)
-       {
-           case Types.TINYINT:
-           case Types.SMALLINT:
-           case Types.INTEGER:
-           case Types.BIGINT:
-           case Types.REAL:
-           case Types.FLOAT:
-           case Types.DOUBLE:
-           case Types.DECIMAL:
-           case Types.NUMERIC:
-               if (x instanceof Boolean)
-                   set(parameterIndex, ((Boolean)x).booleanValue() ? "1" : "0");
-               else
-                   set(parameterIndex, x.toString());
-               break;
-           case Types.CHAR:
-           case Types.VARCHAR:
-           case Types.LONGVARCHAR:
-               setString(parameterIndex, x.toString());
-               break;
-           case Types.DATE:
-               setDate(parameterIndex, (java.sql.Date)x);
-               break;
-           case Types.TIME:
-               setTime(parameterIndex, (Time)x);
-               break;
-           case Types.TIMESTAMP:
-               setTimestamp(parameterIndex, (Timestamp)x);
-               break;
-           case Types.BIT:
-               if (x instanceof Boolean)
-               {
-                   set(parameterIndex, ((Boolean)x).booleanValue() ? "TRUE" : "FALSE");
-               }
-               else
-               {
-                   throw new PSQLException("postgresql.prep.type");
-               }
-               break;
-           case Types.BINARY:
-           case Types.VARBINARY:
-               setObject(parameterIndex, x);
-               break;
-           case Types.OTHER:
-               setString(parameterIndex, ((PGobject)x).getValue());
-               break;
-           default:
-               throw new PSQLException("postgresql.prep.type");
-       }
-   }
-
-   public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException
-   {
-       setObject(parameterIndex, x, targetSqlType, 0);
-   }
-
-   /*
-    * This stores an Object into a parameter.
-    * 

New for 6.4, if the object is not recognised, but it is

-    * Serializable, then the object is serialised using the
-    * org.postgresql.util.Serialize class.
-    */
-   public void setObject(int parameterIndex, Object x) throws SQLException
-   {
-       if (x == null)
-       {
-           setNull(parameterIndex, Types.OTHER);
-           return;
-       }
-       if (x instanceof String)
-           setString(parameterIndex, (String)x);
-       else if (x instanceof BigDecimal)
-           setBigDecimal(parameterIndex, (BigDecimal)x);
-       else if (x instanceof Short)
-           setShort(parameterIndex, ((Short)x).shortValue());
-       else if (x instanceof Integer)
-           setInt(parameterIndex, ((Integer)x).intValue());
-       else if (x instanceof Long)
-           setLong(parameterIndex, ((Long)x).longValue());
-       else if (x instanceof Float)
-           setFloat(parameterIndex, ((Float)x).floatValue());
-       else if (x instanceof Double)
-           setDouble(parameterIndex, ((Double)x).doubleValue());
-       else if (x instanceof byte[])
-           setBytes(parameterIndex, (byte[])x);
-       else if (x instanceof java.sql.Date)
-           setDate(parameterIndex, (java.sql.Date)x);
-       else if (x instanceof Time)
-           setTime(parameterIndex, (Time)x);
-       else if (x instanceof Timestamp)
-           setTimestamp(parameterIndex, (Timestamp)x);
-       else if (x instanceof Boolean)
-           setBoolean(parameterIndex, ((Boolean)x).booleanValue());
-       else if (x instanceof PGobject)
-           setString(parameterIndex, ((PGobject)x).getValue());
-       else
-           // Try to store java object in database
-           setSerialize(parameterIndex, connection.storeObject(x), x.getClass().getName() );
-   }
-
-   /*
-    * Some prepared statements return multiple results; the execute method
-    * handles these complex statements as well as the simpler form of
-    * statements handled by executeQuery and executeUpdate
-    *
-    * @return true if the next result is a ResultSet; false if it is an
-    *  update count or there are no more results
-    * @exception SQLException if a database access error occurs
-    */
-   public boolean execute() throws SQLException
-   {
-       return super.execute(compileQuery());   // in Statement class
-   }
-
-   /*
-    * Returns the SQL statement with the current template values
-    * substituted.
-           * NB: This is identical to compileQuery() except instead of throwing
-           * SQLException if a parameter is null, it places ? instead.
-    */
-   public String toString()
-   {
-       synchronized (sbuf)
-       {
-           sbuf.setLength(0);
-           int i;
-
-           for (i = 0 ; i < inStrings.length ; ++i)
-           {
-               if (inStrings[i] == null)
-                   sbuf.append( '?' );
-               else
-                   sbuf.append (templateStrings[i]);
-               sbuf.append (inStrings[i]);
-           }
-           sbuf.append(templateStrings[inStrings.length]);
-           return sbuf.toString();
-       }
-   }
-
-   // **************************************************************
-   //  END OF PUBLIC INTERFACE
-   // **************************************************************
-
-   /*
-    * There are a lot of setXXX classes which all basically do
-    * the same thing.  We need a method which actually does the
-    * set for us.
-    *
-    * @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 || paramIndex > inStrings.length)
-           throw new PSQLException("postgresql.prep.range");
-       inStrings[paramIndex - 1] = s;
-   }
-
-   /*
-    * Set a parameter to a tablerow-type oid reference.
-    *
-    * @param parameterIndex the first parameter is 1...
-    * @param x the oid of the object from org.postgresql.util.Serialize.store
-    * @param classname the classname of the java object x
-    * @exception SQLException if a database access error occurs
-    */
-   private void setSerialize(int parameterIndex, long x, String classname) throws SQLException
-   {
-       // converts . to _, toLowerCase, and ensures length<32
-       String tablename = Serialize.toPostgreSQL( classname );
-       DriverManager.println("setSerialize: setting " + x + "::" + tablename );
-
-       // OID reference to tablerow-type must be cast like:  ::
-       // Note that postgres support for tablerow data types is incomplete/broken.
-       // This cannot be just a plain OID because then there would be ambiguity
-       // between when you want the oid itself and when you want the object
-       // an oid references.
-       set(parameterIndex, Long.toString(x) + "::" + tablename );
-   }
-
-
-   // ** JDBC 2 Extensions **
-
-   /*
-    * This parses the query and adds it to the current batch
-    */
-   public void addBatch() throws SQLException
-   {
-       super.addBatch(compileQuery());
-   }
-
-   /*
-    * Not sure what this one does, so I'm saying this returns the MetaData for
-    * the last ResultSet returned!
-    */
-   public java.sql.ResultSetMetaData getMetaData() throws SQLException
-   {
-       java.sql.ResultSet rs = getResultSet();
-       if (rs != null)
-           return rs.getMetaData();
-
-       // Does anyone really know what this method does?
-       return null;
-   }
-
-   public void setArray(int i, java.sql.Array x) throws SQLException
-   {
-       setString(i, x.toString());
-   }
-
-   /*
-    * Sets a Blob
-    */
-   public void setBlob(int i, Blob x) throws SQLException
-   {
-       InputStream l_inStream = x.getBinaryStream();
-       int l_length = (int) x.length();
-       LargeObjectManager lom = connection.getLargeObjectAPI();
-       int oid = lom.create();
-       LargeObject lob = lom.open(oid);
-       OutputStream los = lob.getOutputStream();
-       try
-       {
-           // could be buffered, but then the OutputStream returned by LargeObject
-           // is buffered internally anyhow, so there would be no performance
-           // boost gained, if anything it would be worse!
-           int c = l_inStream.read();
-           int p = 0;
-           while (c > -1 && p < l_length)
-           {
-               los.write(c);
-               c = l_inStream.read();
-               p++;
-           }
-           los.close();
-       }
-       catch (IOException se)
-       {
-           throw new PSQLException("postgresql.unusual", se);
-       }
-       // lob is closed by the stream so don't call lob.close()
-       setInt(i, oid);
-   }
-
-   /*
-    * This is similar to setBinaryStream except it uses a Reader instead of
-    * InputStream.
-    */
-   public void setCharacterStream(int i, java.io.Reader x, int length) throws SQLException
-   {
-       if (connection.haveMinimumCompatibleVersion("7.2"))
-       {
-           //Version 7.2 supports CharacterStream for for 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 varchar datatype, but with toast all the text datatypes are capable of
-           //handling very large values.  Thus the implementation ends up calling
-           //setString() since there is no current way to stream the value to the server
-           char[] l_chars = new char[length];
-           int l_charsRead;
-           try
-           {
-               l_charsRead = x.read(l_chars, 0, length);
-           }
-           catch (IOException l_ioe)
-           {
-               throw new PSQLException("postgresql.unusual", l_ioe);
-           }
-           setString(i, new String(l_chars, 0, l_charsRead));
-       }
-       else
-       {
-           //Version 7.1 only supported streams for LargeObjects
-           //but the jdbc spec indicates that streams should be
-           //available for LONGVARCHAR instead
-           LargeObjectManager lom = connection.getLargeObjectAPI();
-           int oid = lom.create();
-           LargeObject lob = lom.open(oid);
-           OutputStream los = lob.getOutputStream();
-           try
-           {
-               // could be buffered, but then the OutputStream returned by LargeObject
-               // is buffered internally anyhow, so there would be no performance
-               // boost gained, if anything it would be worse!
-               int c = x.read();
-               int p = 0;
-               while (c > -1 && p < length)
-               {
-                   los.write(c);
-                   c = x.read();
-                   p++;
-               }
-               los.close();
-           }
-           catch (IOException se)
-           {
-               throw new PSQLException("postgresql.unusual", se);
-           }
-           // lob is closed by the stream so don't call lob.close()
-           setInt(i, oid);
-       }
-   }
-
-   /*
-    * New in 7.1
-    */
-   public void setClob(int i, Clob x) throws SQLException
-   {
-       InputStream l_inStream = x.getAsciiStream();
-       int l_length = (int) x.length();
-       LargeObjectManager lom = connection.getLargeObjectAPI();
-       int oid = lom.create();
-       LargeObject lob = lom.open(oid);
-       OutputStream los = lob.getOutputStream();
-       try
-       {
-           // could be buffered, but then the OutputStream returned by LargeObject
-           // is buffered internally anyhow, so there would be no performance
-           // boost gained, if anything it would be worse!
-           int c = l_inStream.read();
-           int p = 0;
-           while (c > -1 && p < l_length)
-           {
-               los.write(c);
-               c = l_inStream.read();
-               p++;
-           }
-           los.close();
-       }
-       catch (IOException se)
-       {
-           throw new PSQLException("postgresql.unusual", se);
-       }
-       // lob is closed by the stream so don't call lob.close()
-       setInt(i, oid);
-   }
-
-   /*
-    * At least this works as in PostgreSQL null represents anything null ;-)
-    *
-    * New in 7,1
-    */
-   public void setNull(int i, int t, String s) throws SQLException
-   {
-       setNull(i, t);
-   }
-
-   public void setRef(int i, Ref x) throws SQLException
-   {
-       throw org.postgresql.Driver.notImplemented();
-   }
-
-   /*
-    * New in 7,1
-    */
-   public void setDate(int i, java.sql.Date d, java.util.Calendar cal) throws SQLException
-   {
-       if (cal == null)
-           setDate(i, d);
-       else
-       {
-           cal.setTime(d);
-           setDate(i, new java.sql.Date(cal.getTime().getTime()));
-       }
-   }
-
-   /*
-    * New in 7,1
-    */
-   public void setTime(int i, Time t, java.util.Calendar cal) throws SQLException
-   {
-       if (cal == null)
-           setTime(i, t);
-       else
-       {
-           cal.setTime(t);
-           setTime(i, new java.sql.Time(cal.getTime().getTime()));
-       }
-   }
-
-   /*
-    * New in 7,1
-    */
-   public void setTimestamp(int i, Timestamp t, java.util.Calendar cal) throws SQLException
-   {
-       if (cal == null)
-           setTimestamp(i, t);
-       else
-       {
-           cal.setTime(t);
-           setTimestamp(i, new java.sql.Timestamp(cal.getTime().getTime()));
-       }
-   }
-
-}
-