From 6a061da272f04e1463864065f87f1f3fd61d6162 Mon Sep 17 00:00:00 2001
From: "Marc G. Fournier" <scrappy@hub.org>
Date: Sun, 31 Aug 1997 08:15:13 +0000
Subject: [PATCH] Update patch from Peter <patches@maidast.demon.co.uk>

---
 .../jdbc/postgresql/CallableStatement.java    |  241 +-
 .../jdbc/postgresql/Connection.java           | 1613 ++++----
 .../jdbc/postgresql/DatabaseMetaData.java     | 3569 ++++++++++-------
 src/interfaces/jdbc/postgresql/Driver.java    |  500 +--
 src/interfaces/jdbc/postgresql/Field.java     |  160 +-
 src/interfaces/jdbc/postgresql/PG_Object.java |  142 +-
 src/interfaces/jdbc/postgresql/ResultSet.java | 1580 ++++----
 .../jdbc/postgresql/ResultSetMetaData.java    |  821 ++--
 8 files changed, 4657 insertions(+), 3969 deletions(-)

diff --git a/src/interfaces/jdbc/postgresql/CallableStatement.java b/src/interfaces/jdbc/postgresql/CallableStatement.java
index ff7ec7c26f2..ede69bbb121 100644
--- a/src/interfaces/jdbc/postgresql/CallableStatement.java
+++ b/src/interfaces/jdbc/postgresql/CallableStatement.java
@@ -1,126 +1,133 @@
 package postgresql;
 
-import java.math.*;
 import java.sql.*;
+import java.math.*;
 
 /**
- * @version 1.0 15-APR-1997
- * @author <A HREF="mailto:adrian@hottub.org">Adrian Hall</A>
- *
- * CallableStatement is used to execute SQL stored procedures.
- *
- * JDBC provides a stored procedure SQL escape that allows stored procedures
- * to be called in a standard way for all RDBMS's.  This escape syntax has
- * one form that includes a result parameter and one that does not.  If used,
- * the result parameter must be generated as an OUT parameter.  The other
- * parameters may be used for input, output or both.  Parameters are refered
- * to sequentially, by number.  The first parameter is 1.
- *
- * <PRE>
- *	{?= call <procedure-name>[<arg1>,<arg2>, ...]}
- *	{call <procedure-name>[<arg1>,<arg2>, ...]}
- * </PRE>
- *
- * IN parameters are set using the set methods inherited from 
- * PreparedStatement.  The type of all OUT parameters must be registered
- * prior to executing the stored procedure; their values are retrieved
- * after execution via the get methods provided here.
- *
- * A CallableStatement may return a ResultSet or multiple ResultSets.  Multiple
- * ResultSets are handled using operations inherited from Statement.
- *
- * For maximum portability, a call's ResultSets and update counts should be
- * processed prior to getting the values of output parameters.
- *
- * @see java.sql.Connection#prepareCall
- * @see java.sql.ResultSet
- * @see java.sql.CallableStatement
+ * JDBC Interface to Postgres95 functions
  */
-public class CallableStatement implements java.sql.CallableStatement 
-{
-	public void registerOutParameter (int paramterIndex, int sqlType) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public void registerOutParameter (int parameterIndex, int sqlType, int scale) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public boolean wasNull () throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public String getString (int parameterIndex) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public boolean getBoolean (int parameterIndex) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public byte getByte (int parameterIndex) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public short getShort (int parameterIndex) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public int getInt (int parameterIndex) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
 
-	public long getLong (int parameterIndex) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public float getFloat (int parameterIndex) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public double getDouble (int parameterIndex) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public BigDecimal getBigDecimal (int parameterIndex, int scale) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public byte[] getBytes (int parameterIndex) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public Date getDate (int parameterIndex) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public Time getTime (int parameterIndex) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public Timestamp getTimestamp (int parameterIndex) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public Object getObject (int parameterIndex) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
+// Copy methods from the Result set object here.
 
+public class CallableStatement extends PreparedStatement implements java.sql.CallableStatement
+{
+  CallableStatement(Connection c,String q) throws SQLException
+  {
+    super(c,q);
+  }
+  
+  // Before executing a stored procedure call you must explicitly
+  // call registerOutParameter to register the java.sql.Type of each
+  // out parameter.
+  public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException {
+  }
+  
+  // You must also specify the scale for numeric/decimal types:	
+  public void registerOutParameter(int parameterIndex, int sqlType,
+				   int scale) throws SQLException
+  {
+  }
+  
+  public boolean isNull(int parameterIndex) throws SQLException {
+    return true;
+  }
+  
+  // New API (JPM)
+  public boolean wasNull() throws SQLException {
+    // check to see if the last access threw an exception
+    return false; // fake it for now
+  }
+  
+  // Methods for retrieving OUT parameters from this statement.
+  public String getChar(int parameterIndex) throws SQLException {
+    return null;
+  }
+  
+  // New API (JPM)
+  public String getString(int parameterIndex) throws SQLException {
+    return null;
+  }
+  //public String getVarChar(int parameterIndex) throws SQLException {
+  //   return null;
+  //}
+  
+  public String getLongVarChar(int parameterIndex) throws SQLException {
+    return null;
+  }
+  
+  // New API (JPM) (getBit)
+  public boolean getBoolean(int parameterIndex) throws SQLException {
+    return false;
+  }
+  
+  // New API (JPM) (getTinyInt)
+  public byte getByte(int parameterIndex) throws SQLException {
+    return 0;
+  }
+  
+  // New API (JPM) (getSmallInt)
+  public short getShort(int parameterIndex) throws SQLException {
+    return 0;
+  }
+  
+  // New API (JPM) (getInteger)
+  public int getInt(int parameterIndex) throws SQLException {
+    return 0;
+  }
+  
+  // New API (JPM) (getBigInt)
+  public long getLong(int parameterIndex) throws SQLException {
+    return 0;
+  }
+  
+  public float getFloat(int parameterIndex) throws SQLException {
+    return (float) 0.0;
+  }
+  
+  public double getDouble(int parameterIndex) throws SQLException {
+    return 0.0;
+  }
+  
+  public BigDecimal getBigDecimal(int parameterIndex, int scale)
+       throws SQLException {
+	 return null;
+  }
+  
+  // New API (JPM) (getBinary)
+  public byte[] getBytes(int parameterIndex) throws SQLException {
+    return null;
+  }
+  
+  // New API (JPM) (getLongVarBinary)
+  public byte[] getBinaryStream(int parameterIndex) throws SQLException {
+    return null;
+  }
+  
+  public java.sql.Date getDate(int parameterIndex) throws SQLException {
+    return null;
+  }
+  public java.sql.Time getTime(int parameterIndex) throws SQLException {
+    return null;
+  }
+  public java.sql.Timestamp getTimestamp(int parameterIndex)
+       throws SQLException {
+	 return null;
+  }
+  
+  //----------------------------------------------------------------------
+  // Advanced features:
+  
+  // You can obtain a ParameterMetaData object to get information 
+  // about the parameters to this CallableStatement.
+  public DatabaseMetaData getMetaData() {
+    return null;
+  }
+  
+  // getObject returns a Java object for the parameter.
+  // See the JDBC spec's "Dynamic Programming" chapter for details.
+  public Object getObject(int parameterIndex)
+       throws SQLException {
+	 return null;
+  }
 }
+
diff --git a/src/interfaces/jdbc/postgresql/Connection.java b/src/interfaces/jdbc/postgresql/Connection.java
index aa354b61fe1..a208970ae24 100644
--- a/src/interfaces/jdbc/postgresql/Connection.java
+++ b/src/interfaces/jdbc/postgresql/Connection.java
@@ -28,570 +28,569 @@ import postgresql.*;
  */
 public class Connection implements java.sql.Connection 
 {
-	private PG_Stream pg_stream;
-
-	private String PG_HOST;
-	private int PG_PORT;
-	private String PG_USER;
-	private String PG_PASSWORD;
-	private String PG_DATABASE;
-	private boolean PG_STATUS;
-
-	public boolean CONNECTION_OK = true;
-	public boolean CONNECTION_BAD = false;
-
-	private int STARTUP_CODE = 7;
-
-	private boolean autoCommit = true;
-	private boolean readOnly = false;
-	
-	private Driver this_driver;
-	private String this_url;
-	private String cursor = null;	// The positioned update cursor name
-
-	/**
-	 * Connect to a PostgreSQL database back end.
-	 *
-	 * @param host the hostname of the database back end
-	 * @param port the port number of the postmaster process
-	 * @param info a Properties[] thing of the user and password
-	 * @param database the database to connect to
-	 * @param u the URL of the connection
-	 * @param d the Driver instantation of the connection
-	 * @return a valid connection profile
-	 * @exception SQLException if a database access error occurs
-	 */
-	public Connection(String host, int port, Properties info, String database, String url, Driver d) throws SQLException
-	{
-		int len = 288;			// Length of a startup packet
-
-		this_driver = d;
-		this_url = new String(url);
-		PG_DATABASE = new String(database);
-		PG_PASSWORD = new String(info.getProperty("password"));
-		PG_USER = new String(info.getProperty("user"));
-		PG_PORT = port;
-		PG_HOST = new String(host);
-		PG_STATUS = CONNECTION_BAD;
-
-		try
-		{
-			pg_stream = new PG_Stream(host, port);
-		} catch (IOException e) {
-			throw new SQLException ("Connection failed: " + e.toString());
-		}
-		
-		// Now we need to construct and send a startup packet
-		try
-		{
-			pg_stream.SendInteger(len, 4);			len -= 4;
-			pg_stream.SendInteger(STARTUP_CODE, 4);		len -= 4;
-			pg_stream.Send(database.getBytes(), 64);	len -= 64;
-			pg_stream.Send(PG_USER.getBytes(), len);
-		} catch (IOException e) {
-			throw new SQLException("Connection failed: " + e.toString());
-		}
-		ExecSQL(" ");				// Test connection
-		PG_STATUS = CONNECTION_OK;
-	}
-
-	/**
-	 * SQL statements without parameters are normally executed using
-	 * Statement objects.  If the same SQL statement is executed many
-	 * times, it is more efficient to use a PreparedStatement
-	 *
-	 * @return a new Statement object
-	 * @exception SQLException passed through from the constructor
-	 */
-	public java.sql.Statement createStatement() throws SQLException
-	{
-		return new Statement(this);
-	}
-
-	/**
-	 * A SQL statement with or without IN parameters can be pre-compiled
-	 * and stored in a PreparedStatement object.  This object can then
-	 * be used to efficiently execute this statement multiple times.
-	 *
-	 * <B>Note:</B> This method is optimized for handling parametric
-	 * SQL statements that benefit from precompilation if the drivers
-	 * supports precompilation.  PostgreSQL does not support precompilation.
-	 * In this case, the statement is not sent to the database until the
-	 * PreparedStatement is executed.  This has no direct effect on users;
-	 * however it does affect which method throws certain SQLExceptions
-	 *
-	 * @param sql a SQL statement that may contain one or more '?' IN
-	 *	parameter placeholders
-	 * @return a new PreparedStatement object containing the pre-compiled
-	 *	statement.
-	 * @exception SQLException if a database access error occurs.
-	 */
-	public java.sql.PreparedStatement prepareStatement(String sql) throws SQLException
-	{
-		return new PreparedStatement(this, sql);
-	}
-
-	/**
-	 * A SQL stored procedure call statement is handled by creating a
-	 * CallableStatement for it.  The CallableStatement provides methods
-	 * for setting up its IN and OUT parameters and methods for executing
-	 * it.
-	 *
-	 * <B>Note:</B> This method is optimised for handling stored procedure
-	 * call statements.  Some drivers may send the call statement to the
-	 * database when the prepareCall is done; others may wait until the
-	 * CallableStatement is executed.  This has no direct effect on users;
-	 * however, it does affect which method throws certain SQLExceptions
-	 *
-	 * @param sql a SQL statement that may contain one or more '?' parameter
-	 *	placeholders.  Typically this statement is a JDBC function call
-	 *	escape string.
-	 * @return a new CallableStatement object containing the pre-compiled
-	 *	SQL statement
-	 * @exception SQLException if a database access error occurs
-	 */
-	public java.sql.CallableStatement prepareCall(String sql) throws SQLException
-	{
-		throw new SQLException("Callable Statements are not supported at this time");
-//		return new CallableStatement(this, sql);
-	}
-
-	/**
-	 * A driver may convert the JDBC sql grammar into its system's
-	 * native SQL grammar prior to sending it; nativeSQL returns the
-	 * native form of the statement that the driver would have sent.
-	 *
-	 * @param sql a SQL statement that may contain one or more '?'
-	 *	parameter placeholders
-	 * @return the native form of this statement
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String nativeSQL(String sql) throws SQLException
-	{
-		return sql;
-	}
-
-	/**
-	 * If a connection is in auto-commit mode, than all its SQL
-	 * statements will be executed and committed as individual
-	 * transactions.  Otherwise, its SQL statements are grouped
-	 * into transactions that are terminated by either commit()
-	 * or rollback().  By default, new connections are in auto-
-	 * commit mode.  The commit occurs when the statement completes
-	 * or the next execute occurs, whichever comes first.  In the
-	 * case of statements returning a ResultSet, the statement
-	 * completes when the last row of the ResultSet has been retrieved
-	 * or the ResultSet has been closed.  In advanced cases, a single
-	 * statement may return multiple results as well as output parameter
-	 * values.  Here the commit occurs when all results and output param
-	 * values have been retrieved.
-	 *
-	 * @param autoCommit - true enables auto-commit; false disables it
-	 * @exception SQLException if a database access error occurs
-	 */
-	public void setAutoCommit(boolean autoCommit) throws SQLException
-	{
-		if (this.autoCommit == autoCommit)
-			return;
-		if (autoCommit)
-			ExecSQL("end");
-		else
-			ExecSQL("begin");
-		this.autoCommit = autoCommit;
-	}
-
-	/**
-	 * gets the current auto-commit state
-	 * 
-	 * @return Current state of the auto-commit mode
-	 * @exception SQLException (why?)
-	 * @see setAutoCommit
-	 */
-	public boolean getAutoCommit() throws SQLException
-	{
-		return this.autoCommit;
-	}
-
-	/**
-	 * The method commit() makes all changes made since the previous
-	 * commit/rollback permanent and releases any database locks currently
-	 * held by the Connection.  This method should only be used when
-	 * auto-commit has been disabled.  (If autoCommit == true, then we
-	 * just return anyhow)
-	 *
-	 * @exception SQLException if a database access error occurs
-	 * @see setAutoCommit
-	 */
-	public void commit() throws SQLException
-	{
-		if (autoCommit)
-			return;
-		ExecSQL("commit");
-		autoCommit = true;
-		ExecSQL("begin");
-		autoCommit = false;
-	}
-
-	/**
-	 * The method rollback() drops all changes made since the previous
-	 * commit/rollback and releases any database locks currently held by
-	 * the Connection. 
-	 *
-	 * @exception SQLException if a database access error occurs
-	 * @see commit
-	 */
-	public void rollback() throws SQLException
-	{
-		if (autoCommit)
-			return;
-		ExecSQL("rollback");
-		autoCommit = true;
-		ExecSQL("begin");
-		autoCommit = false;
-	}
-
-	/**
-	 * In some cases, it is desirable to immediately release a Connection's
-	 * database and JDBC resources instead of waiting for them to be
-	 * automatically released (cant think why off the top of my head)
-	 *
-	 * <B>Note:</B> A Connection is automatically closed when it is
-	 * garbage collected.  Certain fatal errors also result in a closed
-	 * connection.
-	 *
-	 * @exception SQLException if a database access error occurs
-	 */
-	public void close() throws SQLException
-	{
-		if (pg_stream != null)
-		{
-			try
-			{
-				pg_stream.close();
-			} catch (IOException e) {}
-			pg_stream = null;
-		}
-	}
-
-	/**
-	 * Tests to see if a Connection is closed
-	 *
-	 * @return the status of the connection
-	 * @exception SQLException (why?)
-	 */
-	public boolean isClosed() throws SQLException
-	{
-		return (pg_stream == null);
-	}
-
-	/**
-	 * A connection's database is able to provide information describing
-	 * its tables, its supported SQL grammar, its stored procedures, the
-	 * capabilities of this connection, etc.  This information is made
-	 * available through a DatabaseMetaData object.
-	 *
-	 * @return a DatabaseMetaData object for this connection
-	 * @exception SQLException if a database access error occurs
-	 */
-	public java.sql.DatabaseMetaData getMetaData() throws SQLException
-	{
-//		return new DatabaseMetaData(this);
-		throw new SQLException("DatabaseMetaData not supported");
-	}
-
-	/**
-	 * You can put a connection in read-only mode as a hunt to enable
-	 * database optimizations
-	 *
-	 * <B>Note:</B> setReadOnly cannot be called while in the middle
-	 * of a transaction
-	 *
-	 * @param readOnly - true enables read-only mode; false disables it
-	 * @exception SQLException if a database access error occurs
-	 */
-	public void setReadOnly (boolean readOnly) throws SQLException
-	{
-		this.readOnly = readOnly;
-	}
-
-	/**
-	 * Tests to see if the connection is in Read Only Mode.  Note that
-	 * we cannot really put the database in read only mode, but we pretend
-	 * we can by returning the value of the readOnly flag
-	 *
-	 * @return true if the connection is read only
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean isReadOnly() throws SQLException
-	{
-		return readOnly;
-	}
-
-	/**
-	 * A sub-space of this Connection's database may be selected by
-	 * setting a catalog name.  If the driver does not support catalogs,
-	 * it will silently ignore this request
-	 *
-	 * @exception SQLException if a database access error occurs
-	 */
-	public void setCatalog(String catalog) throws SQLException
-	{
-		// No-op
-	}
-
-	/**
-	 * Return the connections current catalog name, or null if no
-	 * catalog name is set, or we dont support catalogs.
-	 *
-	 * @return the current catalog name or null
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String getCatalog() throws SQLException
-	{
-		return null;
-	}
-
-	/**
-	 * You can call this method to try to change the transaction
-	 * isolation level using one of the TRANSACTION_* values.  
-	 *
-	 * <B>Note:</B> setTransactionIsolation cannot be called while
-	 * in the middle of a transaction
-	 *
-	 * @param level one of the TRANSACTION_* isolation values with
-	 *	the exception of TRANSACTION_NONE; some databases may
-	 *	not support other values
-	 * @exception SQLException if a database access error occurs
-	 * @see java.sql.DatabaseMetaData#supportsTransactionIsolationLevel
-	 */
-	public void setTransactionIsolation(int level) throws SQLException
-	{
-		throw new SQLException("Transaction Isolation Levels are not implemented");
-	}
-	
-	/**
-	 * Get this Connection's current transaction isolation mode.
-	 * 
-	 * @return the current TRANSACTION_* mode value
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getTransactionIsolation() throws SQLException
-	{
-		return java.sql.Connection.TRANSACTION_SERIALIZABLE;
-	}
-
-	/**
-	 * The first warning reported by calls on this Connection is
-	 * returned.
-	 *
-	 * <B>Note:</B> Sebsequent warnings will be changed to this
-	 * SQLWarning
-	 *
-	 * @return the first SQLWarning or null
-	 * @exception SQLException if a database access error occurs
-	 */
-	public SQLWarning getWarnings() throws SQLException
-	{
-		return null;	// We handle warnings as errors
-	}
-
-	/**
-	 * After this call, getWarnings returns null until a new warning
-	 * is reported for this connection.
-	 *
-	 * @exception SQLException if a database access error occurs
-	 */
-	public void clearWarnings() throws SQLException
-	{
-		// Not handles since we handle wanrings as errors
-	}
-
-	// **********************************************************
-	//		END OF PUBLIC INTERFACE
-	// **********************************************************
-	
-	/**
-	 * Send a query to the backend.  Returns one of the ResultSet
-	 * objects.
-	 *
-	 * <B>Note:</B> there does not seem to be any method currently
-	 * in existance to return the update count.
-	 *
-	 * @param sql the SQL statement to be executed
-	 * @return a ResultSet holding the results
-	 * @exception SQLException if a database error occurs
-	 */
-	public synchronized ResultSet ExecSQL(String sql) throws SQLException
-	{
-		Field[] fields = null;
-		Vector tuples = new Vector();
-		byte[] buf = new byte[sql.length()];
-		int fqp = 0;
-		boolean hfr = false;
-		String recv_status = null, msg;
-		SQLException final_error = null;
-
-		if (sql.length() > 8192)
-			throw new SQLException("SQL Statement too long: " + sql);
-		try
-		{
-			pg_stream.SendChar('Q');
-			buf = sql.getBytes();
-			pg_stream.Send(buf);
-			pg_stream.SendChar(0);
-		} catch (IOException e) {
-			throw new SQLException("I/O Error: " + e.toString());
-		}
-
-		while (!hfr || fqp > 0)
-		{
-			int c = pg_stream.ReceiveChar();
-		
-			switch (c)
-			{
-				case 'A':	// Asynchronous Notify
-					int pid = pg_stream.ReceiveInteger(4);
-					msg = pg_stream.ReceiveString(8192);
-					break;
-				case 'B':	// Binary Data Transfer
-					if (fields == null)
-						throw new SQLException("Tuple received before MetaData");
-					tuples.addElement(pg_stream.ReceiveTuple(fields.length, true));
-					break;
-				case 'C':	// Command Status
-					recv_status = pg_stream.ReceiveString(8192);
-					if (fields != null)
-						hfr = true;
-					else
-					{
-						try
-						{
-							pg_stream.SendChar('Q');
-							pg_stream.SendChar(' ');
-							pg_stream.SendChar(0);
-						} catch (IOException e) {
-							throw new SQLException("I/O Error: " + e.toString());
-						}
-						fqp++;
-					}
-					break;
-				case 'D':	// Text Data Transfer
-					if (fields == null)
-						throw new SQLException("Tuple received before MetaData");
-					tuples.addElement(pg_stream.ReceiveTuple(fields.length, false));
-					break;
-				case 'E':	// Error Message
-					msg = pg_stream.ReceiveString(4096);
-					final_error = new SQLException(msg);
-					hfr = true;
-					break;
-				case 'I':	// Empty Query
-					int t = pg_stream.ReceiveChar();
-
-					if (t != 0)
-						throw new SQLException("Garbled Data");
-					if (fqp > 0)
-						fqp--;
-					if (fqp == 0)
-						hfr = true;
-					break;
-				case 'N':	// Error Notification
-					msg = pg_stream.ReceiveString(4096);
-					PrintStream log = DriverManager.getLogStream();
-					log.println(msg);
-					break;
-				case 'P':	// Portal Name
-					String pname = pg_stream.ReceiveString(8192);
-					break;
-				case 'T':	// MetaData Field Description
-					if (fields != null)
-						throw new SQLException("Cannot handle multiple result groups");
-					fields = ReceiveFields();
-					break;
-				default:
-					throw new SQLException("Unknown Response Type: " + (char)c);
-			}
-		}
-		if (final_error != null)
-			throw final_error;
-		return new ResultSet(this, fields, tuples, recv_status, 1);
-	}
-
-	/**
-	 * Receive the field descriptions from the back end
-	 *
-	 * @return an array of the Field object describing the fields
-	 * @exception SQLException if a database error occurs
-	 */
-	private Field[] ReceiveFields() throws SQLException
-	{
-		int nf = pg_stream.ReceiveInteger(2), i;
-		Field[] fields = new Field[nf];
-		
-		for (i = 0 ; i < nf ; ++i)
+  private PG_Stream pg_stream;
+  
+  private String PG_HOST;
+  private int PG_PORT;
+  private String PG_USER;
+  private String PG_PASSWORD;
+  private String PG_DATABASE;
+  private boolean PG_STATUS;
+  
+  public boolean CONNECTION_OK = true;
+  public boolean CONNECTION_BAD = false;
+  
+  private int STARTUP_CODE = 7;
+  
+  private boolean autoCommit = true;
+  private boolean readOnly = false;
+  
+  protected Driver this_driver;
+  private String this_url;
+  private String cursor = null;	// The positioned update cursor name
+  
+  /**
+   * Connect to a PostgreSQL database back end.
+   *
+   * @param host the hostname of the database back end
+   * @param port the port number of the postmaster process
+   * @param info a Properties[] thing of the user and password
+   * @param database the database to connect to
+   * @param u the URL of the connection
+   * @param d the Driver instantation of the connection
+   * @return a valid connection profile
+   * @exception SQLException if a database access error occurs
+   */
+  public Connection(String host, int port, Properties info, String database, String url, Driver d) throws SQLException
+  {
+    int len = 288;			// Length of a startup packet
+    
+    this_driver = d;
+    this_url = new String(url);
+    PG_DATABASE = new String(database);
+    PG_PASSWORD = new String(info.getProperty("password"));
+    PG_USER = new String(info.getProperty("user"));
+    PG_PORT = port;
+    PG_HOST = new String(host);
+    PG_STATUS = CONNECTION_BAD;
+    
+    try
+      {
+	pg_stream = new PG_Stream(host, port);
+      } catch (IOException e) {
+	throw new SQLException ("Connection failed: " + e.toString());
+      }
+      
+      // Now we need to construct and send a startup packet
+      try
+	{
+	  pg_stream.SendInteger(len, 4);			len -= 4;
+	  pg_stream.SendInteger(STARTUP_CODE, 4);		len -= 4;
+	  pg_stream.Send(database.getBytes(), 64);	len -= 64;
+	  pg_stream.Send(PG_USER.getBytes(), len);
+	} catch (IOException e) {
+	  throw new SQLException("Connection failed: " + e.toString());
+	}
+	ExecSQL(" ");				// Test connection
+	PG_STATUS = CONNECTION_OK;
+  }
+  
+  /**
+   * SQL statements without parameters are normally executed using
+   * Statement objects.  If the same SQL statement is executed many
+   * times, it is more efficient to use a PreparedStatement
+   *
+   * @return a new Statement object
+   * @exception SQLException passed through from the constructor
+   */
+  public java.sql.Statement createStatement() throws SQLException
+  {
+    return new Statement(this);
+  }
+  
+  /**
+   * A SQL statement with or without IN parameters can be pre-compiled
+   * and stored in a PreparedStatement object.  This object can then
+   * be used to efficiently execute this statement multiple times.
+   *
+   * <B>Note:</B> This method is optimized for handling parametric
+   * SQL statements that benefit from precompilation if the drivers
+   * supports precompilation.  PostgreSQL does not support precompilation.
+   * In this case, the statement is not sent to the database until the
+   * PreparedStatement is executed.  This has no direct effect on users;
+   * however it does affect which method throws certain SQLExceptions
+   *
+   * @param sql a SQL statement that may contain one or more '?' IN
+   *	parameter placeholders
+   * @return a new PreparedStatement object containing the pre-compiled
+   *	statement.
+   * @exception SQLException if a database access error occurs.
+   */
+  public java.sql.PreparedStatement prepareStatement(String sql) throws SQLException
+  {
+    return new PreparedStatement(this, sql);
+  }
+  
+  /**
+   * A SQL stored procedure call statement is handled by creating a
+   * CallableStatement for it.  The CallableStatement provides methods
+   * for setting up its IN and OUT parameters and methods for executing
+   * it.
+   *
+   * <B>Note:</B> This method is optimised for handling stored procedure
+   * call statements.  Some drivers may send the call statement to the
+   * database when the prepareCall is done; others may wait until the
+   * CallableStatement is executed.  This has no direct effect on users;
+   * however, it does affect which method throws certain SQLExceptions
+   *
+   * @param sql a SQL statement that may contain one or more '?' parameter
+   *	placeholders.  Typically this statement is a JDBC function call
+   *	escape string.
+   * @return a new CallableStatement object containing the pre-compiled
+   *	SQL statement
+   * @exception SQLException if a database access error occurs
+   */
+  public java.sql.CallableStatement prepareCall(String sql) throws SQLException
+  {
+    throw new SQLException("Callable Statements are not supported at this time");
+    //		return new CallableStatement(this, sql);
+  }
+  
+  /**
+   * A driver may convert the JDBC sql grammar into its system's
+   * native SQL grammar prior to sending it; nativeSQL returns the
+   * native form of the statement that the driver would have sent.
+   *
+   * @param sql a SQL statement that may contain one or more '?'
+   *	parameter placeholders
+   * @return the native form of this statement
+   * @exception SQLException if a database access error occurs
+   */
+  public String nativeSQL(String sql) throws SQLException
+  {
+    return sql;
+  }
+  
+  /**
+   * If a connection is in auto-commit mode, than all its SQL
+   * statements will be executed and committed as individual
+   * transactions.  Otherwise, its SQL statements are grouped
+   * into transactions that are terminated by either commit()
+   * or rollback().  By default, new connections are in auto-
+   * commit mode.  The commit occurs when the statement completes
+   * or the next execute occurs, whichever comes first.  In the
+   * case of statements returning a ResultSet, the statement
+   * completes when the last row of the ResultSet has been retrieved
+   * or the ResultSet has been closed.  In advanced cases, a single
+   * statement may return multiple results as well as output parameter
+   * values.  Here the commit occurs when all results and output param
+   * values have been retrieved.
+   *
+   * @param autoCommit - true enables auto-commit; false disables it
+   * @exception SQLException if a database access error occurs
+   */
+  public void setAutoCommit(boolean autoCommit) throws SQLException
+  {
+    if (this.autoCommit == autoCommit)
+      return;
+    if (autoCommit)
+      ExecSQL("end");
+    else
+      ExecSQL("begin");
+    this.autoCommit = autoCommit;
+  }
+  
+  /**
+   * gets the current auto-commit state
+   * 
+   * @return Current state of the auto-commit mode
+   * @exception SQLException (why?)
+   * @see setAutoCommit
+   */
+  public boolean getAutoCommit() throws SQLException
+  {
+    return this.autoCommit;
+  }
+  
+  /**
+   * The method commit() makes all changes made since the previous
+   * commit/rollback permanent and releases any database locks currently
+   * held by the Connection.  This method should only be used when
+   * auto-commit has been disabled.  (If autoCommit == true, then we
+   * just return anyhow)
+   *
+   * @exception SQLException if a database access error occurs
+   * @see setAutoCommit
+   */
+  public void commit() throws SQLException
+  {
+    if (autoCommit)
+      return;
+    ExecSQL("commit");
+    autoCommit = true;
+    ExecSQL("begin");
+    autoCommit = false;
+  }
+  
+  /**
+   * The method rollback() drops all changes made since the previous
+   * commit/rollback and releases any database locks currently held by
+   * the Connection. 
+   *
+   * @exception SQLException if a database access error occurs
+   * @see commit
+   */
+  public void rollback() throws SQLException
+  {
+    if (autoCommit)
+      return;
+    ExecSQL("rollback");
+    autoCommit = true;
+    ExecSQL("begin");
+    autoCommit = false;
+  }
+  
+  /**
+   * In some cases, it is desirable to immediately release a Connection's
+   * database and JDBC resources instead of waiting for them to be
+   * automatically released (cant think why off the top of my head)
+   *
+   * <B>Note:</B> A Connection is automatically closed when it is
+   * garbage collected.  Certain fatal errors also result in a closed
+   * connection.
+   *
+   * @exception SQLException if a database access error occurs
+   */
+  public void close() throws SQLException
+  {
+    if (pg_stream != null)
+      {
+	try
+	  {
+	    pg_stream.close();
+	  } catch (IOException e) {}
+	  pg_stream = null;
+      }
+  }
+  
+  /**
+   * Tests to see if a Connection is closed
+   *
+   * @return the status of the connection
+   * @exception SQLException (why?)
+   */
+  public boolean isClosed() throws SQLException
+  {
+    return (pg_stream == null);
+  }
+  
+  /**
+   * A connection's database is able to provide information describing
+   * its tables, its supported SQL grammar, its stored procedures, the
+   * capabilities of this connection, etc.  This information is made
+   * available through a DatabaseMetaData object.
+   *
+   * @return a DatabaseMetaData object for this connection
+   * @exception SQLException if a database access error occurs
+   */
+  public java.sql.DatabaseMetaData getMetaData() throws SQLException
+  {
+    return new DatabaseMetaData(this);
+  }
+  
+  /**
+   * You can put a connection in read-only mode as a hunt to enable
+   * database optimizations
+   *
+   * <B>Note:</B> setReadOnly cannot be called while in the middle
+   * of a transaction
+   *
+   * @param readOnly - true enables read-only mode; false disables it
+   * @exception SQLException if a database access error occurs
+   */
+  public void setReadOnly (boolean readOnly) throws SQLException
+  {
+    this.readOnly = readOnly;
+  }
+  
+  /**
+   * Tests to see if the connection is in Read Only Mode.  Note that
+   * we cannot really put the database in read only mode, but we pretend
+   * we can by returning the value of the readOnly flag
+   *
+   * @return true if the connection is read only
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean isReadOnly() throws SQLException
+  {
+    return readOnly;
+  }
+  
+  /**
+   * A sub-space of this Connection's database may be selected by
+   * setting a catalog name.  If the driver does not support catalogs,
+   * it will silently ignore this request
+   *
+   * @exception SQLException if a database access error occurs
+   */
+  public void setCatalog(String catalog) throws SQLException
+  {
+    // No-op
+  }
+  
+  /**
+   * Return the connections current catalog name, or null if no
+   * catalog name is set, or we dont support catalogs.
+   *
+   * @return the current catalog name or null
+   * @exception SQLException if a database access error occurs
+   */
+  public String getCatalog() throws SQLException
+  {
+    return null;
+  }
+  
+  /**
+   * You can call this method to try to change the transaction
+   * isolation level using one of the TRANSACTION_* values.  
+   *
+   * <B>Note:</B> setTransactionIsolation cannot be called while
+   * in the middle of a transaction
+   *
+   * @param level one of the TRANSACTION_* isolation values with
+   *	the exception of TRANSACTION_NONE; some databases may
+   *	not support other values
+   * @exception SQLException if a database access error occurs
+   * @see java.sql.DatabaseMetaData#supportsTransactionIsolationLevel
+   */
+  public void setTransactionIsolation(int level) throws SQLException
+  {
+    throw new SQLException("Transaction Isolation Levels are not implemented");
+  }
+  
+  /**
+   * Get this Connection's current transaction isolation mode.
+   * 
+   * @return the current TRANSACTION_* mode value
+   * @exception SQLException if a database access error occurs
+   */
+  public int getTransactionIsolation() throws SQLException
+  {
+    return java.sql.Connection.TRANSACTION_SERIALIZABLE;
+  }
+  
+  /**
+   * The first warning reported by calls on this Connection is
+   * returned.
+   *
+   * <B>Note:</B> Sebsequent warnings will be changed to this
+   * SQLWarning
+   *
+   * @return the first SQLWarning or null
+   * @exception SQLException if a database access error occurs
+   */
+  public SQLWarning getWarnings() throws SQLException
+  {
+    return null;	// We handle warnings as errors
+  }
+  
+  /**
+   * After this call, getWarnings returns null until a new warning
+   * is reported for this connection.
+   *
+   * @exception SQLException if a database access error occurs
+   */
+  public void clearWarnings() throws SQLException
+  {
+    // Not handles since we handle wanrings as errors
+  }
+  
+  // **********************************************************
+  //		END OF PUBLIC INTERFACE
+  // **********************************************************
+  
+  /**
+   * Send a query to the backend.  Returns one of the ResultSet
+   * objects.
+   *
+   * <B>Note:</B> there does not seem to be any method currently
+   * in existance to return the update count.
+   *
+   * @param sql the SQL statement to be executed
+   * @return a ResultSet holding the results
+   * @exception SQLException if a database error occurs
+   */
+  public synchronized ResultSet ExecSQL(String sql) throws SQLException
+  {
+    Field[] fields = null;
+    Vector tuples = new Vector();
+    byte[] buf = new byte[sql.length()];
+    int fqp = 0;
+    boolean hfr = false;
+    String recv_status = null, msg;
+    SQLException final_error = null;
+    
+    if (sql.length() > 8192)
+      throw new SQLException("SQL Statement too long: " + sql);
+    try
+      {
+	pg_stream.SendChar('Q');
+	buf = sql.getBytes();
+	pg_stream.Send(buf);
+	pg_stream.SendChar(0);
+      } catch (IOException e) {
+	throw new SQLException("I/O Error: " + e.toString());
+      }
+      
+      while (!hfr || fqp > 0)
+	{
+	  int c = pg_stream.ReceiveChar();
+	  
+	  switch (c)
+	    {
+	    case 'A':	// Asynchronous Notify
+	      int pid = pg_stream.ReceiveInteger(4);
+	      msg = pg_stream.ReceiveString(8192);
+	      break;
+	    case 'B':	// Binary Data Transfer
+	      if (fields == null)
+		throw new SQLException("Tuple received before MetaData");
+	      tuples.addElement(pg_stream.ReceiveTuple(fields.length, true));
+	      break;
+	    case 'C':	// Command Status
+	      recv_status = pg_stream.ReceiveString(8192);
+	      if (fields != null)
+		hfr = true;
+	      else
 		{
-			String typname = pg_stream.ReceiveString(8192);
-			int typid = pg_stream.ReceiveInteger(4);
-			int typlen = pg_stream.ReceiveInteger(2);
-			fields[i] = new Field(this, typname, typid, typlen);
+		  try
+		    {
+		      pg_stream.SendChar('Q');
+		      pg_stream.SendChar(' ');
+		      pg_stream.SendChar(0);
+		    } catch (IOException e) {
+		      throw new SQLException("I/O Error: " + e.toString());
+		    }
+		    fqp++;
 		}
-		return fields;
-	}
-
-	/**
-	 * In SQL, a result table can be retrieved through a cursor that
-	 * is named.  The current row of a result can be updated or deleted
-	 * using a positioned update/delete statement that references the
-	 * cursor name.
-	 *
-	 * We support one cursor per connection.
-	 *
-	 * setCursorName sets the cursor name.
-	 *
-	 * @param cursor the cursor name
-	 * @exception SQLException if a database access error occurs
-	 */
-	public void setCursorName(String cursor) throws SQLException
-	{
-		this.cursor = cursor;
-	}
-	
-	/**
-	 * getCursorName gets the cursor name.
-	 *
-	 * @return the current cursor name
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String getCursorName() throws SQLException
-	{
-		return cursor;
-	}
-
-	/**
-	 * We are required to bring back certain information by
-	 * the DatabaseMetaData class.  These functions do that.
-	 *
-	 * Method getURL() brings back the URL (good job we saved it)
-	 *
-	 * @return the url
-	 * @exception SQLException just in case...
-	 */
-	public String getURL() throws SQLException
-	{
-		return this_url;
-	}
-
-	/**
-	 * Method getUserName() brings back the User Name (again, we
-	 * saved it)
-	 *
-	 * @return the user name
-	 * @exception SQLException just in case...
-	 */
-	public String getUserName() throws SQLException
-	{
-		return PG_USER;
-	}
+	      break;
+	    case 'D':	// Text Data Transfer
+	      if (fields == null)
+		throw new SQLException("Tuple received before MetaData");
+	      tuples.addElement(pg_stream.ReceiveTuple(fields.length, false));
+	      break;
+	    case 'E':	// Error Message
+	      msg = pg_stream.ReceiveString(4096);
+	      final_error = new SQLException(msg);
+	      hfr = true;
+	      break;
+	    case 'I':	// Empty Query
+	      int t = pg_stream.ReceiveChar();
+	      
+	      if (t != 0)
+		throw new SQLException("Garbled Data");
+	      if (fqp > 0)
+		fqp--;
+	      if (fqp == 0)
+		hfr = true;
+	      break;
+	    case 'N':	// Error Notification
+	      msg = pg_stream.ReceiveString(4096);
+	      PrintStream log = DriverManager.getLogStream();
+	      log.println(msg);
+	      break;
+	    case 'P':	// Portal Name
+	      String pname = pg_stream.ReceiveString(8192);
+	      break;
+	    case 'T':	// MetaData Field Description
+	      if (fields != null)
+		throw new SQLException("Cannot handle multiple result groups");
+	      fields = ReceiveFields();
+	      break;
+	    default:
+	      throw new SQLException("Unknown Response Type: " + (char)c);
+	    }
+	}
+      if (final_error != null)
+	throw final_error;
+      return new ResultSet(this, fields, tuples, recv_status, 1);
+  }
+  
+  /**
+   * Receive the field descriptions from the back end
+   *
+   * @return an array of the Field object describing the fields
+   * @exception SQLException if a database error occurs
+   */
+  private Field[] ReceiveFields() throws SQLException
+  {
+    int nf = pg_stream.ReceiveInteger(2), i;
+    Field[] fields = new Field[nf];
+    
+    for (i = 0 ; i < nf ; ++i)
+      {
+	String typname = pg_stream.ReceiveString(8192);
+	int typid = pg_stream.ReceiveInteger(4);
+	int typlen = pg_stream.ReceiveInteger(2);
+	fields[i] = new Field(this, typname, typid, typlen);
+      }
+    return fields;
+  }
+  
+  /**
+   * In SQL, a result table can be retrieved through a cursor that
+   * is named.  The current row of a result can be updated or deleted
+   * using a positioned update/delete statement that references the
+   * cursor name.
+   *
+   * We support one cursor per connection.
+   *
+   * setCursorName sets the cursor name.
+   *
+   * @param cursor the cursor name
+   * @exception SQLException if a database access error occurs
+   */
+  public void setCursorName(String cursor) throws SQLException
+  {
+    this.cursor = cursor;
+  }
+  
+  /**
+   * getCursorName gets the cursor name.
+   *
+   * @return the current cursor name
+   * @exception SQLException if a database access error occurs
+   */
+  public String getCursorName() throws SQLException
+  {
+    return cursor;
+  }
+  
+  /**
+   * We are required to bring back certain information by
+   * the DatabaseMetaData class.  These functions do that.
+   *
+   * Method getURL() brings back the URL (good job we saved it)
+   *
+   * @return the url
+   * @exception SQLException just in case...
+   */
+  public String getURL() throws SQLException
+  {
+    return this_url;
+  }
+  
+  /**
+   * Method getUserName() brings back the User Name (again, we
+   * saved it)
+   *
+   * @return the user name
+   * @exception SQLException just in case...
+   */
+  public String getUserName() throws SQLException
+  {
+    return PG_USER;
+  }
 }
 
 // ***********************************************************************
@@ -599,249 +598,249 @@ public class Connection implements java.sql.Connection
 //  This class handles all the Streamed I/O for a postgresql connection
 class PG_Stream
 {
-	private Socket connection;
-	private InputStream pg_input;
-	private OutputStream pg_output;
-
-	/**
-	 * Constructor:  Connect to the PostgreSQL back end and return
-	 * a stream connection.
-	 *
-	 * @param host the hostname to connect to
-	 * @param port the port number that the postmaster is sitting on
-	 * @exception IOException if an IOException occurs below it.
-	 */
-	public PG_Stream(String host, int port) throws IOException
-	{
-		connection = new Socket(host, port);
-		pg_input = connection.getInputStream();
-		pg_output = connection.getOutputStream();	
-	}
-
-	/**
-	 * Sends a single character to the back end
-	 *
-	 * @param val the character to be sent
-	 * @exception IOException if an I/O error occurs
-	 */
-	public void SendChar(int val) throws IOException
-	{
-		pg_output.write(val);
-	}
-
-	/**
-	 * Sends an integer to the back end
-	 *
-	 * @param val the integer to be sent
-	 * @param siz the length of the integer in bytes (size of structure)
-	 * @exception IOException if an I/O error occurs
-	 */
-	public void SendInteger(int val, int siz) throws IOException
-	{
-		byte[] buf = new byte[siz];
-
-		while (siz-- > 0)
-		{
-			buf[siz] = (byte)(val & 0xff);
-			val >>= 8;
-		}
-		Send(buf);
-	}
-
-	/**
-	 * Send an array of bytes to the backend
-	 *
-	 * @param buf The array of bytes to be sent
-	 * @exception IOException if an I/O error occurs
-	 */
-	public void Send(byte buf[]) throws IOException
-	{
-		pg_output.write(buf);
-	}
-
-	/**
-	 * Send an exact array of bytes to the backend - if the length
-	 * has not been reached, send nulls until it has.
-	 *
-	 * @param buf the array of bytes to be sent
-	 * @param siz the number of bytes to be sent
-	 * @exception IOException if an I/O error occurs
-	 */
-	public void Send(byte buf[], int siz) throws IOException
-	{
-		int i;
-
-		pg_output.write(buf, 0, (buf.length < siz ? buf.length : siz));
-		if (buf.length < siz)
-		{
-			for (i = buf.length ; i < siz ; ++i)
-			{
-				pg_output.write(0);
-			}
-		}
-	}
-
-	/**
-	 * Receives a single character from the backend
-	 *
-	 * @return the character received
-	 * @exception SQLException if an I/O Error returns
-	 */
-	public int ReceiveChar() throws SQLException
-	{
-		int c = 0;
-	
-		try
-		{
-			c = pg_input.read();
-			if (c < 0) throw new IOException("EOF");
-		} catch (IOException e) {
-			throw new SQLException("Error reading from backend: " + e.toString());
-		}
-		return c;
-	}
-
-	/**
-	 * Receives an integer from the backend
-	 *
-	 * @param siz length of the integer in bytes
-	 * @return the integer received from the backend
-	 * @exception SQLException if an I/O error occurs
-	 */
-	public int ReceiveInteger(int siz) throws SQLException
-	{
-		int n = 0;
-		
-		try
-		{
-			for (int i = 0 ; i < siz ; i++)
-			{
-				int b = pg_input.read();
-			
-				if (b < 0)
-					throw new IOException("EOF");
-				n = n | (b >> (8 * i)) ;
-			}
-		} catch (IOException e) {
-			throw new SQLException("Error reading from backend: " + e.toString());
-		}
-		return n;
-	}
-
-	/**
-	 * Receives a null-terminated string from the backend.  Maximum of
-	 * maxsiz bytes - if we don't see a null, then we assume something
-	 * has gone wrong.
-	 *
-	 * @param maxsiz maximum length of string
-	 * @return string from back end
-	 * @exception SQLException if an I/O error occurs
-	 */
-	public String ReceiveString(int maxsiz) throws SQLException
-	{
-		byte[] rst = new byte[maxsiz];
-		int s = 0;
-
-		try
-		{
-			while (s < maxsiz)
-			{
-				int c = pg_input.read();
-				if (c < 0)
-					throw new IOException("EOF");
-				else if (c == 0)
-					break;
-				else
-					rst[s++] = (byte)c;
-			}
-			if (s >= maxsiz)
-				throw new IOException("Too Much Data");
-		} catch (IOException e) {
-			throw new SQLException("Error reading from backend: " + e.toString());
-		}
-		String v = new String(rst, 0, s);
-		return v;
-	}
-
-	/**
-	 * Read a tuple from the back end.  A tuple is a two dimensional
-	 * array of bytes
-	 *
-	 * @param nf the number of fields expected
-	 * @param bin true if the tuple is a binary tuple
-	 * @return null if the current response has no more tuples, otherwise
-	 *	an array of strings
-	 * @exception SQLException if a data I/O error occurs
-	 */
-	public byte[][] ReceiveTuple(int nf, boolean bin) throws SQLException
-	{
-		int i, bim = (nf + 7)/8;
-		byte[] bitmask = Receive(bim);
-		byte[][] answer = new byte[nf][0];
-
-		int whichbit = 0x80;
-		int whichbyte = 0;
-		
-		for (i = 0 ; i < nf ; ++i)
-		{
-			boolean isNull = ((bitmask[whichbyte] & whichbit) == 0);
-			whichbit >>= 1;
-			if (whichbit == 0)
-			{
-				++whichbyte;
-				whichbit = 0x80;
-			}
-			if (isNull) 
-				answer[i] = null;
-			else
-			{
-				int len = ReceiveInteger(4);
-				if (!bin) 
-					len -= 4;
-				if (len < 0) 
-					len = 0;
-				answer[i] = Receive(len);
-			}
-		}
-		return answer;
-	}
-
-	/**
-	 * Reads in a given number of bytes from the backend
-	 *
-	 * @param siz number of bytes to read
-	 * @return array of bytes received
-	 * @exception SQLException if a data I/O error occurs
-	 */
-	private byte[] Receive(int siz) throws SQLException
-	{
-		byte[] answer = new byte[siz];
-		int s = 0;
-
-		try 
-		{
-			while (s < siz)
-			{
-				int w = pg_input.read(answer, s, siz - s);
-				if (w < 0)
-					throw new IOException("EOF");
-				s += w;
-			}
-		} catch (IOException e) {
-			throw new SQLException("Error reading from backend: " + e.toString());
-		}
-		return answer;
-	}
-	
-	/**
-	 * Closes the connection
-	 *
-	 * @exception IOException if a IO Error occurs
-	 */
-	public void close() throws IOException
-	{
-		pg_output.close();
-		pg_input.close();
-		connection.close();
-	}
+  private Socket connection;
+  private InputStream pg_input;
+  private OutputStream pg_output;
+  
+  /**
+   * Constructor:  Connect to the PostgreSQL back end and return
+   * a stream connection.
+   *
+   * @param host the hostname to connect to
+   * @param port the port number that the postmaster is sitting on
+   * @exception IOException if an IOException occurs below it.
+   */
+  public PG_Stream(String host, int port) throws IOException
+  {
+    connection = new Socket(host, port);
+    pg_input = connection.getInputStream();
+    pg_output = connection.getOutputStream();	
+  }
+  
+  /**
+   * Sends a single character to the back end
+   *
+   * @param val the character to be sent
+   * @exception IOException if an I/O error occurs
+   */
+  public void SendChar(int val) throws IOException
+  {
+    pg_output.write(val);
+  }
+  
+  /**
+   * Sends an integer to the back end
+   *
+   * @param val the integer to be sent
+   * @param siz the length of the integer in bytes (size of structure)
+   * @exception IOException if an I/O error occurs
+   */
+  public void SendInteger(int val, int siz) throws IOException
+  {
+    byte[] buf = new byte[siz];
+    
+    while (siz-- > 0)
+      {
+	buf[siz] = (byte)(val & 0xff);
+	val >>= 8;
+      }
+    Send(buf);
+  }
+  
+  /**
+   * Send an array of bytes to the backend
+   *
+   * @param buf The array of bytes to be sent
+   * @exception IOException if an I/O error occurs
+   */
+  public void Send(byte buf[]) throws IOException
+  {
+    pg_output.write(buf);
+  }
+  
+  /**
+   * Send an exact array of bytes to the backend - if the length
+   * has not been reached, send nulls until it has.
+   *
+   * @param buf the array of bytes to be sent
+   * @param siz the number of bytes to be sent
+   * @exception IOException if an I/O error occurs
+   */
+  public void Send(byte buf[], int siz) throws IOException
+  {
+    int i;
+    
+    pg_output.write(buf, 0, (buf.length < siz ? buf.length : siz));
+    if (buf.length < siz)
+      {
+	for (i = buf.length ; i < siz ; ++i)
+	  {
+	    pg_output.write(0);
+	  }
+      }
+  }
+  
+  /**
+   * Receives a single character from the backend
+   *
+   * @return the character received
+   * @exception SQLException if an I/O Error returns
+   */
+  public int ReceiveChar() throws SQLException
+  {
+    int c = 0;
+    
+    try
+      {
+	c = pg_input.read();
+	if (c < 0) throw new IOException("EOF");
+      } catch (IOException e) {
+	throw new SQLException("Error reading from backend: " + e.toString());
+      }
+      return c;
+  }
+  
+  /**
+   * Receives an integer from the backend
+   *
+   * @param siz length of the integer in bytes
+   * @return the integer received from the backend
+   * @exception SQLException if an I/O error occurs
+   */
+  public int ReceiveInteger(int siz) throws SQLException
+  {
+    int n = 0;
+    
+    try
+      {
+	for (int i = 0 ; i < siz ; i++)
+	  {
+	    int b = pg_input.read();
+	    
+	    if (b < 0)
+	      throw new IOException("EOF");
+	    n = n | (b >> (8 * i)) ;
+	  }
+      } catch (IOException e) {
+	throw new SQLException("Error reading from backend: " + e.toString());
+      }
+      return n;
+  }
+  
+  /**
+   * Receives a null-terminated string from the backend.  Maximum of
+   * maxsiz bytes - if we don't see a null, then we assume something
+   * has gone wrong.
+   *
+   * @param maxsiz maximum length of string
+   * @return string from back end
+   * @exception SQLException if an I/O error occurs
+   */
+  public String ReceiveString(int maxsiz) throws SQLException
+  {
+    byte[] rst = new byte[maxsiz];
+    int s = 0;
+    
+    try
+      {
+	while (s < maxsiz)
+	  {
+	    int c = pg_input.read();
+	    if (c < 0)
+	      throw new IOException("EOF");
+	    else if (c == 0)
+	      break;
+	    else
+	      rst[s++] = (byte)c;
+	  }
+	if (s >= maxsiz)
+	  throw new IOException("Too Much Data");
+      } catch (IOException e) {
+	throw new SQLException("Error reading from backend: " + e.toString());
+      }
+      String v = new String(rst, 0, s);
+      return v;
+  }
+  
+  /**
+   * Read a tuple from the back end.  A tuple is a two dimensional
+   * array of bytes
+   *
+   * @param nf the number of fields expected
+   * @param bin true if the tuple is a binary tuple
+   * @return null if the current response has no more tuples, otherwise
+   *	an array of strings
+   * @exception SQLException if a data I/O error occurs
+   */
+  public byte[][] ReceiveTuple(int nf, boolean bin) throws SQLException
+  {
+    int i, bim = (nf + 7)/8;
+    byte[] bitmask = Receive(bim);
+    byte[][] answer = new byte[nf][0];
+    
+    int whichbit = 0x80;
+    int whichbyte = 0;
+    
+    for (i = 0 ; i < nf ; ++i)
+      {
+	boolean isNull = ((bitmask[whichbyte] & whichbit) == 0);
+	whichbit >>= 1;
+	if (whichbit == 0)
+	  {
+	    ++whichbyte;
+	    whichbit = 0x80;
+	  }
+	if (isNull) 
+	  answer[i] = null;
+	else
+	  {
+	    int len = ReceiveInteger(4);
+	    if (!bin) 
+	      len -= 4;
+	    if (len < 0) 
+	      len = 0;
+	    answer[i] = Receive(len);
+	  }
+      }
+    return answer;
+  }
+  
+  /**
+   * Reads in a given number of bytes from the backend
+   *
+   * @param siz number of bytes to read
+   * @return array of bytes received
+   * @exception SQLException if a data I/O error occurs
+   */
+  private byte[] Receive(int siz) throws SQLException
+  {
+    byte[] answer = new byte[siz];
+    int s = 0;
+    
+    try 
+      {
+	while (s < siz)
+	  {
+	    int w = pg_input.read(answer, s, siz - s);
+	    if (w < 0)
+	      throw new IOException("EOF");
+	    s += w;
+	  }
+      } catch (IOException e) {
+	throw new SQLException("Error reading from backend: " + e.toString());
+      }
+      return answer;
+  }
+  
+  /**
+   * Closes the connection
+   *
+   * @exception IOException if a IO Error occurs
+   */
+  public void close() throws IOException
+  {
+    pg_output.close();
+    pg_input.close();
+    connection.close();
+  }
 }
diff --git a/src/interfaces/jdbc/postgresql/DatabaseMetaData.java b/src/interfaces/jdbc/postgresql/DatabaseMetaData.java
index 259829c3fb4..00485b25856 100644
--- a/src/interfaces/jdbc/postgresql/DatabaseMetaData.java
+++ b/src/interfaces/jdbc/postgresql/DatabaseMetaData.java
@@ -1,6 +1,7 @@
 package postgresql;
 
 import java.sql.*;
+import java.util.*;
 
 /**
  * @version 1.0 15-APR-1997
@@ -30,1527 +31,2053 @@ import java.sql.*;
  */
 public class DatabaseMetaData implements java.sql.DatabaseMetaData 
 {
-	Connection connection;		// The connection association
-
-	public DatabaseMetaData(Connection conn)
-	{
-		this.connection = conn;
-	}
-
-	/**
-	 * Can all the procedures returned by getProcedures be called
-	 * by the current user?
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean allProceduresAreCallable() throws SQLException
-	{
-		return true;		// For now...
-	}
-
-	/**
-	 * Can all the tables returned by getTable be SELECTed by
-	 * the current user?
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean allTablesAreSelectable() throws SQLException
-	{
-		return true;		// For now...
-	}
-
-	/**
-	 * What is the URL for this database?
-	 *
-	 * @return the url or null if it cannott be generated
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String getURL() throws SQLException
-	{
-		return connection.getURL();
-	}
-
-	/**
-	 * What is our user name as known to the database?
-	 *
-	 * @return our database user name
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String getUserName() throws SQLException
-	{
-		return connection.getUserName();
-	}
-
-	/**
-	 * Is the database in read-only mode?
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean isReadOnly() throws SQLException
-	{
-		return connection.isReadOnly();
-	}
-
-	/**
-	 * Are NULL values sorted high?
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean nullsAreSortedHigh() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Are NULL values sorted low?
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean nullsAreSortedLow() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Are NULL values sorted at the start regardless of sort order?
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean nullsAreSortedAtStart() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Are NULL values sorted at the end regardless of sort order?
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean nullsAreSortedAtEnd() throws SQLException
-	{
-		return true;
-	}
-
-	/**
-	 * What is the name of this database product - we hope that it is
-	 * PostgreSQL, so we return that explicitly.
-	 *
-	 * @return the database product name
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String getDatabaseProductName() throws SQLException
-	{
-		return new String("PostgreSQL");
-	}
-
-	/**
-	 * What is the version of this database product.  Note that
-	 * PostgreSQL 6.1 has a system catalog called pg_version - 
-	 * however, select * from pg_version on any database retrieves
-	 * no rows.  For now, we will return the version 6.1 (in the
-	 * hopes that we change this driver as often as we change the
-	 * database)
-	 *
-	 * @return the database version
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String getDatabaseProductVersion() throws SQLException
-	{
-		return ("6.1");
-	}
-
-	/**
-	 * What is the name of this JDBC driver?  If we don't know this
-	 * we are doing something wrong!
-	 *
-	 * @return the JDBC driver name
-	 * @exception SQLException why?
-	 */
-	public String getDriverName() throws SQLException
-	{
-		return new String("PostgreSQL Native Driver");
-	}
-
-	/**
-	 * What is the version string of this JDBC driver?  Again, this is
-	 * static.
-	 *
-	 * @return the JDBC driver name.
-	 * @exception SQLException why?
-	 */
-	public String getDriverVersion() throws SQLException
-	{
-		return new String("1.0");
-	}
-
-	/**
-	 * What is this JDBC driver's major version number?
-	 *
-	 * @return the JDBC driver major version
-	 */
-	public int getDriverMajorVersion()
-	{
-		return 1;
-	}
-
-	/**
-	 * What is this JDBC driver's minor version number?
-	 *
-	 * @return the JDBC driver minor version
-	 */
-	public int getDriverMinorVersion()
-	{
-		return 0;
-	}
-
-	/**
-	 * Does the database store tables in a local file?  No - it
-	 * stores them in a file on the server.
-	 * 
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean usesLocalFiles() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Does the database use a file for each table?  Well, not really,
-	 * since it doesnt use local files. 
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean usesLocalFilePerTable() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Does the database treat mixed case unquoted SQL identifiers
-	 * as case sensitive and as a result store them in mixed case?
-	 * A JDBC-Compliant driver will always return false.
-	 *
-	 * Predicament - what do they mean by "SQL identifiers" - if it
-	 * means the names of the tables and columns, then the answers
-	 * given below are correct - otherwise I don't know.
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsMixedCaseIdentifiers() throws SQLException
-	{
-		return true;
-	}
-
-	/**
-	 * Does the database treat mixed case unquoted SQL identifiers as
-	 * case insensitive and store them in upper case?
-	 *
-	 * @return true if so
-	 */
-	public boolean storesUpperCaseIdentifiers() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Does the database treat mixed case unquoted SQL identifiers as
-	 * case insensitive and store them in lower case?
-	 *
-	 * @return true if so
-	 */
-	public boolean storesLowerCaseIdentifiers() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Does the database treat mixed case unquoted SQL identifiers as
-	 * case insensitive and store them in mixed case?
-	 *
-	 * @return true if so
-	 */
-	public boolean storesMixedCaseIdentifiers() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Does the database treat mixed case quoted SQL identifiers as
-	 * case sensitive and as a result store them in mixed case?  A
-	 * JDBC compliant driver will always return true. 
-	 *
-	 * Predicament - what do they mean by "SQL identifiers" - if it
-	 * means the names of the tables and columns, then the answers
-	 * given below are correct - otherwise I don't know.
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException
-	{
-		return true;
-	}
-
-	/**
-	 * Does the database treat mixed case quoted SQL identifiers as
-	 * case insensitive and store them in upper case?
-	 *
-	 * @return true if so
-	 */
-	public boolean storesUpperCaseQuotedIdentifiers() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Does the database treat mixed case quoted SQL identifiers as case
-	 * insensitive and store them in lower case?
-	 *
-	 * @return true if so
-	 */
-	public boolean storesLowerCaseQuotedIdentifiers() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Does the database treat mixed case quoted SQL identifiers as case
-	 * insensitive and store them in mixed case?
-	 *
-	 * @return true if so
-	 */
-	public boolean storesMixedCaseQuotedIdentifiers() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * What is the string used to quote SQL identifiers?  This returns
-	 * a space if identifier quoting isn't supported.  A JDBC Compliant
-	 * driver will always use a double quote character.
-	 *
-	 * If an SQL identifier is a table name, column name, etc. then
-	 * we do not support it.
-	 *
-	 * @return the quoting string
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String getIdentifierQuoteString() throws SQLException
-	{
-		return new String(" ");
-	}
-
-	/**
-	 * Get a comma separated list of all a database's SQL keywords that
-	 * are NOT also SQL92 keywords.
-	 *
-	 * Within PostgreSQL, the keywords are found in
-	 * 	src/backend/parser/keywords.c
-	 * For SQL Keywords, I took the list provided at
-	 * 	http://web.dementia.org/~shadow/sql/sql3bnf.sep93.txt
-	 * which is for SQL3, not SQL-92, but it is close enough for
-	 * this purpose.
-	 *
-	 * @return a comma separated list of keywords we use
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String getSQLKeywords() throws SQLException
-	{
-		return new String("abort,acl,add,aggregate,append,archive,arch_store,backward,binary,change,cluster,copy,database,delimiters,do,extend,explain,forward,heavy,index,inherits,isnull,light,listen,load,merge,nothing,notify,notnull,oids,purge,rename,replace,retrieve,returns,rule,recipe,setof,stdin,stdout,store,vacuum,verbose,version");
-	}
-
-	public String getNumericFunctions() throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public String getStringFunctions() throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public String getSystemFunctions() throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public String getTimeDateFunctions() throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	/**
-	 * This is the string that can be used to escape '_' and '%' in
-	 * a search string pattern style catalog search parameters
-	 *
-	 * @return the string used to escape wildcard characters
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String getSearchStringEscape() throws SQLException
-	{
-		return new String("\\");
-	}
-
-	/**
-	 * Get all the "extra" characters that can bew used in unquoted
-	 * identifier names (those beyond a-zA-Z0-9 and _)
-	 *
-	 * From the file src/backend/parser/scan.l, an identifier is
-	 * {letter}{letter_or_digit} which makes it just those listed
-	 * above.
-	 *
-	 * @return a string containing the extra characters
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String getExtraNameCharacters() throws SQLException
-	{
-		return new String("");
-	}
-
-	/**
-	 * Is "ALTER TABLE" with an add column supported?
-	 * Yes for PostgreSQL 6.1
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsAlterTableWithAddColumn() throws SQLException
-	{
-		return true;
-	}
-
-	/**
-	 * Is "ALTER TABLE" with a drop column supported?
-	 * Yes for PostgreSQL 6.1
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsAlterTableWithDropColumn() throws SQLException
-	{
-		return true;
-	}
-
-	/**
-	 * Is column aliasing supported?
-	 *
-	 * If so, the SQL AS clause can be used to provide names for
-	 * computed columns or to provide alias names for columns as
-	 * required.  A JDBC Compliant driver always returns true.
-	 *
-	 * e.g.
-	 *
-	 * select count(C) as C_COUNT from T group by C;
-	 *
-	 * should return a column named as C_COUNT instead of count(C)
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsColumnAliasing() throws SQLException
-	{
-		return true;
-	}
-
-	/**
-	 * Are concatenations between NULL and non-NULL values NULL?  A
-	 * JDBC Compliant driver always returns true
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean nullPlusNonNullIsNull() throws SQLException
-	{
-		return true;
-	}
-
-	public boolean supportsConvert() throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public boolean supportsConvert(int fromType, int toType) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public boolean supportsTableCorrelationNames() throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public boolean supportsDifferentTableCorrelationNames() throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	/**
-	 * Are expressions in "ORCER BY" lists supported?
-	 * 
-	 * e.g. select * from t order by a + b;
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsExpressionsInOrderBy() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Can an "ORDER BY" clause use columns not in the SELECT?
-	 * I checked it, and you can't.
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsOrderByUnrelated() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Is some form of "GROUP BY" clause supported?
-	 * I checked it, and yes it is.
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsGroupBy() throws SQLException
-	{
-		return true;
-	}
-
-	/**
-	 * Can a "GROUP BY" clause use columns not in the SELECT?
-	 * I checked it - it seems to allow it
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsGroupByUnrelated() throws SQLException
-	{
-		return true;
-	}
-
-	/**
-	 * Can a "GROUP BY" clause add columns not in the SELECT provided
-	 * it specifies all the columns in the SELECT?  Does anyone actually
-	 * understand what they mean here?
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsGroupByBeyondSelect() throws SQLException
-	{
-		return true;		// For now...
-	}
-
-	/**
-	 * Is the escape character in "LIKE" clauses supported?  A
-	 * JDBC compliant driver always returns true.
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsLikeEscapeClause() throws SQLException
-	{
-		return true;
-	}
-
-	/**
-	 * Are multiple ResultSets from a single execute supported?
-	 * Well, I implemented it, but I dont think this is possible from
-	 * the back ends point of view.
-	 * 
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsMultipleResultSets() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Can we have multiple transactions open at once (on different
-	 * connections?)
-	 * I guess we can have, since Im relying on it.
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsMultipleTransactions() throws SQLException
-	{
-		return true;
-	}
-
-	/**
-	 * Can columns be defined as non-nullable.  A JDBC Compliant driver
-	 * always returns true.  We dont support NOT NULL, so we are not
-	 * JDBC compliant.
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsNonNullableColumns() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Does this driver support the minimum ODBC SQL grammar.  This
-	 * grammar is defined at:
-	 *
-	 * http://www.microsoft.com/msdn/sdk/platforms/doc/odbc/src/intropr.htm
-	 *
-	 * In Appendix C.  From this description, we seem to support the
-	 * ODBC minimal (Level 0) grammar.
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsMinimumSQLGrammar() throws SQLException
-	{
-		return true;
-	}
-
-	/**
-	 * Does this driver support the Core ODBC SQL grammar.  We need
-	 * SQL-92 conformance for this.
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsCoreSQLGrammar() throws SQLException
-	{
-		return false;
-	}
-	
-	/**
-	 * Does this driver support the Extended (Level 2) ODBC SQL
-	 * grammar.  We don't conform to the Core (Level 1), so we can't
-	 * conform to the Extended SQL Grammar.
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsExtendedSQLGrammar() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Does this driver support the ANSI-92 entry level SQL grammar?
-	 * All JDBC Compliant drivers must return true.  I think we have
-	 * to support outer joins for this to be true.
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsANSI92EntryLevelSQL() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Does this driver support the ANSI-92 intermediate level SQL
-	 * grammar?  Anyone who does not support Entry level cannot support
-	 * Intermediate level.
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsANSI92IntermediateSQL() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Does this driver support the ANSI-92 full SQL grammar?
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsANSI92FullSQL() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Is the SQL Integrity Enhancement Facility supported?
-	 * I haven't seen this mentioned anywhere, so I guess not
-	 * 
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsIntegrityEnhancementFacility() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Is some form of outer join supported?  From my knowledge, nope.
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsOuterJoins() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Are full nexted outer joins supported?  Well, we dont support any
-	 * form of outer join, so this is no as well
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsFullOuterJoins() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Is there limited support for outer joins?  (This will be true if
-	 * supportFullOuterJoins is true)
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsLimitedOuterJoins() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * What is the database vendor's preferred term for "schema" - well,
-	 * we do not provide support for schemas, so lets just use that
-	 * term.
-	 *
-	 * @return the vendor term
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String getSchemaTerm() throws SQLException
-	{
-		return new String("Schema");
-	}
-
-	/**
-	 * What is the database vendor's preferred term for "procedure" - 
-	 * I kind of like "Procedure" myself.
-	 *
-	 * @return the vendor term
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String getProcedureTerm() throws SQLException
-	{
-		return new String("Procedure");
-	}
-
-	/**
-	 * What is the database vendor's preferred term for "catalog"? -
-	 * we dont have a preferred term, so just use Catalog
-	 *
-	 * @return the vendor term
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String getCatalogTerm() throws SQLException
-	{
-		return new String("Catalog");
-	}
-
-	/**
-	 * Does a catalog appear at the start of a qualified table name?
-	 * (Otherwise it appears at the end).
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean isCatalogAtStart() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * What is the Catalog separator.  Hmmm....well, I kind of like
-	 * a period (so we get catalog.table definitions). - I don't think
-	 * PostgreSQL supports catalogs anyhow, so it makes no difference.
-	 *
-	 * @return the catalog separator string
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String getCatalogSeparator() throws SQLException
-	{
-		return new String(".");
-	}
-
-	/**
-	 * Can a schema name be used in a data manipulation statement?  Nope.
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsSchemasInDataManipulation() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Can a schema name be used in a procedure call statement?  Nope.
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsSchemasInProcedureCalls() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Can a schema be used in a table definition statement?  Nope.
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsSchemasInTableDefinitions() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Can a schema name be used in an index definition statement?
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsSchemasInIndexDefinitions() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Can a schema name be used in a privilege definition statement?
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Can a catalog name be used in a data manipulation statement?
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsCatalogsInDataManipulation() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Can a catalog name be used in a procedure call statement?
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsCatalogsInProcedureCalls() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Can a catalog name be used in a table definition statement?
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsCatalogsInTableDefinitions() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Can a catalog name be used in an index definition?
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsCatalogsInIndexDefinitions() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Can a catalog name be used in a privilege definition statement?
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * We support cursors for gets only it seems.  I dont see a method
-	 * to get a positioned delete.
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsPositionedDelete() throws SQLException
-	{
-		return false;			// For now...
-	}
-
-	/**
-	 * Is positioned UPDATE supported?
-	 * 
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsPositionedUpdate() throws SQLException
-	{
-		return false;			// For now...
-	}
-
-	public boolean supportsSelectForUpdate() throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public boolean supportsStoredProcedures() throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public boolean supportsSubqueriesInComparisons() throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public boolean supportsSubqueriesInExists() throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public boolean supportsSubqueriesInIns() throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public boolean supportsSubqueriesInQuantifieds() throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public boolean supportsCorrelatedSubqueries() throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	/**
-	 * Is SQL UNION supported?  Nope.
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsUnion() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Is SQL UNION ALL supported?  Nope.
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsUnionAll() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * In PostgreSQL, Cursors are only open within transactions.
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsOpenCursorsAcrossCommit() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Do we support open cursors across multiple transactions?
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsOpenCursorsAcrossRollback() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Can statements remain open across commits?  They may, but
-	 * this driver cannot guarentee that.  In further reflection.
-	 * we are talking a Statement object jere, so the answer is
-	 * yes, since the Statement is only a vehicle to ExecSQL()
-	 *
-	 * @return true if they always remain open; false otherwise
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsOpenStatementsAcrossCommit() throws SQLException
-	{
-		return true;
-	}
-
-	/**
-	 * Can statements remain open across rollbacks?  They may, but
-	 * this driver cannot guarentee that.  In further contemplation,
-	 * we are talking a Statement object here, so the answer is yes,
-	 * since the Statement is only a vehicle to ExecSQL() in Connection
-	 *
-	 * @return true if they always remain open; false otherwise
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsOpenStatementsAcrossRollback() throws SQLException
-	{
-		return true;
-	}
-
-	/**
-	 * How many hex characters can you have in an inline binary literal
-	 *
-	 * @return the max literal length
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getMaxBinaryLiteralLength() throws SQLException
-	{
-		return 0;				// For now...
-	}
-
-	/**
-	 * What is the maximum length for a character literal
-	 * I suppose it is 8190 (8192 - 2 for the quotes)
-	 *
-	 * @return the max literal length
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getMaxCharLiteralLength() throws SQLException
-	{
-		return 8190;
-	}
-
-	/**
-	 * Whats the limit on column name length.  The description of
-	 * pg_class would say '32' (length of pg_class.relname) - we
-	 * should probably do a query for this....but....
-	 *
-	 * @return the maximum column name length
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getMaxColumnNameLength() throws SQLException
-	{
-		return 32;
-	}
-
-	/**
-	 * What is the maximum number of columns in a "GROUP BY" clause?
-	 *
-	 * @return the max number of columns
-	 * @exception SQLException if a database access error occurs	
-	 */
-	public int getMaxColumnsInGroupBy() throws SQLException
-	{
-		return getMaxColumnsInTable();
-	}
-
-	/**
-	 * What's the maximum number of columns allowed in an index?
-	 * 6.0 only allowed one column, but 6.1 introduced multi-column
-	 * indices, so, theoretically, its all of them.
-	 *
-	 * @return max number of columns
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getMaxColumnsInIndex() throws SQLException
-	{
-		return getMaxColumnsInTable();
-	}
-
-	/**
-	 * What's the maximum number of columns in an "ORDER BY clause?
-	 * Theoretically, all of them!
-	 *
-	 * @return the max columns
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getMaxColumnsInOrderBy() throws SQLException
-	{
-		return getMaxColumnsInTable();
-	}
-
-	/**
-	 * What is the maximum number of columns in a "SELECT" list?
-	 * Theoretically, all of them!
-	 *
-	 * @return the max columns
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getMaxColumnsInSelect() throws SQLException
-	{
-		return getMaxColumnsInTable();
-	}
-
-	/**
-	 * What is the maximum number of columns in a table? From the
-	 * create_table(l) manual page...
-	 *
-	 * "The new class is created as a heap with no initial data.  A
-	 * class can have no more than 1600 attributes (realistically,
-	 * this is limited by the fact that tuple sizes must be less than
-	 * 8192 bytes)..."
-	 *
-	 * @return the max columns
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getMaxColumnsInTable() throws SQLException
-	{
-		return 1600;
-	}
-
-	/**
-	 * How many active connection can we have at a time to this
-	 * database?  Well, since it depends on postmaster, which just
-	 * does a listen() followed by an accept() and fork(), its
-	 * basically very high.  Unless the system runs out of processes,
-	 * it can be 65535 (the number of aux. ports on a TCP/IP system).
-	 * I will return 8192 since that is what even the largest system
-	 * can realistically handle,
-	 *
-	 * @return the maximum number of connections
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getMaxConnections() throws SQLException
-	{
-		return 8192;
-	}
-
-	/**
-	 * What is the maximum cursor name length (the same as all
-	 * the other F***** identifiers!)
-	 *
-	 * @return max cursor name length in bytes
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getMaxCursorNameLength() throws SQLException
-	{
-		return 32;
-	}
-
-	/**
-	 * What is the maximum length of an index (in bytes)?  Now, does
-	 * the spec. mean name of an index (in which case its 32, the 
-	 * same as a table) or does it mean length of an index element
-	 * (in which case its 8192, the size of a row) or does it mean
-	 * the number of rows it can access (in which case it 2^32 - 
-	 * a 4 byte OID number)?  I think its the length of an index
-	 * element, personally, so Im setting it to 8192.
-	 *
-	 * @return max index length in bytes
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getMaxIndexLength() throws SQLException
-	{
-		return 8192;
-	}
-
-	public int getMaxSchemaNameLength() throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	/**
-	 * What is the maximum length of a procedure name?
-	 * (length of pg_proc.proname used) - again, I really
-	 * should do a query here to get it.
-	 *
-	 * @return the max name length in bytes
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getMaxProcedureNameLength() throws SQLException
-	{
-		return 32;
-	}
-
-	public int getMaxCatalogNameLength() throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	/**
-	 * What is the maximum length of a single row?  (not including
-	 * blobs).  8192 is defined in PostgreSQL.
-	 *
-	 * @return max row size in bytes
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getMaxRowSize() throws SQLException
-	{
-		return 8192;
-	}
-
-	/**
-	 * Did getMaxRowSize() include LONGVARCHAR and LONGVARBINARY
-	 * blobs?  We don't handle blobs yet
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean doesMaxRowSizeIncludeBlobs() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * What is the maximum length of a SQL statement?
-	 *
-	 * @return max length in bytes
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getMaxStatementLength() throws SQLException
-	{
-		return 8192;
-	}
-
-	/**
-	 * How many active statements can we have open at one time to
-	 * this database?  Basically, since each Statement downloads
-	 * the results as the query is executed, we can have many.  However,
-	 * we can only really have one statement per connection going
-	 * at once (since they are executed serially) - so we return
-	 * one.
-	 *
-	 * @return the maximum
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getMaxStatements() throws SQLException
-	{
-		return 1;
-	}
-
-	/**
-	 * What is the maximum length of a table name?  This was found
-	 * from pg_class.relname length
-	 *
-	 * @return max name length in bytes
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getMaxTableNameLength() throws SQLException
-	{
-		return 32;
-	}
-
-	/**
-	 * What is the maximum number of tables that can be specified
-	 * in a SELECT?  Theoretically, this is the same number as the
-	 * number of tables allowable.  In practice tho, it is much smaller
-	 * since the number of tables is limited by the statement, we
-	 * return 1024 here - this is just a number I came up with (being
-	 * the number of tables roughly of three characters each that you
-	 * can fit inside a 8192 character buffer with comma separators).
-	 *
-	 * @return the maximum
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getMaxTablesInSelect() throws SQLException
-	{
-		return 1024;
-	}
-
-	/**
-	 * What is the maximum length of a user name?  Well, we generally
-	 * use UNIX like user names in PostgreSQL, so I think this would
-	 * be 8.  However, showing the schema for pg_user shows a length
-	 * for username of 32.
-	 *
-	 * @return the max name length in bytes
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getMaxUserNameLength() throws SQLException
-	{
-		return 32;
-	}
-
+  Connection connection;		// The connection association
+  
+  public DatabaseMetaData(Connection conn)
+  {
+    this.connection = conn;
+  }
+  
+  /**
+   * Can all the procedures returned by getProcedures be called
+   * by the current user?
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean allProceduresAreCallable() throws SQLException
+  {
+    return true;		// For now...
+  }
+  
+  /**
+   * Can all the tables returned by getTable be SELECTed by
+   * the current user?
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean allTablesAreSelectable() throws SQLException
+  {
+    return true;		// For now...
+  }
+  
+  /**
+   * What is the URL for this database?
+   *
+   * @return the url or null if it cannott be generated
+   * @exception SQLException if a database access error occurs
+   */
+  public String getURL() throws SQLException
+  {
+    return connection.getURL();
+  }
+  
+  /**
+   * What is our user name as known to the database?
+   *
+   * @return our database user name
+   * @exception SQLException if a database access error occurs
+   */
+  public String getUserName() throws SQLException
+  {
+    return connection.getUserName();
+  }
+  
+  /**
+   * Is the database in read-only mode?
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean isReadOnly() throws SQLException
+  {
+    return connection.isReadOnly();
+  }
+  
+  /**
+   * Are NULL values sorted high?
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean nullsAreSortedHigh() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Are NULL values sorted low?
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean nullsAreSortedLow() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Are NULL values sorted at the start regardless of sort order?
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean nullsAreSortedAtStart() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Are NULL values sorted at the end regardless of sort order?
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean nullsAreSortedAtEnd() throws SQLException
+  {
+    return true;
+  }
+  
+  /**
+   * What is the name of this database product - we hope that it is
+   * PostgreSQL, so we return that explicitly.
+   *
+   * @return the database product name
+   * @exception SQLException if a database access error occurs
+   */
+  public String getDatabaseProductName() throws SQLException
+  {
+    return new String("PostgreSQL");
+  }
+  
+  /**
+   * What is the version of this database product.  Note that
+   * PostgreSQL 6.1 has a system catalog called pg_version - 
+   * however, select * from pg_version on any database retrieves
+   * no rows.  For now, we will return the version 6.1 (in the
+   * hopes that we change this driver as often as we change the
+   * database)
+   *
+   * @return the database version
+   * @exception SQLException if a database access error occurs
+   */
+  public String getDatabaseProductVersion() throws SQLException
+  {
+    return ("6.2");
+  }
+  
+  /**
+   * What is the name of this JDBC driver?  If we don't know this
+   * we are doing something wrong!
+   *
+   * @return the JDBC driver name
+   * @exception SQLException why?
+   */
+  public String getDriverName() throws SQLException
+  {
+    return new String("PostgreSQL Native Driver");
+  }
+  
+  /**
+   * What is the version string of this JDBC driver?  Again, this is
+   * static.
+   *
+   * @return the JDBC driver name.
+   * @exception SQLException why?
+   */
+  public String getDriverVersion() throws SQLException
+  {
+    return new String(Integer.toString(connection.this_driver.getMajorVersion())+"."+Integer.toString(connection.this_driver.getMinorVersion()));
+  }
+  
+  /**
+   * What is this JDBC driver's major version number?
+   *
+   * @return the JDBC driver major version
+   */
+  public int getDriverMajorVersion()
+  {
+    return connection.this_driver.getMajorVersion();
+  }
+  
+  /**
+   * What is this JDBC driver's minor version number?
+   *
+   * @return the JDBC driver minor version
+   */
+  public int getDriverMinorVersion()
+  {
+    return connection.this_driver.getMinorVersion();
+  }
+  
+  /**
+   * Does the database store tables in a local file?  No - it
+   * stores them in a file on the server.
+   * 
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean usesLocalFiles() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Does the database use a file for each table?  Well, not really,
+   * since it doesnt use local files. 
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean usesLocalFilePerTable() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Does the database treat mixed case unquoted SQL identifiers
+   * as case sensitive and as a result store them in mixed case?
+   * A JDBC-Compliant driver will always return false.
+   *
+   * Predicament - what do they mean by "SQL identifiers" - if it
+   * means the names of the tables and columns, then the answers
+   * given below are correct - otherwise I don't know.
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsMixedCaseIdentifiers() throws SQLException
+  {
+    return true;
+  }
+  
+  /**
+   * Does the database treat mixed case unquoted SQL identifiers as
+   * case insensitive and store them in upper case?
+   *
+   * @return true if so
+   */
+  public boolean storesUpperCaseIdentifiers() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Does the database treat mixed case unquoted SQL identifiers as
+   * case insensitive and store them in lower case?
+   *
+   * @return true if so
+   */
+  public boolean storesLowerCaseIdentifiers() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Does the database treat mixed case unquoted SQL identifiers as
+   * case insensitive and store them in mixed case?
+   *
+   * @return true if so
+   */
+  public boolean storesMixedCaseIdentifiers() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Does the database treat mixed case quoted SQL identifiers as
+   * case sensitive and as a result store them in mixed case?  A
+   * JDBC compliant driver will always return true. 
+   *
+   * Predicament - what do they mean by "SQL identifiers" - if it
+   * means the names of the tables and columns, then the answers
+   * given below are correct - otherwise I don't know.
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException
+  {
+    return true;
+  }
+  
+  /**
+   * Does the database treat mixed case quoted SQL identifiers as
+   * case insensitive and store them in upper case?
+   *
+   * @return true if so
+   */
+  public boolean storesUpperCaseQuotedIdentifiers() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Does the database treat mixed case quoted SQL identifiers as case
+   * insensitive and store them in lower case?
+   *
+   * @return true if so
+   */
+  public boolean storesLowerCaseQuotedIdentifiers() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Does the database treat mixed case quoted SQL identifiers as case
+   * insensitive and store them in mixed case?
+   *
+   * @return true if so
+   */
+  public boolean storesMixedCaseQuotedIdentifiers() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * What is the string used to quote SQL identifiers?  This returns
+   * a space if identifier quoting isn't supported.  A JDBC Compliant
+   * driver will always use a double quote character.
+   *
+   * If an SQL identifier is a table name, column name, etc. then
+   * we do not support it.
+   *
+   * @return the quoting string
+   * @exception SQLException if a database access error occurs
+   */
+  public String getIdentifierQuoteString() throws SQLException
+  {
+    return new String(" ");
+  }
+  
+  /**
+   * Get a comma separated list of all a database's SQL keywords that
+   * are NOT also SQL92 keywords.
+   *
+   * Within PostgreSQL, the keywords are found in
+   * 	src/backend/parser/keywords.c
+   * For SQL Keywords, I took the list provided at
+   * 	http://web.dementia.org/~shadow/sql/sql3bnf.sep93.txt
+   * which is for SQL3, not SQL-92, but it is close enough for
+   * this purpose.
+   *
+   * @return a comma separated list of keywords we use
+   * @exception SQLException if a database access error occurs
+   */
+  public String getSQLKeywords() throws SQLException
+  {
+    return new String("abort,acl,add,aggregate,append,archive,arch_store,backward,binary,change,cluster,copy,database,delimiters,do,extend,explain,forward,heavy,index,inherits,isnull,light,listen,load,merge,nothing,notify,notnull,oids,purge,rename,replace,retrieve,returns,rule,recipe,setof,stdin,stdout,store,vacuum,verbose,version");
+  }
+  
+  public String getNumericFunctions() throws SQLException
+  {
+    // XXX-Not Implemented
+    return "";
+  }
+  
+  public String getStringFunctions() throws SQLException
+  {
+    // XXX-Not Implemented
+    return "";
+  }
+  
+  public String getSystemFunctions() throws SQLException
+  {
+    // XXX-Not Implemented
+    return "";
+  }
+  
+  public String getTimeDateFunctions() throws SQLException
+  {
+    // XXX-Not Implemented
+    return "";
+  }
+  
+  /**
+   * This is the string that can be used to escape '_' and '%' in
+   * a search string pattern style catalog search parameters
+   *
+   * @return the string used to escape wildcard characters
+   * @exception SQLException if a database access error occurs
+   */
+  public String getSearchStringEscape() throws SQLException
+  {
+    return new String("\\");
+  }
+  
+  /**
+   * Get all the "extra" characters that can bew used in unquoted
+   * identifier names (those beyond a-zA-Z0-9 and _)
+   *
+   * From the file src/backend/parser/scan.l, an identifier is
+   * {letter}{letter_or_digit} which makes it just those listed
+   * above.
+   *
+   * @return a string containing the extra characters
+   * @exception SQLException if a database access error occurs
+   */
+  public String getExtraNameCharacters() throws SQLException
+  {
+    return new String("");
+  }
+  
+  /**
+   * Is "ALTER TABLE" with an add column supported?
+   * Yes for PostgreSQL 6.1
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsAlterTableWithAddColumn() throws SQLException
+  {
+    return true;
+  }
+  
+  /**
+   * Is "ALTER TABLE" with a drop column supported?
+   * Yes for PostgreSQL 6.1
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsAlterTableWithDropColumn() throws SQLException
+  {
+    return true;
+  }
+  
+  /**
+   * Is column aliasing supported?
+   *
+   * If so, the SQL AS clause can be used to provide names for
+   * computed columns or to provide alias names for columns as
+   * required.  A JDBC Compliant driver always returns true.
+   *
+   * e.g.
+   *
+   * select count(C) as C_COUNT from T group by C;
+   *
+   * should return a column named as C_COUNT instead of count(C)
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsColumnAliasing() throws SQLException
+  {
+    return true;
+  }
+  
+  /**
+   * Are concatenations between NULL and non-NULL values NULL?  A
+   * JDBC Compliant driver always returns true
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean nullPlusNonNullIsNull() throws SQLException
+  {
+    return true;
+  }
+  
+  public boolean supportsConvert() throws SQLException
+  {
+    // XXX-Not Implemented
+    return false;
+  }
+  
+  public boolean supportsConvert(int fromType, int toType) throws SQLException
+  {
+    // XXX-Not Implemented
+    return false;
+  }
+  
+  public boolean supportsTableCorrelationNames() throws SQLException
+  {
+    // XXX-Not Implemented
+    return false;
+  }
+  
+  public boolean supportsDifferentTableCorrelationNames() throws SQLException
+  {
+    // XXX-Not Implemented
+    return false;
+  }
+  
+  /**
+   * Are expressions in "ORCER BY" lists supported?
+   * 
+   * e.g. select * from t order by a + b;
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsExpressionsInOrderBy() throws SQLException
+  {
+    return true;
+  }
+  
+  /**
+   * Can an "ORDER BY" clause use columns not in the SELECT?
+   * I checked it, and you can't.
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsOrderByUnrelated() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Is some form of "GROUP BY" clause supported?
+   * I checked it, and yes it is.
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsGroupBy() throws SQLException
+  {
+    return true;
+  }
+  
+  /**
+   * Can a "GROUP BY" clause use columns not in the SELECT?
+   * I checked it - it seems to allow it
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsGroupByUnrelated() throws SQLException
+  {
+    return true;
+  }
+  
+  /**
+   * Can a "GROUP BY" clause add columns not in the SELECT provided
+   * it specifies all the columns in the SELECT?  Does anyone actually
+   * understand what they mean here?
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsGroupByBeyondSelect() throws SQLException
+  {
+    return true;		// For now...
+  }
+  
+  /**
+   * Is the escape character in "LIKE" clauses supported?  A
+   * JDBC compliant driver always returns true.
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsLikeEscapeClause() throws SQLException
+  {
+    return true;
+  }
+  
+  /**
+   * Are multiple ResultSets from a single execute supported?
+   * Well, I implemented it, but I dont think this is possible from
+   * the back ends point of view.
+   * 
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsMultipleResultSets() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Can we have multiple transactions open at once (on different
+   * connections?)
+   * I guess we can have, since Im relying on it.
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsMultipleTransactions() throws SQLException
+  {
+    return true;
+  }
+  
+  /**
+   * Can columns be defined as non-nullable.  A JDBC Compliant driver
+   * always returns true.  We dont support NOT NULL, so we are not
+   * JDBC compliant.
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsNonNullableColumns() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Does this driver support the minimum ODBC SQL grammar.  This
+   * grammar is defined at:
+   *
+   * http://www.microsoft.com/msdn/sdk/platforms/doc/odbc/src/intropr.htm
+   *
+   * In Appendix C.  From this description, we seem to support the
+   * ODBC minimal (Level 0) grammar.
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsMinimumSQLGrammar() throws SQLException
+  {
+    return true;
+  }
+  
+  /**
+   * Does this driver support the Core ODBC SQL grammar.  We need
+   * SQL-92 conformance for this.
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsCoreSQLGrammar() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Does this driver support the Extended (Level 2) ODBC SQL
+   * grammar.  We don't conform to the Core (Level 1), so we can't
+   * conform to the Extended SQL Grammar.
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsExtendedSQLGrammar() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Does this driver support the ANSI-92 entry level SQL grammar?
+   * All JDBC Compliant drivers must return true.  I think we have
+   * to support outer joins for this to be true.
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsANSI92EntryLevelSQL() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Does this driver support the ANSI-92 intermediate level SQL
+   * grammar?  Anyone who does not support Entry level cannot support
+   * Intermediate level.
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsANSI92IntermediateSQL() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Does this driver support the ANSI-92 full SQL grammar?
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsANSI92FullSQL() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Is the SQL Integrity Enhancement Facility supported?
+   * I haven't seen this mentioned anywhere, so I guess not
+   * 
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsIntegrityEnhancementFacility() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Is some form of outer join supported?  From my knowledge, nope.
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsOuterJoins() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Are full nexted outer joins supported?  Well, we dont support any
+   * form of outer join, so this is no as well
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsFullOuterJoins() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Is there limited support for outer joins?  (This will be true if
+   * supportFullOuterJoins is true)
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsLimitedOuterJoins() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * What is the database vendor's preferred term for "schema" - well,
+   * we do not provide support for schemas, so lets just use that
+   * term.
+   *
+   * @return the vendor term
+   * @exception SQLException if a database access error occurs
+   */
+  public String getSchemaTerm() throws SQLException
+  {
+    return new String("Schema");
+  }
+  
+  /**
+   * What is the database vendor's preferred term for "procedure" - 
+   * I kind of like "Procedure" myself.
+   *
+   * @return the vendor term
+   * @exception SQLException if a database access error occurs
+   */
+  public String getProcedureTerm() throws SQLException
+  {
+    return new String("Procedure");
+  }
+  
+  /**
+   * What is the database vendor's preferred term for "catalog"? -
+   * we dont have a preferred term, so just use Catalog
+   *
+   * @return the vendor term
+   * @exception SQLException if a database access error occurs
+   */
+  public String getCatalogTerm() throws SQLException
+  {
+    return new String("Catalog");
+  }
+  
+  /**
+   * Does a catalog appear at the start of a qualified table name?
+   * (Otherwise it appears at the end).
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean isCatalogAtStart() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * What is the Catalog separator.  Hmmm....well, I kind of like
+   * a period (so we get catalog.table definitions). - I don't think
+   * PostgreSQL supports catalogs anyhow, so it makes no difference.
+   *
+   * @return the catalog separator string
+   * @exception SQLException if a database access error occurs
+   */
+  public String getCatalogSeparator() throws SQLException
+  {
+    return new String(".");
+  }
+  
+  /**
+   * Can a schema name be used in a data manipulation statement?  Nope.
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsSchemasInDataManipulation() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Can a schema name be used in a procedure call statement?  Nope.
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsSchemasInProcedureCalls() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Can a schema be used in a table definition statement?  Nope.
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsSchemasInTableDefinitions() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Can a schema name be used in an index definition statement?
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsSchemasInIndexDefinitions() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Can a schema name be used in a privilege definition statement?
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Can a catalog name be used in a data manipulation statement?
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsCatalogsInDataManipulation() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Can a catalog name be used in a procedure call statement?
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsCatalogsInProcedureCalls() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Can a catalog name be used in a table definition statement?
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsCatalogsInTableDefinitions() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Can a catalog name be used in an index definition?
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsCatalogsInIndexDefinitions() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Can a catalog name be used in a privilege definition statement?
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * We support cursors for gets only it seems.  I dont see a method
+   * to get a positioned delete.
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsPositionedDelete() throws SQLException
+  {
+    return false;			// For now...
+  }
+  
+  /**
+   * Is positioned UPDATE supported?
+   * 
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsPositionedUpdate() throws SQLException
+  {
+    return false;			// For now...
+  }
+  
+  public boolean supportsSelectForUpdate() throws SQLException
+  {
+    // XXX-Not Implemented
+    return false;
+  }
+  
+  public boolean supportsStoredProcedures() throws SQLException
+  {
+    // XXX-Not Implemented
+    return false;
+  }
+  
+  public boolean supportsSubqueriesInComparisons() throws SQLException
+  {
+    // XXX-Not Implemented
+    return false;
+  }
+  
+  public boolean supportsSubqueriesInExists() throws SQLException
+  {
+    // XXX-Not Implemented
+    return false;
+  }
+  
+  public boolean supportsSubqueriesInIns() throws SQLException
+  {
+    // XXX-Not Implemented
+    return false;
+  }
+  
+  public boolean supportsSubqueriesInQuantifieds() throws SQLException
+  {
+    // XXX-Not Implemented
+    return false;
+  }
+  
+  public boolean supportsCorrelatedSubqueries() throws SQLException
+  {
+    // XXX-Not Implemented
+    return false;
+  }
+  
+  /**
+   * Is SQL UNION supported?  Nope.
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsUnion() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Is SQL UNION ALL supported?  Nope.
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsUnionAll() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * In PostgreSQL, Cursors are only open within transactions.
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsOpenCursorsAcrossCommit() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Do we support open cursors across multiple transactions?
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsOpenCursorsAcrossRollback() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Can statements remain open across commits?  They may, but
+   * this driver cannot guarentee that.  In further reflection.
+   * we are talking a Statement object jere, so the answer is
+   * yes, since the Statement is only a vehicle to ExecSQL()
+   *
+   * @return true if they always remain open; false otherwise
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsOpenStatementsAcrossCommit() throws SQLException
+  {
+    return true;
+  }
+  
+  /**
+   * Can statements remain open across rollbacks?  They may, but
+   * this driver cannot guarentee that.  In further contemplation,
+   * we are talking a Statement object here, so the answer is yes,
+   * since the Statement is only a vehicle to ExecSQL() in Connection
+   *
+   * @return true if they always remain open; false otherwise
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsOpenStatementsAcrossRollback() throws SQLException
+  {
+    return true;
+  }
+  
+  /**
+   * How many hex characters can you have in an inline binary literal
+   *
+   * @return the max literal length
+   * @exception SQLException if a database access error occurs
+   */
+  public int getMaxBinaryLiteralLength() throws SQLException
+  {
+    return 0;				// For now...
+  }
+  
+  /**
+   * What is the maximum length for a character literal
+   * I suppose it is 8190 (8192 - 2 for the quotes)
+   *
+   * @return the max literal length
+   * @exception SQLException if a database access error occurs
+   */
+  public int getMaxCharLiteralLength() throws SQLException
+  {
+    return 8190;
+  }
+  
+  /**
+   * Whats the limit on column name length.  The description of
+   * pg_class would say '32' (length of pg_class.relname) - we
+   * should probably do a query for this....but....
+   *
+   * @return the maximum column name length
+   * @exception SQLException if a database access error occurs
+   */
+  public int getMaxColumnNameLength() throws SQLException
+  {
+    return 32;
+  }
+  
+  /**
+   * What is the maximum number of columns in a "GROUP BY" clause?
+   *
+   * @return the max number of columns
+   * @exception SQLException if a database access error occurs	
+   */
+  public int getMaxColumnsInGroupBy() throws SQLException
+  {
+    return getMaxColumnsInTable();
+  }
+  
+  /**
+   * What's the maximum number of columns allowed in an index?
+   * 6.0 only allowed one column, but 6.1 introduced multi-column
+   * indices, so, theoretically, its all of them.
+   *
+   * @return max number of columns
+   * @exception SQLException if a database access error occurs
+   */
+  public int getMaxColumnsInIndex() throws SQLException
+  {
+    return getMaxColumnsInTable();
+  }
+  
+  /**
+   * What's the maximum number of columns in an "ORDER BY clause?
+   * Theoretically, all of them!
+   *
+   * @return the max columns
+   * @exception SQLException if a database access error occurs
+   */
+  public int getMaxColumnsInOrderBy() throws SQLException
+  {
+    return getMaxColumnsInTable();
+  }
+  
+  /**
+   * What is the maximum number of columns in a "SELECT" list?
+   * Theoretically, all of them!
+   *
+   * @return the max columns
+   * @exception SQLException if a database access error occurs
+   */
+  public int getMaxColumnsInSelect() throws SQLException
+  {
+    return getMaxColumnsInTable();
+  }
+  
+  /**
+   * What is the maximum number of columns in a table? From the
+   * create_table(l) manual page...
+   *
+   * "The new class is created as a heap with no initial data.  A
+   * class can have no more than 1600 attributes (realistically,
+   * this is limited by the fact that tuple sizes must be less than
+   * 8192 bytes)..."
+   *
+   * @return the max columns
+   * @exception SQLException if a database access error occurs
+   */
+  public int getMaxColumnsInTable() throws SQLException
+  {
+    return 1600;
+  }
+  
+  /**
+   * How many active connection can we have at a time to this
+   * database?  Well, since it depends on postmaster, which just
+   * does a listen() followed by an accept() and fork(), its
+   * basically very high.  Unless the system runs out of processes,
+   * it can be 65535 (the number of aux. ports on a TCP/IP system).
+   * I will return 8192 since that is what even the largest system
+   * can realistically handle,
+   *
+   * @return the maximum number of connections
+   * @exception SQLException if a database access error occurs
+   */
+  public int getMaxConnections() throws SQLException
+  {
+    return 8192;
+  }
+  
+  /**
+   * What is the maximum cursor name length (the same as all
+   * the other F***** identifiers!)
+   *
+   * @return max cursor name length in bytes
+   * @exception SQLException if a database access error occurs
+   */
+  public int getMaxCursorNameLength() throws SQLException
+  {
+    return 32;
+  }
+  
+  /**
+   * What is the maximum length of an index (in bytes)?  Now, does
+   * the spec. mean name of an index (in which case its 32, the 
+   * same as a table) or does it mean length of an index element
+   * (in which case its 8192, the size of a row) or does it mean
+   * the number of rows it can access (in which case it 2^32 - 
+   * a 4 byte OID number)?  I think its the length of an index
+   * element, personally, so Im setting it to 8192.
+   *
+   * @return max index length in bytes
+   * @exception SQLException if a database access error occurs
+   */
+  public int getMaxIndexLength() throws SQLException
+  {
+    return 8192;
+  }
+  
+  public int getMaxSchemaNameLength() throws SQLException
+  {
+    // XXX-Not Implemented
+    return 0;
+  }
+  
+  /**
+   * What is the maximum length of a procedure name?
+   * (length of pg_proc.proname used) - again, I really
+   * should do a query here to get it.
+   *
+   * @return the max name length in bytes
+   * @exception SQLException if a database access error occurs
+   */
+  public int getMaxProcedureNameLength() throws SQLException
+  {
+    return 32;
+  }
+  
+  public int getMaxCatalogNameLength() throws SQLException
+  {
+    // XXX-Not Implemented
+    return 0;
+  }
+  
+  /**
+   * What is the maximum length of a single row?  (not including
+   * blobs).  8192 is defined in PostgreSQL.
+   *
+   * @return max row size in bytes
+   * @exception SQLException if a database access error occurs
+   */
+  public int getMaxRowSize() throws SQLException
+  {
+    return 8192;
+  }
+  
+  /**
+   * Did getMaxRowSize() include LONGVARCHAR and LONGVARBINARY
+   * blobs?  We don't handle blobs yet
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean doesMaxRowSizeIncludeBlobs() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * What is the maximum length of a SQL statement?
+   *
+   * @return max length in bytes
+   * @exception SQLException if a database access error occurs
+   */
+  public int getMaxStatementLength() throws SQLException
+  {
+    return 8192;
+  }
+  
+  /**
+   * How many active statements can we have open at one time to
+   * this database?  Basically, since each Statement downloads
+   * the results as the query is executed, we can have many.  However,
+   * we can only really have one statement per connection going
+   * at once (since they are executed serially) - so we return
+   * one.
+   *
+   * @return the maximum
+   * @exception SQLException if a database access error occurs
+   */
+  public int getMaxStatements() throws SQLException
+  {
+    return 1;
+  }
+  
+  /**
+   * What is the maximum length of a table name?  This was found
+   * from pg_class.relname length
+   *
+   * @return max name length in bytes
+   * @exception SQLException if a database access error occurs
+   */
+  public int getMaxTableNameLength() throws SQLException
+  {
+    return 32;
+  }
+  
+  /**
+   * What is the maximum number of tables that can be specified
+   * in a SELECT?  Theoretically, this is the same number as the
+   * number of tables allowable.  In practice tho, it is much smaller
+   * since the number of tables is limited by the statement, we
+   * return 1024 here - this is just a number I came up with (being
+   * the number of tables roughly of three characters each that you
+   * can fit inside a 8192 character buffer with comma separators).
+   *
+   * @return the maximum
+   * @exception SQLException if a database access error occurs
+   */
+  public int getMaxTablesInSelect() throws SQLException
+  {
+    return 1024;
+  }
+  
+  /**
+   * What is the maximum length of a user name?  Well, we generally
+   * use UNIX like user names in PostgreSQL, so I think this would
+   * be 8.  However, showing the schema for pg_user shows a length
+   * for username of 32.
+   *
+   * @return the max name length in bytes
+   * @exception SQLException if a database access error occurs
+   */
+  public int getMaxUserNameLength() throws SQLException
+  {
+    return 32;
+  }
+  
+  
+  /**
+   * What is the database's default transaction isolation level?  We
+   * do not support this, so all transactions are SERIALIZABLE.
+   *
+   * @return the default isolation level
+   * @exception SQLException if a database access error occurs
+   * @see Connection
+   */
+  public int getDefaultTransactionIsolation() throws SQLException
+  {
+    return Connection.TRANSACTION_SERIALIZABLE;
+  }
+  
+  /**
+   * Are transactions supported?  If not, commit and rollback are noops
+   * and the isolation level is TRANSACTION_NONE.  We do support
+   * transactions.	
+   *
+   * @return true if transactions are supported
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsTransactions() throws SQLException
+  {
+    return true;
+  }
+  
+  /**
+   * Does the database support the given transaction isolation level?
+   * We only support TRANSACTION_SERIALIZABLE
+   * 
+   * @param level the values are defined in java.sql.Connection
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   * @see Connection
+   */
+  public boolean supportsTransactionIsolationLevel(int level) throws SQLException
+  {
+    if (level == Connection.TRANSACTION_SERIALIZABLE)
+      return true;
+    else
+      return false;
+  }
+  
+  /**
+   * Are both data definition and data manipulation transactions 
+   * supported?  I checked it, and could not do a CREATE TABLE
+   * within a transaction, so I am assuming that we don't
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Are only data manipulation statements withing a transaction
+   * supported?
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean supportsDataManipulationTransactionsOnly() throws SQLException
+  {
+    return true;
+  }
+  
+  /**
+   * Does a data definition statement within a transaction force
+   * the transaction to commit?  I think this means something like:
+   *
+   * CREATE TABLE T (A INT);
+   * INSERT INTO T (A) VALUES (2);
+   * BEGIN;
+   * UPDATE T SET A = A + 1;
+   * CREATE TABLE X (A INT);
+   * SELECT A FROM T INTO X;
+   * COMMIT;
+   *
+   * does the CREATE TABLE call cause a commit?  The answer is no.  
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean dataDefinitionCausesTransactionCommit() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   *  Is a data definition statement within a transaction ignored?
+   * It seems to be (from experiment in previous method)
+   *
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean dataDefinitionIgnoredInTransactions() throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Get a description of stored procedures available in a catalog
+   * 
+   * Only procedure descriptions matching the schema and procedure
+   * name criteria are returned.  They are ordered by PROCEDURE_SCHEM
+   * and PROCEDURE_NAME
+   *
+   * Each procedure description has the following columns:
+   * PROCEDURE_CAT String => procedure catalog (may be null)
+   * PROCEDURE_SCHEM String => procedure schema (may be null)
+   * PROCEDURE_NAME String => procedure name
+   * Field 4 reserved (make it null)
+   * Field 5 reserved (make it null)
+   * Field 6 reserved (make it null)
+   * REMARKS String => explanatory comment on the procedure
+   * PROCEDURE_TYPE short => kind of procedure
+   *	* procedureResultUnknown - May return a result
+   * 	* procedureNoResult - Does not return a result
+   *	* procedureReturnsResult - Returns a result
+   *
+   * @param catalog - a catalog name; "" retrieves those without a
+   *	catalog; null means drop catalog name from criteria
+   * @param schemaParrern - a schema name pattern; "" retrieves those
+   *	without a schema - we ignore this parameter
+   * @param procedureNamePattern - a procedure name pattern
+   * @return ResultSet - each row is a procedure description
+   * @exception SQLException if a database access error occurs
+   */
+  static final int iVarcharOid = 1043; // This is the OID for a varchar()
+  static final int iInt2Oid = 21;	 // This is the OID for an int2
+  public java.sql.ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) throws SQLException
+  {
+    // the field descriptors for the new ResultSet
+    Field f[] = new Field[8];
+    ResultSet r;	// ResultSet for the SQL query that we need to do
+    Vector v = new Vector();		// The new ResultSet tuple stuff
+    String remarks = new String("no remarks");
+    
+    f[0] = new Field(connection, new String("PROCEDURE_CAT"), iVarcharOid, 32);
+    f[1] = new Field(connection, new String("PROCEDURE_SCHEM"), iVarcharOid, 32);
+    f[2] = new Field(connection, new String("PROCEDURE_NAME"), iVarcharOid, 32);
+    f[3] = null;
+    f[4] = null;
+    f[5] = null;
+    f[6] = new Field(connection, new String("REMARKS"), iVarcharOid, 8192);
+    f[7] = new Field(connection, new String("PROCEDURE_TYPE"), iInt2Oid, 2);
+    r = connection.ExecSQL("select proname, proretset from pg_proc order by proname");
+    if (r.getColumnCount() != 2 || r.getTupleCount() <= 1)
+      throw new SQLException("Unexpected return from query for procedure list");
+    while (r.next())
+      {
+	byte[][] tuple = new byte[8][0];
 	
-	/**
-	 * What is the database's default transaction isolation level?  We
-	 * do not support this, so all transactions are SERIALIZABLE.
-	 *
-	 * @return the default isolation level
-	 * @exception SQLException if a database access error occurs
-	 * @see Connection
-	 */
-	public int getDefaultTransactionIsolation() throws SQLException
-	{
-		return Connection.TRANSACTION_SERIALIZABLE;
-	}
-
-	/**
-	 * Are transactions supported?  If not, commit and rollback are noops
-	 * and the isolation level is TRANSACTION_NONE.  We do support
-	 * transactions.	
-	 *
-	 * @return true if transactions are supported
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsTransactions() throws SQLException
-	{
-		return true;
-	}
-
-	/**
-	 * Does the database support the given transaction isolation level?
-	 * We only support TRANSACTION_SERIALIZABLE
-	 * 
-	 * @param level the values are defined in java.sql.Connection
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 * @see Connection
-	 */
-	public boolean supportsTransactionIsolationLevel(int level) throws SQLException
-	{
-		if (level == Connection.TRANSACTION_SERIALIZABLE)
-			return true;
-		else
-			return false;
-	}
-
-	/**
-	 * Are both data definition and data manipulation transactions 
-	 * supported?  I checked it, and could not do a CREATE TABLE
-	 * within a transaction, so I am assuming that we don't
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Are only data manipulation statements withing a transaction
-	 * supported?
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean supportsDataManipulationTransactionsOnly() throws SQLException
-	{
-		return true;
-	}
-
-	/**
-	 * Does a data definition statement within a transaction force
-	 * the transaction to commit?  I think this means something like:
-	 *
-	 * CREATE TABLE T (A INT);
-	 * INSERT INTO T (A) VALUES (2);
-	 * BEGIN;
-	 * UPDATE T SET A = A + 1;
-	 * CREATE TABLE X (A INT);
-	 * SELECT A FROM T INTO X;
-	 * COMMIT;
-	 *
-	 * does the CREATE TABLE call cause a commit?  The answer is no.  
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean dataDefinitionCausesTransactionCommit() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 *  Is a data definition statement within a transaction ignored?
-	 * It seems to be (from experiment in previous method)
-	 *
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean dataDefinitionIgnoredInTransactions() throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Get a description of stored procedures available in a catalog
-	 * 
-	 * Only procedure descriptions matching the schema and procedure
-	 * name criteria are returned.  They are ordered by PROCEDURE_SCHEM
-	 * and PROCEDURE_NAME
-	 *
-	 * Each procedure description has the following columns:
-	 * PROCEDURE_CAT String => procedure catalog (may be null)
-	 * PROCEDURE_SCHEM String => procedure schema (may be null)
-	 * PROCEDURE_NAME String => procedure name
-	 * Field 4 reserved (make it null)
-	 * Field 5 reserved (make it null)
-	 * Field 6 reserved (make it null)
-	 * REMARKS String => explanatory comment on the procedure
-	 * PROCEDURE_TYPE short => kind of procedure
-	 *	* procedureResultUnknown - May return a result
-	 * 	* procedureNoResult - Does not return a result
-	 *	* procedureReturnsResult - Returns a result
-	 *
-	 * @param catalog - a catalog name; "" retrieves those without a
-	 *	catalog; null means drop catalog name from criteria
-	 * @param schemaParrern - a schema name pattern; "" retrieves those
-	 *	without a schema - we ignore this parameter
-	 * @param procedureNamePattern - a procedure name pattern
-	 * @return ResultSet - each row is a procedure description
-	 * @exception SQLException if a database access error occurs
-	 */
-	public java.sql.ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) throws SQLException
-	{
-		Field[] f = new Field[8];		// the field descriptors for the new ResultSet
-		static final int iVarcharOid = 1043;	// This is the OID for a varchar()
-		static final int iInt2Oid = 21;		// This is the OID for an int2
-		ResultSet r;				// ResultSet for the SQL query that we need to do
-		Vector v;				// The new ResultSet tuple stuff
-		String remarks = new String("no remarks");
-
-		Field[0] = new Field(conn, new String("PROCEDURE_CAT"), iVarcharOid, 32);
-		Field[1] = new Field(conn, new String("PROCEDURE_SCHEM"), iVarcharOid, 32);
-		Field[2] = new Field(conn, new String("PROCEDURE_NAME"), iVarcharOid, 32);
-		Field[3] = null;
-		Field[4] = null;
-		Field[5] = null;
-		Field[6] = new Field(conn, new String("REMARKS"), iVarcharOid, 8192);
-		Field[7] = new Field(conn, new String("PROCEDURE_TYPE"), iInt2Oid, 2);
-		r = conn.ExecSQL("select proname, proretset from pg_proc order by proname");
-		if (r.getColumnCount() != 2 || r.getTupleCount() <= 1)
-			throw new SQLException("Unexpected return from query for procedure list");
-		while (r.next())
-		{
-			byte[][] tuple = new byte[8][0];
-
-			String name = r.getString(1);
-			String remarks = new String("no remarks");
-			boolean retset = r.getBoolean(2);
+	String name = r.getString(1);
+	remarks = new String("no remarks");
+	boolean retset = r.getBoolean(2);
 	
-			byte[0] = null;			// Catalog name
-			byte[1] = null;			// Schema name
-			byte[2] = name.getBytes();	// Procedure name
-			byte[3] = null;			// Reserved
-			byte[4] = null;			// Reserved
-			byte[5] = null;			// Reserved
-			byte[6] = remarks.getBytes();	// Remarks
-			if (retset)
-				byte[7] = procedureReturnsResult;
-			else
-				byte[7] = procedureNoResult;
-			v.addElement(byte);
-		}			
-		return new ResultSet(conn, f, v, "OK", 1);
-	}
-
-	public java.sql.ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public java.sql.ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String types[]) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public java.sql.ResultSet getSchemas() throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public java.sql.ResultSet getCatalogs() throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public java.sql.ResultSet getTableTypes() throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public java.sql.ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public java.sql.ResultSet getColumnPrivileges(String catalog, String schema, String table, String columnNamePattern) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public java.sql.ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public java.sql.ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public java.sql.ResultSet getVersionColumns(String catalog, String schema, String table) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public java.sql.ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public java.sql.ResultSet getImportedKeys(String catalog, String schema, String table) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public java.sql.ResultSet getExportedKeys(String catalog, String schema, String table) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public java.sql.ResultSet getCrossReference(String primaryCatalog, String primarySchema, String primaryTable, String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public java.sql.ResultSet getTypeInfo() throws SQLException
-	{
-		// XXX-Not Implemented
-	}
-
-	public java.sql.ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) throws SQLException
-	{
-		// XXX-Not Implemented
-	}
+	tuple[0] = null;			// Catalog name
+	tuple[1] = null;			// Schema name
+	tuple[2] = name.getBytes();	// Procedure name
+	tuple[3] = null;			// Reserved
+	tuple[4] = null;			// Reserved
+	tuple[5] = null;			// Reserved
+	tuple[6] = remarks.getBytes();	// Remarks
+	tuple[7] = new byte[1];
+	if (retset)
+	  tuple[7][0] = (byte)java.sql.DatabaseMetaData.procedureReturnsResult;
+	else
+	  tuple[7][0] = (byte)java.sql.DatabaseMetaData.procedureNoResult;
+	v.addElement(tuple);
+      }
+    return new ResultSet(connection, f, v, "OK", 1);
+  }
+  
+  public java.sql.ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) throws SQLException
+  {
+    // XXX-Not Implemented
+    return null;
+  }
+  
+  public java.sql.ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String types[]) throws SQLException
+  {
+    return connection.createStatement().executeQuery("SELECT '' as TABLE_CAT,'' AS TABLE_SCHEM,relname AS TABLE_NAME,'TABLE' AS TABLE_TYPE,'' AS REMARKS FROM pg_class WHERE relkind = 'r' and relname !~ '^pg_' and relname !~ '^Inv' and relname ~ '"+tableNamePattern+"' ORDER BY TABLE_NAME");
+  }
+  
+  /**
+   * Get the schema names available in this database.  The results
+   * are ordered by schema name.
+   *
+   * <P>The schema column is:
+   *  <OL>
+   *	<LI><B>TABLE_SCHEM</B> String => schema name
+   *  </OL>
+   *
+   * @return ResultSet each row has a single String column that is a
+   * schema name
+   */
+  public java.sql.ResultSet getSchemas() throws SQLException
+  {
+    // XXX-Not Implemented
+    return null;
+  }
+  
+  /**
+   * Get the catalog names available in this database.  The results
+   * are ordered by catalog name.
+   *
+   * <P>The catalog column is:
+   *  <OL>
+   *	<LI><B>TABLE_CAT</B> String => catalog name
+   *  </OL>
+   *
+   * @return ResultSet each row has a single String column that is a
+   * catalog name
+   */
+  // We don't use catalog names, so this returns a single catalog
+  public java.sql.ResultSet getCatalogs() throws SQLException
+  {
+    return connection.createStatement().executeQuery("SELECT '' as TABLE_CAT");
+  }
+  
+  /**
+   * Get the table types available in this database.  The results
+   * are ordered by table type.
+   *
+   * <P>The table type is:
+   *  <OL>
+   *	<LI><B>TABLE_TYPE</B> String => table type.  Typical types are "TABLE",
+   *			"VIEW",	"SYSTEM TABLE", "GLOBAL TEMPORARY",
+   *			"LOCAL TEMPORARY", "ALIAS", "SYNONYM".
+   *  </OL>
+   *
+   * @return ResultSet each row has a single String column that is a
+   * table type
+   */
+  public java.sql.ResultSet getTableTypes() throws SQLException
+  {
+    // XXX-Not Implemented
+    return null;
+  }
+  
+  /**
+   * Get a description of table columns available in a catalog.
+   *
+   * <P>Only column descriptions matching the catalog, schema, table
+   * and column name criteria are returned.  They are ordered by
+   * TABLE_SCHEM, TABLE_NAME and ORDINAL_POSITION.
+   *
+   * <P>Each column description has the following columns:
+   *  <OL>
+   *	<LI><B>TABLE_CAT</B> String => table catalog (may be null)
+   *	<LI><B>TABLE_SCHEM</B> String => table schema (may be null)
+   *	<LI><B>TABLE_NAME</B> String => table name
+   *	<LI><B>COLUMN_NAME</B> String => column name
+   *	<LI><B>DATA_TYPE</B> short => SQL type from java.sql.Types
+   *	<LI><B>TYPE_NAME</B> String => Data source dependent type name
+   *	<LI><B>COLUMN_SIZE</B> int => column size.  For char or date
+   *	    types this is the maximum number of characters, for numeric or
+   *	    decimal types this is precision.
+   *	<LI><B>BUFFER_LENGTH</B> is not used.
+   *	<LI><B>DECIMAL_DIGITS</B> int => the number of fractional digits
+   *	<LI><B>NUM_PREC_RADIX</B> int => Radix (typically either 10 or 2)
+   *	<LI><B>NULLABLE</B> int => is NULL allowed?
+   *      <UL>
+   *      <LI> columnNoNulls - might not allow NULL values
+   *      <LI> columnNullable - definitely allows NULL values
+   *      <LI> columnNullableUnknown - nullability unknown
+   *      </UL>
+   *	<LI><B>REMARKS</B> String => comment describing column (may be null)
+   * 	<LI><B>COLUMN_DEF</B> String => default value (may be null)
+   *	<LI><B>SQL_DATA_TYPE</B> int => unused
+   *	<LI><B>SQL_DATETIME_SUB</B> int => unused
+   *	<LI><B>CHAR_OCTET_LENGTH</B> int => for char types the
+   *       maximum number of bytes in the column
+   *	<LI><B>ORDINAL_POSITION</B> int	=> index of column in table
+   *      (starting at 1)
+   *	<LI><B>IS_NULLABLE</B> String => "NO" means column definitely
+   *      does not allow NULL values; "YES" means the column might
+   *      allow NULL values.  An empty string means nobody knows.
+   *  </OL>
+   *
+   * @param catalog a catalog name; "" retrieves those without a catalog
+   * @param schemaPattern a schema name pattern; "" retrieves those
+   * without a schema
+   * @param tableNamePattern a table name pattern
+   * @param columnNamePattern a column name pattern
+   * @return ResultSet each row is a column description
+   * @see #getSearchStringEscape
+   */
+  public java.sql.ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException
+  {
+    // XXX-Not Implemented
+    // PM: this will be implemented, as soon as I sort out how to convert the
+    // code from the other driver (private note: look at getProcedures() )
+    return null;
+  }
+  
+  /**
+   * Get a description of the access rights for a table's columns.
+   *
+   * <P>Only privileges matching the column name criteria are
+   * returned.  They are ordered by COLUMN_NAME and PRIVILEGE.
+   *
+   * <P>Each privilige description has the following columns:
+   *  <OL>
+   *	<LI><B>TABLE_CAT</B> String => table catalog (may be null)
+   *	<LI><B>TABLE_SCHEM</B> String => table schema (may be null)
+   *	<LI><B>TABLE_NAME</B> String => table name
+   *	<LI><B>COLUMN_NAME</B> String => column name
+   *	<LI><B>GRANTOR</B> => grantor of access (may be null)
+   *	<LI><B>GRANTEE</B> String => grantee of access
+   *	<LI><B>PRIVILEGE</B> String => name of access (SELECT,
+   *      INSERT, UPDATE, REFRENCES, ...)
+   *	<LI><B>IS_GRANTABLE</B> String => "YES" if grantee is permitted
+   *      to grant to others; "NO" if not; null if unknown
+   *  </OL>
+   *
+   * @param catalog a catalog name; "" retrieves those without a catalog
+   * @param schema a schema name; "" retrieves those without a schema
+   * @param table a table name
+   * @param columnNamePattern a column name pattern
+   * @return ResultSet each row is a column privilege description
+   * @see #getSearchStringEscape
+   */
+  public java.sql.ResultSet getColumnPrivileges(String catalog, String schema, String table, String columnNamePattern) throws SQLException
+  {
+    // XXX-Not Implemented
+    return null;
+  }
+  
+  /**
+   * Get a description of the access rights for each table available
+   * in a catalog.
+   *
+   * <P>Only privileges matching the schema and table name
+   * criteria are returned.  They are ordered by TABLE_SCHEM,
+   * TABLE_NAME, and PRIVILEGE.
+   *
+   * <P>Each privilige description has the following columns:
+   *  <OL>
+   *	<LI><B>TABLE_CAT</B> String => table catalog (may be null)
+   *	<LI><B>TABLE_SCHEM</B> String => table schema (may be null)
+   *	<LI><B>TABLE_NAME</B> String => table name
+   *	<LI><B>COLUMN_NAME</B> String => column name
+   *	<LI><B>GRANTOR</B> => grantor of access (may be null)
+   *	<LI><B>GRANTEE</B> String => grantee of access
+   *	<LI><B>PRIVILEGE</B> String => name of access (SELECT,
+   *      INSERT, UPDATE, REFRENCES, ...)
+   *	<LI><B>IS_GRANTABLE</B> String => "YES" if grantee is permitted
+   *      to grant to others; "NO" if not; null if unknown
+   *  </OL>
+   *
+   * @param catalog a catalog name; "" retrieves those without a catalog
+   * @param schemaPattern a schema name pattern; "" retrieves those
+   * without a schema
+   * @param tableNamePattern a table name pattern
+   * @return ResultSet each row is a table privilege description
+   * @see #getSearchStringEscape
+   */
+  public java.sql.ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) throws SQLException
+  {
+    // XXX-Not Implemented
+    return null;
+  }
+  
+  /**
+   * Get a description of a table's optimal set of columns that
+   * uniquely identifies a row. They are ordered by SCOPE.
+   *
+   * <P>Each column description has the following columns:
+   *  <OL>
+   *	<LI><B>SCOPE</B> short => actual scope of result
+   *      <UL>
+   *      <LI> bestRowTemporary - very temporary, while using row
+   *      <LI> bestRowTransaction - valid for remainder of current transaction
+   *      <LI> bestRowSession - valid for remainder of current session
+   *      </UL>
+   *	<LI><B>COLUMN_NAME</B> String => column name
+   *	<LI><B>DATA_TYPE</B> short => SQL data type from java.sql.Types
+   *	<LI><B>TYPE_NAME</B> String => Data source dependent type name
+   *	<LI><B>COLUMN_SIZE</B> int => precision
+   *	<LI><B>BUFFER_LENGTH</B> int => not used
+   *	<LI><B>DECIMAL_DIGITS</B> short	 => scale
+   *	<LI><B>PSEUDO_COLUMN</B> short => is this a pseudo column
+   *      like an Oracle ROWID
+   *      <UL>
+   *      <LI> bestRowUnknown - may or may not be pseudo column
+   *      <LI> bestRowNotPseudo - is NOT a pseudo column
+   *      <LI> bestRowPseudo - is a pseudo column
+   *      </UL>
+   *  </OL>
+   *
+   * @param catalog a catalog name; "" retrieves those without a catalog
+   * @param schema a schema name; "" retrieves those without a schema
+   * @param table a table name
+   * @param scope the scope of interest; use same values as SCOPE
+   * @param nullable include columns that are nullable?
+   * @return ResultSet each row is a column description
+   */
+  public java.sql.ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) throws SQLException
+  {
+    // XXX-Not Implemented
+    return null;
+  }
+  
+  /**
+   * Get a description of a table's columns that are automatically
+   * updated when any value in a row is updated.  They are
+   * unordered.
+   *
+   * <P>Each column description has the following columns:
+   *  <OL>
+   *	<LI><B>SCOPE</B> short => is not used
+   *	<LI><B>COLUMN_NAME</B> String => column name
+   *	<LI><B>DATA_TYPE</B> short => SQL data type from java.sql.Types
+   *	<LI><B>TYPE_NAME</B> String => Data source dependent type name
+   *	<LI><B>COLUMN_SIZE</B> int => precision
+   *	<LI><B>BUFFER_LENGTH</B> int => length of column value in bytes
+   *	<LI><B>DECIMAL_DIGITS</B> short	 => scale
+   *	<LI><B>PSEUDO_COLUMN</B> short => is this a pseudo column
+   *      like an Oracle ROWID
+   *      <UL>
+   *      <LI> versionColumnUnknown - may or may not be pseudo column
+   *      <LI> versionColumnNotPseudo - is NOT a pseudo column
+   *      <LI> versionColumnPseudo - is a pseudo column
+   *      </UL>
+   *  </OL>
+   *
+   * @param catalog a catalog name; "" retrieves those without a catalog
+   * @param schema a schema name; "" retrieves those without a schema
+   * @param table a table name
+   * @return ResultSet each row is a column description
+   */
+ public java.sql.ResultSet getVersionColumns(String catalog, String schema, String table) throws SQLException
+  {
+    // XXX-Not Implemented
+    return null;
+  }
+  
+  /**
+   * Get a description of a table's primary key columns.  They
+   * are ordered by COLUMN_NAME.
+   *
+   * <P>Each column description has the following columns:
+   *  <OL>
+   *	<LI><B>TABLE_CAT</B> String => table catalog (may be null)
+   *	<LI><B>TABLE_SCHEM</B> String => table schema (may be null)
+   *	<LI><B>TABLE_NAME</B> String => table name
+   *	<LI><B>COLUMN_NAME</B> String => column name
+   *	<LI><B>KEY_SEQ</B> short => sequence number within primary key
+   *	<LI><B>PK_NAME</B> String => primary key name (may be null)
+   *  </OL>
+   *
+   * @param catalog a catalog name; "" retrieves those without a catalog
+   * @param schema a schema name pattern; "" retrieves those
+   * without a schema
+   * @param table a table name
+   * @return ResultSet each row is a primary key column description
+   */
+  public java.sql.ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException
+  {
+    return connection.createStatement().executeQuery("SELECT " +
+						     "'' as TABLE_CAT," +
+						     "'' AS TABLE_SCHEM," +
+						     "bc.relname AS TABLE_NAME," +
+						     "ic.relname AS COLUMN_NAME," +
+						     "'1' as KEY_SEQ,"+ // -- fake it as a String for now
+						     "t.typname as PK_NAME " +
+						     " FROM pg_class bc, pg_class ic, pg_index i, pg_attribute a " +
+						     " WHERE relkind = 'r' " + //    -- not indices
+						     "  and bc.relname ~ '"+table+"'" +
+						     "  and i.indrelid = bc.oid" +
+						     "  and i.indexrelid = ic.oid" +
+						     "  and i.indkey[0] = a.attnum" +
+						     "  and i.indproc = '0'::oid" +
+						     "  and a.attrelid = bc.oid" +
+						     " ORDER BY TABLE_NAME, COLUMN_NAME;"
+						     );
+  }
+  
+  /**
+   * Get a description of the primary key columns that are
+   * referenced by a table's foreign key columns (the primary keys
+   * imported by a table).  They are ordered by PKTABLE_CAT,
+   * PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ.
+   *
+   * <P>Each primary key column description has the following columns:
+   *  <OL>
+   *	<LI><B>PKTABLE_CAT</B> String => primary key table catalog
+   *      being imported (may be null)
+   *	<LI><B>PKTABLE_SCHEM</B> String => primary key table schema
+   *      being imported (may be null)
+   *	<LI><B>PKTABLE_NAME</B> String => primary key table name
+   *      being imported
+   *	<LI><B>PKCOLUMN_NAME</B> String => primary key column name
+   *      being imported
+   *	<LI><B>FKTABLE_CAT</B> String => foreign key table catalog (may be null)
+   *	<LI><B>FKTABLE_SCHEM</B> String => foreign key table schema (may be null)
+   *	<LI><B>FKTABLE_NAME</B> String => foreign key table name
+   *	<LI><B>FKCOLUMN_NAME</B> String => foreign key column name
+   *	<LI><B>KEY_SEQ</B> short => sequence number within foreign key
+   *	<LI><B>UPDATE_RULE</B> short => What happens to
+   *       foreign key when primary is updated:
+   *      <UL>
+   *      <LI> importedKeyCascade - change imported key to agree
+   *               with primary key update
+   *      <LI> importedKeyRestrict - do not allow update of primary
+   *               key if it has been imported
+   *      <LI> importedKeySetNull - change imported key to NULL if
+   *               its primary key has been updated
+   *      </UL>
+   *	<LI><B>DELETE_RULE</B> short => What happens to
+   *      the foreign key when primary is deleted.
+   *      <UL>
+   *      <LI> importedKeyCascade - delete rows that import a deleted key
+   *      <LI> importedKeyRestrict - do not allow delete of primary
+   *               key if it has been imported
+   *      <LI> importedKeySetNull - change imported key to NULL if
+   *               its primary key has been deleted
+   *      </UL>
+   *	<LI><B>FK_NAME</B> String => foreign key name (may be null)
+   *	<LI><B>PK_NAME</B> String => primary key name (may be null)
+   *  </OL>
+   *
+   * @param catalog a catalog name; "" retrieves those without a catalog
+   * @param schema a schema name pattern; "" retrieves those
+   * without a schema
+   * @param table a table name
+   * @return ResultSet each row is a primary key column description
+   * @see #getExportedKeys
+   */
+  public java.sql.ResultSet getImportedKeys(String catalog, String schema, String table) throws SQLException
+  {
+    // XXX-Not Implemented
+    return null;
+  }
+  
+  /**
+   * Get a description of a foreign key columns that reference a
+   * table's primary key columns (the foreign keys exported by a
+   * table).  They are ordered by FKTABLE_CAT, FKTABLE_SCHEM,
+   * FKTABLE_NAME, and KEY_SEQ.
+   *
+   * <P>Each foreign key column description has the following columns:
+   *  <OL>
+   *	<LI><B>PKTABLE_CAT</B> String => primary key table catalog (may be null)
+   *	<LI><B>PKTABLE_SCHEM</B> String => primary key table schema (may be null)
+   *	<LI><B>PKTABLE_NAME</B> String => primary key table name
+   *	<LI><B>PKCOLUMN_NAME</B> String => primary key column name
+   *	<LI><B>FKTABLE_CAT</B> String => foreign key table catalog (may be null)
+   *      being exported (may be null)
+   *	<LI><B>FKTABLE_SCHEM</B> String => foreign key table schema (may be null)
+   *      being exported (may be null)
+   *	<LI><B>FKTABLE_NAME</B> String => foreign key table name
+   *      being exported
+   *	<LI><B>FKCOLUMN_NAME</B> String => foreign key column name
+   *      being exported
+   *	<LI><B>KEY_SEQ</B> short => sequence number within foreign key
+   *	<LI><B>UPDATE_RULE</B> short => What happens to
+   *       foreign key when primary is updated:
+   *      <UL>
+   *      <LI> importedKeyCascade - change imported key to agree
+   *               with primary key update
+   *      <LI> importedKeyRestrict - do not allow update of primary
+   *               key if it has been imported
+   *      <LI> importedKeySetNull - change imported key to NULL if
+   *               its primary key has been updated
+   *      </UL>
+   *	<LI><B>DELETE_RULE</B> short => What happens to
+   *      the foreign key when primary is deleted.
+   *      <UL>
+   *      <LI> importedKeyCascade - delete rows that import a deleted key
+   *      <LI> importedKeyRestrict - do not allow delete of primary
+   *               key if it has been imported
+   *      <LI> importedKeySetNull - change imported key to NULL if
+   *               its primary key has been deleted
+   *      </UL>
+   *	<LI><B>FK_NAME</B> String => foreign key identifier (may be null)
+   *	<LI><B>PK_NAME</B> String => primary key identifier (may be null)
+   *  </OL>
+   *
+   * @param catalog a catalog name; "" retrieves those without a catalog
+   * @param schema a schema name pattern; "" retrieves those
+   * without a schema
+   * @param table a table name
+   * @return ResultSet each row is a foreign key column description
+   * @see #getImportedKeys
+   */
+  public java.sql.ResultSet getExportedKeys(String catalog, String schema, String table) throws SQLException
+  {
+    // XXX-Not Implemented
+    return null;
+  }
+  
+  /**
+   * Get a description of the foreign key columns in the foreign key
+   * table that reference the primary key columns of the primary key
+   * table (describe how one table imports another's key.) This
+   * should normally return a single foreign key/primary key pair
+   * (most tables only import a foreign key from a table once.)  They
+   * are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and
+   * KEY_SEQ.
+   *
+   * <P>Each foreign key column description has the following columns:
+   *  <OL>
+   *	<LI><B>PKTABLE_CAT</B> String => primary key table catalog (may be null)
+   *	<LI><B>PKTABLE_SCHEM</B> String => primary key table schema (may be null)
+   *	<LI><B>PKTABLE_NAME</B> String => primary key table name
+   *	<LI><B>PKCOLUMN_NAME</B> String => primary key column name
+   *	<LI><B>FKTABLE_CAT</B> String => foreign key table catalog (may be null)
+   *      being exported (may be null)
+   *	<LI><B>FKTABLE_SCHEM</B> String => foreign key table schema (may be null)
+   *      being exported (may be null)
+   *	<LI><B>FKTABLE_NAME</B> String => foreign key table name
+   *      being exported
+   *	<LI><B>FKCOLUMN_NAME</B> String => foreign key column name
+   *      being exported
+   *	<LI><B>KEY_SEQ</B> short => sequence number within foreign key
+   *	<LI><B>UPDATE_RULE</B> short => What happens to
+   *       foreign key when primary is updated:
+   *      <UL>
+   *      <LI> importedKeyCascade - change imported key to agree
+   *               with primary key update
+   *      <LI> importedKeyRestrict - do not allow update of primary
+   *               key if it has been imported
+   *      <LI> importedKeySetNull - change imported key to NULL if
+   *               its primary key has been updated
+   *      </UL>
+   *	<LI><B>DELETE_RULE</B> short => What happens to
+   *      the foreign key when primary is deleted.
+   *      <UL>
+   *      <LI> importedKeyCascade - delete rows that import a deleted key
+   *      <LI> importedKeyRestrict - do not allow delete of primary
+   *               key if it has been imported
+   *      <LI> importedKeySetNull - change imported key to NULL if
+   *               its primary key has been deleted
+   *      </UL>
+   *	<LI><B>FK_NAME</B> String => foreign key identifier (may be null)
+   *	<LI><B>PK_NAME</B> String => primary key identifier (may be null)
+   *  </OL>
+   *
+   * @param catalog a catalog name; "" retrieves those without a catalog
+   * @param schema a schema name pattern; "" retrieves those
+   * without a schema
+   * @param table a table name
+   * @return ResultSet each row is a foreign key column description
+   * @see #getImportedKeys
+   */
+  public java.sql.ResultSet getCrossReference(String primaryCatalog, String primarySchema, String primaryTable, String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException
+  {
+    // XXX-Not Implemented
+    return null;
+  }
+  
+  /**
+   * Get a description of all the standard SQL types supported by
+   * this database. They are ordered by DATA_TYPE and then by how
+   * closely the data type maps to the corresponding JDBC SQL type.
+   *
+   * <P>Each type description has the following columns:
+   *  <OL>
+   *	<LI><B>TYPE_NAME</B> String => Type name
+   *	<LI><B>DATA_TYPE</B> short => SQL data type from java.sql.Types
+   *	<LI><B>PRECISION</B> int => maximum precision
+   *	<LI><B>LITERAL_PREFIX</B> String => prefix used to quote a literal
+   *      (may be null)
+   *	<LI><B>LITERAL_SUFFIX</B> String => suffix used to quote a literal
+   (may be null)
+   *	<LI><B>CREATE_PARAMS</B> String => parameters used in creating
+   *      the type (may be null)
+   *	<LI><B>NULLABLE</B> short => can you use NULL for this type?
+   *      <UL>
+   *      <LI> typeNoNulls - does not allow NULL values
+   *      <LI> typeNullable - allows NULL values
+   *      <LI> typeNullableUnknown - nullability unknown
+   *      </UL>
+   *	<LI><B>CASE_SENSITIVE</B> boolean=> is it case sensitive?
+   *	<LI><B>SEARCHABLE</B> short => can you use "WHERE" based on this type:
+   *      <UL>
+   *      <LI> typePredNone - No support
+   *      <LI> typePredChar - Only supported with WHERE .. LIKE
+   *      <LI> typePredBasic - Supported except for WHERE .. LIKE
+   *      <LI> typeSearchable - Supported for all WHERE ..
+   *      </UL>
+   *	<LI><B>UNSIGNED_ATTRIBUTE</B> boolean => is it unsigned?
+   *	<LI><B>FIXED_PREC_SCALE</B> boolean => can it be a money value?
+   *	<LI><B>AUTO_INCREMENT</B> boolean => can it be used for an
+   *      auto-increment value?
+   *	<LI><B>LOCAL_TYPE_NAME</B> String => localized version of type name
+   *      (may be null)
+   *	<LI><B>MINIMUM_SCALE</B> short => minimum scale supported
+   *	<LI><B>MAXIMUM_SCALE</B> short => maximum scale supported
+   *	<LI><B>SQL_DATA_TYPE</B> int => unused
+   *	<LI><B>SQL_DATETIME_SUB</B> int => unused
+   *	<LI><B>NUM_PREC_RADIX</B> int => usually 2 or 10
+   *  </OL>
+   *
+   * @return ResultSet each row is a SQL type description
+   */
+  public java.sql.ResultSet getTypeInfo() throws SQLException
+  {
+    // XXX-Not Implemented
+    return null;
+  }
+  
+  /**
+   * Get a description of a table's indices and statistics. They are
+   * ordered by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION.
+   *
+   * <P>Each index column description has the following columns:
+   *  <OL>
+   *	<LI><B>TABLE_CAT</B> String => table catalog (may be null)
+   *	<LI><B>TABLE_SCHEM</B> String => table schema (may be null)
+   *	<LI><B>TABLE_NAME</B> String => table name
+   *	<LI><B>NON_UNIQUE</B> boolean => Can index values be non-unique?
+   *      false when TYPE is tableIndexStatistic
+   *	<LI><B>INDEX_QUALIFIER</B> String => index catalog (may be null);
+   *      null when TYPE is tableIndexStatistic
+   *	<LI><B>INDEX_NAME</B> String => index name; null when TYPE is
+   *      tableIndexStatistic
+   *	<LI><B>TYPE</B> short => index type:
+   *      <UL>
+   *      <LI> tableIndexStatistic - this identifies table statistics that are
+   *           returned in conjuction with a table's index descriptions
+   *      <LI> tableIndexClustered - this is a clustered index
+   *      <LI> tableIndexHashed - this is a hashed index
+   *      <LI> tableIndexOther - this is some other style of index
+   *      </UL>
+   *	<LI><B>ORDINAL_POSITION</B> short => column sequence number
+   *      within index; zero when TYPE is tableIndexStatistic
+   *	<LI><B>COLUMN_NAME</B> String => column name; null when TYPE is
+   *      tableIndexStatistic
+   *	<LI><B>ASC_OR_DESC</B> String => column sort sequence, "A" => ascending,
+   *      "D" => descending, may be null if sort sequence is not supported;
+   *      null when TYPE is tableIndexStatistic
+   *	<LI><B>CARDINALITY</B> int => When TYPE is tableIndexStatisic then
+   *      this is the number of rows in the table; otherwise it is the
+   *      number of unique values in the index.
+   *	<LI><B>PAGES</B> int => When TYPE is  tableIndexStatisic then
+   *      this is the number of pages used for the table, otherwise it
+   *      is the number of pages used for the current index.
+   *	<LI><B>FILTER_CONDITION</B> String => Filter condition, if any.
+   *      (may be null)
+   *  </OL>
+   *
+   * @param catalog a catalog name; "" retrieves those without a catalog
+   * @param schema a schema name pattern; "" retrieves those without a schema
+   * @param table a table name
+   * @param unique when true, return only indices for unique values;
+   *     when false, return indices regardless of whether unique or not
+   * @param approximate when true, result is allowed to reflect approximate
+   *     or out of data values; when false, results are requested to be
+   *     accurate
+   * @return ResultSet each row is an index column description
+   */
+  public java.sql.ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) throws SQLException
+  {
+    // XXX-Not Implemented
+    return null;
+  }
 }
diff --git a/src/interfaces/jdbc/postgresql/Driver.java b/src/interfaces/jdbc/postgresql/Driver.java
index 055a65601aa..674c96fc66d 100644
--- a/src/interfaces/jdbc/postgresql/Driver.java
+++ b/src/interfaces/jdbc/postgresql/Driver.java
@@ -2,12 +2,8 @@ package postgresql;
 
 import java.sql.*;
 import java.util.*;
-import postgresql.*;
 
 /**
- * @version 1.0 15-APR-1997
- * @author <A HREF="mailto:adrian@hottub.org">Adrian Hall</A>
- *
  * The Java SQL framework allows for multiple database drivers.  Each
  * driver should supply a class that implements the Driver interface
  *
@@ -28,242 +24,274 @@ import postgresql.*;
  */
 public class Driver implements java.sql.Driver 
 {
-
-	static 
-	{
-		try
-		{
-			new Driver();
-		} catch (SQLException e) {
-			e.printStackTrace();
-		}
+  // These should be in sync with the backend that the driver was
+  // distributed with
+  static final int MAJORVERSION = 6;
+  static final int MINORVERSION = 2;
+  
+  static 
+  {
+    try {
+      // moved the registerDriver from the constructor to here
+      // because some clients call the driver themselves (I know, as
+      // my early jdbc work did - and that was based on other examples).
+      // Placing it here, means that the driver is registered once only.
+      java.sql.DriverManager.registerDriver(new Driver());
+    } catch (SQLException e) {
+      e.printStackTrace();
+    }
+  }
+  
+  /**
+   * Construct a new driver and register it with DriverManager
+   *
+   * @exception SQLException for who knows what!
+   */
+  public Driver() throws SQLException
+  {
+  }
+  
+  /**
+   * Try to make a database connection to the given URL.  The driver
+   * should return "null" if it realizes it is the wrong kind of
+   * driver to connect to the given URL.  This will be common, as
+   * when the JDBC driverManager is asked to connect to a given URL,
+   * it passes the URL to each loaded driver in turn.
+   *
+   * The driver should raise an SQLException if it is the right driver
+   * to connect to the given URL, but has trouble connecting to the
+   * database.
+   *
+   * The java.util.Properties argument can be used to pass arbitrary
+   * string tag/value pairs as connection arguments.  Normally, at least
+   * "user" and "password" properties should be included in the 
+   * properties.
+   *
+   * Our protocol takes the form:
+   * <PRE>
+   *	jdbc:postgresql://host:port/database
+   * </PRE>
+   *
+   * @param url the URL of the database to connect to
+   * @param info a list of arbitrary tag/value pairs as connection
+   *	arguments
+   * @return a connection to the URL or null if it isnt us
+   * @exception SQLException if a database access error occurs
+   * @see java.sql.Driver#connect
+   */
+  public java.sql.Connection connect(String url, Properties info) throws SQLException
+  {
+    if((props = parseURL(url,info))==null)
+      return null;
+    
+    return new Connection (host(), port(), props, database(), url, this);
+  }
+  
+  /**
+   * Returns true if the driver thinks it can open a connection to the
+   * given URL.  Typically, drivers will return true if they understand
+   * the subprotocol specified in the URL and false if they don't.  Our
+   * protocols start with jdbc:postgresql:
+   *
+   * @see java.sql.Driver#acceptsURL
+   * @param url the URL of the driver
+   * @return true if this driver accepts the given URL
+   * @exception SQLException if a database-access error occurs
+   * 	(Dont know why it would *shrug*)
+   */
+  public boolean acceptsURL(String url) throws SQLException
+  {
+    if(parseURL(url,null)==null)
+      return false;
+    return true;
+  }
+  
+  /**
+   * The getPropertyInfo method is intended to allow a generic GUI
+   * tool to discover what properties it should prompt a human for
+   * in order to get enough information to connect to a database.
+   * Note that depending on the values the human has supplied so
+   * far, additional values may become necessary, so it may be necessary
+   * to iterate through several calls to getPropertyInfo
+   *
+   * @param url the Url of the database to connect to
+   * @param info a proposed list of tag/value pairs that will be sent on
+   * 	connect open.
+   * @return An array of DriverPropertyInfo objects describing
+   * 	possible properties.  This array may be an empty array if
+   *	no properties are required
+   * @exception SQLException if a database-access error occurs
+   * @see java.sql.Driver#getPropertyInfo
+   */
+  public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException
+  {
+    return null;		// We don't need anything except
+    // the username, which is a default
+  }
+  
+  /**
+   * Gets the drivers major version number
+   *
+   * @return the drivers major version number
+   */
+  public int getMajorVersion()
+  {
+    return MAJORVERSION;
+  }
+  
+  /**
+   * Get the drivers minor version number
+   *
+   * @return the drivers minor version number
+   */
+  public int getMinorVersion()
+  {
+    return MINORVERSION;
+  }
+  
+  /**
+   * Report whether the driver is a genuine JDBC compliant driver.  A
+   * driver may only report "true" here if it passes the JDBC compliance
+   * tests, otherwise it is required to return false.  JDBC compliance
+   * requires full support for the JDBC API and full support for SQL 92
+   * Entry Level.  
+   */
+  public boolean jdbcCompliant()
+  {
+    return false;
+  }
+  
+  private Properties props;
+  
+  static private String[] protocols = { "jdbc","postgresql" };
+  
+  /**
+   * Constructs a new DriverURL, splitting the specified URL into its
+   * component parts
+   */
+  Properties parseURL(String url,Properties defaults) throws SQLException
+  {
+    int state = -1;
+    Properties urlProps = new Properties(defaults);
+    String key = new String();
+    String value = new String();
+    
+    StringTokenizer st = new StringTokenizer(url, ":/;=&?", true);
+    for (int count = 0; (st.hasMoreTokens()); count++) {
+      String token = st.nextToken();
+      
+      // PM June 29 1997
+      // Added this, to help me understand how this works.
+      // Unless you want each token to be processed, leave this commented out
+      // but don't delete it.
+      //DriverManager.println("wellFormedURL: state="+state+" count="+count+" token='"+token+"'");
+      
+      // PM Aug 2 1997 - Modified to allow multiple backends
+      if (count <= 3) {
+	if ((count % 2) == 1 && token.equals(":"))
+	  ;
+	else if((count % 2) == 0) {
+	  boolean found=(count==0)?true:false;
+	  for(int tmp=0;tmp<protocols.length;tmp++) {
+	    if(token.equals(protocols[tmp])) {
+	      // PM June 29 1997 Added this property to enable the driver
+	      // to handle multiple backend protocols.
+	      if(count == 2 && tmp > 0) {
+		urlProps.put("Protocol",token);
+		found=true;
+	      }
+	    }
+	  }
+	  
+	  if(found == false)
+	    return null;
+	} else return null;
+      }
+      else if (count > 3) {
+	if (count == 4 && token.equals("/")) state = 0;
+	else if (count == 4) {
+	  urlProps.put("PGDBNAME", token);
+	  state = -2;
 	}
-
-	/**
-	  * Construct a new driver and register it with DriverManager
-	  *
-	  * @exception SQLException for who knows what!
-	  */
-	public Driver() throws SQLException
-	{
-		java.sql.DriverManager.registerDriver(this);
+	else if (count == 5 && state == 0 && token.equals("/"))
+	  state = 1;
+	else if (count == 5 && state == 0)
+	  return null;
+	else if (count == 6 && state == 1)
+	  urlProps.put("PGHOST", token);
+	else if (count == 7 && token.equals(":")) state = 2;
+	else if (count == 8 && state == 2) {
+	  try {
+	    Integer portNumber = Integer.decode(token);
+	    urlProps.put("PGPORT", portNumber.toString());
+	  } catch (Exception e) {
+	    return null;
+	  }
 	}
-	
-	/**
-	 * Try to make a database connection to the given URL.  The driver
-	 * should return "null" if it realizes it is the wrong kind of
-	 * driver to connect to the given URL.  This will be common, as
-	 * when the JDBC driverManager is asked to connect to a given URL,
-	 * it passes the URL to each loaded driver in turn.
-	 *
-	 * The driver should raise an SQLException if it is the right driver
-	 * to connect to the given URL, but has trouble connecting to the
-	 * database.
-	 *
-	 * The java.util.Properties argument can be used to pass arbitrary
-	 * string tag/value pairs as connection arguments.  Normally, at least
-	 * "user" and "password" properties should be included in the 
-	 * properties.
-	 *
-	 * Our protocol takes the form:
-	 * <PRE>
-	 *	jdbc:postgresql://host:port/database
-	 * </PRE>
-	 *
-	 * @param url the URL of the database to connect to
-	 * @param info a list of arbitrary tag/value pairs as connection
-	 *	arguments
-	 * @return a connection to the URL or null if it isnt us
-	 * @exception SQLException if a database access error occurs
-	 * @see java.sql.Driver#connect
-	 */
-	public java.sql.Connection connect(String url, Properties info) throws SQLException
-	{
-		DriverURL dr = new DriverURL(url);
-		int port;
-
-		if (!(dr.protocol().equals("jdbc")))
-                        return null;
-		if (!(dr.subprotocol().equals("postgresql")))
-                        return null;
-		if (dr.host().equals("unknown"))
-                        return null;
-		port = dr.port();
-		if (port == -1)
-                        port = 5432;    // Default PostgreSQL port
-		return new Connection (dr.host(), port, info, dr.database(), url, this);
+	else if ((count == 7 || count == 9) &&
+		 (state == 1 || state == 2) && token.equals("/"))
+	  state = -1;
+	else if (state == -1) {
+	  urlProps.put("PGDBNAME", token);
+	  state = -2;
 	}
-
-	/**
-	 * Returns true if the driver thinks it can open a connection to the
-	 * given URL.  Typically, drivers will return true if they understand
-	 * the subprotocol specified in the URL and false if they don't.  Our
-	 * protocols start with jdbc:postgresql:
-	 *
-	 * @see java.sql.Driver#acceptsURL
-	 * @param url the URL of the driver
-	 * @return true if this driver accepts the given URL
-         * @exception SQLException if a database-access error occurs
-	 * 	(Dont know why it would *shrug*)
-	 */
-	public boolean acceptsURL(String url) throws SQLException
-	{
-		DriverURL dr = new DriverURL(url);
-
-		if (dr.protocol().equals("jdbc"))
-			if (dr.subprotocol().equals("postgresql"))
-				return true;
-		return false;
+	else if (state <= -2 && (count % 2) == 1) {
+	  // PM Aug 2 1997 - added tests for ? and &
+	  if (token.equals(";") || token.equals("?") || token.equals("&") ) state = -3;
+	  else if (token.equals("=")) state = -5;
 	}
-
-	/**
-	 * The getPropertyInfo method is intended to allow a generic GUI
-	 * tool to discover what properties it should prompt a human for
-	 * in order to get enough information to connect to a database.
-	 * Note that depending on the values the human has supplied so
-	 * far, additional values may become necessary, so it may be necessary
-	 * to iterate through several calls to getPropertyInfo
-	 *
-	 * @param url the Url of the database to connect to
-	 * @param info a proposed list of tag/value pairs that will be sent on
-	 * 	connect open.
-	 * @return An array of DriverPropertyInfo objects describing
-	 * 	possible properties.  This array may be an empty array if
-	 *	no properties are required
-	 * @exception SQLException if a database-access error occurs
-	 * @see java.sql.Driver#getPropertyInfo
-	 */
-	public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException
-	{
-		return null;		// We don't need anything except
-					// the username, which is a default
-	}
-
-	/**
-	 * Gets the drivers major version number
-	 *
-	 * @return the drivers major version number
-	 */
-	public int getMajorVersion()
-	{
-		return 1;
-	}
-	
-	/**
-	 * Get the drivers minor version number
-	 *
-	 * @return the drivers minor version number
-	 */
-	public int getMinorVersion()
-	{
-		return 0;
-	}
-	
-	/**
-	 * Report whether the driver is a genuine JDBC compliant driver.  A
-	 * driver may only report "true" here if it passes the JDBC compliance
-	 * tests, otherwise it is required to return false.  JDBC compliance
-	 * requires full support for the JDBC API and full support for SQL 92
-	 * Entry Level.  
-	 */
-	public boolean jdbcCompliant()
-	{
-		return false;
+	else if (state <= -2 && (count % 2) == 0) {
+	  if (state == -3) key = token;
+	  else if (state == -5) {
+	    value = token;
+	    //DriverManager.println("put("+key+","+value+")");
+	    urlProps.put(key, value);
+	    state = -2;
+	  }
 	}
+      }
+    }
+    
+    // PM June 29 1997
+    // This now outputs the properties only if we are logging
+    if(DriverManager.getLogStream() != null)
+      urlProps.list(DriverManager.getLogStream());
+    
+    return urlProps;
+    
+  }
+  
+  /**
+   * Returns the hostname portion of the URL
+   */
+  public String host()
+  {
+    return props.getProperty("PGHOST","localhost");
+  }
+  
+  /**
+   * Returns the port number portion of the URL
+   * or -1 if no port was specified
+   */
+  public int port()
+  {
+    return Integer.parseInt(props.getProperty("PGPORT","5432"));
+  }
+  
+  /**
+   * Returns the database name of the URL
+   */
+  public String database()
+  {
+    return props.getProperty("PGDBNAME");
+  }
+  
+  /**
+   * Returns any property
+   */
+  public String property(String name)
+  {
+    return props.getProperty(name);
+  }
 }
 
-/**
- * The DriverURL class splits a JDBC URL into its subcomponents
- *
- *	protocol:subprotocol:/[/host[:port]/][database]
- */
-class DriverURL
-{
-	private String protocol, subprotocol, host, database;
-	private int port = -1;
-
-	/**
-	 * Constructs a new DriverURL, splitting the specified URL into its
-	 * component parts
-	 */
-	public DriverURL(String url) throws SQLException
-	{
-		int a, b, c;
-		String tmp, hostport, dbportion;
-
-		a = url.indexOf(':');
-		if (a == -1)
-			throw new SQLException("Bad URL Protocol specifier");
-		b = url.indexOf(':', a+1);
-		if (b == -1)
-			throw new SQLException("Bad URL Subprotocol specifier");
-                protocol = new String(url.substring(0, a));
-		subprotocol = new String(url.substring(a+1, b));
-                tmp = new String(url.substring(b+1, url.length()));
-		if (tmp.length() < 2)
-			throw new SQLException("Bad URL Database specifier");
-                if (!tmp.substring(0, 2).equals("//"))
-		{
-			host = new String("unknown");
-			port = -1;
-			database = new String(tmp.substring(1, tmp.length()));
-			return;
-		}
-		dbportion = new String(tmp.substring(2, tmp.length()));
-		c = dbportion.indexOf('/');
-		if (c == -1)
-			throw new SQLException("Bad URL Database specifier");
-		a = dbportion.indexOf(':');
-		if (a == -1)
-		{
-			host = new String(dbportion.substring(0, c));
-			port = -1;
-			database = new String(dbportion.substring(c+1, dbportion.length()));
-		} else {
-			host = new String(dbportion.substring(0, a));
-			port = Integer.valueOf(dbportion.substring(a+1, c)).intValue();
-			database = new String(dbportion.substring(c+1, dbportion.length()));
-		}
-	}
-
-	/**
-	 * Returns the protocol name of the DriverURL
-	 */
-	public String protocol()
-	{
-		return protocol;
-	}
-
-	/**
-	 * Returns the subprotocol name of the DriverURL
-	 */
-	public String subprotocol()
-	{
-		return subprotocol;
-	}
-
-	/**
-	 * Returns the hostname portion of the URL
-	 */
-	public String host()
-	{
-		return host;
-	}
-
-	/**
-	 * Returns the port number portion of the URL
-	 * or -1 if no port was specified
-	 */
-	public int port()
-	{
-		return port;
-	}
-
-	/**
-	 * Returns the database name of the URL
-	 */
-	public String database()
-	{
-		return database;
-	}
-}
diff --git a/src/interfaces/jdbc/postgresql/Field.java b/src/interfaces/jdbc/postgresql/Field.java
index 3d27dc6c786..2beb1d29411 100644
--- a/src/interfaces/jdbc/postgresql/Field.java
+++ b/src/interfaces/jdbc/postgresql/Field.java
@@ -13,77 +13,91 @@ import postgresql.*;
  */
 public class Field
 {
-	int length;		// Internal Length of this field
-	int oid;		// OID of the type
-	Connection conn;	// Connection Instantation
-	String name;		// Name of this field
-
-	int sql_type = -1;	// The entry in java.sql.Types for this field
-	String type_name = null;// The sql type name
-
-	/**
-	 *	Construct a field based on the information fed to it.
-	 *
-	 * @param conn the connection this field came from
-	 * @param name the name of the field
-	 * @param oid the OID of the field
-	 * @param len the length of the field
-	 */
-	public Field(Connection conn, String name, int oid, int length)
-	{
-		this.conn = conn;
-		this.name = name;
-		this.oid = oid;
-		this.length = length;
-	}
-
-	/**
-	 * the ResultSet and ResultMetaData both need to handle the SQL
-	 * type, which is gained from another query.  Note that we cannot
-	 * use getObject() in this, since getObject uses getSQLType().
-	 *
-	 * @return the entry in Types that refers to this field
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getSQLType() throws SQLException
-	{
-		if (sql_type == -1)
-		{
-			ResultSet result = (postgresql.ResultSet)conn.ExecSQL("select typname from pg_type where oid = " + oid);
-			if (result.getColumnCount() != 1 || result.getTupleCount() != 1)
-				throw new SQLException("Unexpected return from query for type");
-			result.next();
-			type_name = result.getString(1);
-			if (type_name.equals("int2"))				sql_type = Types.SMALLINT;
-			else if (type_name.equals("int4"))			sql_type = Types.INTEGER;
-			else if (type_name.equals("int8"))			sql_type = Types.BIGINT;
-			else if (type_name.equals("cash"))			sql_type = Types.DECIMAL;
-			else if (type_name.equals("money"))			sql_type = Types.DECIMAL;
-			else if (type_name.equals("float4"))			sql_type = Types.REAL;
-			else if (type_name.equals("float8"))			sql_type = Types.DOUBLE;
-			else if (type_name.equals("bpchar"))			sql_type = Types.CHAR;
-			else if (type_name.equals("varchar"))			sql_type = Types.VARCHAR;
-			else if (type_name.equals("bool"))			sql_type = Types.BIT;
-			else if (type_name.equals("date"))			sql_type = Types.DATE;
-			else if (type_name.equals("time"))			sql_type = Types.TIME;
-			else if (type_name.equals("abstime"))			sql_type = Types.TIMESTAMP;
-			else							sql_type = Types.OTHER;
-		}	
-		return sql_type;
-	}
-
-	/**
-	 * We also need to get the type name as returned by the back end.
-	 * This is held in type_name AFTER a call to getSQLType.  Since
-	 * we get this information within getSQLType (if it isn't already
-	 * done), we can just call getSQLType and throw away the result.
-	 *
-	 * @return the String representation of the type of this field
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String getTypeName() throws SQLException
-	{
-		int sql = getSQLType();
-		return type_name;
-	}
+  int length;		// Internal Length of this field
+  int oid;		// OID of the type
+  Connection conn;	// Connection Instantation
+  String name;		// Name of this field
+  
+  int sql_type = -1;	// The entry in java.sql.Types for this field
+  String type_name = null;// The sql type name
+  
+  /**
+   *	Construct a field based on the information fed to it.
+   *
+   * @param conn the connection this field came from
+   * @param name the name of the field
+   * @param oid the OID of the field
+   * @param len the length of the field
+   */
+  public Field(Connection conn, String name, int oid, int length)
+  {
+    this.conn = conn;
+    this.name = name;
+    this.oid = oid;
+    this.length = length;
+  }
+  
+  /**
+   * the ResultSet and ResultMetaData both need to handle the SQL
+   * type, which is gained from another query.  Note that we cannot
+   * use getObject() in this, since getObject uses getSQLType().
+   *
+   * @return the entry in Types that refers to this field
+   * @exception SQLException if a database access error occurs
+   */
+  public int getSQLType() throws SQLException
+  {
+    if (sql_type == -1)
+      {
+	ResultSet result = (postgresql.ResultSet)conn.ExecSQL("select typname from pg_type where oid = " + oid);
+	if (result.getColumnCount() != 1 || result.getTupleCount() != 1)
+	  throw new SQLException("Unexpected return from query for type");
+	result.next();
+	type_name = result.getString(1);
+	if (type_name.equals("int2"))
+	  sql_type = Types.SMALLINT;
+	else if (type_name.equals("int4"))
+	  sql_type = Types.INTEGER;
+	else if (type_name.equals("int8"))
+	  sql_type = Types.BIGINT;
+	else if (type_name.equals("cash"))
+	  sql_type = Types.DECIMAL;
+	else if (type_name.equals("money"))
+	  sql_type = Types.DECIMAL;
+	else if (type_name.equals("float4"))
+	  sql_type = Types.REAL;
+	else if (type_name.equals("float8"))
+	  sql_type = Types.DOUBLE;
+	else if (type_name.equals("bpchar"))
+	  sql_type = Types.CHAR;
+	else if (type_name.equals("varchar"))
+	  sql_type = Types.VARCHAR;
+	else if (type_name.equals("bool"))
+	  sql_type = Types.BIT;
+	else if (type_name.equals("date"))
+	  sql_type = Types.DATE;
+	else if (type_name.equals("time"))
+	  sql_type = Types.TIME;
+	else if (type_name.equals("abstime"))
+	  sql_type = Types.TIMESTAMP;
+	else
+	  sql_type = Types.OTHER;
+      }	
+    return sql_type;
+  }
+  
+  /**
+   * We also need to get the type name as returned by the back end.
+   * This is held in type_name AFTER a call to getSQLType.  Since
+   * we get this information within getSQLType (if it isn't already
+   * done), we can just call getSQLType and throw away the result.
+   *
+   * @return the String representation of the type of this field
+   * @exception SQLException if a database access error occurs
+   */
+  public String getTypeName() throws SQLException
+  {
+    int sql = getSQLType();
+    return type_name;
+  }
 }
diff --git a/src/interfaces/jdbc/postgresql/PG_Object.java b/src/interfaces/jdbc/postgresql/PG_Object.java
index 89518dc0d8d..22c0c039c61 100644
--- a/src/interfaces/jdbc/postgresql/PG_Object.java
+++ b/src/interfaces/jdbc/postgresql/PG_Object.java
@@ -14,18 +14,132 @@ import postgresql.*;
  */
 public class PG_Object
 {
-	public String	type;
-	public String	value;
-
-	/**
-	 *	Constructor for the PostgreSQL generic object
-	 *
-	 * @param type a string describing the type of the object
-	 * @param value a string representation of the value of the object
-	 */
-	public PG_Object(String type, String value)
-	{
-		this.type = type;
-		this.value = value;
-	}
+  public String	type;
+  public String	value;
+  
+  /**
+   *	Constructor for the PostgreSQL generic object
+   *
+   * @param type a string describing the type of the object
+   * @param value a string representation of the value of the object
+   */
+  public PG_Object(String type, String value) throws SQLException
+  {
+    this.type = type;
+    this.value = value;
+  }
+  
+  /**
+   * This returns true if the object is a 'box'
+   */
+  public boolean isBox()
+  {
+    return type.equals("box");
+  }
+  
+  /**
+   * This returns a PGbox object, or null if it's not
+   * @return PGbox
+   */
+  public PGbox getBox() throws SQLException
+  {
+    if(isBox())
+      return new PGbox(value);
+    return null;
+  }
+  
+  /**
+   * This returns true if the object is a 'point'
+   */
+  public boolean isCircle()
+  {
+    return type.equals("circle");
+  }
+  
+  /**
+   * This returns a PGcircle object, or null if it's not
+   * @return PGcircle
+   */
+  public PGcircle getCircle() throws SQLException
+  {
+    if(isCircle())
+      return new PGcircle(value);
+    return null;
+  }
+  
+  /**
+   * This returns true if the object is a 'lseg' (line segment)
+   */
+  public boolean isLseg()
+  {
+    return type.equals("lseg");
+  }
+  
+  /**
+   * This returns a PGlsegobject, or null if it's not
+   * @return PGlseg
+   */
+  public PGlseg getLseg() throws SQLException
+  {
+    if(isLseg())
+      return new PGlseg(value);
+    return null;
+  }
+  
+  /**
+   * This returns true if the object is a 'path'
+   */
+  public boolean isPath()
+  {
+    return type.equals("path");
+  }
+  
+  /**
+   * This returns a PGpath object, or null if it's not
+   * @return PGpath
+   */
+  public PGpath getPath() throws SQLException
+  {
+    if(isPath())
+      return new PGpath(value);
+    return null;
+  }
+  
+  /**
+   * This returns true if the object is a 'point'
+   */
+  public boolean isPoint()
+  {
+    return type.equals("point");
+  }
+  
+  /**
+   * This returns a PGpoint object, or null if it's not
+   * @return PGpoint object
+   */
+  public PGpoint getPoint() throws SQLException
+  {
+    if(isPoint())
+      return new PGpoint(value);
+    return null;
+  }
+  
+  /**
+   * This returns true if the object is a 'polygon'
+   */
+  public boolean isPolygon()
+  {
+    return type.equals("polygon");
+  }
+  
+  /**
+   * This returns a PGpolygon object, or null if it's not
+   * @return PGpolygon
+   */
+  public PGpolygon getPolygon() throws SQLException
+  {
+    if(isPolygon())
+      return new PGpolygon(value);
+    return null;
+  }
 }
diff --git a/src/interfaces/jdbc/postgresql/ResultSet.java b/src/interfaces/jdbc/postgresql/ResultSet.java
index c5894e7bffc..d9222ee8ea2 100644
--- a/src/interfaces/jdbc/postgresql/ResultSet.java
+++ b/src/interfaces/jdbc/postgresql/ResultSet.java
@@ -9,9 +9,6 @@ import java.sql.*;
 import postgresql.*;
 
 /**
- * @version 1.0 15-APR-1997
- * @author <A HREF="mailto:adrian@hottub.org">Adrian Hall</A>
- *
  * A ResultSet provides access to a table of data generated by executing a
  * Statement.  The table rows are retrieved in sequence.  Within a row its
  * column values can be accessed in any order.
@@ -54,792 +51,793 @@ import postgresql.*;
  */
 public class ResultSet implements java.sql.ResultSet 
 {
-	Vector rows;		// The results
-	Field fields[];		// The field descriptions
-	String status;		// Status of the result
-	int updateCount;	// How many rows did we get back?
-	int current_row;	// Our pointer to where we are at
-	byte[][] this_row;	// the current row result
-	Connection connection;	// the connection which we returned from
-	SQLWarning warnings = null;	// The warning chain
-	boolean wasNullFlag = false;	// the flag for wasNull()
-
-	//  We can chain multiple resultSets together - this points to
-	// next resultSet in the chain.
-	private ResultSet next = null;
-
-	/**
-	 * Create a new ResultSet - Note that we create ResultSets to
-	 * represent the results of everything.
-	 *
-	 * @param fields an array of Field objects (basically, the
-	 *	ResultSet MetaData)
-	 * @param tuples Vector of the actual data
-	 * @param status the status string returned from the back end
-	 * @param updateCount the number of rows affected by the operation
-	 * @param cursor the positioned update/delete cursor name
-	 */
-	public ResultSet(Connection conn, Field[] fields, Vector tuples, String status, int updateCount)
-	{
-		this.connection = conn;
-		this.fields = fields;
-		this.rows = tuples;
-		this.status = status;
-		this.updateCount = updateCount;
-		this.this_row = null;
-		this.current_row = -1;
-	}
-
-	/**
-	 * A ResultSet is initially positioned before its first row,
-	 * the first call to next makes the first row the current row;
-	 * the second call makes the second row the current row, etc.
-	 *
-	 * If an input stream from the previous row is open, it is
-	 * implicitly closed.  The ResultSet's warning chain is cleared
-	 * when a new row is read
-	 *
-	 * @return true if the new current is valid; false if there are no
-	 *	more rows
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean next() throws SQLException
-	{
-		if (++current_row >= rows.size())
-			return false;
-		this_row = (byte [][])rows.elementAt(current_row);
-		return true;
-	}
-
-	/**
-	 * In some cases, it is desirable to immediately release a ResultSet
-	 * database and JDBC resources instead of waiting for this to happen
-	 * when it is automatically closed.  The close method provides this
-	 * immediate release.
-	 *
-	 * <B>Note:</B> A ResultSet is automatically closed by the Statement
-	 * the Statement that generated it when that Statement is closed,
-	 * re-executed, or is used to retrieve the next result from a sequence
-	 * of multiple results.  A ResultSet is also automatically closed 
-	 * when it is garbage collected.
-	 *
-	 * @exception SQLException if a database access error occurs
-	 */
-	public void close() throws SQLException
-	{
-		// No-op
-	}
-
-	/**
-	 * A column may have the value of SQL NULL; wasNull() reports whether
-	 * the last column read had this special value.  Note that you must
-	 * first call getXXX on a column to try to read its value and then
-	 * call wasNull() to find if the value was SQL NULL
-	 *
-	 * @return true if the last column read was SQL NULL
-	 * @exception SQLException if a database access error occurred
-	 */
-	public boolean wasNull() throws SQLException
-	{
-		return wasNullFlag;
-	}
-
-	/**
-	 * Get the value of a column in the current row as a Java String
-	 *
-	 * @param columnIndex the first column is 1, the second is 2...
-	 * @return the column value, null for SQL NULL
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String getString(int columnIndex) throws SQLException
-	{
-		byte[] bytes = getBytes(columnIndex);
-
-		if (bytes == null)
-			return null;
-		return new String(bytes);
-	}
-
-	/**
-	 * Get the value of a column in the current row as a Java boolean
-	 *
-	 * @param columnIndex the first column is 1, the second is 2...
-	 * @return the column value, false for SQL NULL
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean getBoolean(int columnIndex) throws SQLException
-	{
-		String s = getString(columnIndex);
-
-		if (s != null)
-		{
-			int c = s.charAt(0);
-			return ((c == 't') || (c == 'T'));
-		}
-		return false;		// SQL NULL
-	}
-
-	/**
-	 * Get the value of a column in the current row as a Java byte.
-	 *
-	 * @param columnIndex the first column is 1, the second is 2,...
-	 * @return the column value; 0 if SQL NULL
-	 * @exception SQLException if a database access error occurs
-	 */
-	public byte getByte(int columnIndex) throws SQLException
-	{
-		String s = getString(columnIndex);
-		
-		if (s != null)
-		{
-			try
-			{
-				return Byte.parseByte(s);
-			} catch (NumberFormatException e) {
-				throw new SQLException("Bad Byte Form: " + s);
-			}
-		}
-		return 0;		// SQL NULL
-	}
-
-	/**
-	 * Get the value of a column in the current row as a Java short.
-	 *
-	 * @param columnIndex the first column is 1, the second is 2,...
-	 * @return the column value; 0 if SQL NULL
-	 * @exception SQLException if a database access error occurs
-	 */
-	public short getShort(int columnIndex) throws SQLException
-	{
-		String s = getString(columnIndex);
-
-		if (s != null)
-		{
-			try
-			{
-				return Short.parseShort(s);
-			} catch (NumberFormatException e) {
-				throw new SQLException("Bad Short Form: " + s);
-			}
-		}
-		return 0;		// SQL NULL
-	}
-
-	/**
-	 * Get the value of a column in the current row as a Java int.
-	 *
-	 * @param columnIndex the first column is 1, the second is 2,...
-	 * @return the column value; 0 if SQL NULL
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getInt(int columnIndex) throws SQLException
-	{
-		String s = getString(columnIndex);
-
-		if (s != null)
-		{
-			try
-			{
-				return Integer.parseInt(s);
-			} catch (NumberFormatException e) {
-				throw new SQLException ("Bad Integer Form: " + s);
-			}
-		}
-		return 0;		// SQL NULL
-	}
-
-	/**
-	 * Get the value of a column in the current row as a Java long.
-	 *
-	 * @param columnIndex the first column is 1, the second is 2,...
-	 * @return the column value; 0 if SQL NULL
-	 * @exception SQLException if a database access error occurs
-	 */
-	public long getLong(int columnIndex) throws SQLException
-	{
-		String s = getString(columnIndex);
-
-		if (s != null)
-		{
-			try
-			{
-				return Long.parseLong(s);
-			} catch (NumberFormatException e) {
-				throw new SQLException ("Bad Long Form: " + s);
-			}
-		}
-		return 0;		// SQL NULL
-	}
-
-	/**
-	 * Get the value of a column in the current row as a Java float.
-	 *
-	 * @param columnIndex the first column is 1, the second is 2,...
-	 * @return the column value; 0 if SQL NULL
-	 * @exception SQLException if a database access error occurs
-	 */
-	public float getFloat(int columnIndex) throws SQLException
-	{
-		String s = getString(columnIndex);
-	
-		if (s != null)
-		{
-			try
-			{
-				return Float.valueOf(s).floatValue();
-			} catch (NumberFormatException e) {
-				throw new SQLException ("Bad Float Form: " + s);
-			}
-		}
-		return 0;		// SQL NULL
-	}
-
-	/**
-	 * Get the value of a column in the current row as a Java double.
-	 *
-	 * @param columnIndex the first column is 1, the second is 2,...
-	 * @return the column value; 0 if SQL NULL
-	 * @exception SQLException if a database access error occurs
-	 */
-	public double getDouble(int columnIndex) throws SQLException
-	{
-		String s = getString(columnIndex);
-	
-		if (s != null)
-		{
-			try
-			{
-				return Double.valueOf(s).doubleValue();
-			} catch (NumberFormatException e) {
-				throw new SQLException ("Bad Double Form: " + s);
-			}
-		}
-		return 0;		// SQL NULL
-	}
-
-	/**
-	 * Get the value of a column in the current row as a 
-	 * java.lang.BigDecimal object
-	 *
-	 * @param columnIndex  the first column is 1, the second is 2...
-	 * @param scale the number of digits to the right of the decimal
-	 * @return the column value; if the value is SQL NULL, null
-	 * @exception SQLException if a database access error occurs
-	 */
-	public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException
-	{
-		String s = getString(columnIndex);
-		BigDecimal val;
-
-		if (s != null)
-		{
-			try
-			{
-				val = new BigDecimal(s);
-			} catch (NumberFormatException e) {
-				throw new SQLException ("Bad BigDecimal Form: " + s);
-			}
-			try
-			{
-				return val.setScale(scale);
-			} catch (ArithmeticException e) {
-				throw new SQLException ("Bad BigDecimal Form: " + s);
-			}
-		}
-		return null;		// SQL NULL
-	}
-
-	/**
-	 * Get the value of a column in the current row as a Java byte array
-	 * The bytes represent the raw values returned by the driver.
-	 *
-	 * @param columnIndex the first column is 1, the second is 2, ...
-	 * @return the column value; if the value is SQL NULL, the result
-	 *	is null
-	 * @exception SQLException if a database access error occurs
-	 */
-	public byte[] getBytes(int columnIndex) throws SQLException
-	{
-		if (columnIndex < 1 || columnIndex > fields.length)
-			throw new SQLException("Column Index out of range");
-		wasNullFlag = (this_row[columnIndex - 1] == null);
-		return this_row[columnIndex - 1];
-	}
-
-	/**
-	 * Get the value of a column in the current row as a java.sql.Date
-	 * object
-	 *
-	 * @param columnIndex the first column is 1, the second is 2...
-	 * @return the column value; null if SQL NULL
-	 * @exception SQLException if a database access error occurs
-	 */
-	public java.sql.Date getDate(int columnIndex) throws SQLException
-	{
-		String s = getString(columnIndex);
-	
-		if (s != null)
-		{
-			try
-			{
-				if (s.length() != 10)
-					throw new NumberFormatException("Wrong Length!");
-				int mon = Integer.parseInt(s.substring(0,2));
-				int day = Integer.parseInt(s.substring(3,5));
-				int yr = Integer.parseInt(s.substring(6));
-				return new java.sql.Date(yr - 1900, mon -1, day);
-			} catch (NumberFormatException e) {
-				throw new SQLException("Bad Date Form: " + s);
-			}
-		}
-		return null;		// SQL NULL
-	}
-
-	/**
-	 * Get the value of a column in the current row as a java.sql.Time
-	 * object
-	 *
-	 * @param columnIndex the first column is 1, the second is 2...
-	 * @return the column value; null if SQL NULL
-	 * @exception SQLException if a database access error occurs
-	 */
-	public Time getTime(int columnIndex) throws SQLException
-	{
-		String s = getString(columnIndex);
-
-		if (s != null)
-		{
-			try
-			{
-				if (s.length() != 5 && s.length() != 8)
-					throw new NumberFormatException("Wrong Length!");
-				int hr = Integer.parseInt(s.substring(0,2));
-				int min = Integer.parseInt(s.substring(3,5));
-				int sec = (s.length() == 5) ? 0 : Integer.parseInt(s.substring(6));
-				return new Time(hr, min, sec);
-			} catch (NumberFormatException e) {
-				throw new SQLException ("Bad Time Form: " + s);
-			}
-		}
-		return null;		// SQL NULL
-	}
-
-	/**
-	 * Get the value of a column in the current row as a 
-	 * java.sql.Timestamp object
-	 *
-	 * @param columnIndex the first column is 1, the second is 2...
-	 * @return the column value; null if SQL NULL
-	 * @exception SQLException if a database access error occurs
-	 */
-	public Timestamp getTimestamp(int columnIndex) throws SQLException
-	{
-		String s = getString(columnIndex);
-		DateFormat df = DateFormat.getDateInstance();
-
-		if (s != null)
-		{
-			try
-			{
-				java.sql.Date d = (java.sql.Date)df.parse(s);
-				return new Timestamp(d.getTime());
-			} catch (ParseException e) {
-				throw new SQLException("Bad Timestamp Format: " + s);
-			}
-		}
-		return null;		// SQL NULL
-	}
-
-	/**
-	 * A column value can be retrieved as a stream of ASCII characters
-	 * and then read in chunks from the stream.  This method is 
-	 * particular suitable for retrieving large LONGVARCHAR values.
-	 * The JDBC driver will do any necessary conversion from the
-	 * database format into ASCII.
-	 *
-	 * <B>Note:</B> All the data in the returned stream must be read
-	 * prior to getting the value of any other column.  The next call
-	 * to a get method implicitly closes the stream.  Also, a stream
-	 * may return 0 for available() whether there is data available
-	 * or not.
-	 *
-	 * We implement an ASCII stream as a Binary stream - we should really
-	 * do the data conversion, but I cannot be bothered to implement this
-	 * right now.
-	 *
-	 * @param columnIndex the first column is 1, the second is 2, ...
-	 * @return a Java InputStream that delivers the database column
-	 * 	value as a stream of one byte ASCII characters.  If the
-	 *	value is SQL NULL then the result is null
-	 * @exception SQLException if a database access error occurs
-	 * @see getBinaryStream
-	 */
-	public InputStream getAsciiStream(int columnIndex) throws SQLException
-	{
-		return getBinaryStream(columnIndex);
-	}
-
-	/**
-	 * A column value can also be retrieved as a stream of Unicode
-	 * characters. We implement this as a binary stream.
-	 *
-	 * @param columnIndex the first column is 1, the second is 2...
-	 * @return a Java InputStream that delivers the database column value
-	 * 	as a stream of two byte Unicode characters.  If the value is
-	 *	SQL NULL, then the result is null
-	 * @exception SQLException if a database access error occurs
-	 * @see getAsciiStream
-	 * @see getBinaryStream
-	 */
-	public InputStream getUnicodeStream(int columnIndex) throws SQLException
-	{
-		return getBinaryStream(columnIndex);
-	}
-
-	/**
-	 * A column value can also be retrieved as a binary strea.  This
-	 * method is suitable for retrieving LONGVARBINARY values.
-	 *
-	 * @param columnIndex the first column is 1, the second is 2...
-	 * @return a Java InputStream that delivers the database column value
-	 * 	as a stream of two byte Unicode characters.  If the value is
-	 *	SQL NULL, then the result is null
-	 * @exception SQLException if a database access error occurs
-	 * @see getAsciiStream
-	 * @see getUnicodeStream
-	 */
-	public InputStream getBinaryStream(int columnIndex) throws SQLException
-	{
-		byte b[] = getBytes(columnIndex);
-
-		if (b != null)
-			return new ByteArrayInputStream(b);
-		return null;		// SQL NULL
-	}
-
-	/**
-	 * The following routines simply convert the columnName into
-	 * a columnIndex and then call the appropriate routine above.
-	 *
-	 * @param columnName is the SQL name of the column
-	 * @return the column value
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String getString(String columnName) throws SQLException
-	{
-		return getString(findColumn(columnName));
-	}
-
-	public boolean getBoolean(String columnName) throws SQLException
-	{
-		return getBoolean(findColumn(columnName));
-	}
-
-	public byte getByte(String columnName) throws SQLException
-	{
-
-		return getByte(findColumn(columnName));
-	}
-
-	public short getShort(String columnName) throws SQLException
-	{
-		return getShort(findColumn(columnName));
-	}
-
-	public int getInt(String columnName) throws SQLException
-	{
-		return getInt(findColumn(columnName));
-	}
-
-	public long getLong(String columnName) throws SQLException
-	{
-		return getLong(findColumn(columnName));
-	}
-
-	public float getFloat(String columnName) throws SQLException
-	{
-		return getFloat(findColumn(columnName));
-	}
-
-	public double getDouble(String columnName) throws SQLException
-	{
-		return getDouble(findColumn(columnName));
-	}
-
-	public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException
-	{
-		return getBigDecimal(findColumn(columnName), scale);
-	}
-
-	public byte[] getBytes(String columnName) throws SQLException
-	{
-		return getBytes(findColumn(columnName));
-	}
-
-	public java.sql.Date getDate(String columnName) throws SQLException
-	{
-		return getDate(findColumn(columnName));
-	}
-
-	public Time getTime(String columnName) throws SQLException
-	{
-		return getTime(findColumn(columnName));
-	}
-
-	public Timestamp getTimestamp(String columnName) throws SQLException
-	{
-		return getTimestamp(findColumn(columnName));
-	}
-
-	public InputStream getAsciiStream(String columnName) throws SQLException
-	{
-		return getAsciiStream(findColumn(columnName));
-	}
-
-	public InputStream getUnicodeStream(String columnName) throws SQLException
-	{
-		return getUnicodeStream(findColumn(columnName));
-	}
-
-	public InputStream getBinaryStream(String columnName) throws SQLException
-	{
-		return getBinaryStream(findColumn(columnName));
-	}
-
-	/**
-	 * The first warning reported by calls on this ResultSet is
-	 * returned.  Subsequent ResultSet warnings will be chained
-	 * to this SQLWarning.
-	 *
-	 * The warning chain is automatically cleared each time a new
-	 * row is read.
-	 *
-	 * <B>Note:</B> This warning chain only covers warnings caused by
-	 * ResultSet methods.  Any warnings caused by statement methods
-	 * (such as reading OUT parameters) will be chained on the
-	 * Statement object.
-	 *
-	 * @return the first SQLWarning or null;
-	 * @exception SQLException if a database access error occurs.
-	 */
-	public SQLWarning getWarnings() throws SQLException
-	{
-		return warnings;
-	}
-
-	/**
-	 * After this call, getWarnings returns null until a new warning
-	 * is reported for this ResultSet
-	 *
-	 * @exception SQLException if a database access error occurs
-	 */
-	public void clearWarnings() throws SQLException
-	{
-		warnings = null;
-	}
-
-	/**
-	 * Get the name of the SQL cursor used by this ResultSet
-	 *
-	 * In SQL, a result table is retrieved though a cursor that is
-	 * named.  The current row of a result can be updated or deleted
-	 * using a positioned update/delete statement that references
-	 * the cursor name.
-	 *
-	 * JDBC supports this SQL feature by providing the name of the
-	 * SQL cursor used by a ResultSet.  The current row of a ResulSet
-	 * is also the current row of this SQL cursor.
-	 *
-	 * <B>Note:</B> If positioned update is not supported, a SQLException
-	 * is thrown.
-	 *
-	 * @return the ResultSet's SQL cursor name.
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String getCursorName() throws SQLException
-	{
-		return connection.getCursorName();
-	}
-
-	/**
-	 * The numbers, types and properties of a ResultSet's columns are
-	 * provided by the getMetaData method
-	 *
-	 * @return a description of the ResultSet's columns
-	 * @exception SQLException if a database access error occurs
-	 */
-	public java.sql.ResultSetMetaData getMetaData() throws SQLException
-	{
-		return new ResultSetMetaData(rows, fields);
-	}
-
-	/**
-	 * Get the value of a column in the current row as a Java object
-	 *
-	 * This method will return the value of the given column as a
-	 * Java object.  The type of the Java object will be the default
-	 * Java Object type corresponding to the column's SQL type, following
-	 * the mapping specified in the JDBC specification.
-	 *
-	 * This method may also be used to read database specific abstract
-	 * data types.
-	 *
-	 * @param columnIndex the first column is 1, the second is 2...
-	 * @return a Object holding the column value
-	 * @exception SQLException if a database access error occurs
-	 */
-	public Object getObject(int columnIndex) throws SQLException
-	{
-		Field field;
-		
-		if (columnIndex < 1 || columnIndex > fields.length)
-			throw new SQLException("Column index out of range");
-		field = fields[columnIndex - 1];
-
-		switch (field.getSQLType())
-		{
-			case Types.BIT:
-				return new Boolean(getBoolean(columnIndex));
-			case Types.SMALLINT:
-				return new Integer(getInt(columnIndex));
-			case Types.INTEGER:
-				return new Integer(getInt(columnIndex));
-			case Types.BIGINT:
-				return new Long(getLong(columnIndex));
-			case Types.NUMERIC:
-				return getBigDecimal(columnIndex, 0);
-			case Types.REAL:
-				return new Float(getFloat(columnIndex));
-			case Types.DOUBLE:
-				return new Double(getDouble(columnIndex));
-			case Types.CHAR:
-			case Types.VARCHAR:
-				return getString(columnIndex);
-			case Types.DATE:
-				return getDate(columnIndex);
-			case Types.TIME:
-				return getTime(columnIndex);
-			case Types.TIMESTAMP:
-				return getTimestamp(columnIndex);
-			default:
-				return new PG_Object(field.getTypeName(), getString(columnIndex));
-		}
-	}
-
-	/**
-	 * Get the value of a column in the current row as a Java object
-	 *
-	 * This method will return the value of the given column as a
-	 * Java object.  The type of the Java object will be the default
-	 * Java Object type corresponding to the column's SQL type, following
-	 * the mapping specified in the JDBC specification.
-	 *
-	 * This method may also be used to read database specific abstract
-	 * data types.
-	 *
-	 * @param columnName is the SQL name of the column
-	 * @return a Object holding the column value
-	 * @exception SQLException if a database access error occurs
-	 */
-	public Object getObject(String columnName) throws SQLException
-	{
-		return getObject(findColumn(columnName));
-	}
-
-	/**
-	 * Map a ResultSet column name to a ResultSet column index
-	 *
-	 * @param columnName the name of the column
-	 * @return the column index
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int findColumn(String columnName) throws SQLException
-	{
-		int i;
-
-		for (i = 0 ; i < fields.length; ++i)
-			if (fields[i].name.equalsIgnoreCase(columnName))
-				return (i+1);
-		throw new SQLException ("Column name not found");
-	}
-
-	// ************************************************************
-	//	END OF PUBLIC INTERFACE
-	// ************************************************************
-	
-	/**
-	 * We at times need to know if the resultSet we are working
-	 * with is the result of an UPDATE, DELETE or INSERT (in which
-	 * case, we only have a row count), or of a SELECT operation
-	 * (in which case, we have multiple fields) - this routine
-	 * tells us.
-	 *
-	 * @return true if we have tuples available
-	 */
-	public boolean reallyResultSet()
-	{
-		return (fields != null);
-	}
-
-	/**
-	 * Since ResultSets can be chained, we need some method of
-	 * finding the next one in the chain.  The method getNext()
-	 * returns the next one in the chain.
-	 *
-	 * @return the next ResultSet, or null if there are none
-	 */
-	public ResultSet getNext()
-	{
-		return next;
-	}
-
-	/**
-	 * This following method allows us to add a ResultSet object
-	 * to the end of the current chain.
-	 *
-	 * @param r the resultset to add to the end of the chain.
-	 */
-	public void append(ResultSet r)
-	{
-		if (next == null)
-			next = r;
-		else
-			next.append(r);
-	}
-
-	/**
-	 * If we are just a place holder for results, we still need
-	 * to get an updateCount.  This method returns it.
-	 *
-	 * @return the updateCount
-	 */
-	public int getResultCount()
-	{
-		return updateCount;
-	}
-
-	/**
-	 * We also need to provide a couple of auxiliary functions for
-	 * the implementation of the ResultMetaData functions.  In
-	 * particular, we need to know the number of rows and the
-	 * number of columns.  Rows are also known as Tuples
-	 *
-	 * getTupleCount returns the number of rows
-	 *
-	 * @return the number of rows
-	 */
-	public int getTupleCount()
-	{
-		return rows.size();
-	}
-
-	/**
-	 * getColumnCount returns the number of columns
-	 *
-	 * @return the number of columns
-	 */
-	public int getColumnCount()
-	{
-		return fields.length;
-	}
+  Vector rows;			// The results
+  Field fields[];		// The field descriptions
+  String status;		// Status of the result
+  int updateCount;		// How many rows did we get back?
+  int current_row;		// Our pointer to where we are at
+  byte[][] this_row;		// the current row result
+  Connection connection;	// the connection which we returned from
+  SQLWarning warnings = null;	// The warning chain
+  boolean wasNullFlag = false;	// the flag for wasNull()
+  
+  //  We can chain multiple resultSets together - this points to
+  // next resultSet in the chain.
+  private ResultSet next = null;
+  
+  /**
+   * Create a new ResultSet - Note that we create ResultSets to
+   * represent the results of everything.
+   *
+   * @param fields an array of Field objects (basically, the
+   *	ResultSet MetaData)
+   * @param tuples Vector of the actual data
+   * @param status the status string returned from the back end
+   * @param updateCount the number of rows affected by the operation
+   * @param cursor the positioned update/delete cursor name
+   */
+  public ResultSet(Connection conn, Field[] fields, Vector tuples, String status, int updateCount)
+  {
+    this.connection = conn;
+    this.fields = fields;
+    this.rows = tuples;
+    this.status = status;
+    this.updateCount = updateCount;
+    this.this_row = null;
+    this.current_row = -1;
+  }
+  
+  /**
+   * A ResultSet is initially positioned before its first row,
+   * the first call to next makes the first row the current row;
+   * the second call makes the second row the current row, etc.
+   *
+   * If an input stream from the previous row is open, it is
+   * implicitly closed.  The ResultSet's warning chain is cleared
+   * when a new row is read
+   *
+   * @return true if the new current is valid; false if there are no
+   *	more rows
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean next() throws SQLException
+  {
+    if (++current_row >= rows.size())
+      return false;
+    this_row = (byte [][])rows.elementAt(current_row);
+    return true;
+  }
+  
+  /**
+   * In some cases, it is desirable to immediately release a ResultSet
+   * database and JDBC resources instead of waiting for this to happen
+   * when it is automatically closed.  The close method provides this
+   * immediate release.
+   *
+   * <B>Note:</B> A ResultSet is automatically closed by the Statement
+   * the Statement that generated it when that Statement is closed,
+   * re-executed, or is used to retrieve the next result from a sequence
+   * of multiple results.  A ResultSet is also automatically closed 
+   * when it is garbage collected.
+   *
+   * @exception SQLException if a database access error occurs
+   */
+  public void close() throws SQLException
+  {
+    // No-op
+  }
+  
+  /**
+   * A column may have the value of SQL NULL; wasNull() reports whether
+   * the last column read had this special value.  Note that you must
+   * first call getXXX on a column to try to read its value and then
+   * call wasNull() to find if the value was SQL NULL
+   *
+   * @return true if the last column read was SQL NULL
+   * @exception SQLException if a database access error occurred
+   */
+  public boolean wasNull() throws SQLException
+  {
+    return wasNullFlag;
+  }
+  
+  /**
+   * Get the value of a column in the current row as a Java String
+   *
+   * @param columnIndex the first column is 1, the second is 2...
+   * @return the column value, null for SQL NULL
+   * @exception SQLException if a database access error occurs
+   */
+  public String getString(int columnIndex) throws SQLException
+  {
+    byte[] bytes = getBytes(columnIndex);
+    
+    if (bytes == null)
+      return null;
+    return new String(bytes);
+  }
+  
+  /**
+   * Get the value of a column in the current row as a Java boolean
+   *
+   * @param columnIndex the first column is 1, the second is 2...
+   * @return the column value, false for SQL NULL
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean getBoolean(int columnIndex) throws SQLException
+  {
+    String s = getString(columnIndex);
+    
+    if (s != null)
+      {
+	int c = s.charAt(0);
+	return ((c == 't') || (c == 'T'));
+      }
+    return false;		// SQL NULL
+  }
+  
+  /**
+   * Get the value of a column in the current row as a Java byte.
+   *
+   * @param columnIndex the first column is 1, the second is 2,...
+   * @return the column value; 0 if SQL NULL
+   * @exception SQLException if a database access error occurs
+   */
+  public byte getByte(int columnIndex) throws SQLException
+  {
+    String s = getString(columnIndex);
+    
+    if (s != null)
+      {
+	try
+	  {
+	    return Byte.parseByte(s);
+	  } catch (NumberFormatException e) {
+	    throw new SQLException("Bad Byte Form: " + s);
+	  }
+      }
+    return 0;		// SQL NULL
+  }
+  
+  /**
+   * Get the value of a column in the current row as a Java short.
+   *
+   * @param columnIndex the first column is 1, the second is 2,...
+   * @return the column value; 0 if SQL NULL
+   * @exception SQLException if a database access error occurs
+   */
+  public short getShort(int columnIndex) throws SQLException
+  {
+    String s = getString(columnIndex);
+    
+    if (s != null)
+      {
+	try
+	  {
+	    return Short.parseShort(s);
+	  } catch (NumberFormatException e) {
+	    throw new SQLException("Bad Short Form: " + s);
+	  }
+      }
+    return 0;		// SQL NULL
+  }
+  
+  /**
+   * Get the value of a column in the current row as a Java int.
+   *
+   * @param columnIndex the first column is 1, the second is 2,...
+   * @return the column value; 0 if SQL NULL
+   * @exception SQLException if a database access error occurs
+   */
+  public int getInt(int columnIndex) throws SQLException
+  {
+    String s = getString(columnIndex);
+    
+    if (s != null)
+      {
+	try
+	  {
+	    return Integer.parseInt(s);
+	  } catch (NumberFormatException e) {
+	    throw new SQLException ("Bad Integer Form: " + s);
+	  }
+      }
+    return 0;		// SQL NULL
+  }
+  
+  /**
+   * Get the value of a column in the current row as a Java long.
+   *
+   * @param columnIndex the first column is 1, the second is 2,...
+   * @return the column value; 0 if SQL NULL
+   * @exception SQLException if a database access error occurs
+   */
+  public long getLong(int columnIndex) throws SQLException
+  {
+    String s = getString(columnIndex);
+    
+    if (s != null)
+      {
+	try
+	  {
+	    return Long.parseLong(s);
+	  } catch (NumberFormatException e) {
+	    throw new SQLException ("Bad Long Form: " + s);
+	  }
+      }
+    return 0;		// SQL NULL
+  }
+  
+  /**
+   * Get the value of a column in the current row as a Java float.
+   *
+   * @param columnIndex the first column is 1, the second is 2,...
+   * @return the column value; 0 if SQL NULL
+   * @exception SQLException if a database access error occurs
+   */
+  public float getFloat(int columnIndex) throws SQLException
+  {
+    String s = getString(columnIndex);
+    
+    if (s != null)
+      {
+	try
+	  {
+	    return Float.valueOf(s).floatValue();
+	  } catch (NumberFormatException e) {
+	    throw new SQLException ("Bad Float Form: " + s);
+	  }
+      }
+    return 0;		// SQL NULL
+  }
+  
+  /**
+   * Get the value of a column in the current row as a Java double.
+   *
+   * @param columnIndex the first column is 1, the second is 2,...
+   * @return the column value; 0 if SQL NULL
+   * @exception SQLException if a database access error occurs
+   */
+  public double getDouble(int columnIndex) throws SQLException
+  {
+    String s = getString(columnIndex);
+    
+    if (s != null)
+      {
+	try
+	  {
+	    return Double.valueOf(s).doubleValue();
+	  } catch (NumberFormatException e) {
+	    throw new SQLException ("Bad Double Form: " + s);
+	  }
+      }
+    return 0;		// SQL NULL
+  }
+  
+  /**
+   * Get the value of a column in the current row as a 
+   * java.lang.BigDecimal object
+   *
+   * @param columnIndex  the first column is 1, the second is 2...
+   * @param scale the number of digits to the right of the decimal
+   * @return the column value; if the value is SQL NULL, null
+   * @exception SQLException if a database access error occurs
+   */
+  public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException
+  {
+    String s = getString(columnIndex);
+    BigDecimal val;
+    
+    if (s != null)
+      {
+	try
+	  {
+	    val = new BigDecimal(s);
+	  } catch (NumberFormatException e) {
+	    throw new SQLException ("Bad BigDecimal Form: " + s);
+	  }
+	  try
+	    {
+	      return val.setScale(scale);
+	    } catch (ArithmeticException e) {
+	      throw new SQLException ("Bad BigDecimal Form: " + s);
+	    }
+      }
+    return null;		// SQL NULL
+  }
+  
+  /**
+   * Get the value of a column in the current row as a Java byte array
+   * The bytes represent the raw values returned by the driver.
+   *
+   * @param columnIndex the first column is 1, the second is 2, ...
+   * @return the column value; if the value is SQL NULL, the result
+   *	is null
+   * @exception SQLException if a database access error occurs
+   */
+  public byte[] getBytes(int columnIndex) throws SQLException
+  {
+    if (columnIndex < 1 || columnIndex > fields.length)
+      throw new SQLException("Column Index out of range");
+    wasNullFlag = (this_row[columnIndex - 1] == null);
+    return this_row[columnIndex - 1];
+  }
+  
+  /**
+   * Get the value of a column in the current row as a java.sql.Date
+   * object
+   *
+   * @param columnIndex the first column is 1, the second is 2...
+   * @return the column value; null if SQL NULL
+   * @exception SQLException if a database access error occurs
+   */
+  public java.sql.Date getDate(int columnIndex) throws SQLException
+  {
+    String s = getString(columnIndex);
+    
+    if (s != null)
+      {
+	try
+	  {
+	    if (s.length() != 10)
+	      throw new NumberFormatException("Wrong Length!");
+	    int mon = Integer.parseInt(s.substring(0,2));
+	    int day = Integer.parseInt(s.substring(3,5));
+	    int yr = Integer.parseInt(s.substring(6));
+	    return new java.sql.Date(yr - 1900, mon -1, day);
+	  } catch (NumberFormatException e) {
+	    throw new SQLException("Bad Date Form: " + s);
+	  }
+      }
+    return null;		// SQL NULL
+  }
+  
+  /**
+   * Get the value of a column in the current row as a java.sql.Time
+   * object
+   *
+   * @param columnIndex the first column is 1, the second is 2...
+   * @return the column value; null if SQL NULL
+   * @exception SQLException if a database access error occurs
+   */
+  public Time getTime(int columnIndex) throws SQLException
+  {
+    String s = getString(columnIndex);
+    
+    if (s != null)
+      {
+	try
+	  {
+	    if (s.length() != 5 && s.length() != 8)
+	      throw new NumberFormatException("Wrong Length!");
+	    int hr = Integer.parseInt(s.substring(0,2));
+	    int min = Integer.parseInt(s.substring(3,5));
+	    int sec = (s.length() == 5) ? 0 : Integer.parseInt(s.substring(6));
+	    return new Time(hr, min, sec);
+	  } catch (NumberFormatException e) {
+	    throw new SQLException ("Bad Time Form: " + s);
+	  }
+      }
+    return null;		// SQL NULL
+  }
+  
+  /**
+   * Get the value of a column in the current row as a 
+   * java.sql.Timestamp object
+   *
+   * @param columnIndex the first column is 1, the second is 2...
+   * @return the column value; null if SQL NULL
+   * @exception SQLException if a database access error occurs
+   */
+  public Timestamp getTimestamp(int columnIndex) throws SQLException
+  {
+    String s = getString(columnIndex);
+    DateFormat df = DateFormat.getDateInstance();
+    
+    if (s != null)
+      {
+	try
+	  {
+	    java.sql.Date d = (java.sql.Date)df.parse(s);
+	    return new Timestamp(d.getTime());
+	  } catch (ParseException e) {
+	    throw new SQLException("Bad Timestamp Format: " + s);
+	  }
+      }
+    return null;		// SQL NULL
+  }
+  
+  /**
+   * A column value can be retrieved as a stream of ASCII characters
+   * and then read in chunks from the stream.  This method is 
+   * particular suitable for retrieving large LONGVARCHAR values.
+   * The JDBC driver will do any necessary conversion from the
+   * database format into ASCII.
+   *
+   * <B>Note:</B> All the data in the returned stream must be read
+   * prior to getting the value of any other column.  The next call
+   * to a get method implicitly closes the stream.  Also, a stream
+   * may return 0 for available() whether there is data available
+   * or not.
+   *
+   * We implement an ASCII stream as a Binary stream - we should really
+   * do the data conversion, but I cannot be bothered to implement this
+   * right now.
+   *
+   * @param columnIndex the first column is 1, the second is 2, ...
+   * @return a Java InputStream that delivers the database column
+   * 	value as a stream of one byte ASCII characters.  If the
+   *	value is SQL NULL then the result is null
+   * @exception SQLException if a database access error occurs
+   * @see getBinaryStream
+   */
+  public InputStream getAsciiStream(int columnIndex) throws SQLException
+  {
+    return getBinaryStream(columnIndex);
+  }
+  
+  /**
+   * A column value can also be retrieved as a stream of Unicode
+   * characters. We implement this as a binary stream.
+   *
+   * @param columnIndex the first column is 1, the second is 2...
+   * @return a Java InputStream that delivers the database column value
+   * 	as a stream of two byte Unicode characters.  If the value is
+   *	SQL NULL, then the result is null
+   * @exception SQLException if a database access error occurs
+   * @see getAsciiStream
+   * @see getBinaryStream
+   */
+  public InputStream getUnicodeStream(int columnIndex) throws SQLException
+  {
+    return getBinaryStream(columnIndex);
+  }
+  
+  /**
+   * A column value can also be retrieved as a binary strea.  This
+   * method is suitable for retrieving LONGVARBINARY values.
+   *
+   * @param columnIndex the first column is 1, the second is 2...
+   * @return a Java InputStream that delivers the database column value
+   * 	as a stream of two byte Unicode characters.  If the value is
+   *	SQL NULL, then the result is null
+   * @exception SQLException if a database access error occurs
+   * @see getAsciiStream
+   * @see getUnicodeStream
+   */
+  public InputStream getBinaryStream(int columnIndex) throws SQLException
+  {
+    byte b[] = getBytes(columnIndex);
+    
+    if (b != null)
+      return new ByteArrayInputStream(b);
+    return null;		// SQL NULL
+  }
+  
+  /**
+   * The following routines simply convert the columnName into
+   * a columnIndex and then call the appropriate routine above.
+   *
+   * @param columnName is the SQL name of the column
+   * @return the column value
+   * @exception SQLException if a database access error occurs
+   */
+  public String getString(String columnName) throws SQLException
+  {
+    return getString(findColumn(columnName));
+  }
+  
+  public boolean getBoolean(String columnName) throws SQLException
+  {
+    return getBoolean(findColumn(columnName));
+  }
+  
+  public byte getByte(String columnName) throws SQLException
+  {
+    
+    return getByte(findColumn(columnName));
+  }
+  
+  public short getShort(String columnName) throws SQLException
+  {
+    return getShort(findColumn(columnName));
+  }
+  
+  public int getInt(String columnName) throws SQLException
+  {
+    return getInt(findColumn(columnName));
+  }
+  
+  public long getLong(String columnName) throws SQLException
+  {
+    return getLong(findColumn(columnName));
+  }
+  
+  public float getFloat(String columnName) throws SQLException
+  {
+    return getFloat(findColumn(columnName));
+  }
+  
+  public double getDouble(String columnName) throws SQLException
+  {
+    return getDouble(findColumn(columnName));
+  }
+  
+  public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException
+  {
+    return getBigDecimal(findColumn(columnName), scale);
+  }
+  
+  public byte[] getBytes(String columnName) throws SQLException
+  {
+    return getBytes(findColumn(columnName));
+  }
+  
+  public java.sql.Date getDate(String columnName) throws SQLException
+  {
+    return getDate(findColumn(columnName));
+  }
+  
+  public Time getTime(String columnName) throws SQLException
+  {
+    return getTime(findColumn(columnName));
+  }
+  
+  public Timestamp getTimestamp(String columnName) throws SQLException
+  {
+    return getTimestamp(findColumn(columnName));
+  }
+  
+  public InputStream getAsciiStream(String columnName) throws SQLException
+  {
+    return getAsciiStream(findColumn(columnName));
+  }
+  
+  public InputStream getUnicodeStream(String columnName) throws SQLException
+  {
+    return getUnicodeStream(findColumn(columnName));
+  }
+  
+  public InputStream getBinaryStream(String columnName) throws SQLException
+  {
+    return getBinaryStream(findColumn(columnName));
+  }
+  
+  /**
+   * The first warning reported by calls on this ResultSet is
+   * returned.  Subsequent ResultSet warnings will be chained
+   * to this SQLWarning.
+   *
+   * The warning chain is automatically cleared each time a new
+   * row is read.
+   *
+   * <B>Note:</B> This warning chain only covers warnings caused by
+   * ResultSet methods.  Any warnings caused by statement methods
+   * (such as reading OUT parameters) will be chained on the
+   * Statement object.
+   *
+   * @return the first SQLWarning or null;
+   * @exception SQLException if a database access error occurs.
+   */
+  public SQLWarning getWarnings() throws SQLException
+  {
+    return warnings;
+  }
+  
+  /**
+   * After this call, getWarnings returns null until a new warning
+   * is reported for this ResultSet
+   *
+   * @exception SQLException if a database access error occurs
+   */
+  public void clearWarnings() throws SQLException
+  {
+    warnings = null;
+  }
+  
+  /**
+   * Get the name of the SQL cursor used by this ResultSet
+   *
+   * In SQL, a result table is retrieved though a cursor that is
+   * named.  The current row of a result can be updated or deleted
+   * using a positioned update/delete statement that references
+   * the cursor name.
+   *
+   * JDBC supports this SQL feature by providing the name of the
+   * SQL cursor used by a ResultSet.  The current row of a ResulSet
+   * is also the current row of this SQL cursor.
+   *
+   * <B>Note:</B> If positioned update is not supported, a SQLException
+   * is thrown.
+   *
+   * @return the ResultSet's SQL cursor name.
+   * @exception SQLException if a database access error occurs
+   */
+  public String getCursorName() throws SQLException
+  {
+    return connection.getCursorName();
+  }
+  
+  /**
+   * The numbers, types and properties of a ResultSet's columns are
+   * provided by the getMetaData method
+   *
+   * @return a description of the ResultSet's columns
+   * @exception SQLException if a database access error occurs
+   */
+  public java.sql.ResultSetMetaData getMetaData() throws SQLException
+  {
+    return new ResultSetMetaData(rows, fields);
+  }
+  
+  /**
+   * Get the value of a column in the current row as a Java object
+   *
+   * This method will return the value of the given column as a
+   * Java object.  The type of the Java object will be the default
+   * Java Object type corresponding to the column's SQL type, following
+   * the mapping specified in the JDBC specification.
+   *
+   * This method may also be used to read database specific abstract
+   * data types.
+   *
+   * @param columnIndex the first column is 1, the second is 2...
+   * @return a Object holding the column value
+   * @exception SQLException if a database access error occurs
+   */
+  public Object getObject(int columnIndex) throws SQLException
+  {
+    Field field;
+    
+    if (columnIndex < 1 || columnIndex > fields.length)
+      throw new SQLException("Column index out of range");
+    field = fields[columnIndex - 1];
+    
+    switch (field.getSQLType())
+      {
+      case Types.BIT:
+	return new Boolean(getBoolean(columnIndex));
+      case Types.SMALLINT:
+	return new Integer(getInt(columnIndex));
+      case Types.INTEGER:
+	return new Integer(getInt(columnIndex));
+      case Types.BIGINT:
+	return new Long(getLong(columnIndex));
+      case Types.NUMERIC:
+	return getBigDecimal(columnIndex, 0);
+      case Types.REAL:
+	return new Float(getFloat(columnIndex));
+      case Types.DOUBLE:
+	return new Double(getDouble(columnIndex));
+      case Types.CHAR:
+      case Types.VARCHAR:
+	return getString(columnIndex);
+      case Types.DATE:
+	return getDate(columnIndex);
+      case Types.TIME:
+	return getTime(columnIndex);
+      case Types.TIMESTAMP:
+	return getTimestamp(columnIndex);
+      default:
+	return new PG_Object(field.getTypeName(), getString(columnIndex));
+      }
+  }
+  
+  /**
+   * Get the value of a column in the current row as a Java object
+   *
+   * This method will return the value of the given column as a
+   * Java object.  The type of the Java object will be the default
+   * Java Object type corresponding to the column's SQL type, following
+   * the mapping specified in the JDBC specification.
+   *
+   * This method may also be used to read database specific abstract
+   * data types.
+   *
+   * @param columnName is the SQL name of the column
+   * @return a Object holding the column value
+   * @exception SQLException if a database access error occurs
+   */
+  public Object getObject(String columnName) throws SQLException
+  {
+    return getObject(findColumn(columnName));
+  }
+  
+  /**
+   * Map a ResultSet column name to a ResultSet column index
+   *
+   * @param columnName the name of the column
+   * @return the column index
+   * @exception SQLException if a database access error occurs
+   */
+  public int findColumn(String columnName) throws SQLException
+  {
+    int i;
+    
+    for (i = 0 ; i < fields.length; ++i)
+      if (fields[i].name.equalsIgnoreCase(columnName))
+	return (i+1);
+    throw new SQLException ("Column name not found");
+  }
+  
+  // ************************************************************
+  //	END OF PUBLIC INTERFACE
+  // ************************************************************
+  
+  /**
+   * We at times need to know if the resultSet we are working
+   * with is the result of an UPDATE, DELETE or INSERT (in which
+   * case, we only have a row count), or of a SELECT operation
+   * (in which case, we have multiple fields) - this routine
+   * tells us.
+   *
+   * @return true if we have tuples available
+   */
+  public boolean reallyResultSet()
+  {
+    return (fields != null);
+  }
+  
+  /**
+   * Since ResultSets can be chained, we need some method of
+   * finding the next one in the chain.  The method getNext()
+   * returns the next one in the chain.
+   *
+   * @return the next ResultSet, or null if there are none
+   */
+  public ResultSet getNext()
+  {
+    return next;
+  }
+  
+  /**
+   * This following method allows us to add a ResultSet object
+   * to the end of the current chain.
+   *
+   * @param r the resultset to add to the end of the chain.
+   */
+  public void append(ResultSet r)
+  {
+    if (next == null)
+      next = r;
+    else
+      next.append(r);
+  }
+  
+  /**
+   * If we are just a place holder for results, we still need
+   * to get an updateCount.  This method returns it.
+   *
+   * @return the updateCount
+   */
+  public int getResultCount()
+  {
+    return updateCount;
+  }
+  
+  /**
+   * We also need to provide a couple of auxiliary functions for
+   * the implementation of the ResultMetaData functions.  In
+   * particular, we need to know the number of rows and the
+   * number of columns.  Rows are also known as Tuples
+   *
+   * getTupleCount returns the number of rows
+   *
+   * @return the number of rows
+   */
+  public int getTupleCount()
+  {
+    return rows.size();
+  }
+  
+  /**
+   * getColumnCount returns the number of columns
+   *
+   * @return the number of columns
+   */
+  public int getColumnCount()
+  {
+    return fields.length;
+  }
 }
+
diff --git a/src/interfaces/jdbc/postgresql/ResultSetMetaData.java b/src/interfaces/jdbc/postgresql/ResultSetMetaData.java
index a6974b3076e..f058e2e0ba6 100644
--- a/src/interfaces/jdbc/postgresql/ResultSetMetaData.java
+++ b/src/interfaces/jdbc/postgresql/ResultSetMetaData.java
@@ -16,414 +16,415 @@ import postgresql.*;
  */
 public class ResultSetMetaData implements java.sql.ResultSetMetaData 
 {
-	Vector rows;
-	Field[] fields;
-
-	/**
-	 *	Initialise for a result with a tuple set and
-	 *	a field descriptor set
-	 *
-	 * @param rows the Vector of rows returned by the ResultSet
-	 * @param fields the array of field descriptors
-	 */
-	public ResultSetMetaData(Vector rows, Field[] fields)
-	{
-		this.rows = rows;
-		this.fields = fields;
-	}
-	
-	/**
-	 * Whats the number of columns in the ResultSet?
-	 *
-	 * @return the number
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getColumnCount() throws SQLException
-	{
-		return fields.length;
-	}
-
-	/**
-	 * Is the column automatically numbered (and thus read-only)
-	 * I believe that PostgreSQL does not support this feature.
-	 *
-	 * @param column the first column is 1, the second is 2...
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean isAutoIncrement(int column) throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Does a column's case matter? ASSUMPTION: Any field that is
-	 * not obviously case insensitive is assumed to be case sensitive
-	 *
-	 * @param column the first column is 1, the second is 2...
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean isCaseSensitive(int column) throws SQLException
-	{
-		int sql_type = getField(column).getSQLType();
-
-		switch (sql_type)
-		{
-			case Types.SMALLINT:
-			case Types.INTEGER:
-			case Types.FLOAT:
-			case Types.REAL:
-			case Types.DOUBLE:
-			case Types.DATE:
-			case Types.TIME:
-			case Types.TIMESTAMP:
-				return false;
-			default:
-				return true;
-		}
-	}
-
-	/**
-	 * Can the column be used in a WHERE clause?  Basically for
-	 * this, I split the functions into two types: recognised
-	 * types (which are always useable), and OTHER types (which
-	 * may or may not be useable).  The OTHER types, for now, I
-	 * will assume they are useable.  We should really query the
-	 * catalog to see if they are useable.
-	 *
-	 * @param column the first column is 1, the second is 2...
-	 * @return true if they can be used in a WHERE clause
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean isSearchable(int column) throws SQLException
-	{
-		int sql_type = getField(column).getSQLType();
-
-		// This switch is pointless, I know - but it is a set-up
-		// for further expansion.		
-		switch (sql_type)
-		{
-			case Types.OTHER:
-				return true;
-			default:
-				return true;
-		}
-	}
-
-	/**
-	 * Is the column a cash value?  6.1 introduced the cash/money
-	 * type, which haven't been incorporated as of 970414, so I
-	 * just check the type name for both 'cash' and 'money'
-	 *
-	 * @param column the first column is 1, the second is 2...
-	 * @return true if its a cash column
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean isCurrency(int column) throws SQLException
-	{
-		String type_name = getField(column).getTypeName();
-
-		if (type_name.equals("cash"))
-			return true;
-		if (type_name.equals("money"))
-			return true;
-		return false;
-	}
-
-	/**
-	 * Can you put a NULL in this column?  I think this is always
-	 * true in 6.1's case.  It would only be false if the field had
-	 * been defined NOT NULL (system catalogs could be queried?)
-	 *
-	 * @param column the first column is 1, the second is 2...
-	 * @return one of the columnNullable values
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int isNullable(int column) throws SQLException
-	{
-		return columnNullable;	// We can always put NULL in
-	}
-
-	/**
-	 * Is the column a signed number? In PostgreSQL, all numbers
-	 * are signed, so this is trivial.  However, strings are not
-	 * signed (duh!)
-	 * 
-	 * @param column the first column is 1, the second is 2...
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean isSigned(int column) throws SQLException
-	{
-		int sql_type = getField(column).getSQLType();
-	
-		switch (sql_type)
-		{
-			case Types.SMALLINT:
-			case Types.INTEGER:
-			case Types.FLOAT:
-			case Types.REAL:
-			case Types.DOUBLE:
-				return true;
-			case Types.DATE:
-			case Types.TIME:
-			case Types.TIMESTAMP:
-				return false;	// I don't know about these?
-			default:
-				return false;
-		}
-	}
-
-	/**
-	 * What is the column's normal maximum width in characters?
-	 *
-	 * @param column the first column is 1, the second is 2, etc.
-	 * @return the maximum width
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getColumnDisplaySize(int column) throws SQLException
-	{
-		int max = getColumnLabel(column).length();
-		int i;
-
-		for (i = 0 ; i < rows.size(); ++i)
-		{
-			byte[][] x = (byte[][])(rows.elementAt(i));
-			int xl = x[column - 1].length;
-			if (xl > max)
-				max = xl;
-		}
-		return max;
-	}
-
-	/**
-	 * What is the suggested column title for use in printouts and
-	 * displays?  We suggest the ColumnName!
-	 *
-	 * @param column the first column is 1, the second is 2, etc.
-	 * @return the column label
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String getColumnLabel(int column) throws SQLException
-	{
-		return getColumnName(column);
-	}
-
-	/**
-	 * What's a column's name?
-	 *
-	 * @param column the first column is 1, the second is 2, etc.
-	 * @return the column name
-	 * @exception SQLException if a databvase access error occurs
-	 */
-	public String getColumnName(int column) throws SQLException
-	{
-		return getField(column).name;
-	}
-
-	/**
-	 * What is a column's table's schema?  This relies on us knowing
-	 * the table name....which I don't know how to do as yet.  The 
-	 * JDBC specification allows us to return "" if this is not
-	 * applicable.
-	 *
-	 * @param column the first column is 1, the second is 2...
-	 * @return the Schema
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String getSchemaName(int column) throws SQLException
-	{
-		String table_name = getTableName(column);
-
-		// If the table name is invalid, so are we.
-		if (table_name.equals(""))
-			return "";	
-		return "";		// Ok, so I don't know how to
-					// do this as yet.
-	}
-
-	/**
-	 * What is a column's number of decimal digits.
-	 *
-	 * @param column the first column is 1, the second is 2...
-	 * @return the precision
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getPrecision(int column) throws SQLException
-	{
-		int sql_type = getField(column).getSQLType();
-
-		switch (sql_type)
-		{
-			case Types.SMALLINT:
-				return 5;	
-			case Types.INTEGER:
-				return 10;
-			case Types.REAL:
-				return 8;
-			case Types.FLOAT:
-				return 16;
-			case Types.DOUBLE:
-				return 16;
-			default:
-				throw new SQLException("no precision for non-numeric data types.");
-		}
-	}
-
-	/**
-	 * What is a column's number of digits to the right of the
-	 * decimal point?
-	 *
-	 * @param column the first column is 1, the second is 2...
-	 * @return the scale
-	 * @exception SQLException if a database access error occurs
-	 */
-	public int getScale(int column) throws SQLException
-	{
-		int sql_type = getField(column).getSQLType();
-
-		switch (sql_type)
-		{
-			case Types.SMALLINT:
-				return 0;
-			case Types.INTEGER:
-				return 0;
-			case Types.REAL:
-				return 8;
-			case Types.FLOAT:
-				return 16;
-			case Types.DOUBLE:
-				return 16;
-			default:
-				throw new SQLException("no scale for non-numeric data types");
-		}
-	}
-
-	/**
-	 * Whats a column's table's name?  How do I find this out?  Both
-	 * getSchemaName() and getCatalogName() rely on knowing the table
-	 * Name, so we need this before we can work on them.
-	 *
-	 * @param column the first column is 1, the second is 2...
-	 * @return column name, or "" if not applicable
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String getTableName(int column) throws SQLException
-	{
-		return "";
-	}
-
-	/**
-	 * What's a column's table's catalog name?  As with getSchemaName(),
-	 * we can say that if getTableName() returns n/a, then we can too -
-	 * otherwise, we need to work on it.
-	 * 
-	 * @param column the first column is 1, the second is 2...
-	 * @return catalog name, or "" if not applicable
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String getCatalogName(int column) throws SQLException
-	{
-		String table_name = getTableName(column);
-
-		if (table_name.equals(""))
-			return "";
-		return "";		// As with getSchemaName(), this
-					// is just the start of it.
-	}
-	
-	/**
-	 * What is a column's SQL Type? (java.sql.Type int)
-	 *
-	 * @param column the first column is 1, the second is 2, etc.
-	 * @return the java.sql.Type value
-	 * @exception SQLException if a database access error occurs
-	 * @see postgresql.Field#getSQLType
-	 * @see java.sql.Types
-	 */
-	public int getColumnType(int column) throws SQLException
-	{
-		return getField(column).getSQLType();
-	}
-
-	/**
-	 * Whats is the column's data source specific type name?
-	 *
-	 * @param column the first column is 1, the second is 2, etc.
-	 * @return the type name
-	 * @exception SQLException if a database access error occurs
-	 */
-	public String getColumnTypeName(int column) throws SQLException
-	{
-		return getField(column).getTypeName();
-	}
-
-	/**
-	 * Is the column definitely not writable?  In reality, we would
-	 * have to check the GRANT/REVOKE stuff for this to be effective,
-	 * and I haven't really looked into that yet, so this will get
-	 * re-visited.
-	 *
-	 * @param column the first column is 1, the second is 2, etc.
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean isReadOnly(int column) throws SQLException
-	{
-		return false;
-	}
-
-	/**
-	 * Is it possible for a write on the column to succeed?  Again, we
-	 * would in reality have to check the GRANT/REVOKE stuff, which
-	 * I haven't worked with as yet.  However, if it isn't ReadOnly, then
-	 * it is obviously writable.
-	 *
-	 * @param column the first column is 1, the second is 2, etc.
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean isWritable(int column) throws SQLException
-	{
-		if (isReadOnly(column))
-			return true;
-		else
-			return false;
-	}
-
-	/**
-	 * Will a write on this column definately succeed?  Hmmm...this
-	 * is a bad one, since the two preceding functions have not been
-	 * really defined.  I cannot tell is the short answer.  I thus
-	 * return isWritable() just to give us an idea.
-	 *
-	 * @param column the first column is 1, the second is 2, etc..
-	 * @return true if so
-	 * @exception SQLException if a database access error occurs
-	 */
-	public boolean isDefinitelyWritable(int column) throws SQLException
-	{
-		return isWritable(column);
-	}
-
-	// ********************************************************
-	// 	END OF PUBLIC INTERFACE
-	// ********************************************************
-	
-	/**
-	 * For several routines in this package, we need to convert
-	 * a columnIndex into a Field[] descriptor.  Rather than do
-	 * the same code several times, here it is.
-	 * 
-	 * @param columnIndex the first column is 1, the second is 2...
-	 * @return the Field description
-	 * @exception SQLException if a database access error occurs
-	 */
-	private Field getField(int columnIndex) throws SQLException
-	{
-		if (columnIndex < 1 || columnIndex > fields.length)
-			throw new SQLException("Column index out of range");
-		return fields[columnIndex - 1];
-	}
+  Vector rows;
+  Field[] fields;
+  
+  /**
+   *	Initialise for a result with a tuple set and
+   *	a field descriptor set
+   *
+   * @param rows the Vector of rows returned by the ResultSet
+   * @param fields the array of field descriptors
+   */
+  public ResultSetMetaData(Vector rows, Field[] fields)
+  {
+    this.rows = rows;
+    this.fields = fields;
+  }
+  
+  /**
+   * Whats the number of columns in the ResultSet?
+   *
+   * @return the number
+   * @exception SQLException if a database access error occurs
+   */
+  public int getColumnCount() throws SQLException
+  {
+    return fields.length;
+  }
+  
+  /**
+   * Is the column automatically numbered (and thus read-only)
+   * I believe that PostgreSQL does not support this feature.
+   *
+   * @param column the first column is 1, the second is 2...
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean isAutoIncrement(int column) throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Does a column's case matter? ASSUMPTION: Any field that is
+   * not obviously case insensitive is assumed to be case sensitive
+   *
+   * @param column the first column is 1, the second is 2...
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean isCaseSensitive(int column) throws SQLException
+  {
+    int sql_type = getField(column).getSQLType();
+    
+    switch (sql_type)
+      {
+      case Types.SMALLINT:
+      case Types.INTEGER:
+      case Types.FLOAT:
+      case Types.REAL:
+      case Types.DOUBLE:
+      case Types.DATE:
+      case Types.TIME:
+      case Types.TIMESTAMP:
+	return false;
+      default:
+	return true;
+      }
+  }
+  
+  /**
+   * Can the column be used in a WHERE clause?  Basically for
+   * this, I split the functions into two types: recognised
+   * types (which are always useable), and OTHER types (which
+   * may or may not be useable).  The OTHER types, for now, I
+   * will assume they are useable.  We should really query the
+   * catalog to see if they are useable.
+   *
+   * @param column the first column is 1, the second is 2...
+   * @return true if they can be used in a WHERE clause
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean isSearchable(int column) throws SQLException
+  {
+    int sql_type = getField(column).getSQLType();
+    
+    // This switch is pointless, I know - but it is a set-up
+    // for further expansion.		
+    switch (sql_type)
+      {
+      case Types.OTHER:
+	return true;
+      default:
+	return true;
+      }
+  }
+  
+  /**
+   * Is the column a cash value?  6.1 introduced the cash/money
+   * type, which haven't been incorporated as of 970414, so I
+   * just check the type name for both 'cash' and 'money'
+   *
+   * @param column the first column is 1, the second is 2...
+   * @return true if its a cash column
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean isCurrency(int column) throws SQLException
+  {
+    String type_name = getField(column).getTypeName();
+    
+    if (type_name.equals("cash"))
+      return true;
+    if (type_name.equals("money"))
+      return true;
+    return false;
+  }
+  
+  /**
+   * Can you put a NULL in this column?  I think this is always
+   * true in 6.1's case.  It would only be false if the field had
+   * been defined NOT NULL (system catalogs could be queried?)
+   *
+   * @param column the first column is 1, the second is 2...
+   * @return one of the columnNullable values
+   * @exception SQLException if a database access error occurs
+   */
+  public int isNullable(int column) throws SQLException
+  {
+    return columnNullable;	// We can always put NULL in
+  }
+  
+  /**
+   * Is the column a signed number? In PostgreSQL, all numbers
+   * are signed, so this is trivial.  However, strings are not
+   * signed (duh!)
+   * 
+   * @param column the first column is 1, the second is 2...
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean isSigned(int column) throws SQLException
+  {
+    int sql_type = getField(column).getSQLType();
+    
+    switch (sql_type)
+      {
+      case Types.SMALLINT:
+      case Types.INTEGER:
+      case Types.FLOAT:
+      case Types.REAL:
+      case Types.DOUBLE:
+	return true;
+      case Types.DATE:
+      case Types.TIME:
+      case Types.TIMESTAMP:
+	return false;	// I don't know about these?
+      default:
+	return false;
+      }
+  }
+  
+  /**
+   * What is the column's normal maximum width in characters?
+   *
+   * @param column the first column is 1, the second is 2, etc.
+   * @return the maximum width
+   * @exception SQLException if a database access error occurs
+   */
+  public int getColumnDisplaySize(int column) throws SQLException
+  {
+    int max = getColumnLabel(column).length();
+    int i;
+    
+    for (i = 0 ; i < rows.size(); ++i)
+      {
+	byte[][] x = (byte[][])(rows.elementAt(i));
+	int xl = x[column - 1].length;
+	if (xl > max)
+	  max = xl;
+      }
+    return max;
+  }
+  
+  /**
+   * What is the suggested column title for use in printouts and
+   * displays?  We suggest the ColumnName!
+   *
+   * @param column the first column is 1, the second is 2, etc.
+   * @return the column label
+   * @exception SQLException if a database access error occurs
+   */
+  public String getColumnLabel(int column) throws SQLException
+  {
+    return getColumnName(column);
+  }
+  
+  /**
+   * What's a column's name?
+   *
+   * @param column the first column is 1, the second is 2, etc.
+   * @return the column name
+   * @exception SQLException if a databvase access error occurs
+   */
+  public String getColumnName(int column) throws SQLException
+  {
+    return getField(column).name;
+  }
+  
+  /**
+   * What is a column's table's schema?  This relies on us knowing
+   * the table name....which I don't know how to do as yet.  The 
+   * JDBC specification allows us to return "" if this is not
+   * applicable.
+   *
+   * @param column the first column is 1, the second is 2...
+   * @return the Schema
+   * @exception SQLException if a database access error occurs
+   */
+  public String getSchemaName(int column) throws SQLException
+  {
+    String table_name = getTableName(column);
+    
+    // If the table name is invalid, so are we.
+    if (table_name.equals(""))
+      return "";	
+    return "";		// Ok, so I don't know how to
+    // do this as yet.
+  }
+  
+  /**
+   * What is a column's number of decimal digits.
+   *
+   * @param column the first column is 1, the second is 2...
+   * @return the precision
+   * @exception SQLException if a database access error occurs
+   */
+  public int getPrecision(int column) throws SQLException
+  {
+    int sql_type = getField(column).getSQLType();
+    
+    switch (sql_type)
+      {
+      case Types.SMALLINT:
+	return 5;	
+      case Types.INTEGER:
+	return 10;
+      case Types.REAL:
+	return 8;
+      case Types.FLOAT:
+	return 16;
+      case Types.DOUBLE:
+	return 16;
+      default:
+	throw new SQLException("no precision for non-numeric data types.");
+      }
+  }
+  
+  /**
+   * What is a column's number of digits to the right of the
+   * decimal point?
+   *
+   * @param column the first column is 1, the second is 2...
+   * @return the scale
+   * @exception SQLException if a database access error occurs
+   */
+  public int getScale(int column) throws SQLException
+  {
+    int sql_type = getField(column).getSQLType();
+    
+    switch (sql_type)
+      {
+      case Types.SMALLINT:
+	return 0;
+      case Types.INTEGER:
+	return 0;
+      case Types.REAL:
+	return 8;
+      case Types.FLOAT:
+	return 16;
+      case Types.DOUBLE:
+	return 16;
+      default:
+	throw new SQLException("no scale for non-numeric data types");
+      }
+  }
+  
+  /**
+   * Whats a column's table's name?  How do I find this out?  Both
+   * getSchemaName() and getCatalogName() rely on knowing the table
+   * Name, so we need this before we can work on them.
+   *
+   * @param column the first column is 1, the second is 2...
+   * @return column name, or "" if not applicable
+   * @exception SQLException if a database access error occurs
+   */
+  public String getTableName(int column) throws SQLException
+  {
+    return "";
+  }
+  
+  /**
+   * What's a column's table's catalog name?  As with getSchemaName(),
+   * we can say that if getTableName() returns n/a, then we can too -
+   * otherwise, we need to work on it.
+   * 
+   * @param column the first column is 1, the second is 2...
+   * @return catalog name, or "" if not applicable
+   * @exception SQLException if a database access error occurs
+   */
+  public String getCatalogName(int column) throws SQLException
+  {
+    String table_name = getTableName(column);
+    
+    if (table_name.equals(""))
+      return "";
+    return "";		// As with getSchemaName(), this
+    // is just the start of it.
+  }
+  
+  /**
+   * What is a column's SQL Type? (java.sql.Type int)
+   *
+   * @param column the first column is 1, the second is 2, etc.
+   * @return the java.sql.Type value
+   * @exception SQLException if a database access error occurs
+   * @see postgresql.Field#getSQLType
+   * @see java.sql.Types
+   */
+  public int getColumnType(int column) throws SQLException
+  {
+    return getField(column).getSQLType();
+  }
+  
+  /**
+   * Whats is the column's data source specific type name?
+   *
+   * @param column the first column is 1, the second is 2, etc.
+   * @return the type name
+   * @exception SQLException if a database access error occurs
+   */
+  public String getColumnTypeName(int column) throws SQLException
+  {
+    return getField(column).getTypeName();
+  }
+  
+  /**
+   * Is the column definitely not writable?  In reality, we would
+   * have to check the GRANT/REVOKE stuff for this to be effective,
+   * and I haven't really looked into that yet, so this will get
+   * re-visited.
+   *
+   * @param column the first column is 1, the second is 2, etc.
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean isReadOnly(int column) throws SQLException
+  {
+    return false;
+  }
+  
+  /**
+   * Is it possible for a write on the column to succeed?  Again, we
+   * would in reality have to check the GRANT/REVOKE stuff, which
+   * I haven't worked with as yet.  However, if it isn't ReadOnly, then
+   * it is obviously writable.
+   *
+   * @param column the first column is 1, the second is 2, etc.
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean isWritable(int column) throws SQLException
+  {
+    if (isReadOnly(column))
+      return true;
+    else
+      return false;
+  }
+  
+  /**
+   * Will a write on this column definately succeed?  Hmmm...this
+   * is a bad one, since the two preceding functions have not been
+   * really defined.  I cannot tell is the short answer.  I thus
+   * return isWritable() just to give us an idea.
+   *
+   * @param column the first column is 1, the second is 2, etc..
+   * @return true if so
+   * @exception SQLException if a database access error occurs
+   */
+  public boolean isDefinitelyWritable(int column) throws SQLException
+  {
+    return isWritable(column);
+  }
+  
+  // ********************************************************
+  // 	END OF PUBLIC INTERFACE
+  // ********************************************************
+  
+  /**
+   * For several routines in this package, we need to convert
+   * a columnIndex into a Field[] descriptor.  Rather than do
+   * the same code several times, here it is.
+   * 
+   * @param columnIndex the first column is 1, the second is 2...
+   * @return the Field description
+   * @exception SQLException if a database access error occurs
+   */
+  private Field getField(int columnIndex) throws SQLException
+  {
+    if (columnIndex < 1 || columnIndex > fields.length)
+      throw new SQLException("Column index out of range");
+    return fields[columnIndex - 1];
+  }
 }
+
-- 
GitLab