diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java b/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java
index 9c4d2b1cd9cbfe6105ad1bfac3783dbbca085192..6b06cc873e0e3bd36375a0575d1ecb58698783ec 100644
--- a/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java
+++ b/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java
@@ -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
+	 *
+	 * <p><B>Note:</B> 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.
+	 *
+	 * <p>Implementation note:
+	 * <br>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.
+	 *
+	 * <P><B>Note:</B> 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.
+	 *
+	 * <P><B>Note:</B> 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.
+	 *
+	 * <P><B>Note:</B> 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.
+	 *
+	 * <P>The given Java object will be converted to the targetSqlType before
+	 * being sent to the database.
+	 *
+	 * <P>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.
+	 * <p>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:  <oid>::<tablename>
+		// 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 );
+	}
 
 
 }
diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/CallableStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc1/CallableStatement.java
index 10e8c5f4171db2f1f73b8494d0b8f344abe95dfa..dab157f97b624a6dcc3fa59ad329b17b8b3ece79 100644
--- a/src/interfaces/jdbc/org/postgresql/jdbc1/CallableStatement.java
+++ b/src/interfaces/jdbc/org/postgresql/jdbc1/CallableStatement.java
@@ -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
diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1Connection.java b/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1Connection.java
index 55e527bd4908c6c6d033978c3e9f64efffcf6078..249a41049b6ed2c3f86e043da65fbbf18cb9fa5c 100644
--- a/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1Connection.java
+++ b/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1Connection.java
@@ -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
index 0000000000000000000000000000000000000000..b065b5722461557e454bc68746ed02ec94822614
--- /dev/null
+++ b/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1PreparedStatement.java
@@ -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);
+	}
+
+}
diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1Statement.java b/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1Statement.java
index bb073eae99871cdfaae4186c57815a14e14efaf9..f56841b3df8a0ff24b1f30d052a12f57eb765d33 100644
--- a/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1Statement.java
+++ b/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1Statement.java
@@ -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
index 9ef9a4289e59f816e05289b4ed642a68e54a7493..0000000000000000000000000000000000000000
--- a/src/interfaces/jdbc/org/postgresql/jdbc1/PreparedStatement.java
+++ /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.
- *
- * <p><B>Note:</B> 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.
- *
- * <p>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
-	 *
-	 * <p><B>Note:</B> 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.
-	 *
-	 * <p>Implementation note:
-	 * <br>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.
-	 *
-	 * <P><B>Note:</B> 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.
-	 *
-	 * <P><B>Note:</B> 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.
-	 *
-	 * <P><B>Note:</B> 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.
-	 *
-	 * <P>The given Java object will be converted to the targetSqlType before
-	 * being sent to the database.
-	 *
-	 * <P>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.
-	 * <p>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;
-	}
-}
diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java b/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java
index 50c5d942bbf63ce71e53e46d756bf8c681b6d123..d2c5ee07607a39dd84f1fa141f0f5f77d81a54f2 100644
--- a/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java
+++ b/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java
@@ -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;
 	}
diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2Statement.java b/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2Statement.java
index 3d6f6553ced3fea5afba83d7e4c81cbbcabf5d1d..47c2c77983153637d94df8a2c0e5f714de6fcc81 100644
--- a/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2Statement.java
+++ b/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2Statement.java
@@ -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()));
+		}
+	}
 }
diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/CallableStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc2/CallableStatement.java
index 9d37bf04bc50c42cacc133b394cb719e3a1f6289..51dd9b2c7f0138b26f65e0eda732e2b976d51441 100644
--- a/src/interfaces/jdbc/org/postgresql/jdbc2/CallableStatement.java
+++ b/src/interfaces/jdbc/org/postgresql/jdbc2/CallableStatement.java
@@ -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
diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Connection.java b/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Connection.java
index cfbb3486ec6f6d25dc6b0ca25110bedf73a6e65e..787b14e62af6485d84fb46c398b9327521f26420 100644
--- a/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Connection.java
+++ b/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Connection.java
@@ -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
index 0000000000000000000000000000000000000000..0472007d3dd91cea4f851913fb9d022c2176bb61
--- /dev/null
+++ b/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2PreparedStatement.java
@@ -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);
+	}
+
+}
+
diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Statement.java b/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Statement.java
index 31cec93821a4f8dde7b01b811a3d584c5e579246..4f63d10c14f485caa190501568b4812dcd533ca3 100644
--- a/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Statement.java
+++ b/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Statement.java
@@ -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
index 21aba8d9ee089ff84ad991c7873d25f6e66a7bec..0000000000000000000000000000000000000000
--- a/src/interfaces/jdbc/org/postgresql/jdbc2/PreparedStatement.java
+++ /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.
- *
- * <p><B>Note:</B> 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.
- *
- * <p>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
-	 *
-	 * <p><B>Note:</B> 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.
-	 *
-	 * <p>Implementation note:
-	 * <br>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.
-	 *
-	 * <P><B>Note:</B> 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 **
-	 *
-	 * <P><B>Note:</B> 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.
-	 *
-	 * <P><B>Note:</B> 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.
-	 *
-	 * <P>The given Java object will be converted to the targetSqlType before
-	 * being sent to the database.
-	 *
-	 * <P>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.
-	 * <p>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:  <oid>::<tablename>
-		// 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()));
-		}
-	}
-
-}
-