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