summaryrefslogtreecommitdiff
path: root/src/interfaces/jdbc/postgresql/Connection.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/jdbc/postgresql/Connection.java')
-rw-r--r--src/interfaces/jdbc/postgresql/Connection.java1282
1 files changed, 482 insertions, 800 deletions
diff --git a/src/interfaces/jdbc/postgresql/Connection.java b/src/interfaces/jdbc/postgresql/Connection.java
index be15b38abe..df354776f7 100644
--- a/src/interfaces/jdbc/postgresql/Connection.java
+++ b/src/interfaces/jdbc/postgresql/Connection.java
@@ -1,41 +1,28 @@
package postgresql;
import java.io.*;
-import java.lang.*;
-import java.lang.reflect.*;
import java.net.*;
-import java.util.*;
import java.sql.*;
+import java.util.*;
+import postgresql.Field;
import postgresql.fastpath.*;
import postgresql.largeobject.*;
import postgresql.util.*;
/**
- * A Connection represents a session with a specific database. Within the
- * context of a Connection, SQL statements are executed and results are
- * returned.
+ * $Id: Connection.java,v 1.14 1999/01/17 04:51:50 momjian Exp $
*
- * <P>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 obtained
- * with the getMetaData method.
+ * This abstract class is used by postgresql.Driver to open either the JDBC1 or
+ * JDBC2 versions of the Connection class.
*
- * <p><B>Note:</B> By default, the Connection automatically commits changes
- * after executing each statement. If auto-commit has been disabled, an
- * explicit commit must be done or database changes will not be saved.
- *
- * @see java.sql.Connection
*/
-public class Connection implements java.sql.Connection
+public abstract class Connection
{
// This is the network stream associated with this connection
- protected PG_Stream pg_stream;
+ public PG_Stream pg_stream;
// This is set by postgresql.Statement.setMaxRows()
- protected int maxrows = 0; // maximum no. of rows; 0 = unlimited
-
- // This is a cache of the DatabaseMetaData instance for this connection
- protected DatabaseMetaData metadata;
+ public int maxrows = 0; // maximum no. of rows; 0 = unlimited
private String PG_HOST;
private int PG_PORT;
@@ -47,10 +34,10 @@ public class Connection implements java.sql.Connection
public boolean CONNECTION_OK = true;
public boolean CONNECTION_BAD = false;
- private boolean autoCommit = true;
- private boolean readOnly = false;
+ public boolean autoCommit = true;
+ public boolean readOnly = false;
- protected Driver this_driver;
+ public Driver this_driver;
private String this_url;
private String cursor = null; // The positioned update cursor name
@@ -78,12 +65,12 @@ public class Connection implements java.sql.Connection
// It's here, because it's shared across this connection only.
// Hence it cannot be static within the Field class, because it would then
// be across all connections, which could be to different backends.
- protected Hashtable fieldCache = new Hashtable();
+ public Hashtable fieldCache = new Hashtable();
/**
* This is the current date style of the backend
*/
- protected int currentDateStyle;
+ public int currentDateStyle;
/**
* This defines the formats for dates, according to the various date styles.
@@ -113,29 +100,29 @@ public class Connection implements java.sql.Connection
};
// Now handle notices as warnings, so things like "show" now work
- protected SQLWarning firstWarning = null;
+ public SQLWarning firstWarning = null;
- /**
- * Connect to a PostgreSQL database back end.
- *
- * <p><b>Important Notice</b>
- *
- * <br>Although this will connect to the database, user code should open
- * the connection via the DriverManager.getConnection() methods only.
- *
- * <br>This should only be called from the postgresql.Driver class.
- *
- * @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
- {
+ /**
+ * This is called by Class.forName() from within postgresql.Driver
+ */
+ public Connection()
+ {
+ }
+
+ /**
+ * This method actually opens the connection. It is called by Driver.
+ *
+ * @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
+ */
+ protected void openConnection(String host, int port, Properties info, String database, String url, Driver d) throws SQLException
+ {
// Throw an exception if the user or password properties are missing
// This occasionally occurs when the client uses the properties version
// of getConnection(), and is a common question on the email lists
@@ -262,777 +249,472 @@ public class Connection implements java.sql.Connection
// Also, this query replaced the NULL query issued to test the
// connection.
//
- clearWarnings();
+ firstWarning = null;
ExecSQL("show datestyle");
// Initialise object handling
initObjectTypes();
// Mark the connection as ok, and cleanup
- clearWarnings();
+ firstWarning = null;
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
- {
- if(metadata==null)
- metadata = new DatabaseMetaData(this);
- return metadata;
- }
-
- /**
- * 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 firstWarning;
- }
-
- /**
- * 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
- {
- firstWarning = null;
- }
-
- // **********************************************************
- // END OF PUBLIC INTERFACE
- // **********************************************************
-
- /**
- * This adds a warning to the warning chain.
- * @param msg message to add
- */
- public void addWarning(String msg)
- {
- DriverManager.println(msg);
+ }
- // Add the warning to the chain
- if(firstWarning!=null)
- firstWarning.setNextWarning(new SQLWarning(msg));
- else
- firstWarning = new SQLWarning(msg);
+ // These methods used to be in the main Connection implementation. As they
+ // are common to all implementations (JDBC1 or 2), they are placed here.
+ // This should make it easy to maintain the two specifications.
- // Now check for some specific messages
+ /**
+ * This adds a warning to the warning chain.
+ * @param msg message to add
+ */
+ public void addWarning(String msg)
+ {
+ DriverManager.println(msg);
+
+ // Add the warning to the chain
+ if(firstWarning!=null)
+ firstWarning.setNextWarning(new SQLWarning(msg));
+ else
+ firstWarning = new SQLWarning(msg);
+
+ // Now check for some specific messages
+
+ // This is generated by the SQL "show datestyle"
+ if(msg.startsWith("NOTICE:") && msg.indexOf("DateStyle")>0) {
+ // 13 is the length off "DateStyle is "
+ msg = msg.substring(msg.indexOf("DateStyle is ")+13);
+
+ for(int i=0;i<dateStyles.length;i+=2)
+ if(msg.startsWith(dateStyles[i]))
+ currentDateStyle=i+1; // this is the index of the format
+ }
+ }
- // This is generated by the SQL "show datestyle"
- if(msg.startsWith("NOTICE:") && msg.indexOf("DateStyle")>0) {
- // 13 is the length off "DateStyle is "
- msg = msg.substring(msg.indexOf("DateStyle is ")+13);
-
- for(int i=0;i<dateStyles.length;i+=2)
- if(msg.startsWith(dateStyles[i]))
- currentDateStyle=i+1; // this is the index of the format
+ /**
+ * @return the date format for the current date style of the backend
+ */
+ public String getDateStyle()
+ {
+ return dateStyles[currentDateStyle];
}
- }
-
- /**
- * @return the date format for the current date style of the backend
- */
- public String getDateStyle()
- {
- return dateStyles[currentDateStyle];
- }
-
- /**
- * 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 ResultSet ExecSQL(String sql) throws SQLException
- {
- // added Oct 7 1998 to give us thread safety.
- synchronized(pg_stream) {
-
- 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);
- pg_stream.flush();
- } catch (IOException e) {
- throw new SQLException("I/O Error: " + e.toString());
- }
-
- while (!hfr || fqp > 0)
- {
- Object tup=null; // holds rows as they are recieved
-
- 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");
- tup = pg_stream.ReceiveTuple(fields.length, true);
- // This implements Statement.setMaxRows()
- if(maxrows==0 || tuples.size()<maxrows)
- tuples.addElement(tup);
- break;
- case 'C': // Command Status
- recv_status = pg_stream.ReceiveString(8192);
- if (fields != null)
- hfr = true;
- else
+ /**
+ * 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 java.sql.ResultSet ExecSQL(String sql) throws SQLException
+ {
+ // added Oct 7 1998 to give us thread safety.
+ synchronized(pg_stream) {
+
+ 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
{
- try
- {
- pg_stream.SendChar('Q');
- pg_stream.SendChar(' ');
- pg_stream.SendChar(0);
- pg_stream.flush();
- } catch (IOException e) {
- throw new SQLException("I/O Error: " + e.toString());
- }
- fqp++;
+ pg_stream.SendChar('Q');
+ buf = sql.getBytes();
+ pg_stream.Send(buf);
+ pg_stream.SendChar(0);
+ pg_stream.flush();
+ } catch (IOException e) {
+ throw new SQLException("I/O Error: " + e.toString());
}
- break;
- case 'D': // Text Data Transfer
- if (fields == null)
- throw new SQLException("Tuple received before MetaData");
- tup = pg_stream.ReceiveTuple(fields.length, false);
- // This implements Statement.setMaxRows()
- if(maxrows==0 || tuples.size()<maxrows)
- tuples.addElement(tup);
- 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
- addWarning(pg_stream.ReceiveString(4096));
- 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);
+
+ while (!hfr || fqp > 0)
+ {
+ Object tup=null; // holds rows as they are recieved
+
+ 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");
+ tup = pg_stream.ReceiveTuple(fields.length, true);
+ // This implements Statement.setMaxRows()
+ if(maxrows==0 || tuples.size()<maxrows)
+ tuples.addElement(tup);
+ 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);
+ pg_stream.flush();
+ } 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");
+ tup = pg_stream.ReceiveTuple(fields.length, false);
+ // This implements Statement.setMaxRows()
+ if(maxrows==0 || tuples.size()<maxrows)
+ tuples.addElement(tup);
+ 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
+ addWarning(pg_stream.ReceiveString(4096));
+ 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 getResultSet(this, fields, tuples, recv_status, 1);
+ //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.ReceiveIntegerR(2), i;
+ Field[] fields = new Field[nf];
+
+ for (i = 0 ; i < nf ; ++i)
+ {
+ String typname = pg_stream.ReceiveString(8192);
+ int typid = pg_stream.ReceiveIntegerR(4);
+ int typlen = pg_stream.ReceiveIntegerR(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;
+ }
+
+ /**
+ * This returns the Fastpath API for the current connection.
+ *
+ * <p><b>NOTE:</b> This is not part of JDBC, but allows access to
+ * functions on the postgresql backend itself.
+ *
+ * <p>It is primarily used by the LargeObject API
+ *
+ * <p>The best way to use this is as follows:
+ *
+ * <p><pre>
+ * import postgresql.fastpath.*;
+ * ...
+ * Fastpath fp = ((postgresql.Connection)myconn).getFastpathAPI();
+ * </pre>
+ *
+ * <p>where myconn is an open Connection to postgresql.
+ *
+ * @return Fastpath object allowing access to functions on the postgresql
+ * backend.
+ * @exception SQLException by Fastpath when initialising for first time
+ */
+ public Fastpath getFastpathAPI() throws SQLException
+ {
+ if(fastpath==null)
+ fastpath = new Fastpath(this,pg_stream);
+ return fastpath;
+ }
+
+ // This holds a reference to the Fastpath API if already open
+ private Fastpath fastpath = null;
+
+ /**
+ * This returns the LargeObject API for the current connection.
+ *
+ * <p><b>NOTE:</b> This is not part of JDBC, but allows access to
+ * functions on the postgresql backend itself.
+ *
+ * <p>The best way to use this is as follows:
+ *
+ * <p><pre>
+ * import postgresql.largeobject.*;
+ * ...
+ * LargeObjectManager lo = ((postgresql.Connection)myconn).getLargeObjectAPI();
+ * </pre>
+ *
+ * <p>where myconn is an open Connection to postgresql.
+ *
+ * @return LargeObject object that implements the API
+ * @exception SQLException by LargeObject when initialising for first time
+ */
+ public LargeObjectManager getLargeObjectAPI() throws SQLException
+ {
+ if(largeobject==null)
+ largeobject = new LargeObjectManager(this);
+ return largeobject;
+ }
+
+ // This holds a reference to the LargeObject API if already open
+ private LargeObjectManager largeobject = null;
+
+ /**
+ * This method is used internally to return an object based around
+ * postgresql's more unique data types.
+ *
+ * <p>It uses an internal Hashtable to get the handling class. If the
+ * type is not supported, then an instance of postgresql.util.PGobject
+ * is returned.
+ *
+ * You can use the getValue() or setValue() methods to handle the returned
+ * object. Custom objects can have their own methods.
+ *
+ * In 6.4, this is extended to use the postgresql.util.Serialize class to
+ * allow the Serialization of Java Objects into the database without using
+ * Blobs. Refer to that class for details on how this new feature works.
+ *
+ * @return PGobject for this type, and set to value
+ * @exception SQLException if value is not correct for this type
+ * @see postgresql.util.Serialize
+ */
+ public Object getObject(String type,String value) throws SQLException
+ {
+ try {
+ Object o = objectTypes.get(type);
+
+ // If o is null, then the type is unknown, so check to see if type
+ // is an actual table name. If it does, see if a Class is known that
+ // can handle it
+ if(o == null) {
+ Serialize ser = new Serialize(this,type);
+ objectTypes.put(type,ser);
+ return ser.fetch(Integer.parseInt(value));
+ }
+
+ // If o is not null, and it is a String, then its a class name that
+ // extends PGobject.
+ //
+ // This is used to implement the postgresql unique types (like lseg,
+ // point, etc).
+ if(o instanceof String) {
+ // 6.3 style extending PG_Object
+ PGobject obj = null;
+ obj = (PGobject)(Class.forName((String)o).newInstance());
+ obj.setType(type);
+ obj.setValue(value);
+ return (Object)obj;
+ } else {
+ // If it's an object, it should be an instance of our Serialize class
+ // If so, then call it's fetch method.
+ if(o instanceof Serialize)
+ return ((Serialize)o).fetch(Integer.parseInt(value));
}
+ } catch(SQLException sx) {
+ // rethrow the exception. Done because we capture any others next
+ sx.fillInStackTrace();
+ throw sx;
+ } catch(Exception ex) {
+ throw new SQLException("Failed to create object for "+type+": "+ex);
}
- if (final_error != null)
- throw final_error;
- return new ResultSet(this, fields, tuples, recv_status, 1);
+
+ // should never be reached
+ return null;
}
- }
-
- /**
- * 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.ReceiveIntegerR(2), i;
- Field[] fields = new Field[nf];
- for (i = 0 ; i < nf ; ++i)
- {
- String typname = pg_stream.ReceiveString(8192);
- int typid = pg_stream.ReceiveIntegerR(4);
- int typlen = pg_stream.ReceiveIntegerR(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;
- }
-
- /**
- * This returns the Fastpath API for the current connection.
- *
- * <p><b>NOTE:</b> This is not part of JDBC, but allows access to
- * functions on the postgresql backend itself.
- *
- * <p>It is primarily used by the LargeObject API
- *
- * <p>The best way to use this is as follows:
- *
- * <p><pre>
- * import postgresql.fastpath.*;
- * ...
- * Fastpath fp = ((postgresql.Connection)myconn).getFastpathAPI();
- * </pre>
- *
- * <p>where myconn is an open Connection to postgresql.
- *
- * @return Fastpath object allowing access to functions on the postgresql
- * backend.
- * @exception SQLException by Fastpath when initialising for first time
- */
- public Fastpath getFastpathAPI() throws SQLException
- {
- if(fastpath==null)
- fastpath = new Fastpath(this,pg_stream);
- return fastpath;
- }
-
- // This holds a reference to the Fastpath API if already open
- private Fastpath fastpath = null;
-
- /**
- * This returns the LargeObject API for the current connection.
- *
- * <p><b>NOTE:</b> This is not part of JDBC, but allows access to
- * functions on the postgresql backend itself.
- *
- * <p>The best way to use this is as follows:
- *
- * <p><pre>
- * import postgresql.largeobject.*;
- * ...
- * LargeObjectManager lo = ((postgresql.Connection)myconn).getLargeObjectAPI();
- * </pre>
- *
- * <p>where myconn is an open Connection to postgresql.
- *
- * @return LargeObject object that implements the API
- * @exception SQLException by LargeObject when initialising for first time
- */
- public LargeObjectManager getLargeObjectAPI() throws SQLException
- {
- if(largeobject==null)
- largeobject = new LargeObjectManager(this);
- return largeobject;
- }
-
- // This holds a reference to the LargeObject API if already open
- private LargeObjectManager largeobject = null;
-
- /**
- * This method is used internally to return an object based around
- * postgresql's more unique data types.
- *
- * <p>It uses an internal Hashtable to get the handling class. If the
- * type is not supported, then an instance of postgresql.util.PGobject
- * is returned.
- *
- * You can use the getValue() or setValue() methods to handle the returned
- * object. Custom objects can have their own methods.
- *
- * In 6.4, this is extended to use the postgresql.util.Serialize class to
- * allow the Serialization of Java Objects into the database without using
- * Blobs. Refer to that class for details on how this new feature works.
- *
- * @return PGobject for this type, and set to value
- * @exception SQLException if value is not correct for this type
- * @see postgresql.util.Serialize
- */
- protected Object getObject(String type,String value) throws SQLException
- {
- try {
- Object o = objectTypes.get(type);
-
- // If o is null, then the type is unknown, so check to see if type
- // is an actual table name. If it does, see if a Class is known that
- // can handle it
- if(o == null) {
- Serialize ser = new Serialize(this,type);
- objectTypes.put(type,ser);
- return ser.fetch(Integer.parseInt(value));
- }
-
- // If o is not null, and it is a String, then its a class name that
- // extends PGobject.
- //
- // This is used to implement the postgresql unique types (like lseg,
- // point, etc).
- if(o instanceof String) {
- // 6.3 style extending PG_Object
- PGobject obj = null;
- obj = (PGobject)(Class.forName((String)o).newInstance());
- obj.setType(type);
- obj.setValue(value);
- return (Object)obj;
- } else {
- // If it's an object, it should be an instance of our Serialize class
- // If so, then call it's fetch method.
- if(o instanceof Serialize)
- return ((Serialize)o).fetch(Integer.parseInt(value));
- }
- } catch(SQLException sx) {
- // rethrow the exception. Done because we capture any others next
- sx.fillInStackTrace();
- throw sx;
- } catch(Exception ex) {
- throw new SQLException("Failed to create object for "+type+": "+ex);
+ /**
+ * This stores an object into the database.
+ * @param o Object to store
+ * @return OID of the new rectord
+ * @exception SQLException if value is not correct for this type
+ * @see postgresql.util.Serialize
+ */
+ public int putObject(Object o) throws SQLException
+ {
+ try {
+ String type = o.getClass().getName();
+ Object x = objectTypes.get(type);
+
+ // If x is null, then the type is unknown, so check to see if type
+ // is an actual table name. If it does, see if a Class is known that
+ // can handle it
+ if(x == null) {
+ Serialize ser = new Serialize(this,type);
+ objectTypes.put(type,ser);
+ return ser.store(o);
+ }
+
+ // If it's an object, it should be an instance of our Serialize class
+ // If so, then call it's fetch method.
+ if(x instanceof Serialize)
+ return ((Serialize)x).store(o);
+
+ // Thow an exception because the type is unknown
+ throw new SQLException("The object could not be stored. Check that any tables required have already been created in the database.");
+
+ } catch(SQLException sx) {
+ // rethrow the exception. Done because we capture any others next
+ sx.fillInStackTrace();
+ throw sx;
+ } catch(Exception ex) {
+ throw new SQLException("Failed to store object: "+ex);
+ }
}
- // should never be reached
- return null;
- }
-
- /**
- * This stores an object into the database.
- * @param o Object to store
- * @return OID of the new rectord
- * @exception SQLException if value is not correct for this type
- * @see postgresql.util.Serialize
- */
- protected int putObject(Object o) throws SQLException
- {
- try {
- String type = o.getClass().getName();
- Object x = objectTypes.get(type);
-
- // If x is null, then the type is unknown, so check to see if type
- // is an actual table name. If it does, see if a Class is known that
- // can handle it
- if(x == null) {
- Serialize ser = new Serialize(this,type);
- objectTypes.put(type,ser);
- return ser.store(o);
- }
-
- // If it's an object, it should be an instance of our Serialize class
- // If so, then call it's fetch method.
- if(x instanceof Serialize)
- return ((Serialize)x).store(o);
-
- // Thow an exception because the type is unknown
- throw new SQLException("The object could not be stored. Check that any tables required have already been created in the database.");
-
- } catch(SQLException sx) {
- // rethrow the exception. Done because we capture any others next
- sx.fillInStackTrace();
- throw sx;
- } catch(Exception ex) {
- throw new SQLException("Failed to store object: "+ex);
+ /**
+ * This allows client code to add a handler for one of postgresql's
+ * more unique data types.
+ *
+ * <p><b>NOTE:</b> This is not part of JDBC, but an extension.
+ *
+ * <p>The best way to use this is as follows:
+ *
+ * <p><pre>
+ * ...
+ * ((postgresql.Connection)myconn).addDataType("mytype","my.class.name");
+ * ...
+ * </pre>
+ *
+ * <p>where myconn is an open Connection to postgresql.
+ *
+ * <p>The handling class must extend postgresql.util.PGobject
+ *
+ * @see postgresql.util.PGobject
+ */
+ public void addDataType(String type,String name)
+ {
+ objectTypes.put(type,name);
}
- }
-
- /**
- * This allows client code to add a handler for one of postgresql's
- * more unique data types.
- *
- * <p><b>NOTE:</b> This is not part of JDBC, but an extension.
- *
- * <p>The best way to use this is as follows:
- *
- * <p><pre>
- * ...
- * ((postgresql.Connection)myconn).addDataType("mytype","my.class.name");
- * ...
- * </pre>
- *
- * <p>where myconn is an open Connection to postgresql.
- *
- * <p>The handling class must extend postgresql.util.PGobject
- *
- * @see postgresql.util.PGobject
- */
- public void addDataType(String type,String name)
- {
- objectTypes.put(type,name);
- }
-
- // This holds the available types
- private Hashtable objectTypes = new Hashtable();
-
- // This array contains the types that are supported as standard.
- //
- // The first entry is the types name on the database, the second
- // the full class name of the handling class.
- //
- private static final String defaultObjectTypes[][] = {
- {"box", "postgresql.geometric.PGbox"},
- {"circle", "postgresql.geometric.PGcircle"},
- {"line", "postgresql.geometric.PGline"},
- {"lseg", "postgresql.geometric.PGlseg"},
- {"path", "postgresql.geometric.PGpath"},
- {"point", "postgresql.geometric.PGpoint"},
- {"polygon", "postgresql.geometric.PGpolygon"},
- {"money", "postgresql.util.PGmoney"}
- };
-
- // This initialises the objectTypes hashtable
- private void initObjectTypes()
- {
- for(int i=0;i<defaultObjectTypes.length;i++)
- objectTypes.put(defaultObjectTypes[i][0],defaultObjectTypes[i][1]);
- }
+
+ // This holds the available types
+ private Hashtable objectTypes = new Hashtable();
+
+ // This array contains the types that are supported as standard.
+ //
+ // The first entry is the types name on the database, the second
+ // the full class name of the handling class.
+ //
+ private static final String defaultObjectTypes[][] = {
+ {"box", "postgresql.geometric.PGbox"},
+ {"circle", "postgresql.geometric.PGcircle"},
+ {"line", "postgresql.geometric.PGline"},
+ {"lseg", "postgresql.geometric.PGlseg"},
+ {"path", "postgresql.geometric.PGpath"},
+ {"point", "postgresql.geometric.PGpoint"},
+ {"polygon", "postgresql.geometric.PGpolygon"},
+ {"money", "postgresql.util.PGmoney"}
+ };
+
+ // This initialises the objectTypes hashtable
+ private void initObjectTypes()
+ {
+ for(int i=0;i<defaultObjectTypes.length;i++)
+ objectTypes.put(defaultObjectTypes[i][0],defaultObjectTypes[i][1]);
+ }
+
+ // These are required by other common classes
+ public abstract java.sql.Statement createStatement() throws SQLException;
+
+ /**
+ * This returns a resultset. It must be overridden, so that the correct
+ * version (from jdbc1 or jdbc2) are returned.
+ */
+ protected abstract java.sql.ResultSet getResultSet(postgresql.Connection conn, Field[] fields, Vector tuples, String status, int updateCount) throws SQLException;
}
-
-// ***********************************************************************
-