diff options
Diffstat (limited to 'src/interfaces/jdbc/org/postgresql/jdbc2')
14 files changed, 1265 insertions, 2570 deletions
diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2Connection.java b/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2Connection.java new file mode 100644 index 0000000000..8faefad65f --- /dev/null +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2Connection.java @@ -0,0 +1,203 @@ +package org.postgresql.jdbc2; + + +import java.io.*; +import java.net.ConnectException; +import java.sql.*; +import org.postgresql.util.PSQLException; + +/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2Connection.java,v 1.1 2002/07/23 03:59:55 barry Exp $ + * This class defines methods of the jdbc2 specification. This class extends + * org.postgresql.jdbc1.AbstractJdbc1Connection which provides the jdbc1 + * methods. The real Connection class (for jdbc2) is org.postgresql.jdbc2.Jdbc2Connection + */ +public abstract class AbstractJdbc2Connection extends org.postgresql.jdbc1.AbstractJdbc1Connection +{ + /* + * The current type mappings + */ + protected java.util.Map typemap; + + public java.sql.Statement createStatement() throws SQLException + { + // The spec says default of TYPE_FORWARD_ONLY but everyone is used to + // using TYPE_SCROLL_INSENSITIVE + return createStatement(java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_READ_ONLY); + } + + public abstract java.sql.Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException; + + public java.sql.PreparedStatement prepareStatement(String sql) throws SQLException + { + return prepareStatement(sql, java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_READ_ONLY); + } + + public abstract java.sql.PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException; + + public java.sql.CallableStatement prepareCall(String sql) throws SQLException + { + return prepareCall(sql, java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_READ_ONLY); + } + + public abstract java.sql.CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException; + + public java.util.Map getTypeMap() throws SQLException + { + return typemap; + } + + + public void setTypeMap(java.util.Map map) throws SQLException + { + typemap = map; + } + + public void cancelQuery() throws SQLException + { + org.postgresql.PG_Stream cancelStream = null; + try { + cancelStream = new org.postgresql.PG_Stream(PG_HOST, PG_PORT); + } catch (ConnectException cex) { + // Added by Peter Mount <peter@retep.org.uk> + // ConnectException is thrown when the connection cannot be made. + // we trap this an return a more meaningful message for the end user + throw new PSQLException ("postgresql.con.refused"); + } catch (IOException e) { + throw new PSQLException ("postgresql.con.failed",e); + } + + // Now we need to construct and send a cancel packet + try { + cancelStream.SendInteger(16, 4); + cancelStream.SendInteger(80877102, 4); + cancelStream.SendInteger(pid, 4); + cancelStream.SendInteger(ckey, 4); + cancelStream.flush(); + } + catch(IOException e) { + throw new PSQLException("postgresql.con.failed",e); + } + finally { + try { + if(cancelStream != null) + cancelStream.close(); + } + catch(IOException e) {} // Ignore + } + } + + + /* + * This overides the standard internal getObject method so that we can + * check the jdbc2 type map first + */ + public Object getObject(String type, String value) throws SQLException + { + if (typemap != null) + { + SQLData d = (SQLData) typemap.get(type); + if (d != null) + { + // Handle the type (requires SQLInput & SQLOutput classes to be implemented) + throw org.postgresql.Driver.notImplemented(); + } + } + + // Default to the original method + return super.getObject(type, value); + } + + + //Because the get/setLogStream methods are deprecated in JDBC2 + //we use the get/setLogWriter methods here for JDBC2 by overriding + //the base version of this method + protected void enableDriverManagerLogging() { + if (DriverManager.getLogWriter() == null) { + DriverManager.setLogWriter(new PrintWriter(System.out)); + } + } + + + /* + * This implemetation uses the jdbc2Types array to support the jdbc2 + * datatypes. Basically jdbc1 and jdbc2 are the same, except that + * jdbc2 adds the Array types. + */ + public int getSQLType(String pgTypeName) + { + int sqlType = Types.OTHER; // default value + for (int i = 0;i < jdbc2Types.length;i++) + { + if (pgTypeName.equals(jdbc2Types[i])) + { + sqlType = jdbc2Typei[i]; + break; + } + } + return sqlType; + } + + /* + * This table holds the org.postgresql names for the types supported. + * Any types that map to Types.OTHER (eg POINT) don't go into this table. + * They default automatically to Types.OTHER + * + * Note: This must be in the same order as below. + * + * Tip: keep these grouped together by the Types. value + */ + private static final String jdbc2Types[] = { + "int2", + "int4", "oid", + "int8", + "cash", "money", + "numeric", + "float4", + "float8", + "bpchar", "char", "char2", "char4", "char8", "char16", + "varchar", "text", "name", "filename", + "bytea", + "bool", + "date", + "time", + "abstime", "timestamp", "timestamptz", + "_bool", "_char", "_int2", "_int4", "_text", + "_oid", "_varchar", "_int8", "_float4", "_float8", + "_abstime", "_date", "_time", "_timestamp", "_numeric", + "_bytea" + }; + + /* + * This table holds the JDBC type for each entry above. + * + * Note: This must be in the same order as above + * + * Tip: keep these grouped together by the Types. value + */ + private static final int jdbc2Typei[] = { + Types.SMALLINT, + Types.INTEGER, Types.INTEGER, + Types.BIGINT, + Types.DOUBLE, Types.DOUBLE, + Types.NUMERIC, + Types.REAL, + Types.DOUBLE, + Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.BINARY, + Types.BIT, + Types.DATE, + Types.TIME, + Types.TIMESTAMP, Types.TIMESTAMP, Types.TIMESTAMP, + Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, + Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, + Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, + Types.ARRAY + }; + + + + +} + + diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java b/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java new file mode 100644 index 0000000000..50c5d942bb --- /dev/null +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java @@ -0,0 +1,752 @@ +package org.postgresql.jdbc2; + + +import java.math.BigDecimal; +import java.io.*; +import java.sql.*; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Vector; +import org.postgresql.Field; +import org.postgresql.core.Encoding; +import org.postgresql.largeobject.*; +import org.postgresql.util.PGbytea; +import org.postgresql.util.PSQLException; + +/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2ResultSet.java,v 1.1 2002/07/23 03:59:55 barry Exp $ + * This class defines methods of the jdbc2 specification. This class extends + * org.postgresql.jdbc1.AbstractJdbc1ResultSet which provides the jdbc1 + * methods. The real Statement class (for jdbc2) is org.postgresql.jdbc2.Jdbc2ResultSet + */ +public class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.AbstractJdbc1ResultSet +{ + protected Jdbc2Statement statement; + + protected String sqlQuery=null; + + public AbstractJdbc2ResultSet(org.postgresql.PGConnection conn, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) + { + super(conn, fields, tuples, status, updateCount, insertOID, binaryCursor); + } + + public java.net.URL getURL(int columnIndex) throws SQLException + { + return null; + } + + public java.net.URL getURL(String columnName) throws SQLException + { + return null; + } + + /* + * Get the value of a column in the current row as a Java object + * + * <p>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. + * + * <p>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; + + checkResultSet( columnIndex ); + + wasNullFlag = (this_row[columnIndex - 1] == null); + if (wasNullFlag) + return null; + + field = fields[columnIndex - 1]; + + // some fields can be null, mainly from those returned by MetaData methods + if (field == null) + { + wasNullFlag = true; + return null; + } + + switch (field.getSQLType()) + { + case Types.BIT: + return getBoolean(columnIndex) ? Boolean.TRUE : Boolean.FALSE; + case Types.SMALLINT: + return new Short(getShort(columnIndex)); + case Types.INTEGER: + return new Integer(getInt(columnIndex)); + case Types.BIGINT: + return new Long(getLong(columnIndex)); + case Types.NUMERIC: + return getBigDecimal + (columnIndex, (field.getMod() == -1) ? -1 : ((field.getMod() - 4) & 0xffff)); + 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); + case Types.BINARY: + case Types.VARBINARY: + return getBytes(columnIndex); + case Types.ARRAY: + return getArray(columnIndex); + default: + String type = field.getPGType(); + // if the backend doesn't know the type then coerce to String + if (type.equals("unknown")) + { + return getString(columnIndex); + } + else + { + return connection.getObject(field.getPGType(), getString(columnIndex)); + } + } + } + + public boolean absolute(int index) throws SQLException + { + // index is 1-based, but internally we use 0-based indices + int internalIndex; + + if (index == 0) + throw new SQLException("Cannot move to index of 0"); + + final int rows_size = rows.size(); + + //if index<0, count from the end of the result set, but check + //to be sure that it is not beyond the first index + if (index < 0) + { + if (index >= -rows_size) + internalIndex = rows_size + index; + else + { + beforeFirst(); + return false; + } + } + else + { + //must be the case that index>0, + //find the correct place, assuming that + //the index is not too large + if (index <= rows_size) + internalIndex = index - 1; + else + { + afterLast(); + return false; + } + } + + current_row = internalIndex; + this_row = (byte [][])rows.elementAt(internalIndex); + return true; + } + + public void afterLast() throws SQLException + { + final int rows_size = rows.size(); + if (rows_size > 0) + current_row = rows_size; + } + + public void beforeFirst() throws SQLException + { + if (rows.size() > 0) + current_row = -1; + } + + public void cancelRowUpdates() throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public void deleteRow() throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public boolean first() throws SQLException + { + if (rows.size() <= 0) + return false; + + current_row = 0; + this_row = (byte [][])rows.elementAt(current_row); + + rowBuffer=new byte[this_row.length][]; + System.arraycopy(this_row,0,rowBuffer,0,this_row.length); + + return true; + } + + public java.sql.Array getArray(String colName) throws SQLException + { + return getArray(findColumn(colName)); + } + + public java.sql.Array getArray(int i) throws SQLException + { + wasNullFlag = (this_row[i - 1] == null); + if (wasNullFlag) + return null; + + if (i < 1 || i > fields.length) + throw new PSQLException("postgresql.res.colrange"); + return (java.sql.Array) new org.postgresql.jdbc2.Array( connection, i, fields[i - 1], (java.sql.ResultSet)this ); + } + + public java.math.BigDecimal getBigDecimal(int columnIndex) throws SQLException + { + return getBigDecimal(columnIndex, -1); + } + + public java.math.BigDecimal getBigDecimal(String columnName) throws SQLException + { + return getBigDecimal(findColumn(columnName)); + } + + public Blob getBlob(String columnName) throws SQLException + { + return getBlob(findColumn(columnName)); + } + + public Blob getBlob(int i) throws SQLException + { + return new org.postgresql.largeobject.PGblob(connection, getInt(i)); + } + + public java.io.Reader getCharacterStream(String columnName) throws SQLException + { + return getCharacterStream(findColumn(columnName)); + } + + public java.io.Reader getCharacterStream(int i) throws SQLException + { + checkResultSet( i ); + wasNullFlag = (this_row[i - 1] == null); + if (wasNullFlag) + return null; + + if (((AbstractJdbc2Connection)connection).haveMinimumCompatibleVersion("7.2")) + { + //Version 7.2 supports AsciiStream for all the PG text types + //As the spec/javadoc for this method indicate this is to be used for + //large text values (i.e. LONGVARCHAR) PG doesn't have a separate + //long string datatype, but with toast the text datatype is capable of + //handling very large values. Thus the implementation ends up calling + //getString() since there is no current way to stream the value from the server + return new CharArrayReader(getString(i).toCharArray()); + } + else + { + // In 7.1 Handle as BLOBS so return the LargeObject input stream + Encoding encoding = connection.getEncoding(); + InputStream input = getBinaryStream(i); + return encoding.getDecodingReader(input); + } + } + + public Clob getClob(String columnName) throws SQLException + { + return getClob(findColumn(columnName)); + } + + public Clob getClob(int i) throws SQLException + { + return new org.postgresql.largeobject.PGclob(connection, getInt(i)); + } + + public int getConcurrency() throws SQLException + { + // The standard ResultSet class will now return + // CONCUR_READ_ONLY. A sub-class will overide this if the query was + // updateable. + return java.sql.ResultSet.CONCUR_READ_ONLY; + } + + public java.sql.Date getDate(int i, java.util.Calendar cal) throws SQLException + { + // If I read the specs, this should use cal only if we don't + // store the timezone, and if we do, then act just like getDate()? + // for now... + return getDate(i); + } + + public Time getTime(int i, java.util.Calendar cal) throws SQLException + { + // If I read the specs, this should use cal only if we don't + // store the timezone, and if we do, then act just like getTime()? + // for now... + return getTime(i); + } + + public Timestamp getTimestamp(int i, java.util.Calendar cal) throws SQLException + { + // If I read the specs, this should use cal only if we don't + // store the timezone, and if we do, then act just like getDate()? + // for now... + return getTimestamp(i); + } + + public java.sql.Date getDate(String c, java.util.Calendar cal) throws SQLException + { + return getDate(findColumn(c), cal); + } + + public Time getTime(String c, java.util.Calendar cal) throws SQLException + { + return getTime(findColumn(c), cal); + } + + public Timestamp getTimestamp(String c, java.util.Calendar cal) throws SQLException + { + return getTimestamp(findColumn(c), cal); + } + + public int getFetchDirection() throws SQLException + { + //PostgreSQL normally sends rows first->last + return java.sql.ResultSet.FETCH_FORWARD; + } + + public int getFetchSize() throws SQLException + { + // In this implementation we return the entire result set, so + // here return the number of rows we have. Sub-classes can return a proper + // value + return rows.size(); + } + + public Object getObject(String columnName, java.util.Map map) throws SQLException + { + return getObject(findColumn(columnName), map); + } + + /* + * This checks against map for the type of column i, and if found returns + * an object based on that mapping. The class must implement the SQLData + * interface. + */ + public Object getObject(int i, java.util.Map map) throws SQLException + { + throw org.postgresql.Driver.notImplemented(); + } + + public Ref getRef(String columnName) throws SQLException + { + return getRef(findColumn(columnName)); + } + + public Ref getRef(int i) throws SQLException + { + //The backend doesn't yet have SQL3 REF types + throw new PSQLException("postgresql.psqlnotimp"); + } + + public int getRow() throws SQLException + { + final int rows_size = rows.size(); + + if (current_row < 0 || current_row >= rows_size) + return 0; + + return current_row + 1; + } + + // This one needs some thought, as not all ResultSets come from a statement + public java.sql.Statement getStatement() throws SQLException + { + return statement; + } + + public int getType() throws SQLException + { + // This implementation allows scrolling but is not able to + // see any changes. Sub-classes may overide this to return a more + // meaningful result. + return java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE; + } + + public void insertRow() throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public boolean isAfterLast() throws SQLException + { + final int rows_size = rows.size(); + return (current_row >= rows_size && rows_size > 0); + } + + public boolean isBeforeFirst() throws SQLException + { + return (current_row < 0 && rows.size() > 0); + } + + public boolean isFirst() throws SQLException + { + return (current_row == 0 && rows.size() >= 0); + } + + public boolean isLast() throws SQLException + { + final int rows_size = rows.size(); + return (current_row == rows_size - 1 && rows_size > 0); + } + + public boolean last() throws SQLException + { + final int rows_size = rows.size(); + if (rows_size <= 0) + return false; + + current_row = rows_size - 1; + this_row = (byte [][])rows.elementAt(current_row); + + rowBuffer=new byte[this_row.length][]; + System.arraycopy(this_row,0,rowBuffer,0,this_row.length); + + return true; + } + + public void moveToCurrentRow() throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public void moveToInsertRow() throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public boolean previous() throws SQLException + { + if (--current_row < 0) + return false; + this_row = (byte [][])rows.elementAt(current_row); + System.arraycopy(this_row,0,rowBuffer,0,this_row.length); + return true; + } + + public void refreshRow() throws SQLException + { + throw new PSQLException("postgresql.notsensitive"); + } + + public boolean relative(int rows) throws SQLException + { + //have to add 1 since absolute expects a 1-based index + return absolute(current_row + 1 + rows); + } + + public boolean rowDeleted() throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + return false; // javac complains about not returning a value! + } + + public boolean rowInserted() throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + return false; // javac complains about not returning a value! + } + + public boolean rowUpdated() throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + return false; // javac complains about not returning a value! + } + + public void setFetchDirection(int direction) throws SQLException + { + throw new PSQLException("postgresql.psqlnotimp"); + } + + public void setFetchSize(int rows) throws SQLException + { + // Sub-classes should implement this as part of their cursor support + throw org.postgresql.Driver.notImplemented(); + } + + public void updateAsciiStream(int columnIndex, + java.io.InputStream x, + int length + ) throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public void updateAsciiStream(String columnName, + java.io.InputStream x, + int length + ) throws SQLException + { + updateAsciiStream(findColumn(columnName), x, length); + } + + public void updateBigDecimal(int columnIndex, + java.math.BigDecimal x + ) throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public void updateBigDecimal(String columnName, + java.math.BigDecimal x + ) throws SQLException + { + updateBigDecimal(findColumn(columnName), x); + } + + public void updateBinaryStream(int columnIndex, + java.io.InputStream x, + int length + ) throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public void updateBinaryStream(String columnName, + java.io.InputStream x, + int length + ) throws SQLException + { + updateBinaryStream(findColumn(columnName), x, length); + } + + public void updateBoolean(int columnIndex, boolean x) throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public void updateBoolean(String columnName, boolean x) throws SQLException + { + updateBoolean(findColumn(columnName), x); + } + + public void updateByte(int columnIndex, byte x) throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public void updateByte(String columnName, byte x) throws SQLException + { + updateByte(findColumn(columnName), x); + } + + public void updateBytes(String columnName, byte[] x) throws SQLException + { + updateBytes(findColumn(columnName), x); + } + + public void updateBytes(int columnIndex, byte[] x) throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public void updateCharacterStream(int columnIndex, + java.io.Reader x, + int length + ) throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public void updateCharacterStream(String columnName, + java.io.Reader x, + int length + ) throws SQLException + { + updateCharacterStream(findColumn(columnName), x, length); + } + + public void updateDate(int columnIndex, java.sql.Date x) throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public void updateDate(String columnName, java.sql.Date x) throws SQLException + { + updateDate(findColumn(columnName), x); + } + + public void updateDouble(int columnIndex, double x) throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public void updateDouble(String columnName, double x) throws SQLException + { + updateDouble(findColumn(columnName), x); + } + + public void updateFloat(int columnIndex, float x) throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public void updateFloat(String columnName, float x) throws SQLException + { + updateFloat(findColumn(columnName), x); + } + + public void updateInt(int columnIndex, int x) throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public void updateInt(String columnName, int x) throws SQLException + { + updateInt(findColumn(columnName), x); + } + + public void updateLong(int columnIndex, long x) throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public void updateLong(String columnName, long x) throws SQLException + { + updateLong(findColumn(columnName), x); + } + + public void updateNull(int columnIndex) throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public void updateNull(String columnName) throws SQLException + { + updateNull(findColumn(columnName)); + } + + public void updateObject(int columnIndex, Object x) throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public void updateObject(String columnName, Object x) throws SQLException + { + updateObject(findColumn(columnName), x); + } + + public void updateObject(int columnIndex, Object x, int scale) throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public void updateObject(String columnName, Object x, int scale) throws SQLException + { + updateObject(findColumn(columnName), x, scale); + } + + public void updateRow() throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public void updateShort(int columnIndex, short x) throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public void updateShort(String columnName, short x) throws SQLException + { + updateShort(findColumn(columnName), x); + } + + public void updateString(int columnIndex, String x) throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public void updateString(String columnName, String x) throws SQLException + { + updateString(findColumn(columnName), x); + } + + public void updateTime(int columnIndex, Time x) throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public void updateTime(String columnName, Time x) throws SQLException + { + updateTime(findColumn(columnName), x); + } + + public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException + { + // only sub-classes implement CONCUR_UPDATEABLE + notUpdateable(); + } + + public void updateTimestamp(String columnName, Timestamp x) throws SQLException + { + updateTimestamp(findColumn(columnName), x); + } + + // helper method. Throws an SQLException when an update is not possible + public void notUpdateable() throws SQLException + { + throw new PSQLException("postgresql.noupdate"); + } + + /* + * It's used currently by getStatement() but may also with the new core + * package. + */ + public void setStatement(Jdbc2Statement statement) + { + this.statement = statement; + } + + public void setSQLQuery(String sqlQuery) { + this.sqlQuery=sqlQuery; + } +} + diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2Statement.java b/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2Statement.java new file mode 100644 index 0000000000..3d6f6553ce --- /dev/null +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2Statement.java @@ -0,0 +1,142 @@ +package org.postgresql.jdbc2; + + +import java.sql.*; +import java.util.Vector; +import org.postgresql.util.PSQLException; + +/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2Statement.java,v 1.1 2002/07/23 03:59:55 barry Exp $ + * This class defines methods of the jdbc2 specification. This class extends + * org.postgresql.jdbc1.AbstractJdbc1Statement which provides the jdbc1 + * methods. The real Statement class (for jdbc2) is org.postgresql.jdbc2.Jdbc2Statement + */ +public abstract class AbstractJdbc2Statement extends org.postgresql.jdbc1.AbstractJdbc1Statement +{ + + protected Vector batch = null; + protected int resultsettype; // the resultset type to return + protected int concurrency; // is it updateable or not? + + /* + * Execute a SQL statement that may return multiple results. We + * don't have to worry about this since we do not support multiple + * ResultSets. You can use getResultSet or getUpdateCount to + * retrieve the result. + * + * @param sql any SQL statement + * @return true if the next result is a ResulSet, false if it is + * an update count or there are no more results + * @exception SQLException if a database access error occurs + */ + public boolean execute(String sql) throws SQLException + { + boolean l_return = super.execute(sql); + + //Now do the jdbc2 specific stuff + //required for ResultSet.getStatement() to work + ((AbstractJdbc2ResultSet)result).setStatement((Jdbc2Statement)this); + + // Added this so that the Updateable resultset knows the query that gave this + ((AbstractJdbc2ResultSet)result).setSQLQuery(sql); + + return l_return; + } + + // ** JDBC 2 Extensions ** + + public void addBatch(String sql) throws SQLException + { + if (batch == null) + batch = new Vector(); + batch.addElement(sql); + } + + public void clearBatch() throws SQLException + { + if (batch != null) + batch.removeAllElements(); + } + + public int[] executeBatch() throws SQLException + { + if (batch == null) + batch = new Vector(); + int size = batch.size(); + int[] result = new int[size]; + int i = 0; + try + { + for (i = 0;i < size;i++) + result[i] = this.executeUpdate((String)batch.elementAt(i)); + } + catch (SQLException e) + { + int[] resultSucceeded = new int[i]; + System.arraycopy(result, 0, resultSucceeded, 0, i); + + PBatchUpdateException updex = + new PBatchUpdateException("postgresql.stat.batch.error", + new Integer(i), batch.elementAt(i), resultSucceeded); + updex.setNextException(e); + + throw updex; + } + finally + { + batch.removeAllElements(); + } + return result; + } + + public void cancel() throws SQLException + { + ((AbstractJdbc2Connection)connection).cancelQuery(); + } + + public java.sql.Connection getConnection() throws SQLException + { + return (java.sql.Connection)connection; + } + + public int getFetchDirection() throws SQLException + { + throw new PSQLException("postgresql.psqlnotimp"); + } + + public int getFetchSize() throws SQLException + { + // This one can only return a valid value when were a cursor? + throw org.postgresql.Driver.notImplemented(); + } + + public int getResultSetConcurrency() throws SQLException + { + return concurrency; + } + + public int getResultSetType() throws SQLException + { + return resultsettype; + } + + public void setFetchDirection(int direction) throws SQLException + { + throw org.postgresql.Driver.notImplemented(); + } + + public void setFetchSize(int rows) throws SQLException + { + throw org.postgresql.Driver.notImplemented(); + } + + public void setResultSetConcurrency(int value) throws SQLException + { + concurrency = value; + } + + public void setResultSetType(int value) throws SQLException + { + resultsettype = value; + } + +} diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/Array.java b/src/interfaces/jdbc/org/postgresql/jdbc2/Array.java index 7cc842ec36..2105802d66 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc2/Array.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/Array.java @@ -25,9 +25,9 @@ import org.postgresql.util.*; public class Array implements java.sql.Array { - private org.postgresql.Connection conn = null; + private org.postgresql.PGConnection conn = null; private org.postgresql.Field field = null; - private org.postgresql.jdbc2.ResultSet rs = null; + private ResultSet rs; private int idx = 0; private String rawString = null; @@ -39,14 +39,14 @@ public class Array implements java.sql.Array * @param field the Field descriptor for the field to load into this Array * @param rs the ResultSet from which to get the data for this Array */ - public Array( org.postgresql.Connection conn, int idx, Field field, org.postgresql.jdbc2.ResultSet rs ) + public Array( org.postgresql.PGConnection conn, int idx, Field field, ResultSet rs ) throws SQLException { this.conn = conn; this.field = field; - this.rs = rs; + this.rs = rs; this.idx = idx; - this.rawString = rs.getFixedString(idx); + this.rawString = ((AbstractJdbc2ResultSet)rs).getFixedString(idx); } public Object getArray() throws SQLException @@ -124,33 +124,33 @@ public class Array implements java.sql.Array case Types.BIT: retVal = new boolean[ count ]; for ( ; count > 0; count-- ) - ((boolean[])retVal)[i++] = ResultSet.toBoolean( arrayContents[(int)index++] ); + ((boolean[])retVal)[i++] = Jdbc2ResultSet.toBoolean( arrayContents[(int)index++] ); break; case Types.SMALLINT: case Types.INTEGER: retVal = new int[ count ]; for ( ; count > 0; count-- ) - ((int[])retVal)[i++] = ResultSet.toInt( arrayContents[(int)index++] ); + ((int[])retVal)[i++] = Jdbc2ResultSet.toInt( arrayContents[(int)index++] ); break; case Types.BIGINT: retVal = new long[ count ]; for ( ; count > 0; count-- ) - ((long[])retVal)[i++] = ResultSet.toLong( arrayContents[(int)index++] ); + ((long[])retVal)[i++] = Jdbc2ResultSet.toLong( arrayContents[(int)index++] ); break; case Types.NUMERIC: retVal = new BigDecimal[ count ]; for ( ; count > 0; count-- ) - ((BigDecimal[])retVal)[i++] = ResultSet.toBigDecimal( arrayContents[(int)index++], 0 ); + ((BigDecimal[])retVal)[i++] = Jdbc2ResultSet.toBigDecimal( arrayContents[(int)index++], 0 ); break; case Types.REAL: retVal = new float[ count ]; for ( ; count > 0; count-- ) - ((float[])retVal)[i++] = ResultSet.toFloat( arrayContents[(int)index++] ); + ((float[])retVal)[i++] = Jdbc2ResultSet.toFloat( arrayContents[(int)index++] ); break; case Types.DOUBLE: retVal = new double[ count ]; for ( ; count > 0; count-- ) - ((double[])retVal)[i++] = ResultSet.toDouble( arrayContents[(int)index++] ); + ((double[])retVal)[i++] = Jdbc2ResultSet.toDouble( arrayContents[(int)index++] ); break; case Types.CHAR: case Types.VARCHAR: @@ -161,18 +161,18 @@ public class Array implements java.sql.Array case Types.DATE: retVal = new java.sql.Date[ count ]; for ( ; count > 0; count-- ) - ((java.sql.Date[])retVal)[i++] = ResultSet.toDate( arrayContents[(int)index++] ); + ((java.sql.Date[])retVal)[i++] = Jdbc2ResultSet.toDate( arrayContents[(int)index++] ); break; case Types.TIME: retVal = new java.sql.Time[ count ]; for ( ; count > 0; count-- ) - ((java.sql.Time[])retVal)[i++] = ResultSet.toTime( arrayContents[(int)index++], rs, getBaseTypeName() ); + ((java.sql.Time[])retVal)[i++] = Jdbc2ResultSet.toTime( arrayContents[(int)index++], rs, getBaseTypeName() ); break; case Types.TIMESTAMP: retVal = new Timestamp[ count ]; StringBuffer sbuf = null; for ( ; count > 0; count-- ) - ((java.sql.Timestamp[])retVal)[i++] = ResultSet.toTimestamp( arrayContents[(int)index++], rs, getBaseTypeName() ); + ((java.sql.Timestamp[])retVal)[i++] = Jdbc2ResultSet.toTimestamp( arrayContents[(int)index++], rs, getBaseTypeName() ); break; // Other datatypes not currently supported. If you are really using other types ask @@ -216,12 +216,12 @@ public class Array implements java.sql.Array Object array = getArray( index, count, map ); Vector rows = new Vector(); Field[] fields = new Field[2]; - fields[0] = new Field(conn, "INDEX", conn.getOID("int2"), 2); + fields[0] = new Field(conn, "INDEX", conn.getPGType("int2"), 2); switch ( getBaseType() ) { case Types.BIT: boolean[] booleanArray = (boolean[]) array; - fields[1] = new Field(conn, "VALUE", conn.getOID("bool"), 1); + fields[1] = new Field(conn, "VALUE", conn.getPGType("bool"), 1); for ( int i = 0; i < booleanArray.length; i++ ) { byte[][] tuple = new byte[2][0]; @@ -230,11 +230,11 @@ public class Array implements java.sql.Array rows.addElement(tuple); } case Types.SMALLINT: - fields[1] = new Field(conn, "VALUE", conn.getOID("int2"), 2); + fields[1] = new Field(conn, "VALUE", conn.getPGType("int2"), 2); case Types.INTEGER: int[] intArray = (int[]) array; if ( fields[1] == null ) - fields[1] = new Field(conn, "VALUE", conn.getOID("int4"), 4); + fields[1] = new Field(conn, "VALUE", conn.getPGType("int4"), 4); for ( int i = 0; i < intArray.length; i++ ) { byte[][] tuple = new byte[2][0]; @@ -245,7 +245,7 @@ public class Array implements java.sql.Array break; case Types.BIGINT: long[] longArray = (long[]) array; - fields[1] = new Field(conn, "VALUE", conn.getOID("int8"), 8); + fields[1] = new Field(conn, "VALUE", conn.getPGType("int8"), 8); for ( int i = 0; i < longArray.length; i++ ) { byte[][] tuple = new byte[2][0]; @@ -256,7 +256,7 @@ public class Array implements java.sql.Array break; case Types.NUMERIC: BigDecimal[] bdArray = (BigDecimal[]) array; - fields[1] = new Field(conn, "VALUE", conn.getOID("numeric"), -1); + fields[1] = new Field(conn, "VALUE", conn.getPGType("numeric"), -1); for ( int i = 0; i < bdArray.length; i++ ) { byte[][] tuple = new byte[2][0]; @@ -267,7 +267,7 @@ public class Array implements java.sql.Array break; case Types.REAL: float[] floatArray = (float[]) array; - fields[1] = new Field(conn, "VALUE", conn.getOID("float4"), 4); + fields[1] = new Field(conn, "VALUE", conn.getPGType("float4"), 4); for ( int i = 0; i < floatArray.length; i++ ) { byte[][] tuple = new byte[2][0]; @@ -278,7 +278,7 @@ public class Array implements java.sql.Array break; case Types.DOUBLE: double[] doubleArray = (double[]) array; - fields[1] = new Field(conn, "VALUE", conn.getOID("float8"), 8); + fields[1] = new Field(conn, "VALUE", conn.getPGType("float8"), 8); for ( int i = 0; i < doubleArray.length; i++ ) { byte[][] tuple = new byte[2][0]; @@ -288,11 +288,11 @@ public class Array implements java.sql.Array } break; case Types.CHAR: - fields[1] = new Field(conn, "VALUE", conn.getOID("char"), 1); + fields[1] = new Field(conn, "VALUE", conn.getPGType("char"), 1); case Types.VARCHAR: String[] strArray = (String[]) array; if ( fields[1] == null ) - fields[1] = new Field(conn, "VALUE", conn.getOID("varchar"), -1); + fields[1] = new Field(conn, "VALUE", conn.getPGType("varchar"), -1); for ( int i = 0; i < strArray.length; i++ ) { byte[][] tuple = new byte[2][0]; @@ -303,7 +303,7 @@ public class Array implements java.sql.Array break; case Types.DATE: java.sql.Date[] dateArray = (java.sql.Date[]) array; - fields[1] = new Field(conn, "VALUE", conn.getOID("date"), 4); + fields[1] = new Field(conn, "VALUE", conn.getPGType("date"), 4); for ( int i = 0; i < dateArray.length; i++ ) { byte[][] tuple = new byte[2][0]; @@ -314,7 +314,7 @@ public class Array implements java.sql.Array break; case Types.TIME: java.sql.Time[] timeArray = (java.sql.Time[]) array; - fields[1] = new Field(conn, "VALUE", conn.getOID("time"), 8); + fields[1] = new Field(conn, "VALUE", conn.getPGType("time"), 8); for ( int i = 0; i < timeArray.length; i++ ) { byte[][] tuple = new byte[2][0]; @@ -325,7 +325,7 @@ public class Array implements java.sql.Array break; case Types.TIMESTAMP: java.sql.Timestamp[] timestampArray = (java.sql.Timestamp[]) array; - fields[1] = new Field(conn, "VALUE", conn.getOID("timestamp"), 8); + fields[1] = new Field(conn, "VALUE", conn.getPGType("timestamp"), 8); for ( int i = 0; i < timestampArray.length; i++ ) { byte[][] tuple = new byte[2][0]; @@ -340,7 +340,7 @@ public class Array implements java.sql.Array default: throw org.postgresql.Driver.notImplemented(); } - return new ResultSet((org.postgresql.jdbc2.Connection)conn, fields, rows, "OK", 1 ); + return new Jdbc2ResultSet((org.postgresql.jdbc2.Jdbc2Connection)conn, fields, rows, "OK", 1 ); } public String toString() diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/CallableStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc2/CallableStatement.java index 4aa0348325..9d37bf04bc 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc2/CallableStatement.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/CallableStatement.java @@ -45,7 +45,7 @@ public class CallableStatement extends org.postgresql.jdbc2.PreparedStatement im /* * @exception SQLException on failure */ - public CallableStatement(Connection c, String q) throws SQLException + public CallableStatement(Jdbc2Connection c, String q) throws SQLException { super(c, q); // don't parse yet.. } diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/Connection.java b/src/interfaces/jdbc/org/postgresql/jdbc2/Connection.java deleted file mode 100644 index 9ab3cced8e..0000000000 --- a/src/interfaces/jdbc/org/postgresql/jdbc2/Connection.java +++ /dev/null @@ -1,332 +0,0 @@ -package org.postgresql.jdbc2; - -// IMPORTANT NOTE: This file implements the JDBC 2 version of the driver. -// If you make any modifications to this file, you must make sure that the -// changes are also made (if relevent) to the related JDBC 1 class in the -// org.postgresql.jdbc1 package. - -import java.io.*; -import java.lang.*; -import java.lang.reflect.*; -import java.net.*; -import java.util.*; -import java.sql.*; -import org.postgresql.Field; -import org.postgresql.fastpath.*; -import org.postgresql.largeobject.*; -import org.postgresql.util.*; - -/* - * $Id: Connection.java,v 1.20 2002/06/24 06:16:27 barry Exp $ - * - * A Connection represents a session with a specific database. Within the - * context of a Connection, SQL statements are executed and results are - * returned. - * - * <P>A Connection's database is able to provide information describing - * its tables, its supported SQL grammar, its stored procedures, the - * capabilities of this connection, etc. This information is obtained - * with the getMetaData method. - * - * <p><B>Note:</B> By default, the Connection automatically commits changes - * after executing each statement. If auto-commit has been disabled, an - * explicit commit must be done or database changes will not be saved. - * - * @see java.sql.Connection - */ -public class Connection extends org.postgresql.Connection implements java.sql.Connection -{ - // This is a cache of the DatabaseMetaData instance for this connection - protected DatabaseMetaData metadata; - - /* - * The current type mappings - */ - protected java.util.Map typemap; - - /* - * 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 - { - // The spec says default of TYPE_FORWARD_ONLY but everyone is used to - // using TYPE_SCROLL_INSENSITIVE - return createStatement(java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_READ_ONLY); - } - - /* - * 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 - * - * @param resultSetType to use - * @param resultSetCuncurrency to use - * @return a new Statement object - * @exception SQLException passed through from the constructor - */ - public java.sql.Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException - { - Statement s = new Statement(this); - s.setResultSetType(resultSetType); - s.setResultSetConcurrency(resultSetConcurrency); - return s; - } - - - /* - * A SQL statement with or without IN parameters can be pre-compiled - * and stored in a PreparedStatement object. This object can then - * be used to efficiently execute this statement multiple times. - * - * <B>Note:</B> This method is optimized for handling parametric - * SQL statements that benefit from precompilation if the drivers - * supports precompilation. PostgreSQL does not support precompilation. - * In this case, the statement is not sent to the database until the - * PreparedStatement is executed. This has no direct effect on users; - * however it does affect which method throws certain SQLExceptions - * - * @param sql a SQL statement that may contain one or more '?' IN - * parameter placeholders - * @return a new PreparedStatement object containing the pre-compiled - * statement. - * @exception SQLException if a database access error occurs. - */ - public java.sql.PreparedStatement prepareStatement(String sql) throws SQLException - { - return prepareStatement(sql, java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_READ_ONLY); - } - - public java.sql.PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException - { - PreparedStatement s = new PreparedStatement(this, sql); - s.setResultSetType(resultSetType); - s.setResultSetConcurrency(resultSetConcurrency); - return s; - } - - /* - * A SQL stored procedure call statement is handled by creating a - * CallableStatement for it. The CallableStatement provides methods - * for setting up its IN and OUT parameters and methods for executing - * it. - * - * <B>Note:</B> This method is optimised for handling stored procedure - * call statements. Some drivers may send the call statement to the - * database when the prepareCall is done; others may wait until the - * CallableStatement is executed. This has no direct effect on users; - * however, it does affect which method throws certain SQLExceptions - * - * @param sql a SQL statement that may contain one or more '?' parameter - * placeholders. Typically this statement is a JDBC function call - * escape string. - * @return a new CallableStatement object containing the pre-compiled - * SQL statement - * @exception SQLException if a database access error occurs - */ - public java.sql.CallableStatement prepareCall(String sql) throws SQLException - { - return prepareCall(sql, java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_READ_ONLY); - } - - public java.sql.CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException - { - CallableStatement s = new CallableStatement(this,sql); - s.setResultSetType(resultSetType); - s.setResultSetConcurrency(resultSetConcurrency); - return s; - } - - /* - * Tests to see if a Connection is closed. - * - * Peter Feb 7 2000: Now I've discovered that this doesn't actually obey the - * specifications. Under JDBC2.1, this should only be valid _after_ close() - * has been called. It's result is not guraranteed to be valid before, and - * client code should not use it to see if a connection is open. The spec says - * that the client should monitor the SQLExceptions thrown when their queries - * fail because the connection is dead. - * - * I don't like this definition. As it doesn't hurt breaking it here, our - * isClosed() implementation does test the connection, so for PostgreSQL, you - * can rely on isClosed() returning a valid result. - * - * @return the status of the connection - * @exception SQLException (why?) - */ - public boolean isClosed() throws SQLException - { - // If the stream is gone, then close() was called - if (pg_stream == null) - return true; - return false; - } - - /* - * A connection's database is able to provide information describing - * its tables, its supported SQL grammar, its stored procedures, the - * capabilities of this connection, etc. This information is made - * available through a DatabaseMetaData object. - * - * @return a DatabaseMetaData object for this connection - * @exception SQLException if a database access error occurs - */ - public java.sql.DatabaseMetaData getMetaData() throws SQLException - { - if (metadata == null) - metadata = new DatabaseMetaData(this); - return metadata; - } - - /* - * This overides the method in org.postgresql.Connection and returns a - * ResultSet. - */ - public java.sql.ResultSet getResultSet(org.postgresql.Connection conn, java.sql.Statement stat, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException - { - // In 7.1 we now test concurrency to see which class to return. If we are not working with a - // Statement then default to a normal ResultSet object. - if (stat != null) - { - if (stat.getResultSetConcurrency() == java.sql.ResultSet.CONCUR_UPDATABLE) - return new org.postgresql.jdbc2.UpdateableResultSet((org.postgresql.jdbc2.Connection)conn, fields, tuples, status, updateCount, insertOID, binaryCursor); - } - - return new org.postgresql.jdbc2.ResultSet((org.postgresql.jdbc2.Connection)conn, fields, tuples, status, updateCount, insertOID, binaryCursor); - } - - // ***************** - // JDBC 2 extensions - // ***************** - - public java.util.Map getTypeMap() throws SQLException - { - // new in 7.1 - return typemap; - } - - - public void setTypeMap(java.util.Map map) throws SQLException - { - // new in 7.1 - typemap = map; - } - - /* - * This overides the standard internal getObject method so that we can - * check the jdbc2 type map first - * - * @return PGobject for this type, and set to value - * @exception SQLException if value is not correct for this type - * @see org.postgresql.util.Serialize - */ - public Object getObject(String type, String value) throws SQLException - { - if (typemap != null) - { - SQLData d = (SQLData) typemap.get(type); - if (d != null) - { - // Handle the type (requires SQLInput & SQLOutput classes to be implemented) - throw org.postgresql.Driver.notImplemented(); - } - } - - // Default to the original method - return super.getObject(type, value); - } - - /* An implementation of the abstract method in the parent class. - * This implemetation uses the jdbc2Types array to support the jdbc2 - * datatypes. Basically jdbc1 and jdbc2 are the same, except that - * jdbc2 adds the Array types. - */ - public int getSQLType(String pgTypeName) - { - int sqlType = Types.OTHER; // default value - for (int i = 0;i < jdbc2Types.length;i++) - { - if (pgTypeName.equals(jdbc2Types[i])) - { - sqlType = jdbc2Typei[i]; - break; - } - } - return sqlType; - } - - /* - * This table holds the org.postgresql names for the types supported. - * Any types that map to Types.OTHER (eg POINT) don't go into this table. - * They default automatically to Types.OTHER - * - * Note: This must be in the same order as below. - * - * Tip: keep these grouped together by the Types. value - */ - private static final String jdbc2Types[] = { - "int2", - "int4", "oid", - "int8", - "cash", "money", - "numeric", - "float4", - "float8", - "bpchar", "char", "char2", "char4", "char8", "char16", - "varchar", "text", "name", "filename", - "bytea", - "bool", - "date", - "time", - "abstime", "timestamp", "timestamptz", - "_bool", "_char", "_int2", "_int4", "_text", - "_oid", "_varchar", "_int8", "_float4", "_float8", - "_abstime", "_date", "_time", "_timestamp", "_numeric", - "_bytea" - }; - - /* - * This table holds the JDBC type for each entry above. - * - * Note: This must be in the same order as above - * - * Tip: keep these grouped together by the Types. value - */ - private static final int jdbc2Typei[] = { - Types.SMALLINT, - Types.INTEGER, Types.INTEGER, - Types.BIGINT, - Types.DOUBLE, Types.DOUBLE, - Types.NUMERIC, - Types.REAL, - Types.DOUBLE, - Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, - Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, - Types.BINARY, - Types.BIT, - Types.DATE, - Types.TIME, - Types.TIMESTAMP, Types.TIMESTAMP, Types.TIMESTAMP, - Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, - Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, - Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, - Types.ARRAY - }; - - //Because the get/setLogStream methods are deprecated in JDBC2 - //we use the get/setLogWriter methods here for JDBC2 by overriding - //the base version of this method - protected void enableDriverManagerLogging() { - if (DriverManager.getLogWriter() == null) { - DriverManager.setLogWriter(new PrintWriter(System.out)); - } - } - -} - -// *********************************************************************** - diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/DatabaseMetaData.java b/src/interfaces/jdbc/org/postgresql/jdbc2/DatabaseMetaData.java index 3cc224e6e8..77415d051d 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc2/DatabaseMetaData.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/DatabaseMetaData.java @@ -15,7 +15,7 @@ import org.postgresql.util.PSQLException; /* * This class provides information about the database as a whole. * - * $Id: DatabaseMetaData.java,v 1.58 2002/07/12 13:07:48 davec Exp $ + * $Id: DatabaseMetaData.java,v 1.59 2002/07/23 03:59:55 barry Exp $ * * <p>Many of the methods here return lists of information in ResultSets. You * can use the normal ResultSet methods such as getString and getInt to @@ -39,7 +39,7 @@ import org.postgresql.util.PSQLException; */ public class DatabaseMetaData implements java.sql.DatabaseMetaData { - Connection connection; // The connection association + Jdbc2Connection connection; // The connection association // These define various OID's. Hopefully they will stay constant. static final int iVarcharOid = 1043; // OID for varchar @@ -48,7 +48,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData static final int iInt4Oid = 23; // OID for int4 static final int VARHDRSZ = 4; // length for int4 - public DatabaseMetaData(Connection conn) + public DatabaseMetaData(Jdbc2Connection conn) { this.connection = conn; } @@ -1653,7 +1653,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData v.addElement(tuple); } - return new ResultSet(connection, f, v, "OK", 1); + return new Jdbc2ResultSet(connection, f, v, "OK", 1); } /* @@ -1731,7 +1731,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData // add query loop here - return new ResultSet(connection, f, v, "OK", 1); + return new Jdbc2ResultSet(connection, f, v, "OK", 1); } /* @@ -1825,7 +1825,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData byte remarks[] = null; - if (((org.postgresql.ResultSet)dr).getTupleCount() == 1) + if (((AbstractJdbc2ResultSet)dr).getTupleCount() == 1) { dr.next(); remarks = dr.getBytes(1); @@ -1866,7 +1866,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData v.addElement(tuple); } r.close(); - return new ResultSet(connection, f, v, "OK", 1); + return new Jdbc2ResultSet(connection, f, v, "OK", 1); } // This array contains the valid values for the types argument @@ -1913,7 +1913,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData f[0] = new Field(connection, "TABLE_SCHEM", iVarcharOid, 32); tuple[0] = "".getBytes(); v.addElement(tuple); - return new ResultSet(connection, f, v, "OK", 1); + return new Jdbc2ResultSet(connection, f, v, "OK", 1); } /* @@ -1958,7 +1958,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData tuple[0] = getTableTypes[i][0].getBytes(); v.addElement(tuple); } - return new ResultSet(connection, f, v, "OK", 1); + return new Jdbc2ResultSet(connection, f, v, "OK", 1); } /* @@ -2154,7 +2154,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData } r.close(); - return new ResultSet(connection, f, v, "OK", 1); + return new Jdbc2ResultSet(connection, f, v, "OK", 1); } /* @@ -2218,7 +2218,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData //v.addElement(tuple); } - return new ResultSet(connection, f, v, "OK", 1); + return new Jdbc2ResultSet(connection, f, v, "OK", 1); } /* @@ -2281,7 +2281,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData //v.addElement(tuple); } - return new ResultSet(connection, f, v, "OK", 1); + return new Jdbc2ResultSet(connection, f, v, "OK", 1); } /* @@ -2337,7 +2337,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData f[6] = new Field(connection, "DECIMAL_DIGITS", iInt2Oid, 2); f[7] = new Field(connection, "PSEUDO_COLUMN", iInt2Oid, 2); - return new ResultSet(connection, f, v, "OK", 1); + return new Jdbc2ResultSet(connection, f, v, "OK", 1); } /* @@ -2680,7 +2680,7 @@ WHERE tuples.addElement(tuple); } - return new ResultSet(connection, f, tuples, "OK", 1); + return new Jdbc2ResultSet(connection, f, tuples, "OK", 1); } /* @@ -2959,7 +2959,7 @@ WHERE v.addElement(tuple); } rs.close(); - return new ResultSet(connection, f, v, "OK", 1); + return new Jdbc2ResultSet(connection, f, v, "OK", 1); } throw new PSQLException("postgresql.metadata.unavailable"); @@ -3097,7 +3097,7 @@ WHERE } } - return new ResultSet(connection, f, v, "OK", 1); + return new Jdbc2ResultSet(connection, f, v, "OK", 1); } diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Connection.java b/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Connection.java new file mode 100644 index 0000000000..cfbb3486ec --- /dev/null +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Connection.java @@ -0,0 +1,62 @@ +package org.postgresql.jdbc2; + + +import java.sql.*; +import java.util.Vector; +import org.postgresql.Field; + +/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/Jdbc2Connection.java,v 1.1 2002/07/23 03:59:55 barry Exp $ + * This class implements the java.sql.Connection interface for JDBC2. + * However most of the implementation is really done in + * org.postgresql.jdbc2.AbstractJdbc2Connection or one of it's parents + */ +public class Jdbc2Connection extends org.postgresql.jdbc2.AbstractJdbc2Connection implements java.sql.Connection +{ + + public java.sql.Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException + { + Jdbc2Statement s = new Jdbc2Statement(this); + s.setResultSetType(resultSetType); + s.setResultSetConcurrency(resultSetConcurrency); + return s; + } + + + public java.sql.PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException + { + org.postgresql.jdbc2.PreparedStatement s = new org.postgresql.jdbc2.PreparedStatement(this, sql); + s.setResultSetType(resultSetType); + s.setResultSetConcurrency(resultSetConcurrency); + return s; + } + + public java.sql.CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException + { + org.postgresql.jdbc2.CallableStatement s = new org.postgresql.jdbc2.CallableStatement(this,sql); + s.setResultSetType(resultSetType); + s.setResultSetConcurrency(resultSetConcurrency); + return s; + } + + public java.sql.DatabaseMetaData getMetaData() throws SQLException + { + if (metadata == null) + metadata = new org.postgresql.jdbc2.DatabaseMetaData(this); + return metadata; + } + + public java.sql.ResultSet getResultSet(java.sql.Statement stat, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException + { + if (stat != null) + { + if (stat.getResultSetConcurrency() == java.sql.ResultSet.CONCUR_UPDATABLE) + return new org.postgresql.jdbc2.UpdateableResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor); + } + + return new Jdbc2ResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor); + } + + +} + + diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2ResultSet.java b/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2ResultSet.java new file mode 100644 index 0000000000..7200cf549a --- /dev/null +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2ResultSet.java @@ -0,0 +1,32 @@ +package org.postgresql.jdbc2; + + +import java.sql.*; +import java.util.Vector; +import org.postgresql.Field; + +/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/Jdbc2ResultSet.java,v 1.1 2002/07/23 03:59:55 barry Exp $ + * This class implements the java.sql.ResultSet interface for JDBC2. + * However most of the implementation is really done in + * org.postgresql.jdbc2.AbstractJdbc2ResultSet or one of it's parents + */ +public class Jdbc2ResultSet extends org.postgresql.jdbc2.AbstractJdbc2ResultSet implements java.sql.ResultSet +{ + + public Jdbc2ResultSet(Jdbc2Connection conn, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) + { + super(conn, fields, tuples, status, updateCount, insertOID, binaryCursor); + } + + public Jdbc2ResultSet(Jdbc2Connection conn, Field[] fields, Vector tuples, String status, int updateCount) + { + super(conn, fields, tuples, status, updateCount, 0, false); + } + + public java.sql.ResultSetMetaData getMetaData() throws SQLException + { + return new ResultSetMetaData(rows, fields); + } + +} + diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Statement.java b/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Statement.java new file mode 100644 index 0000000000..31cec93821 --- /dev/null +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Statement.java @@ -0,0 +1,21 @@ +package org.postgresql.jdbc2; + + +import java.sql.*; + +/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/Jdbc2Statement.java,v 1.1 2002/07/23 03:59:55 barry Exp $ + * This class implements the java.sql.Statement interface for JDBC2. + * However most of the implementation is really done in + * org.postgresql.jdbc2.AbstractJdbc2Statement or one of it's parents + */ +public class Jdbc2Statement extends org.postgresql.jdbc2.AbstractJdbc2Statement implements java.sql.Statement +{ + + public Jdbc2Statement (Jdbc2Connection c) + { + connection = c; + resultsettype = java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE; + concurrency = java.sql.ResultSet.CONCUR_READ_ONLY; + } + +} diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/PreparedStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc2/PreparedStatement.java index 5638a2692d..21aba8d9ee 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc2/PreparedStatement.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/PreparedStatement.java @@ -29,12 +29,12 @@ import org.postgresql.util.*; * @see ResultSet * @see java.sql.PreparedStatement */ -public class PreparedStatement extends Statement implements java.sql.PreparedStatement +public class PreparedStatement extends Jdbc2Statement implements java.sql.PreparedStatement { String sql; String[] templateStrings; String[] inStrings; - Connection connection; + Jdbc2Connection connection; // Some performance caches private StringBuffer sbuf = new StringBuffer(); @@ -49,7 +49,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta * @param sql the SQL statement with ? for IN markers * @exception SQLException if something bad occurs */ - public PreparedStatement(Connection connection, String sql) throws SQLException + public PreparedStatement(Jdbc2Connection connection, String sql) throws SQLException { super(connection); diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/ResultSet.java b/src/interfaces/jdbc/org/postgresql/jdbc2/ResultSet.java deleted file mode 100644 index f5489f4e97..0000000000 --- a/src/interfaces/jdbc/org/postgresql/jdbc2/ResultSet.java +++ /dev/null @@ -1,1802 +0,0 @@ -package org.postgresql.jdbc2; - -// IMPORTANT NOTE: This file implements the JDBC 2 version of the driver. -// If you make any modifications to this file, you must make sure that the -// changes are also made (if relevent) to the related JDBC 1 class in the -// org.postgresql.jdbc1 package. - -import java.lang.*; -import java.io.*; -import java.math.*; -import java.text.*; -import java.util.*; -import java.sql.*; -import org.postgresql.Field; -import org.postgresql.largeobject.*; -import org.postgresql.util.*; -import org.postgresql.core.Encoding; - -/* - * 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. - * - * <P>A ResultSet maintains a cursor pointing to its current row of data. - * Initially the cursor is positioned before the first row. The 'next' - * method moves the cursor to the next row. - * - * <P>The getXXX methods retrieve column values for the current row. You can - * retrieve values either using the index number of the column, or by using - * the name of the column. In general using the column index will be more - * efficient. Columns are numbered from 1. - * - * <P>For maximum portability, ResultSet columns within each row should be read - * in left-to-right order and each column should be read only once. - * - *<P> For the getXXX methods, the JDBC driver attempts to convert the - * underlying data to the specified Java type and returns a suitable Java - * value. See the JDBC specification for allowable mappings from SQL types - * to Java types with the ResultSet getXXX methods. - * - * <P>Column names used as input to getXXX methods are case insenstive. When - * performing a getXXX using a column name, if several columns have the same - * name, then the value of the first matching column will be returned. The - * column name option is designed to be used when column names are used in the - * SQL Query. For columns that are NOT explicitly named in the query, it is - * best to use column numbers. If column names were used there is no way for - * the programmer to guarentee that they actually refer to the intended - * columns. - * - * <P>A ResultSet is automatically closed by 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. - * - * <P>The number, types and properties of a ResultSet's columns are provided by - * the ResultSetMetaData object returned by the getMetaData method. - * - * @see ResultSetMetaData - * @see java.sql.ResultSet - */ -public class ResultSet extends org.postgresql.ResultSet implements java.sql.ResultSet -{ - protected org.postgresql.jdbc2.Statement statement; - - private StringBuffer sbuf = null; - protected byte[][] rowBuffer=null; - protected String sqlQuery=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, long insertOID, boolean binaryCursor) - { - super(conn, fields, tuples, status, updateCount, insertOID, binaryCursor); - } - - /* - * 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) - { - super(conn, fields, tuples, status, updateCount, 0, false); - } - - /* - * 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. - * - * <p>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 (rows == null) - throw new PSQLException("postgresql.con.closed"); - - - if (++current_row >= rows.size()) - return false; - - this_row = (byte [][])rows.elementAt(current_row); - - rowBuffer=new byte[this_row.length][]; - System.arraycopy(this_row,0,rowBuffer,0,this_row.length); - 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. - * - * <p><B>Note:</B> A ResultSet is automatically closed by the Statement - * the Statement that generated it when that Statement is closed, - * re-executed, or is used to retrieve the next result from a sequence - * of multiple results. A ResultSet is also automatically closed - * when it is garbage collected. - * - * @exception SQLException if a database access error occurs - */ - public void close() throws SQLException - { - //release resources held (memory for tuples) - if (rows != null) - { - rows = null; - } - } - - /* - * 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 - { - checkResultSet( columnIndex ); - wasNullFlag = (this_row[columnIndex - 1] == null); - if (wasNullFlag) - return null; - - Encoding encoding = connection.getEncoding(); - return encoding.decode(this_row[columnIndex - 1]); - } - - /* - * 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 - { - return toBoolean( getString(columnIndex) ); - } - - /* - * 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 PSQLException("postgresql.res.badbyte", 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 = getFixedString(columnIndex); - - if (s != null) - { - try - { - return Short.parseShort(s); - } - catch (NumberFormatException e) - { - throw new PSQLException("postgresql.res.badshort", 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 - { - return toInt( getFixedString(columnIndex) ); - } - - /* - * 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 - { - return toLong( getFixedString(columnIndex) ); - } - - /* - * 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 - { - return toFloat( getFixedString(columnIndex) ); - } - - /* - * 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 - { - return toDouble( getFixedString(columnIndex) ); - } - - /* - * Get the value of a column in the current row as a - * java.math.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 - * @deprecated - */ - public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException - { - return toBigDecimal( getFixedString(columnIndex), scale ); - } - - /* - * Get the value of a column in the current row as a Java byte array. - * - * <p>In normal use, the bytes represent the raw values returned by the - * backend. However, if the column is an OID, then it is assumed to - * refer to a Large Object, and that object is returned as a byte array. - * - * <p><b>Be warned</b> If the large object is huge, then you may run out - * of memory. - * - * @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 - { - checkResultSet( columnIndex ); - wasNullFlag = (this_row[columnIndex - 1] == null); - if (!wasNullFlag) - { - if (binaryCursor) - { - //If the data is already binary then just return it - return this_row[columnIndex - 1]; - } - else if (connection.haveMinimumCompatibleVersion("7.2")) - { - //Version 7.2 supports the bytea datatype for byte arrays - if (fields[columnIndex - 1].getPGType().equals("bytea")) - { - return PGbytea.toBytes(this_row[columnIndex - 1]); - } - else - { - return this_row[columnIndex - 1]; - } - } - else - { - //Version 7.1 and earlier supports LargeObjects for byte arrays - // Handle OID's as BLOBS - if ( fields[columnIndex - 1].getOID() == 26) - { - LargeObjectManager lom = connection.getLargeObjectAPI(); - LargeObject lob = lom.open(getInt(columnIndex)); - byte buf[] = lob.read(lob.size()); - lob.close(); - return buf; - } - else - { - return this_row[columnIndex - 1]; - } - } - } - return null; - } - - /* - * 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 - { - return toDate( getString(columnIndex) ); - } - - /* - * 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 - { - return toTime( getString(columnIndex), this, fields[columnIndex-1].getPGType() ); - } - - /* - * 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 - { - return toTimestamp( getString(columnIndex), this, fields[columnIndex-1].getPGType() ); - } - - /* - * 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. - * - * <p><B>Note:</B> All the data in the returned stream must be read - * prior to getting the value of any other column. The next call - * to a get method implicitly closes the stream. Also, a stream - * may return 0 for available() whether there is data available - * or not. - * - *<p> 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 - { - checkResultSet( columnIndex ); - wasNullFlag = (this_row[columnIndex - 1] == null); - if (wasNullFlag) - return null; - - if (connection.haveMinimumCompatibleVersion("7.2")) - { - //Version 7.2 supports AsciiStream for all the PG text types - //As the spec/javadoc for this method indicate this is to be used for - //large text values (i.e. LONGVARCHAR) PG doesn't have a separate - //long string datatype, but with toast the text datatype is capable of - //handling very large values. Thus the implementation ends up calling - //getString() since there is no current way to stream the value from the server - try - { - return new ByteArrayInputStream(getString(columnIndex).getBytes("ASCII")); - } - catch (UnsupportedEncodingException l_uee) - { - throw new PSQLException("postgresql.unusual", l_uee); - } - } - else - { - // In 7.1 Handle as BLOBS so return the LargeObject input stream - return getBinaryStream(columnIndex); - } - } - - /* - * A column value can also be retrieved as a stream of Unicode - * characters. We implement this as a binary stream. - * - * ** DEPRECATED IN JDBC 2 ** - * - * @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 - * @deprecated in JDBC2.0 - */ - public InputStream getUnicodeStream(int columnIndex) throws SQLException - { - checkResultSet( columnIndex ); - wasNullFlag = (this_row[columnIndex - 1] == null); - if (wasNullFlag) - return null; - - if (connection.haveMinimumCompatibleVersion("7.2")) - { - //Version 7.2 supports AsciiStream for all the PG text types - //As the spec/javadoc for this method indicate this is to be used for - //large text values (i.e. LONGVARCHAR) PG doesn't have a separate - //long string datatype, but with toast the text datatype is capable of - //handling very large values. Thus the implementation ends up calling - //getString() since there is no current way to stream the value from the server - try - { - return new ByteArrayInputStream(getString(columnIndex).getBytes("UTF-8")); - } - catch (UnsupportedEncodingException l_uee) - { - throw new PSQLException("postgresql.unusual", l_uee); - } - } - else - { - // In 7.1 Handle as BLOBS so return the LargeObject input stream - 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 bytes. 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 - { - checkResultSet( columnIndex ); - wasNullFlag = (this_row[columnIndex - 1] == null); - if (wasNullFlag) - return null; - - if (connection.haveMinimumCompatibleVersion("7.2")) - { - //Version 7.2 supports BinaryStream for all PG bytea type - //As the spec/javadoc for this method indicate this is to be used for - //large binary values (i.e. LONGVARBINARY) PG doesn't have a separate - //long binary datatype, but with toast the bytea datatype is capable of - //handling very large values. Thus the implementation ends up calling - //getBytes() since there is no current way to stream the value from the server - byte b[] = getBytes(columnIndex); - if (b != null) - return new ByteArrayInputStream(b); - } - else - { - // In 7.1 Handle as BLOBS so return the LargeObject input stream - if ( fields[columnIndex - 1].getOID() == 26) - { - LargeObjectManager lom = connection.getLargeObjectAPI(); - LargeObject lob = lom.open(getInt(columnIndex)); - return lob.getInputStream(); - } - } - return 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)); - } - - /* - * @deprecated - */ - 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)); - } - - /* - * - * ** DEPRECATED IN JDBC 2 ** - * - * @deprecated - */ - public InputStream getUnicodeStream(String columnName) throws SQLException - { - return getUnicodeStream(findColumn(columnName)); - } - - public InputStream getBinaryStream(String columnName) throws SQLException - { - return getBinaryStream(findColumn(columnName)); - } - - public java.net.URL getURL(int columnIndex) throws SQLException - { - return null; - } - - public java.net.URL getURL(String columnName) throws SQLException - { - return null; - - } - - public void updateRef(int colIndex,java.sql.Ref ref) throws SQLException { - - } - public void updateRef(String colName,java.sql.Ref ref) throws SQLException { - } - public void updateBlob(int colIndex,java.sql.Blob blob) throws SQLException { - } - public void updateBlob(String colName,java.sql.Blob blob) throws SQLException { - } - public void updateClob(int colIndex,java.sql.Clob clob) throws SQLException { - } - public void updateClob(String colName,java.sql.Clob clob) throws SQLException { - } - public void updateArray(int colIndex,java.sql.Array array) throws SQLException { - } - public void updateArray(String colName,java.sql.Array array) throws SQLException { - } - - /* - * The first warning reported by calls on this ResultSet is - * returned. Subsequent ResultSet warnings will be chained - * to this SQLWarning. - * - * <p>The warning chain is automatically cleared each time a new - * row is read. - * - * <p><B>Note:</B> This warning chain only covers warnings caused by - * ResultSet methods. Any warnings caused by statement methods - * (such as reading OUT parameters) will be chained on the - * Statement object. - * - * @return the first SQLWarning or null; - * @exception SQLException if a database access error occurs. - */ - public SQLWarning getWarnings() throws SQLException - { - return warnings; - } - - /* - * After this call, getWarnings returns null until a new warning - * is reported for this ResultSet - * - * @exception SQLException if a database access error occurs - */ - public void clearWarnings() throws SQLException - { - warnings = null; - } - - /* - * Get the name of the SQL cursor used by this ResultSet - * - * <p>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. - * - * <p>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. - * - * <p><B>Note:</B> If positioned update is not supported, a SQLException - * is thrown. - * - * @return the ResultSet's SQL cursor name. - * @exception SQLException if a database access error occurs - */ - public String getCursorName() throws SQLException - { - return connection.getCursorName(); - } - - /* - * The numbers, types and properties of a ResultSet's columns are - * provided by the getMetaData method - * - * @return a description of the ResultSet's columns - * @exception SQLException if a database access error occurs - */ - public java.sql.ResultSetMetaData getMetaData() throws SQLException - { - return new ResultSetMetaData(rows, fields); - } - - /* - * Get the value of a column in the current row as a Java object - * - * <p>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. - * - * <p>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; - - checkResultSet( columnIndex ); - - wasNullFlag = (this_row[columnIndex - 1] == null); - if (wasNullFlag) - return null; - - field = fields[columnIndex - 1]; - - // some fields can be null, mainly from those returned by MetaData methods - if (field == null) - { - wasNullFlag = true; - return null; - } - - switch (field.getSQLType()) - { - case Types.BIT: - return getBoolean(columnIndex) ? Boolean.TRUE : Boolean.FALSE; - case Types.SMALLINT: - return new Short(getShort(columnIndex)); - case Types.INTEGER: - return new Integer(getInt(columnIndex)); - case Types.BIGINT: - return new Long(getLong(columnIndex)); - case Types.NUMERIC: - return getBigDecimal - (columnIndex, (field.getMod() == -1) ? -1 : ((field.getMod() - 4) & 0xffff)); - 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); - case Types.BINARY: - case Types.VARBINARY: - return getBytes(columnIndex); - case Types.ARRAY: - return getArray(columnIndex); - default: - String type = field.getPGType(); - // if the backend doesn't know the type then coerce to String - if (type.equals("unknown")) - { - return getString(columnIndex); - } - else - { - return connection.getObject(field.getPGType(), getString(columnIndex)); - } - } - } - - /* - * Get the value of a column in the current row as a Java object - * - *<p> 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. - * - * <p>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; - - final int flen = fields.length; - for (i = 0 ; i < flen; ++i) - if (fields[i].getName().equalsIgnoreCase(columnName)) - return (i + 1); - throw new PSQLException ("postgresql.res.colname", columnName); - } - - // ** JDBC 2 Extensions ** - - public boolean absolute(int index) throws SQLException - { - // index is 1-based, but internally we use 0-based indices - int internalIndex; - - if (index == 0) - throw new SQLException("Cannot move to index of 0"); - - final int rows_size = rows.size(); - - //if index<0, count from the end of the result set, but check - //to be sure that it is not beyond the first index - if (index < 0) - { - if (index >= -rows_size) - internalIndex = rows_size + index; - else - { - beforeFirst(); - return false; - } - } - else - { - //must be the case that index>0, - //find the correct place, assuming that - //the index is not too large - if (index <= rows_size) - internalIndex = index - 1; - else - { - afterLast(); - return false; - } - } - - current_row = internalIndex; - this_row = (byte [][])rows.elementAt(internalIndex); - return true; - } - - public void afterLast() throws SQLException - { - final int rows_size = rows.size(); - if (rows_size > 0) - current_row = rows_size; - } - - public void beforeFirst() throws SQLException - { - if (rows.size() > 0) - current_row = -1; - } - - public void cancelRowUpdates() throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public void deleteRow() throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public boolean first() throws SQLException - { - if (rows.size() <= 0) - return false; - - current_row = 0; - this_row = (byte [][])rows.elementAt(current_row); - - rowBuffer=new byte[this_row.length][]; - System.arraycopy(this_row,0,rowBuffer,0,this_row.length); - - return true; - } - - public java.sql.Array getArray(String colName) throws SQLException - { - return getArray(findColumn(colName)); - } - - public java.sql.Array getArray(int i) throws SQLException - { - wasNullFlag = (this_row[i - 1] == null); - if (wasNullFlag) - return null; - - if (i < 1 || i > fields.length) - throw new PSQLException("postgresql.res.colrange"); - return (java.sql.Array) new org.postgresql.jdbc2.Array( connection, i, fields[i - 1], this ); - } - - public java.math.BigDecimal getBigDecimal(int columnIndex) throws SQLException - { - return getBigDecimal(columnIndex, -1); - } - - public java.math.BigDecimal getBigDecimal(String columnName) throws SQLException - { - return getBigDecimal(findColumn(columnName)); - } - - public Blob getBlob(String columnName) throws SQLException - { - return getBlob(findColumn(columnName)); - } - - public Blob getBlob(int i) throws SQLException - { - return new org.postgresql.largeobject.PGblob(connection, getInt(i)); - } - - public java.io.Reader getCharacterStream(String columnName) throws SQLException - { - return getCharacterStream(findColumn(columnName)); - } - - public java.io.Reader getCharacterStream(int i) throws SQLException - { - checkResultSet( i ); - wasNullFlag = (this_row[i - 1] == null); - if (wasNullFlag) - return null; - - if (connection.haveMinimumCompatibleVersion("7.2")) - { - //Version 7.2 supports AsciiStream for all the PG text types - //As the spec/javadoc for this method indicate this is to be used for - //large text values (i.e. LONGVARCHAR) PG doesn't have a separate - //long string datatype, but with toast the text datatype is capable of - //handling very large values. Thus the implementation ends up calling - //getString() since there is no current way to stream the value from the server - return new CharArrayReader(getString(i).toCharArray()); - } - else - { - // In 7.1 Handle as BLOBS so return the LargeObject input stream - Encoding encoding = connection.getEncoding(); - InputStream input = getBinaryStream(i); - return encoding.getDecodingReader(input); - } - } - - /* - * New in 7.1 - */ - public Clob getClob(String columnName) throws SQLException - { - return getClob(findColumn(columnName)); - } - - /* - * New in 7.1 - */ - public Clob getClob(int i) throws SQLException - { - return new org.postgresql.largeobject.PGclob(connection, getInt(i)); - } - - public int getConcurrency() throws SQLException - { - // New in 7.1 - The standard ResultSet class will now return - // CONCUR_READ_ONLY. A sub-class will overide this if the query was - // updateable. - return CONCUR_READ_ONLY; - } - - public java.sql.Date getDate(int i, java.util.Calendar cal) throws SQLException - { - // new in 7.1: If I read the specs, this should use cal only if we don't - // store the timezone, and if we do, then act just like getDate()? - // for now... - return getDate(i); - } - - public Time getTime(int i, java.util.Calendar cal) throws SQLException - { - // new in 7.1: If I read the specs, this should use cal only if we don't - // store the timezone, and if we do, then act just like getTime()? - // for now... - return getTime(i); - } - - public Timestamp getTimestamp(int i, java.util.Calendar cal) throws SQLException - { - // new in 7.1: If I read the specs, this should use cal only if we don't - // store the timezone, and if we do, then act just like getDate()? - // for now... - return getTimestamp(i); - } - - public java.sql.Date getDate(String c, java.util.Calendar cal) throws SQLException - { - return getDate(findColumn(c), cal); - } - - public Time getTime(String c, java.util.Calendar cal) throws SQLException - { - return getTime(findColumn(c), cal); - } - - public Timestamp getTimestamp(String c, java.util.Calendar cal) throws SQLException - { - return getTimestamp(findColumn(c), cal); - } - - public int getFetchDirection() throws SQLException - { - // new in 7.1: PostgreSQL normally sends rows first->last - return FETCH_FORWARD; - } - - public int getFetchSize() throws SQLException - { - // new in 7.1: In this implementation we return the entire result set, so - // here return the number of rows we have. Sub-classes can return a proper - // value - return rows.size(); - } - - public Object getObject(String columnName, java.util.Map map) throws SQLException - { - return getObject(findColumn(columnName), map); - } - - /* - * This checks against map for the type of column i, and if found returns - * an object based on that mapping. The class must implement the SQLData - * interface. - */ - public Object getObject(int i, java.util.Map map) throws SQLException - { - /* In preparation - SQLInput s = new PSQLInput(this,i); - String t = getTypeName(i); - SQLData o = (SQLData) map.get(t); - // If the type is not in the map, then pass to the existing code - if (o==null) - return getObject(i); - o.readSQL(s,t); - return o; - */throw org.postgresql.Driver.notImplemented(); - } - - public Ref getRef(String columnName) throws SQLException - { - return getRef(findColumn(columnName)); - } - - public Ref getRef(int i) throws SQLException - { - // new in 7.1: The backend doesn't yet have SQL3 REF types - throw new PSQLException("postgresql.psqlnotimp"); - } - - public int getRow() throws SQLException - { - final int rows_size = rows.size(); - - if (current_row < 0 || current_row >= rows_size) - return 0; - - return current_row + 1; - } - - // This one needs some thought, as not all ResultSets come from a statement - public java.sql.Statement getStatement() throws SQLException - { - return statement; - } - - public int getType() throws SQLException - { - // New in 7.1. This implementation allows scrolling but is not able to - // see any changes. Sub-classes may overide this to return a more - // meaningful result. - return TYPE_SCROLL_INSENSITIVE; - } - - public void insertRow() throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public boolean isAfterLast() throws SQLException - { - final int rows_size = rows.size(); - return (current_row >= rows_size && rows_size > 0); - } - - public boolean isBeforeFirst() throws SQLException - { - return (current_row < 0 && rows.size() > 0); - } - - public boolean isFirst() throws SQLException - { - return (current_row == 0 && rows.size() >= 0); - } - - public boolean isLast() throws SQLException - { - final int rows_size = rows.size(); - return (current_row == rows_size - 1 && rows_size > 0); - } - - public boolean last() throws SQLException - { - final int rows_size = rows.size(); - if (rows_size <= 0) - return false; - - current_row = rows_size - 1; - this_row = (byte [][])rows.elementAt(current_row); - - rowBuffer=new byte[this_row.length][]; - System.arraycopy(this_row,0,rowBuffer,0,this_row.length); - - return true; - } - - public void moveToCurrentRow() throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public void moveToInsertRow() throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public boolean previous() throws SQLException - { - if (--current_row < 0) - return false; - this_row = (byte [][])rows.elementAt(current_row); - System.arraycopy(this_row,0,rowBuffer,0,this_row.length); - return true; - } - - public void refreshRow() throws SQLException - { - throw new PSQLException("postgresql.notsensitive"); - } - - // Peter: Implemented in 7.0 - public boolean relative(int rows) throws SQLException - { - //have to add 1 since absolute expects a 1-based index - return absolute(current_row + 1 + rows); - } - - public boolean rowDeleted() throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - return false; // javac complains about not returning a value! - } - - public boolean rowInserted() throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - return false; // javac complains about not returning a value! - } - - public boolean rowUpdated() throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - return false; // javac complains about not returning a value! - } - - public void setFetchDirection(int direction) throws SQLException - { - // In 7.1, the backend doesn't yet support this - throw new PSQLException("postgresql.psqlnotimp"); - } - - public void setFetchSize(int rows) throws SQLException - { - // Sub-classes should implement this as part of their cursor support - throw org.postgresql.Driver.notImplemented(); - } - - public void updateAsciiStream(int columnIndex, - java.io.InputStream x, - int length - ) throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public void updateAsciiStream(String columnName, - java.io.InputStream x, - int length - ) throws SQLException - { - updateAsciiStream(findColumn(columnName), x, length); - } - - public void updateBigDecimal(int columnIndex, - java.math.BigDecimal x - ) throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public void updateBigDecimal(String columnName, - java.math.BigDecimal x - ) throws SQLException - { - updateBigDecimal(findColumn(columnName), x); - } - - public void updateBinaryStream(int columnIndex, - java.io.InputStream x, - int length - ) throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public void updateBinaryStream(String columnName, - java.io.InputStream x, - int length - ) throws SQLException - { - updateBinaryStream(findColumn(columnName), x, length); - } - - public void updateBoolean(int columnIndex, boolean x) throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public void updateBoolean(String columnName, boolean x) throws SQLException - { - updateBoolean(findColumn(columnName), x); - } - - public void updateByte(int columnIndex, byte x) throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public void updateByte(String columnName, byte x) throws SQLException - { - updateByte(findColumn(columnName), x); - } - - public void updateBytes(String columnName, byte[] x) throws SQLException - { - updateBytes(findColumn(columnName), x); - } - - public void updateBytes(int columnIndex, byte[] x) throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public void updateCharacterStream(int columnIndex, - java.io.Reader x, - int length - ) throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public void updateCharacterStream(String columnName, - java.io.Reader x, - int length - ) throws SQLException - { - updateCharacterStream(findColumn(columnName), x, length); - } - - public void updateDate(int columnIndex, java.sql.Date x) throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public void updateDate(String columnName, java.sql.Date x) throws SQLException - { - updateDate(findColumn(columnName), x); - } - - public void updateDouble(int columnIndex, double x) throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public void updateDouble(String columnName, double x) throws SQLException - { - updateDouble(findColumn(columnName), x); - } - - public void updateFloat(int columnIndex, float x) throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public void updateFloat(String columnName, float x) throws SQLException - { - updateFloat(findColumn(columnName), x); - } - - public void updateInt(int columnIndex, int x) throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public void updateInt(String columnName, int x) throws SQLException - { - updateInt(findColumn(columnName), x); - } - - public void updateLong(int columnIndex, long x) throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public void updateLong(String columnName, long x) throws SQLException - { - updateLong(findColumn(columnName), x); - } - - public void updateNull(int columnIndex) throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public void updateNull(String columnName) throws SQLException - { - updateNull(findColumn(columnName)); - } - - public void updateObject(int columnIndex, Object x) throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public void updateObject(String columnName, Object x) throws SQLException - { - updateObject(findColumn(columnName), x); - } - - public void updateObject(int columnIndex, Object x, int scale) throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public void updateObject(String columnName, Object x, int scale) throws SQLException - { - updateObject(findColumn(columnName), x, scale); - } - - public void updateRow() throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public void updateShort(int columnIndex, short x) throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public void updateShort(String columnName, short x) throws SQLException - { - updateShort(findColumn(columnName), x); - } - - public void updateString(int columnIndex, String x) throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public void updateString(String columnName, String x) throws SQLException - { - updateString(findColumn(columnName), x); - } - - public void updateTime(int columnIndex, Time x) throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public void updateTime(String columnName, Time x) throws SQLException - { - updateTime(findColumn(columnName), x); - } - - public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException - { - // only sub-classes implement CONCUR_UPDATEABLE - notUpdateable(); - } - - public void updateTimestamp(String columnName, Timestamp x) throws SQLException - { - updateTimestamp(findColumn(columnName), x); - } - - // helper method. Throws an SQLException when an update is not possible - public void notUpdateable() throws SQLException - { - throw new PSQLException("postgresql.noupdate"); - } - - /* - * This is called by Statement to register itself with this statement. - * It's used currently by getStatement() but may also with the new core - * package. - */ - public void setStatement(org.postgresql.jdbc2.Statement statement) - { - this.statement = statement; - } - - //----------------- Formatting Methods ------------------- - - public static boolean toBoolean(String s) - { - if (s != null) - { - int c = s.charAt(0); - return ((c == 't') || (c == 'T') || (c == '1')); - } - return false; // SQL NULL - } - - public static int toInt(String s) throws SQLException - { - if (s != null) - { - try - { - return Integer.parseInt(s); - } - catch (NumberFormatException e) - { - throw new PSQLException ("postgresql.res.badint", s); - } - } - return 0; // SQL NULL - } - - public static long toLong(String s) throws SQLException - { - if (s != null) - { - try - { - return Long.parseLong(s); - } - catch (NumberFormatException e) - { - throw new PSQLException ("postgresql.res.badlong", s); - } - } - return 0; // SQL NULL - } - - public static BigDecimal toBigDecimal(String s, int scale) throws SQLException - { - BigDecimal val; - if (s != null) - { - try - { - val = new BigDecimal(s); - } - catch (NumberFormatException e) - { - throw new PSQLException ("postgresql.res.badbigdec", s); - } - if (scale == -1) - return val; - try - { - return val.setScale(scale); - } - catch (ArithmeticException e) - { - throw new PSQLException ("postgresql.res.badbigdec", s); - } - } - return null; // SQL NULL - } - - public static float toFloat(String s) throws SQLException - { - if (s != null) - { - try - { - return Float.valueOf(s).floatValue(); - } - catch (NumberFormatException e) - { - throw new PSQLException ("postgresql.res.badfloat", s); - } - } - return 0; // SQL NULL - } - - public static double toDouble(String s) throws SQLException - { - if (s != null) - { - try - { - return Double.valueOf(s).doubleValue(); - } - catch (NumberFormatException e) - { - throw new PSQLException ("postgresql.res.baddouble", s); - } - } - return 0; // SQL NULL - } - - public static java.sql.Date toDate(String s) throws SQLException - { - if (s == null) - return null; - // length == 10: SQL Date - // length > 10: SQL Timestamp, assumes PGDATESTYLE=ISO - try - { - return java.sql.Date.valueOf((s.length() == 10) ? s : s.substring(0, 10)); - } - catch (NumberFormatException e) - { - throw new PSQLException("postgresql.res.baddate", s); - } - } - - public static Time toTime(String s, ResultSet resultSet, String pgDataType) throws SQLException - { - if (s == null) - return null; // SQL NULL - try - { - if (s.length() == 8) { - //value is a time value - return java.sql.Time.valueOf(s); - } else if (s.indexOf(".") == 8) { - //value is a time value with fractional seconds - java.sql.Time l_time = java.sql.Time.valueOf(s.substring(0,8)); - String l_strMillis = s.substring(9); - if (l_strMillis.length() > 3) - l_strMillis = l_strMillis.substring(0,3); - int l_millis = Integer.parseInt(l_strMillis); - if (l_millis < 10) { - l_millis = l_millis * 100; - } else if (l_millis < 100) { - l_millis = l_millis * 10; - } - return new java.sql.Time(l_time.getTime() + l_millis); - } else { - //value is a timestamp - return new java.sql.Time(toTimestamp(s, resultSet, pgDataType).getTime()); - } - } - catch (NumberFormatException e) - { - throw new PSQLException("postgresql.res.badtime", s); - } - } - - /** - * Parse a string and return a timestamp representing its value. - * - * The driver is set to return ISO date formated strings. We modify this - * string from the ISO format to a format that Java can understand. Java - * expects timezone info as 'GMT+09:00' where as ISO gives '+09'. - * Java also expects fractional seconds to 3 places where postgres - * will give, none, 2 or 6 depending on the time and postgres version. - * From version 7.2 postgres returns fractional seconds to 6 places. - * If available, we drop the last 3 digits. - * - * @param s The ISO formated date string to parse. - * @param resultSet The ResultSet this date is part of. - * - * @return null if s is null or a timestamp of the parsed string s. - * - * @throws SQLException if there is a problem parsing s. - **/ - public static Timestamp toTimestamp(String s, ResultSet resultSet, String pgDataType) - throws SQLException - { - if (s == null) - return null; - - // We must be synchronized here incase more theads access the ResultSet - // bad practice but possible. Anyhow this is to protect sbuf and - // SimpleDateFormat objects - synchronized (resultSet) - { - SimpleDateFormat df = null; - if ( org.postgresql.Driver.logDebug ) org.postgresql.Driver.debug("the data from the DB is "+s); - - // If first time, create the buffer, otherwise clear it. - if (resultSet.sbuf == null) - resultSet.sbuf = new StringBuffer(); - else - resultSet.sbuf.setLength(0); - - // Copy s into sbuf for parsing. - resultSet.sbuf.append(s); - int slen = s.length(); - - if (slen > 19) - { - // The len of the ISO string to the second value is 19 chars. If - // greater then 19, there may be tz info and perhaps fractional - // second info which we need to change to java to read it. - - // cut the copy to second value "2001-12-07 16:29:22" - int i = 19; - resultSet.sbuf.setLength(i); - - char c = s.charAt(i++); - if (c == '.') - { - // Found a fractional value. Append up to 3 digits including - // the leading '.' - do - { - if (i < 24) - resultSet.sbuf.append(c); - c = s.charAt(i++); - } while (i < slen && Character.isDigit(c)); - - // If there wasn't at least 3 digits we should add some zeros - // to make up the 3 digits we tell java to expect. - for (int j = i; j < 24; j++) - resultSet.sbuf.append('0'); - } - else - { - // No fractional seconds, lets add some. - resultSet.sbuf.append(".000"); - } - - if (i < slen) - { - // prepend the GMT part and then add the remaining bit of - // the string. - resultSet.sbuf.append(" GMT"); - resultSet.sbuf.append(c); - resultSet.sbuf.append(s.substring(i, slen)); - - // Lastly, if the tz part doesn't specify the :MM part then - // we add ":00" for java. - if (slen - i < 5) - resultSet.sbuf.append(":00"); - - // we'll use this dateformat string to parse the result. - df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS z"); - } - else - { - // Just found fractional seconds but no timezone. - //If timestamptz then we use GMT, else local timezone - if (pgDataType.equals("timestamptz")) { - resultSet.sbuf.append(" GMT"); - df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS z"); - } else { - df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); - } - } - } - else if (slen == 19) - { - // No tz or fractional second info. - //If timestamptz then we use GMT, else local timezone - if (pgDataType.equals("timestamptz")) { - resultSet.sbuf.append(" GMT"); - df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); - } else { - df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - } - } - else - { - // We must just have a date. This case is - // needed if this method is called on a date - // column - df = new SimpleDateFormat("yyyy-MM-dd"); - } - - try - { - // All that's left is to parse the string and return the ts. - if ( org.postgresql.Driver.logDebug ) org.postgresql.Driver.debug( "" + df.parse(resultSet.sbuf.toString()).getTime() ); - - return new Timestamp(df.parse(resultSet.sbuf.toString()).getTime()); - } - catch (ParseException e) - { - throw new PSQLException("postgresql.res.badtimestamp", new Integer(e.getErrorOffset()), s); - } - } - } - - public void setSQLQuery(String sqlQuery) { - this.sqlQuery=sqlQuery; - } -} - diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/Statement.java b/src/interfaces/jdbc/org/postgresql/jdbc2/Statement.java deleted file mode 100644 index a00025ff72..0000000000 --- a/src/interfaces/jdbc/org/postgresql/jdbc2/Statement.java +++ /dev/null @@ -1,381 +0,0 @@ -package org.postgresql.jdbc2; - -// IMPORTANT NOTE: This file implements the JDBC 2 version of the driver. -// If you make any modifications to this file, you must make sure that the -// changes are also made (if relevent) to the related JDBC 1 class in the -// org.postgresql.jdbc1 package. - -import java.sql.*; -import java.util.Vector; -import org.postgresql.util.*; - -/* - * A Statement object is used for executing a static SQL statement and - * obtaining the results produced by it. - * - * <p>Only one ResultSet per Statement can be open at any point in time. - * Therefore, if the reading of one ResultSet is interleaved with the - * reading of another, each must have been generated by different - * Statements. All statement execute methods implicitly close a - * statement's current ResultSet if an open one exists. - * - * @see java.sql.Statement - * @see ResultSet - */ -public class Statement extends org.postgresql.Statement implements java.sql.Statement -{ - private Connection connection; // The connection who created us - private Vector batch = null; - private int resultsettype; // the resultset type to return - private int concurrency; // is it updateable or not? - - /* - * Constructor for a Statement. It simply sets the connection - * that created us. - * - * @param c the Connection instantation that creates us - */ - public Statement (Connection c) - { - connection = c; - resultsettype = java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE; - concurrency = java.sql.ResultSet.CONCUR_READ_ONLY; - } - - /* - * Execute a SQL statement that retruns a single ResultSet - * - * @param sql typically a static SQL SELECT statement - * @return a ResulSet that contains the data produced by the query - * @exception SQLException if a database access error occurs - */ - public java.sql.ResultSet executeQuery(String sql) throws SQLException - { - this.execute(sql); - while (result != null && !((org.postgresql.ResultSet)result).reallyResultSet()) - result = ((org.postgresql.ResultSet)result).getNext(); - if (result == null) - throw new PSQLException("postgresql.stat.noresult"); - return result; - } - - /* - * Execute a SQL INSERT, UPDATE or DELETE statement. In addition - * SQL statements that return nothing such as SQL DDL statements - * can be executed - * - * @param sql a SQL statement - * @return either a row count, or 0 for SQL commands - * @exception SQLException if a database access error occurs - */ - public int executeUpdate(String sql) throws SQLException - { - this.execute(sql); - if (((org.postgresql.ResultSet)result).reallyResultSet()) - throw new PSQLException("postgresql.stat.result"); - return this.getUpdateCount(); - } - - /* - * setCursorName defines the SQL cursor name that will be used by - * subsequent execute methods. This name can then be used in SQL - * positioned update/delete statements to identify the current row - * in the ResultSet generated by this statement. If a database - * doesn't support positioned update/delete, this method is a - * no-op. - * - * <p><B>Note:</B> By definition, positioned update/delete execution - * must be done by a different Statement than the one which - * generated the ResultSet being used for positioning. Also, cursor - * names must be unique within a Connection. - * - * <p>We throw an additional constriction. There can only be one - * cursor active at any one time. - * - * @param name the new cursor name - * @exception SQLException if a database access error occurs - */ - public void setCursorName(String name) throws SQLException - { - connection.setCursorName(name); - } - - /* - * Execute a SQL statement that may return multiple results. We - * don't have to worry about this since we do not support multiple - * ResultSets. You can use getResultSet or getUpdateCount to - * retrieve the result. - * - * @param sql any SQL statement - * @return true if the next result is a ResulSet, false if it is - * an update count or there are no more results - * @exception SQLException if a database access error occurs - */ - public boolean execute(String sql) throws SQLException - { - if (escapeProcessing) - sql = escapeSQL(sql); - - // New in 7.1, if we have a previous resultset then force it to close - // This brings us nearer to compliance, and helps memory management. - // Internal stuff will call ExecSQL directly, bypassing this. - if (result != null) - { - java.sql.ResultSet rs = getResultSet(); - if (rs != null) - rs.close(); - } - - - // New in 7.1, pass Statement so that ExecSQL can customise to it - result = connection.ExecSQL(sql, this); - - // New in 7.1, required for ResultSet.getStatement() to work - ((org.postgresql.jdbc2.ResultSet)result).setStatement(this); - - // Added this so that the Updateable resultset knows the query that gave this - ((org.postgresql.jdbc2.ResultSet)result).setSQLQuery(sql); - - - return (result != null && ((org.postgresql.ResultSet)result).reallyResultSet()); - } - - /* - * getUpdateCount returns the current result as an update count, - * if the result is a ResultSet or there are no more results, -1 - * is returned. It should only be called once per result. - * - * @return the current result as an update count. - * @exception SQLException if a database access error occurs - */ - public int getUpdateCount() throws SQLException - { - if (result == null) - return -1; - if (((org.postgresql.ResultSet)result).reallyResultSet()) - return -1; - return ((org.postgresql.ResultSet)result).getResultCount(); - } - - /* - * getMoreResults moves to a Statement's next result. If it returns - * true, this result is a ResulSet. - * - * @return true if the next ResultSet is valid - * @exception SQLException if a database access error occurs - */ - public boolean getMoreResults() throws SQLException - { - result = ((org.postgresql.ResultSet)result).getNext(); - return (result != null && ((org.postgresql.ResultSet)result).reallyResultSet()); - } - - // ** JDBC 2 Extensions ** - - public void addBatch(String sql) throws SQLException - { - if (batch == null) - batch = new Vector(); - batch.addElement(sql); - } - - public void clearBatch() throws SQLException - { - if (batch != null) - batch.removeAllElements(); - } - - public int[] executeBatch() throws SQLException - { - if (batch == null) - batch = new Vector(); - int size = batch.size(); - int[] result = new int[size]; - int i = 0; - try - { - for (i = 0;i < size;i++) - result[i] = this.executeUpdate((String)batch.elementAt(i)); - } - catch (SQLException e) - { - int[] resultSucceeded = new int[i]; - System.arraycopy(result, 0, resultSucceeded, 0, i); - - PBatchUpdateException updex = - new PBatchUpdateException("postgresql.stat.batch.error", - new Integer(i), batch.elementAt(i), resultSucceeded); - updex.setNextException(e); - - throw updex; - } - finally - { - batch.removeAllElements(); - } - return result; - } - - public void cancel() throws SQLException - { - connection.cancelQuery(); - } - - public java.sql.Connection getConnection() throws SQLException - { - return (java.sql.Connection)connection; - } - - public int getFetchDirection() throws SQLException - { - throw new PSQLException("postgresql.psqlnotimp"); - } - - public int getFetchSize() throws SQLException - { - // This one can only return a valid value when were a cursor? - throw org.postgresql.Driver.notImplemented(); - } - - public int getResultSetConcurrency() throws SQLException - { - // new in 7.1 - return concurrency; - } - - public int getResultSetType() throws SQLException - { - // new in 7.1 - return resultsettype; - } - - public void setFetchDirection(int direction) throws SQLException - { - throw org.postgresql.Driver.notImplemented(); - } - - public void setFetchSize(int rows) throws SQLException - { - throw org.postgresql.Driver.notImplemented(); - } - - /* - * New in 7.1 - */ - public void setResultSetConcurrency(int value) throws SQLException - { - concurrency = value; - } - - /* - * New in 7.1 - */ - public void setResultSetType(int value) throws SQLException - { - resultsettype = value; - } - - // In JDK 1.4 not implemented - /** - * - * @param num - * @return - * @throws SQLException - */ - public boolean getMoreResults(int num) throws SQLException - { - throw org.postgresql.Driver.notImplemented(); - } - - /** - * - * @return - * @throws SQLException - */ - public java.sql.ResultSet getGeneratedKeys() throws SQLException - { - throw org.postgresql.Driver.notImplemented(); - } - - /** - * - * @param a - * @param b - * @return - * @throws SQLException - */ - public int executeUpdate(String a, int b) throws SQLException - { - throw org.postgresql.Driver.notImplemented(); - } - - /** - * - * @param a - * @param b - * @return - * @throws SQLException - */ - public int executeUpdate(String a, int[] b) throws SQLException - { - throw org.postgresql.Driver.notImplemented(); - - } - - public int executeUpdate(String a, String[] b) throws SQLException - { - throw org.postgresql.Driver.notImplemented(); - - } - - /** - * - * @param a - * @param b - * @return - * @throws SQLException - */ - public boolean execute(String a, int b) throws SQLException - { - throw org.postgresql.Driver.notImplemented(); - - } - - /** - * - * @param a - * @param b - * @return - * @throws SQLException - */ - public boolean execute(String a, int[] b) throws SQLException - { - throw org.postgresql.Driver.notImplemented(); - - } - - /** - * - * @param a - * @param b - * @return - * @throws SQLException - */ - public boolean execute(String a, String[] b) throws SQLException - { - throw org.postgresql.Driver.notImplemented(); - - } - - /** - * - * @return - * @throws SQLException - */ - public int getResultSetHoldability() throws SQLException - { - throw org.postgresql.Driver.notImplemented(); - - } - -}
\ No newline at end of file diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/UpdateableResultSet.java b/src/interfaces/jdbc/org/postgresql/jdbc2/UpdateableResultSet.java index 9ff8be4080..6f6f67d839 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc2/UpdateableResultSet.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/UpdateableResultSet.java @@ -1,9 +1,7 @@ package org.postgresql.jdbc2; // IMPORTANT NOTE: This is the begining of supporting updateable ResultSets. -// It is not a working solution (yet)! // -// You will notice here we really do throw org.postgresql.Driver.notImplemented() // This is because here we should be updateable, so any unimplemented methods // must say so. // @@ -27,7 +25,7 @@ import org.postgresql.Driver; * @see ResultSetMetaData * @see java.sql.ResultSet */ -public class UpdateableResultSet extends org.postgresql.jdbc2.ResultSet +public class UpdateableResultSet extends org.postgresql.jdbc2.Jdbc2ResultSet { @@ -118,7 +116,7 @@ public class UpdateableResultSet extends org.postgresql.jdbc2.ResultSet * @param updateCount the number of rows affected by the operation * @param cursor the positioned update/delete cursor name */ - public UpdateableResultSet(Connection conn, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) + public UpdateableResultSet(Jdbc2Connection conn, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) { super(conn, fields, tuples, status, updateCount, insertOID, binaryCursor); } @@ -274,7 +272,7 @@ public class UpdateableResultSet extends org.postgresql.jdbc2.ResultSet { // we have to get the last inserted OID and put it in the resultset - long insertedOID = ((org.postgresql.Statement)insertStatement).getLastOID(); + long insertedOID = ((AbstractJdbc2Statement)insertStatement).getLastOID(); updateValues.put("oid", new Long(insertedOID) ); @@ -670,7 +668,7 @@ public class UpdateableResultSet extends org.postgresql.jdbc2.ResultSet selectStatement.setObject( i, ((PrimaryKey)primaryKeys.get(j)).getValue() ); } - org.postgresql.jdbc2.ResultSet rs = (org.postgresql.jdbc2.ResultSet) selectStatement.executeQuery(); + Jdbc2ResultSet rs = (Jdbc2ResultSet) selectStatement.executeQuery(); if( rs.first() ) { @@ -1274,7 +1272,7 @@ public class UpdateableResultSet extends org.postgresql.jdbc2.ResultSet else { // otherwise go and get the primary keys and create a hashtable of keys - java.sql.ResultSet rs = ((org.postgresql.jdbc2.Connection)connection).getMetaData().getPrimaryKeys("","",tableName); + java.sql.ResultSet rs = ((java.sql.Connection)connection).getMetaData().getPrimaryKeys("","",tableName); for( ; rs.next(); i++ ) |