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;
+ }
}
+
*/
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;
+ }
}
// ***********************************************************************
// 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();
+ }
}
package postgresql;
import java.sql.*;
+import java.util.*;
/**
* @version 1.0 15-APR-1997
*/
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;
+ }
}
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
*
*/
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;
- }
-}
*/
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;
+ }
}
*/
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;
+ }
}
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.
*/
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;
+ }
}
+
*/
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];
+ }
}
+