diff --git a/src/interfaces/jdbc/Makefile b/src/interfaces/jdbc/Makefile index 3b88af4d3c718718aa8a338b4c38aa56c8b3f41e..fc881a34ba2060eda6f14c69aade7a64831c7659 100644 --- a/src/interfaces/jdbc/Makefile +++ b/src/interfaces/jdbc/Makefile @@ -4,7 +4,7 @@ # # Copyright (c) 2001, PostgreSQL Global Development Group # -# $Header: /cvsroot/pgsql/src/interfaces/jdbc/Attic/Makefile,v 1.34 2002/03/05 17:55:23 momjian Exp $ +# $Header: /cvsroot/pgsql/src/interfaces/jdbc/Attic/Makefile,v 1.35 2002/07/23 03:59:54 barry Exp $ # #------------------------------------------------------------------------- @@ -38,5 +38,5 @@ uninstall: clean distclean maintainer-clean: $(ANT) -buildfile $(srcdir)/build.xml clean -check: +check: all $(ANT) -buildfile $(srcdir)/build.xml test diff --git a/src/interfaces/jdbc/build.xml b/src/interfaces/jdbc/build.xml index c8b541d6a66b2f4425d308b47cf979affedf2fc8..278053eeace0d0ea095e228f291c1a73c52539f5 100644 --- a/src/interfaces/jdbc/build.xml +++ b/src/interfaces/jdbc/build.xml @@ -6,7 +6,7 @@ This file now requires Ant 1.4.1. 2002-04-18 - $Header: /cvsroot/pgsql/src/interfaces/jdbc/Attic/build.xml,v 1.24 2002/06/27 04:38:01 barry Exp $ + $Header: /cvsroot/pgsql/src/interfaces/jdbc/Attic/build.xml,v 1.25 2002/07/23 03:59:54 barry Exp $ --> @@ -29,7 +29,7 @@ in the CLASSPATH (ie JDK1.2 or later), and then enterprise if the javax.sql.DataSource class is present. - Important: This must have the following order: jdbc1, jdbc2, enterprise + Important: This must have the following order: jdbc1, jdbc2, jdbc3 --> <target name="check_versions"> <condition property="jdbc1"> @@ -39,22 +39,12 @@ <or> <equals arg1="${ant.java.version}" arg2="1.2"/> <equals arg1="${ant.java.version}" arg2="1.3"/> - <equals arg1="${ant.java.version}" arg2="1.4"/> </or> </condition> <condition property="jdbc3"> <equals arg1="${ant.java.version}" arg2="1.4"/> </condition> - <condition property="datasource"> - <and> - <or> - <equals arg1="${ant.java.version}" arg2="1.2"/> - <equals arg1="${ant.java.version}" arg2="1.3"/> - <equals arg1="${ant.java.version}" arg2="1.4"/> - </or> - <available classname="javax.sql.DataSource"/> - </and> - </condition> + <available property="datasource" classname="javax.sql.DataSource"/> <available property="junit" classname="junit.framework.Test" /> </target> @@ -97,16 +87,17 @@ <exclude name="${package}/jdbc1/**" unless="jdbc1"/> <exclude name="${package}/jdbc2/**" unless="jdbc2"/> + <exclude name="${package}/jdbc3/**" unless="jdbc3"/> - <exclude name="${package}/largeobject/PGblob.java" unless="jdbc2" /> - <exclude name="${package}/largeobject/PGclob.java" unless="jdbc2" /> + <exclude name="${package}/largeobject/PGblob.java" if="jdbc1" /> + <exclude name="${package}/largeobject/PGclob.java" if="jdbc1" /> <exclude name="${package}/PostgresqlDataSource.java" unless="datasource" /> <exclude name="${package}/xa/**" unless="datasource" /> <exclude name="${package}/test/**" unless="junit" /> - <exclude name="${package}/test/jdbc2/**" unless="jdbc2" /> - <exclude name="${package}/test/JDBC2Tests.java" unless="jdbc2" /> + <exclude name="${package}/test/jdbc2/**" if="jdbc1" /> + <exclude name="${package}/test/JDBC2Tests.java" if="jdbc1" /> </javac> </target> @@ -121,10 +112,10 @@ <equals arg1="${jdbc1}" arg2="true"/> </condition> <condition property="edition" value="JDBC2"> - <or> <equals arg1="${jdbc2}" arg2="true"/> - <equals arg1="${jdbc3}" arg2="true"/> <!-- fake it for now --> - </or> + </condition> + <condition property="edition" value="JDBC3"> + <equals arg1="${jdbc3}" arg2="true"/> </condition> <condition property="edition" value="JDBC2 Enterprise"> <and> @@ -134,8 +125,8 @@ </condition> <!-- determine the connection class --> - <property name="connectclass" value="org.postgresql.jdbc1.Connection" /> - <available property="connectclass" value="org.postgresql.jdbc2.Connection" classname="java.lang.ThreadLocal" /> + <property name="connectclass" value="org.postgresql.jdbc1.Jdbc1Connection" /> + <available property="connectclass" value="org.postgresql.jdbc2.Jdbc2Connection" classname="java.lang.ThreadLocal" /> <!-- Some defaults --> <filter token="MAJORVERSION" value="${major}" /> @@ -173,13 +164,13 @@ <javac srcdir="${srcdir}" destdir="${builddir}" debug="${debug}"> <include name="example/**" /> <exclude name="example/corba/**"/> - <exclude name="example/blobtest.java" unless="jdk1.2+"/> + <exclude name="example/blobtest.java" if="jdbc1"/> </javac> </target> <!-- Builds the corba example --> - <target name="corba" if="jdk1.2+"> + <target name="corba" if="jdbc2"> <exec dir="${srcdir}/example/corba" executable="idl2java"> <arg value="stock.idl" /> </exec> @@ -230,8 +221,8 @@ <target name="test" depends="jar" if="junit"> <javac srcdir="${srcdir}" destdir="${builddir}" debug="${debug}"> - <include name="${package}/test/jdbc2/**" if="jdk1.2+" /> - <include name="${package}/test/java2ee/**" if="jdk1.2e+" /> + <include name="${package}/test/jdbc2/**" if="jdbc2" /> + <include name="${package}/test/jdbc2/**" if="jdbc3" /> </javac> <java fork="yes" classname="junit.${junit.ui}.TestRunner" taskname="junit" failonerror="true"> diff --git a/src/interfaces/jdbc/example/ImageViewer.java b/src/interfaces/jdbc/example/ImageViewer.java index f61a8870e7be88c0e336b4bd0ed838bef5806a5b..0401780b5cae23f22a253313ad4c0c42669f26d3 100644 --- a/src/interfaces/jdbc/example/ImageViewer.java +++ b/src/interfaces/jdbc/example/ImageViewer.java @@ -205,7 +205,7 @@ public class ImageViewer implements ItemListener stat = db.createStatement(); // Also, get the LargeObjectManager for this connection - lom = ((org.postgresql.Connection)db).getLargeObjectAPI(); + lom = ((org.postgresql.PGConnection)db).getLargeObjectAPI(); // Now refresh the image selection list refreshList(); @@ -299,7 +299,7 @@ public class ImageViewer implements ItemListener try { // fetch the large object manager - LargeObjectManager lom = ((org.postgresql.Connection)db).getLargeObjectAPI(); + LargeObjectManager lom = ((org.postgresql.PGConnection)db).getLargeObjectAPI(); db.setAutoCommit(false); diff --git a/src/interfaces/jdbc/example/basic.java b/src/interfaces/jdbc/example/basic.java index 9a4469d83a0d92555df9246ce59302818ad0eb14..5f07a56c3f52a423e6905765624f4faa61aaf26c 100644 --- a/src/interfaces/jdbc/example/basic.java +++ b/src/interfaces/jdbc/example/basic.java @@ -6,7 +6,7 @@ import java.text.*; /* * - * $Id: basic.java,v 1.11 2001/11/25 23:26:56 barry Exp $ + * $Id: basic.java,v 1.12 2002/07/23 03:59:54 barry Exp $ * * This example tests the basic components of the JDBC driver, and shows * how even the simplest of queries can be implemented. @@ -87,9 +87,8 @@ public class basic st.executeUpdate("insert into basic values (3,1)"); // This shows how to get the oid of a just inserted row - // updated for 7.1 st.executeUpdate("insert into basic values (4,1)"); - long insertedOID = ((org.postgresql.Statement)st).getLastOID(); + long insertedOID = ((org.postgresql.PGStatement)st).getLastOID(); System.out.println("Inserted row with oid " + insertedOID); // Now change the value of b from 1 to 8 diff --git a/src/interfaces/jdbc/example/blobtest.java b/src/interfaces/jdbc/example/blobtest.java index 271026250dd63ee646675e9d9f84b13e8ea65326..d517d267b75b644fc4de07396993b3b4b727de1a 100644 --- a/src/interfaces/jdbc/example/blobtest.java +++ b/src/interfaces/jdbc/example/blobtest.java @@ -76,7 +76,7 @@ public class blobtest // objects, however the unique methods available to postgresql makes // things a little easier. System.out.println("Gaining access to large object api"); - lobj = ((org.postgresql.Connection)db).getLargeObjectAPI(); + lobj = ((org.postgresql.PGConnection)db).getLargeObjectAPI(); int oid = ownapi_test1(); ownapi_test2(oid); diff --git a/src/interfaces/jdbc/example/threadsafe.java b/src/interfaces/jdbc/example/threadsafe.java index cca7be75beec695d903e8868091c0fe601315100..c35570a4c2a424ef7bc353cdcaa3a507f867e1b8 100644 --- a/src/interfaces/jdbc/example/threadsafe.java +++ b/src/interfaces/jdbc/example/threadsafe.java @@ -301,7 +301,7 @@ public class threadsafe //st = c.createStatement(); // create a blob - lom = ((org.postgresql.Connection)c).getLargeObjectAPI(); + lom = ((org.postgresql.PGConnection)c).getLargeObjectAPI(); oid = lom.create(); System.out.println("Thread 3 has created a blob of oid " + oid); } diff --git a/src/interfaces/jdbc/org/postgresql/Driver.java.in b/src/interfaces/jdbc/org/postgresql/Driver.java.in index c53747902ff90662e4ecc8428c5f977e44a3498d..ecb22c7a0daf2e0341d7f1478b8638a2f02d22f3 100644 --- a/src/interfaces/jdbc/org/postgresql/Driver.java.in +++ b/src/interfaces/jdbc/org/postgresql/Driver.java.in @@ -116,7 +116,7 @@ public class Driver implements java.sql.Driver { if (Driver.logDebug) Driver.debug("connect " + url); - org.postgresql.Connection con = (org.postgresql.Connection)(Class.forName("@JDBCCONNECTCLASS@").newInstance()); + @JDBCCONNECTCLASS@ con = (@JDBCCONNECTCLASS@)(Class.forName("@JDBCCONNECTCLASS@").newInstance()); con.openConnection (host(), port(), props, database(), url, this); return (java.sql.Connection)con; } diff --git a/src/interfaces/jdbc/org/postgresql/Field.java b/src/interfaces/jdbc/org/postgresql/Field.java index 8ab28057ef2850b6c78338de4649779d87e4735b..1dbaa72c0977e0b466be718e27145f041531aeb3 100644 --- a/src/interfaces/jdbc/org/postgresql/Field.java +++ b/src/interfaces/jdbc/org/postgresql/Field.java @@ -17,7 +17,7 @@ public class Field private int mod; // type modifier of this field private String name; // Name of this field - private Connection conn; // Connection Instantation + private org.postgresql.PGConnection conn; // Connection Instantation /* @@ -28,7 +28,7 @@ public class Field * @param oid the OID of the field * @param len the length of the field */ - public Field(Connection conn, String name, int oid, int length, int mod) + public Field(org.postgresql.PGConnection conn, String name, int oid, int length, int mod) { this.conn = conn; this.name = name; @@ -45,7 +45,7 @@ public class Field * @param oid the OID of the field * @param len the length of the field */ - public Field(Connection conn, String name, int oid, int length) + public Field(org.postgresql.PGConnection conn, String name, int oid, int length) { this(conn, name, oid, length, 0); } diff --git a/src/interfaces/jdbc/org/postgresql/PGConnection.java b/src/interfaces/jdbc/org/postgresql/PGConnection.java new file mode 100644 index 0000000000000000000000000000000000000000..c05f31222c57a046b3a678687d7f263913c4a200 --- /dev/null +++ b/src/interfaces/jdbc/org/postgresql/PGConnection.java @@ -0,0 +1,72 @@ +package org.postgresql; + +import java.sql.*; +import java.util.Properties; +import java.util.Vector; +import org.postgresql.core.Encoding; +import org.postgresql.fastpath.Fastpath; +import org.postgresql.largeobject.LargeObjectManager; + +/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/Attic/PGConnection.java,v 1.1 2002/07/23 03:59:55 barry Exp $ + * This interface defines PostgreSQL extentions to the java.sql.Connection interface. + * Any java.sql.Connection object returned by the driver will also implement this + * interface + */ +public interface PGConnection +{ + /* + * Get the character encoding to use for this connection. + */ + public Encoding getEncoding() throws SQLException; + + /* + * This method returns the java.sql.Types type for a postgres datatype name + */ + public int getSQLType(String pgTypeName) throws SQLException; + + /* + * This returns the java.sql.Types type for a postgres datatype OID + */ + public int getSQLType(int oid) throws SQLException; + + /* + * This returns the postgres datatype name from the + * postgres datatype OID + */ + public String getPGType(int oid) throws SQLException; + + /* + * This returns the postgres datatype OID from the + * postgres datatype name + */ + public int getPGType(String typeName) throws SQLException; + + /* + * This returns the LargeObject API for the current connection. + */ + public LargeObjectManager getLargeObjectAPI() throws SQLException; + + /* + * This returns the Fastpath API for the current connection. + */ + public Fastpath getFastpathAPI() throws SQLException; + + /* + * This method is used internally to return an object based around + * org.postgresql's more unique data types. + * + * <p>It uses an internal Hashtable to get the handling class. If the + * type is not supported, then an instance of org.postgresql.util.PGobject + * is returned. + * + * You can use the getValue() or setValue() methods to handle the returned + * object. Custom objects can have their own methods. + * + * @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; + +} + diff --git a/src/interfaces/jdbc/org/postgresql/PGStatement.java b/src/interfaces/jdbc/org/postgresql/PGStatement.java new file mode 100644 index 0000000000000000000000000000000000000000..1295afbe5aa57e6a571c2dae2b22fac954df5b7f --- /dev/null +++ b/src/interfaces/jdbc/org/postgresql/PGStatement.java @@ -0,0 +1,21 @@ +package org.postgresql; + + +import java.sql.*; + +/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/Attic/PGStatement.java,v 1.3 2002/07/23 03:59:55 barry Exp $ + * This interface defines PostgreSQL extentions to the java.sql.Statement interface. + * Any java.sql.Statement object returned by the driver will also implement this + * interface + */ +public interface PGStatement +{ + + /* + * Returns the Last inserted/updated oid. + * @return OID of last insert + * @since 7.3 + */ + public long getLastOID() throws SQLException; + +} diff --git a/src/interfaces/jdbc/org/postgresql/ResultSet.java b/src/interfaces/jdbc/org/postgresql/ResultSet.java deleted file mode 100644 index 6e533eed01086d75d5737edd986990ab32c50c71..0000000000000000000000000000000000000000 --- a/src/interfaces/jdbc/org/postgresql/ResultSet.java +++ /dev/null @@ -1,264 +0,0 @@ -package org.postgresql; - -import java.lang.*; -import java.io.*; -import java.math.*; -import java.text.*; -import java.util.*; -import java.sql.*; -import org.postgresql.largeobject.*; -import org.postgresql.util.*; - -/* - * This class implements the common internal methods used by both JDBC 1 and - * JDBC 2 specifications. - */ -public abstract class ResultSet -{ - protected Vector rows; // The results - protected Field fields[]; // The field descriptions - protected String status; // Status of the result - protected boolean binaryCursor = false; // is the data binary or Strings - protected int updateCount; // How many rows did we get back? - protected long insertOID; // The oid of an inserted row - protected int current_row; // Our pointer to where we are at - protected byte[][] this_row; // the current row result - protected Connection connection; // the connection which we returned from - protected SQLWarning warnings = null; // The warning chain - protected boolean wasNullFlag = false; // the flag for wasNull() - - // We can chain multiple resultSets together - this points to - // next resultSet in the chain. - protected ResultSet next = null; - - /* - * Create a new ResultSet - Note that we create ResultSets to - * represent the results of everything. - * - * @param fields an array of Field objects (basically, the - * ResultSet MetaData) - * @param tuples Vector of the actual data - * @param status the status string returned from the back end - * @param updateCount the number of rows affected by the operation - * @param cursor the positioned update/delete cursor name - */ - public ResultSet(Connection conn, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) - { - this.connection = conn; - this.fields = fields; - this.rows = tuples; - this.status = status; - this.updateCount = updateCount; - this.insertOID = insertOID; - this.this_row = null; - this.current_row = -1; - this.binaryCursor = 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) - { - this(conn, fields, tuples, status, updateCount, 0, false); - } - - /* - * We at times need to know if the resultSet we are working - * with is the result of an UPDATE, DELETE or INSERT (in which - * case, we only have a row count), or of a SELECT operation - * (in which case, we have multiple fields) - this routine - * tells us. - * - * @return true if we have tuples available - */ - public boolean reallyResultSet() - { - return (fields != null); - } - - /* - * Since ResultSets can be chained, we need some method of - * finding the next one in the chain. The method getNext() - * returns the next one in the chain. - * - * @return the next ResultSet, or null if there are none - */ - public java.sql.ResultSet getNext() - { - return (java.sql.ResultSet)next; - } - - /* - * This following method allows us to add a ResultSet object - * to the end of the current chain. - * - * @param r the resultset to add to the end of the chain. - */ - public void append(ResultSet r) - { - if (next == null) - next = r; - else - next.append(r); - } - - /* - * If we are just a place holder for results, we still need - * to get an updateCount. This method returns it. - * - * @return the updateCount - */ - public int getResultCount() - { - return updateCount; - } - - /* - * We also need to provide a couple of auxiliary functions for - * the implementation of the ResultMetaData functions. In - * particular, we need to know the number of rows and the - * number of columns. Rows are also known as Tuples - * - * @return the number of rows - */ - public int getTupleCount() - { - return rows.size(); - } - - /* - * getColumnCount returns the number of columns - * - * @return the number of columns - */ - public int getColumnCount() - { - return fields.length; - } - - /* - * Returns the status message from the backend.<p> - * It is used internally by the driver. - * - * @return the status string from the backend - */ - public String getStatusString() - { - return status; - } - - /* - * returns the OID of a field.<p> - * It is used internally by the driver. - * - * @param field field id - * @return the oid of that field's type - */ - public int getColumnOID(int field) - { - return fields[field -1].getOID(); - } - - /* - * returns the OID of the last inserted row. Deprecated in 7.2 because - * range for OID values is greater than java signed int. - * @deprecated Replaced by getLastOID() in 7.2 - */ - public int getInsertedOID() - { - return (int) getLastOID(); - } - - - /* - * returns the OID of the last inserted row - * @since 7.2 - */ - public long getLastOID() - { - return insertOID; - } - - /* - * This is part of the JDBC API, but is required by org.postgresql.Field - */ - public abstract void close() throws SQLException; - public abstract boolean next() throws SQLException; - public abstract String getString(int i) throws SQLException; - - /* - * This is used to fix get*() methods on Money fields. It should only be - * used by those methods! - * - * It converts ($##.##) to -##.## and $##.## to ##.## - */ - public String getFixedString(int col) throws SQLException - { - String s = getString(col); - - // Handle SQL Null - wasNullFlag = (this_row[col - 1] == null); - if (wasNullFlag) - return null; - - // Handle Money - if (s.charAt(0) == '(') - { - s = "-" + org.postgresql.util.PGtokenizer.removePara(s).substring(1); - } - if (s.charAt(0) == '$') - { - s = s.substring(1); - } - - return s; - } - - /** - * 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; - } - - /** - * Add a warning chain to the current warning chain - * @param warnings warnings to add - */ - public void addWarnings(SQLWarning warnings) { - if ( this.warnings != null ) - this.warnings.setNextWarning(warnings); - else - this.warnings = warnings; - } - protected void checkResultSet( int column ) throws SQLException - { - if ( this_row == null ) throw new PSQLException("postgresql.res.nextrequired"); - if ( column < 1 || column > fields.length ) throw new PSQLException("postgresql.res.colrange" ); - } -} - diff --git a/src/interfaces/jdbc/org/postgresql/core/QueryExecutor.java b/src/interfaces/jdbc/org/postgresql/core/QueryExecutor.java index bfa6af3572380fef41cae2f54c3edc634d73b7ea..40c6a31d7f8a12f286c642f03a92a4ccaefbcf9d 100644 --- a/src/interfaces/jdbc/org/postgresql/core/QueryExecutor.java +++ b/src/interfaces/jdbc/org/postgresql/core/QueryExecutor.java @@ -13,7 +13,7 @@ import org.postgresql.util.PSQLException; * <p>The lifetime of a QueryExecutor object is from sending the query * until the response has been received from the backend. * - * $Id: QueryExecutor.java,v 1.12 2002/03/26 05:52:49 barry Exp $ + * $Id: QueryExecutor.java,v 1.13 2002/07/23 03:59:55 barry Exp $ */ public class QueryExecutor @@ -22,18 +22,18 @@ public class QueryExecutor private final String sql; private final java.sql.Statement statement; private final PG_Stream pg_stream; - private final org.postgresql.Connection connection; + private final org.postgresql.jdbc1.AbstractJdbc1Connection connection; public QueryExecutor(String sql, java.sql.Statement statement, PG_Stream pg_stream, - org.postgresql.Connection connection) + java.sql.Connection connection) throws SQLException { this.sql = sql; this.statement = statement; this.pg_stream = pg_stream; - this.connection = connection; + this.connection = (org.postgresql.jdbc1.AbstractJdbc1Connection)connection; if (statement != null) maxRows = statement.getMaxRows(); @@ -122,7 +122,7 @@ public class QueryExecutor if ( errorMessage != null ) throw new SQLException( errorMessage.toString() ); - return connection.getResultSet(connection, statement, fields, tuples, status, update_count, insert_oid, binaryCursor); + return connection.getResultSet(statement, fields, tuples, status, update_count, insert_oid, binaryCursor); } } diff --git a/src/interfaces/jdbc/org/postgresql/fastpath/Fastpath.java b/src/interfaces/jdbc/org/postgresql/fastpath/Fastpath.java index 20f5a6f3e2610eb39a560524bdb7958e409d454e..d166b10f83b658f48f42801793464ded4efa6660 100644 --- a/src/interfaces/jdbc/org/postgresql/fastpath/Fastpath.java +++ b/src/interfaces/jdbc/org/postgresql/fastpath/Fastpath.java @@ -28,7 +28,7 @@ public class Fastpath // to a connection). protected Hashtable func = new Hashtable(); - protected org.postgresql.Connection conn; // our connection + protected org.postgresql.PGConnection conn; // our connection protected org.postgresql.PG_Stream stream; // the network stream /* @@ -41,7 +41,7 @@ public class Fastpath * @param conn org.postgresql.Connection to attach to * @param stream The network stream to the backend */ - public Fastpath(org.postgresql.Connection conn, org.postgresql.PG_Stream stream) + public Fastpath(org.postgresql.PGConnection conn, org.postgresql.PG_Stream stream) { this.conn = conn; this.stream = stream; @@ -113,7 +113,7 @@ public class Fastpath //------------------------------ // Notice from backend case 'N': - conn.addWarning(stream.ReceiveString(conn.getEncoding())); + ((org.postgresql.jdbc1.AbstractJdbc1Connection)conn).addWarning(stream.ReceiveString(conn.getEncoding())); break; case 'V': diff --git a/src/interfaces/jdbc/org/postgresql/Connection.java b/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Connection.java similarity index 89% rename from src/interfaces/jdbc/org/postgresql/Connection.java rename to src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Connection.java index 7951ddd1ecb1cec5e90c59b14e639e9c7b5e0e69..98aa33e5c916e5fed394c05618fa608314ccf1a3 100644 --- a/src/interfaces/jdbc/org/postgresql/Connection.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Connection.java @@ -1,34 +1,38 @@ -package org.postgresql; +package org.postgresql.jdbc1; -import java.io.*; -import java.net.*; + +import java.io.IOException; +import java.net.ConnectException; import java.sql.*; import java.util.*; import org.postgresql.Driver; -import org.postgresql.Field; -import org.postgresql.fastpath.*; -import org.postgresql.largeobject.*; -import org.postgresql.util.*; +import org.postgresql.PG_Stream; import org.postgresql.core.*; +import org.postgresql.fastpath.Fastpath; +import org.postgresql.largeobject.LargeObjectManager; +import org.postgresql.util.*; + -/* - * $Id: Connection.java,v 1.48 2002/06/11 02:55:15 barry Exp $ - * - * This abstract class is used by org.postgresql.Driver to open either the JDBC1 or - * JDBC2 versions of the Connection class. - * +/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Connection.java,v 1.1 2002/07/23 03:59:55 barry Exp $ + * This class defines methods of the jdbc1 specification. This class is + * extended by org.postgresql.jdbc2.AbstractJdbc2Connection which adds the jdbc2 + * methods. The real Connection class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Connection */ -public abstract class Connection +public abstract class AbstractJdbc1Connection implements org.postgresql.PGConnection { // This is the network stream associated with this connection public PG_Stream pg_stream; - private String PG_HOST; - private int PG_PORT; - private String PG_USER; - private String PG_DATABASE; - private boolean PG_STATUS; - private String compatible; + protected String PG_HOST; + protected int PG_PORT; + protected String PG_USER; + protected String PG_DATABASE; + protected boolean PG_STATUS; + protected String compatible; + + // The PID an cancellation key we get from the backend process + protected int pid; + protected int ckey; /* The encoding to use for this connection. @@ -43,7 +47,7 @@ public abstract class Connection public boolean autoCommit = true; public boolean readOnly = false; - public Driver this_driver; + public org.postgresql.Driver this_driver; private String this_url; private String cursor = null; // The positioned update cursor name @@ -74,50 +78,6 @@ public abstract class Connection */ private int isolationLevel = java.sql.Connection.TRANSACTION_READ_COMMITTED; - // The PID an cancellation key we get from the backend process - public int pid; - public int ckey; - - /* - * This is called by Class.forName() from within org.postgresql.Driver - */ - public Connection() - {} - - public void cancelQuery() throws SQLException - { - PG_Stream cancelStream = null; - try { - cancelStream = new 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 method actually opens the connection. It is called by Driver. * @@ -125,12 +85,11 @@ public abstract class Connection * @param port the port number of the postmaster process * @param info a Properties[] thing of the user and password * @param database the database to connect to - * @param u the URL of the connection + * @param url the URL of the connection * @param d the Driver instantation of the connection - * @return a valid connection profile * @exception SQLException if a database access error occurs */ - protected void openConnection(String host, int port, Properties info, String database, String url, Driver d) throws SQLException + public void openConnection(String host, int port, Properties info, String database, String url, org.postgresql.Driver d) throws SQLException { firstWarning = null; @@ -140,7 +99,7 @@ public abstract class Connection if (info.getProperty("user") == null) throw new PSQLException("postgresql.con.user"); - this_driver = d; + this_driver = (org.postgresql.Driver)d; this_url = url; PG_DATABASE = database; @@ -168,19 +127,19 @@ public abstract class Connection int l_logLevel = 0; try { l_logLevel = Integer.parseInt(l_logLevelProp); - if (l_logLevel > Driver.DEBUG || l_logLevel < Driver.INFO) { + if (l_logLevel > org.postgresql.Driver.DEBUG || l_logLevel < org.postgresql.Driver.INFO) { l_logLevel = 0; } } catch (Exception l_e) { //invalid value for loglevel ignore } if (l_logLevel > 0) { - Driver.setLogLevel(l_logLevel); + org.postgresql.Driver.setLogLevel(l_logLevel); enableDriverManagerLogging(); } //Print out the driver version number - if (Driver.logInfo) Driver.info(Driver.getVersion()); + if (org.postgresql.Driver.logInfo) org.postgresql.Driver.info(org.postgresql.Driver.getVersion()); // Now make the initial connection try @@ -238,7 +197,7 @@ public abstract class Connection rst[0] = (byte)pg_stream.ReceiveChar(); rst[1] = (byte)pg_stream.ReceiveChar(); salt = new String(rst, 0, 2); - if (Driver.logDebug) Driver.debug("Crypt salt=" + salt); + if (org.postgresql.Driver.logDebug) org.postgresql.Driver.debug("Crypt salt=" + salt); } // Or get the md5 password salt if there is one @@ -250,7 +209,7 @@ public abstract class Connection rst[2] = (byte)pg_stream.ReceiveChar(); rst[3] = (byte)pg_stream.ReceiveChar(); salt = new String(rst, 0, 4); - if (Driver.logDebug) Driver.debug("MD5 salt=" + salt); + if (org.postgresql.Driver.logDebug) org.postgresql.Driver.debug("MD5 salt=" + salt); } // now send the auth packet @@ -260,15 +219,15 @@ public abstract class Connection break; case AUTH_REQ_KRB4: - if (Driver.logDebug) Driver.debug("postgresql: KRB4"); + if (org.postgresql.Driver.logDebug) org.postgresql.Driver.debug("postgresql: KRB4"); throw new PSQLException("postgresql.con.kerb4"); case AUTH_REQ_KRB5: - if (Driver.logDebug) Driver.debug("postgresql: KRB5"); + if (org.postgresql.Driver.logDebug) org.postgresql.Driver.debug("postgresql: KRB5"); throw new PSQLException("postgresql.con.kerb5"); case AUTH_REQ_PASSWORD: - if (Driver.logDebug) Driver.debug("postgresql: PASSWORD"); + if (org.postgresql.Driver.logDebug) org.postgresql.Driver.debug("postgresql: PASSWORD"); pg_stream.SendInteger(5 + password.length(), 4); pg_stream.Send(password.getBytes()); pg_stream.SendInteger(0, 1); @@ -276,7 +235,7 @@ public abstract class Connection break; case AUTH_REQ_CRYPT: - if (Driver.logDebug) Driver.debug("postgresql: CRYPT"); + if (org.postgresql.Driver.logDebug) org.postgresql.Driver.debug("postgresql: CRYPT"); String crypted = UnixCrypt.crypt(salt, password); pg_stream.SendInteger(5 + crypted.length(), 4); pg_stream.Send(crypted.getBytes()); @@ -285,7 +244,7 @@ public abstract class Connection break; case AUTH_REQ_MD5: - if (Driver.logDebug) Driver.debug("postgresql: MD5"); + if (org.postgresql.Driver.logDebug) org.postgresql.Driver.debug("postgresql: MD5"); byte[] digest = MD5Digest.encode(PG_USER, password, salt); pg_stream.SendInteger(5 + digest.length, 4); pg_stream.Send(digest); @@ -386,10 +345,23 @@ public abstract class Connection PG_STATUS = CONNECTION_OK; } + + /* + * Return the instance of org.postgresql.Driver + * that created this connection + */ + public org.postgresql.Driver getDriver() + { + return this_driver; + } + // These methods used to be in the main Connection implementation. As they // are common to all implementations (JDBC1 or 2), they are placed here. // This should make it easy to maintain the two specifications. +//BJL TODO this method shouldn't need to take a Connection since this can be used. + public abstract java.sql.ResultSet getResultSet(java.sql.Statement stat, org.postgresql.Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException; + /* * This adds a warning to the warning chain. * @param msg message to add @@ -448,7 +420,7 @@ public abstract class Connection */ public java.sql.ResultSet ExecSQL(String sql, java.sql.Statement stat) throws SQLException { - return new QueryExecutor(sql, stat, pg_stream, this).execute(); + return new QueryExecutor(sql, stat, pg_stream, (java.sql.Connection)this).execute(); } /* @@ -569,7 +541,7 @@ public abstract class Connection public LargeObjectManager getLargeObjectAPI() throws SQLException { if (largeobject == null) - largeobject = new LargeObjectManager(this); + largeobject = new LargeObjectManager((java.sql.Connection)this); return largeobject; } @@ -606,7 +578,7 @@ public abstract class Connection // can handle it if (o == null) { - Serialize ser = new Serialize(this, type); + Serialize ser = new Serialize((java.sql.Connection)this, type); objectTypes.put(type, ser); return ser.fetch(Integer.parseInt(value)); } @@ -679,7 +651,7 @@ public abstract class Connection // can handle it if (x == null) { - Serialize ser = new Serialize(this, type); + Serialize ser = new Serialize((java.sql.Connection)this, type); objectTypes.put(type, ser); return ser.storeObject(o); } @@ -756,15 +728,6 @@ public abstract class Connection objectTypes.put(defaultObjectTypes[i][0], defaultObjectTypes[i][1]); } - // These are required by other common classes - public abstract java.sql.Statement createStatement() throws SQLException; - - /* - * This returns a resultset. It must be overridden, so that the correct - * version (from jdbc1 or jdbc2) are returned. - */ - public abstract 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 some cases, it is desirable to immediately release a Connection's * database and JDBC resources instead of waiting for them to be @@ -1162,8 +1125,8 @@ public abstract class Connection // it's not in the cache, so perform a query, and add the result to the cache if (sqlType == null) { - ResultSet result = (org.postgresql.ResultSet)ExecSQL("select typname from pg_type where oid = " + oid); - if (result.getColumnCount() != 1 || result.getTupleCount() != 1) + ResultSet result = ExecSQL("select typname from pg_type where oid = " + oid); + if (((AbstractJdbc1ResultSet)result).getColumnCount() != 1 || ((AbstractJdbc1ResultSet)result).getTupleCount() != 1) throw new PSQLException("postgresql.unexpected"); result.next(); String pgType = result.getString(1); @@ -1177,20 +1140,12 @@ public abstract class Connection return sqlType.intValue(); } - /* - * This returns the java.sql.Types type for a PG type - * - * @param pgTypeName PostgreSQL type name - * @return the java.sql.Types type - */ - public abstract int getSQLType(String pgTypeName); - /* * This returns the oid for a given PG data type * @param typeName PostgreSQL type name * @return PostgreSQL oid value for a field of this type */ - public int getOID(String typeName) throws SQLException + public int getPGType(String typeName) throws SQLException { int oid = -1; if (typeName != null) @@ -1203,9 +1158,9 @@ public abstract class Connection else { // it's not in the cache, so perform a query, and add the result to the cache - ResultSet result = (org.postgresql.ResultSet)ExecSQL("select oid from pg_type where typname='" + ResultSet result = ExecSQL("select oid from pg_type where typname='" + typeName + "'"); - if (result.getColumnCount() != 1 || result.getTupleCount() != 1) + if (((AbstractJdbc1ResultSet)result).getColumnCount() != 1 || ((AbstractJdbc1ResultSet)result).getTupleCount() != 1) throw new PSQLException("postgresql.unexpected"); result.next(); oid = Integer.parseInt(result.getString(1)); @@ -1242,5 +1197,91 @@ public abstract class Connection } } + // This is a cache of the DatabaseMetaData instance for this connection + protected java.sql.DatabaseMetaData metadata; + + + /* + * Tests to see if a Connection is closed + * + * @return the status of the connection + * @exception SQLException (why?) + */ + public boolean isClosed() throws SQLException + { + return (pg_stream == null); + } + + /* + * This implemetation uses the jdbc1Types array to support the jdbc1 + * 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 < jdbc1Types.length;i++) + { + if (pgTypeName.equals(jdbc1Types[i])) + { + sqlType = jdbc1Typei[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 jdbc1Types[] = { + "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" + }; + + /* + * 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 jdbc1Typei[] = { + 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 + }; + + } + diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java b/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java new file mode 100644 index 0000000000000000000000000000000000000000..5aa4f90298a07ab1153a3fee44934309f686f41e --- /dev/null +++ b/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java @@ -0,0 +1,957 @@ +package org.postgresql.jdbc1; + + +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/jdbc1/Attic/AbstractJdbc1ResultSet.java,v 1.1 2002/07/23 03:59:55 barry Exp $ + * This class defines methods of the jdbc1 specification. This class is + * extended by org.postgresql.jdbc2.AbstractJdbc2ResultSet which adds the jdbc2 + * methods. The real ResultSet class (for jdbc1) is org.postgresql.jdbc1.Jdbc1ResultSet + */ +public abstract class AbstractJdbc1ResultSet +{ + + protected Vector rows; // The results + protected Field fields[]; // The field descriptions + protected String status; // Status of the result + protected boolean binaryCursor = false; // is the data binary or Strings + protected int updateCount; // How many rows did we get back? + protected long insertOID; // The oid of an inserted row + protected int current_row; // Our pointer to where we are at + protected byte[][] this_row; // the current row result + protected org.postgresql.PGConnection connection; // the connection which we returned from + protected SQLWarning warnings = null; // The warning chain + protected boolean wasNullFlag = false; // the flag for wasNull() + + // We can chain multiple resultSets together - this points to + // next resultSet in the chain. + protected ResultSet next = null; + + protected StringBuffer sbuf = null; + public byte[][] rowBuffer=null; + + + public AbstractJdbc1ResultSet(org.postgresql.PGConnection conn, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) + { + this.connection = conn; + this.fields = fields; + this.rows = tuples; + this.status = status; + this.updateCount = updateCount; + this.insertOID = insertOID; + this.this_row = null; + this.current_row = -1; + this.binaryCursor = binaryCursor; + } + + + 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; + } + + public void close() throws SQLException + { + //release resources held (memory for tuples) + if (rows != null) + { + rows = null; + } + } + + public boolean wasNull() throws SQLException + { + return wasNullFlag; + } + + 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]); + } + + public boolean getBoolean(int columnIndex) throws SQLException + { + return toBoolean( getString(columnIndex) ); + } + + + 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 + } + + 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 + } + + public int getInt(int columnIndex) throws SQLException + { + return toInt( getFixedString(columnIndex) ); + } + + public long getLong(int columnIndex) throws SQLException + { + return toLong( getFixedString(columnIndex) ); + } + + public float getFloat(int columnIndex) throws SQLException + { + return toFloat( getFixedString(columnIndex) ); + } + + public double getDouble(int columnIndex) throws SQLException + { + return toDouble( getFixedString(columnIndex) ); + } + + 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 (((AbstractJdbc1Connection)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; + } + + public java.sql.Date getDate(int columnIndex) throws SQLException + { + return toDate( getString(columnIndex) ); + } + + public Time getTime(int columnIndex) throws SQLException + { + return toTime( getString(columnIndex), (java.sql.ResultSet)this, fields[columnIndex-1].getPGType() ); + } + + public Timestamp getTimestamp(int columnIndex) throws SQLException + { + return toTimestamp( getString(columnIndex), (java.sql.ResultSet)this, fields[columnIndex-1].getPGType() ); + } + + public InputStream getAsciiStream(int columnIndex) throws SQLException + { + checkResultSet( columnIndex ); + wasNullFlag = (this_row[columnIndex - 1] == null); + if (wasNullFlag) + return null; + + if (((AbstractJdbc1Connection)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); + } + } + + public InputStream getUnicodeStream(int columnIndex) throws SQLException + { + checkResultSet( columnIndex ); + wasNullFlag = (this_row[columnIndex - 1] == null); + if (wasNullFlag) + return null; + + if (((AbstractJdbc1Connection)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); + } + } + + public InputStream getBinaryStream(int columnIndex) throws SQLException + { + checkResultSet( columnIndex ); + wasNullFlag = (this_row[columnIndex - 1] == null); + if (wasNullFlag) + return null; + + if (((AbstractJdbc1Connection)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; + } + + public String getString(String columnName) throws SQLException + { + return getString(findColumn(columnName)); + } + + public boolean getBoolean(String columnName) throws SQLException + { + return getBoolean(findColumn(columnName)); + } + + public byte getByte(String columnName) throws SQLException + { + + return getByte(findColumn(columnName)); + } + + public short getShort(String columnName) throws SQLException + { + return getShort(findColumn(columnName)); + } + + public int getInt(String columnName) throws SQLException + { + return getInt(findColumn(columnName)); + } + + public long getLong(String columnName) throws SQLException + { + return getLong(findColumn(columnName)); + } + + public float getFloat(String columnName) throws SQLException + { + return getFloat(findColumn(columnName)); + } + + public double getDouble(String columnName) throws SQLException + { + return getDouble(findColumn(columnName)); + } + + public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException + { + return getBigDecimal(findColumn(columnName), scale); + } + + public byte[] getBytes(String columnName) throws SQLException + { + return getBytes(findColumn(columnName)); + } + + public java.sql.Date getDate(String columnName) throws SQLException + { + return getDate(findColumn(columnName)); + } + + public Time getTime(String columnName) throws SQLException + { + return getTime(findColumn(columnName)); + } + + public Timestamp getTimestamp(String columnName) throws SQLException + { + return getTimestamp(findColumn(columnName)); + } + + public InputStream getAsciiStream(String columnName) throws SQLException + { + return getAsciiStream(findColumn(columnName)); + } + + public InputStream getUnicodeStream(String columnName) throws SQLException + { + return getUnicodeStream(findColumn(columnName)); + } + + public InputStream getBinaryStream(String columnName) throws SQLException + { + return getBinaryStream(findColumn(columnName)); + } + + public SQLWarning getWarnings() throws SQLException + { + return warnings; + } + + public void clearWarnings() throws SQLException + { + warnings = null; + } + + public void addWarnings(SQLWarning warnings) { + if ( this.warnings != null ) + this.warnings.setNextWarning(warnings); + else + this.warnings = warnings; + } + + public String getCursorName() throws SQLException + { + return ((AbstractJdbc1Connection)connection).getCursorName(); + } + + /* + * 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; + + if (columnIndex < 1 || columnIndex > fields.length) + throw new PSQLException("postgresql.res.colrange"); + 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); + 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 Object getObject(String columnName) throws SQLException + { + return getObject(findColumn(columnName)); + } + + /* + * Map a ResultSet column name to a ResultSet column index + */ + 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); + } + + + /* + * We at times need to know if the resultSet we are working + * with is the result of an UPDATE, DELETE or INSERT (in which + * case, we only have a row count), or of a SELECT operation + * (in which case, we have multiple fields) - this routine + * tells us. + */ + public boolean reallyResultSet() + { + return (fields != null); + } + + /* + * Since ResultSets can be chained, we need some method of + * finding the next one in the chain. The method getNext() + * returns the next one in the chain. + * + * @return the next ResultSet, or null if there are none + */ + public java.sql.ResultSet getNext() + { + return (java.sql.ResultSet)next; + } + + /* + * This following method allows us to add a ResultSet object + * to the end of the current chain. + */ + public void append(AbstractJdbc1ResultSet r) + { + if (next == null) + next = (java.sql.ResultSet)r; + else + ((AbstractJdbc1ResultSet)next).append(r); + } + + /* + * If we are just a place holder for results, we still need + * to get an updateCount. This method returns it. + */ + public int getResultCount() + { + return updateCount; + } + + /* + * We also need to provide a couple of auxiliary functions for + * the implementation of the ResultMetaData functions. In + * particular, we need to know the number of rows and the + * number of columns. Rows are also known as Tuples + */ + public int getTupleCount() + { + return rows.size(); + } + + /* + * getColumnCount returns the number of columns + */ + public int getColumnCount() + { + return fields.length; + } + + /* + * Returns the status message from the backend.<p> + * It is used internally by the driver. + */ + public String getStatusString() + { + return status; + } + + /* + * returns the OID of a field.<p> + * It is used internally by the driver. + */ + public int getColumnOID(int field) + { + return fields[field -1].getOID(); + } + + /* + * returns the OID of the last inserted row. Deprecated in 7.2 because + * range for OID values is greater than java signed int. + * @deprecated Replaced by getLastOID() in 7.2 + */ + public int getInsertedOID() + { + return (int) getLastOID(); + } + + + /* + * returns the OID of the last inserted row + * @since 7.2 + */ + public long getLastOID() + { + return insertOID; + } + + /* + * This is used to fix get*() methods on Money fields. It should only be + * used by those methods! + * + * It converts ($##.##) to -##.## and $##.## to ##.## + */ + public String getFixedString(int col) throws SQLException + { + String s = getString(col); + + // Handle SQL Null + wasNullFlag = (this_row[col - 1] == null); + if (wasNullFlag) + return null; + + // Handle Money + if (s.charAt(0) == '(') + { + s = "-" + org.postgresql.util.PGtokenizer.removePara(s).substring(1); + } + if (s.charAt(0) == '$') + { + s = s.substring(1); + } + + return s; + } + + protected void checkResultSet( int column ) throws SQLException + { + if ( this_row == null ) throw new PSQLException("postgresql.res.nextrequired"); + if ( column < 1 || column > fields.length ) throw new PSQLException("postgresql.res.colrange" ); + } + + //----------------- 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, java.sql.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, java.sql.ResultSet resultSet, String pgDataType) + throws SQLException + { + AbstractJdbc1ResultSet rs = (AbstractJdbc1ResultSet)resultSet; + 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 (rs) + { + 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 (rs.sbuf == null) + rs.sbuf = new StringBuffer(); + else + rs.sbuf.setLength(0); + + // Copy s into sbuf for parsing. + rs.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; + rs.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) + rs.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++) + rs.sbuf.append('0'); + } + else + { + // No fractional seconds, lets add some. + rs.sbuf.append(".000"); + } + + if (i < slen) + { + // prepend the GMT part and then add the remaining bit of + // the string. + rs.sbuf.append(" GMT"); + rs.sbuf.append(c); + rs.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) + rs.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")) { + rs.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")) { + rs.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(rs.sbuf.toString()).getTime() ); + + return new Timestamp(df.parse(rs.sbuf.toString()).getTime()); + } + catch (ParseException e) + { + throw new PSQLException("postgresql.res.badtimestamp", new Integer(e.getErrorOffset()), s); + } + } + } + + + +} + diff --git a/src/interfaces/jdbc/org/postgresql/Statement.java b/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java similarity index 61% rename from src/interfaces/jdbc/org/postgresql/Statement.java rename to src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java index ea2cc0d0c33094ca88ab5f7d2750e86e41180fdb..9c4d2b1cd9cbfe6105ad1bfac3783dbbca085192 100644 --- a/src/interfaces/jdbc/org/postgresql/Statement.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java @@ -1,24 +1,22 @@ -package org.postgresql; +package org.postgresql.jdbc1; import java.sql.*; import org.postgresql.util.PSQLException; -/* - * This class defines methods implemented by the two subclasses - * org.postgresql.jdbc1.Statement and org.postgresql.jdbc2.Statement that are - * unique to PostgreSQL's JDBC driver. - * +/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.1 2002/07/23 03:59:55 barry Exp $ + * This class defines methods of the jdbc1 specification. This class is + * extended by org.postgresql.jdbc2.AbstractJdbc2Statement which adds the jdbc2 + * methods. The real Statement class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Statement */ - -public abstract class Statement +public abstract class AbstractJdbc1Statement implements org.postgresql.PGStatement { + // The connection who created us + protected AbstractJdbc1Connection connection; + /** The warnings chain. */ protected SQLWarning warnings = null; - /** The current results */ - protected java.sql.ResultSet result = null; - /** Maximum number of rows to return, 0 = unlimited */ protected int maxrows = 0; @@ -27,14 +25,146 @@ public abstract class Statement protected boolean escapeProcessing = true; + /** The current results */ + protected java.sql.ResultSet result = null; + // Static variables for parsing SQL when escapeProcessing is true. private static final short IN_SQLCODE = 0; private static final short IN_STRING = 1; private static final short BACKSLASH = 2; private static final short ESC_TIMEDATE = 3; - public Statement() - {} + /* + * 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 && !((AbstractJdbc1ResultSet)result).reallyResultSet()) + result = ((AbstractJdbc1ResultSet)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 (((AbstractJdbc1ResultSet)result).reallyResultSet()) + throw new PSQLException("postgresql.stat.result"); + return this.getUpdateCount(); + } + + /* + * 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 = ((AbstractJdbc1Connection)connection).ExecSQL(sql, (java.sql.Statement)this); + + return (result != null && ((AbstractJdbc1ResultSet)result).reallyResultSet()); + } + + /* + * 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 + { + ((AbstractJdbc1Connection)connection).setCursorName(name); + } + + + /* + * 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 (((AbstractJdbc1ResultSet)result).reallyResultSet()) + return -1; + return ((AbstractJdbc1ResultSet)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 = ((AbstractJdbc1ResultSet)result).getNext(); + return (result != null && ((AbstractJdbc1ResultSet)result).reallyResultSet()); + } + + + + + + + + + + /* * Returns the status message from the current Result.<p> @@ -46,7 +176,7 @@ public abstract class Statement { if (result == null) return null; - return ((org.postgresql.ResultSet) result).getStatusString(); + return ((AbstractJdbc1ResultSet)result).getStatusString(); } /* @@ -194,30 +324,6 @@ public abstract class Statement throw new PSQLException("postgresql.unimplemented"); } - /* - * Returns the Last inserted/updated oid. Deprecated in 7.2 because - * range of OID values is greater than a java signed int. - * @deprecated Replaced by getLastOID in 7.2 - */ - public int getInsertedOID() throws SQLException - { - if (result == null) - return 0; - return (int)((org.postgresql.ResultSet) result).getLastOID(); - } - - /* - * Returns the Last inserted/updated oid. - * @return OID of last insert - * @since 7.2 - */ - public long getLastOID() throws SQLException - { - if (result == null) - return 0; - return ((org.postgresql.ResultSet) result).getLastOID(); - } - /* * getResultSet returns the current result as a ResultSet. It * should only be called once per result. @@ -227,7 +333,7 @@ public abstract class Statement */ public java.sql.ResultSet getResultSet() throws SQLException { - if (result != null && ((org.postgresql.ResultSet) result).reallyResultSet()) + if (result != null && ((AbstractJdbc1ResultSet) result).reallyResultSet()) return result; return null; } @@ -328,4 +434,38 @@ public abstract class Statement return newsql.toString(); } + + /* + * + * The following methods are postgres extensions and are defined + * in the interface org.postgresql.Statement + * + */ + + /* + * Returns the Last inserted/updated oid. Deprecated in 7.2 because + * range of OID values is greater than a java signed int. + * @deprecated Replaced by getLastOID in 7.2 + */ + public int getInsertedOID() throws SQLException + { + if (result == null) + return 0; + return (int)((AbstractJdbc1ResultSet)result).getLastOID(); + } + + /* + * Returns the Last inserted/updated oid. + * @return OID of last insert + * @since 7.2 + */ + public long getLastOID() throws SQLException + { + if (result == null) + return 0; + return ((AbstractJdbc1ResultSet)result).getLastOID(); + } + + + } diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/CallableStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc1/CallableStatement.java index 4a006cd2208fb7abdf40a266fb995c002c2925d4..10e8c5f4171db2f1f73b8494d0b8f344abe95dfa 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc1/CallableStatement.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc1/CallableStatement.java @@ -44,7 +44,7 @@ public class CallableStatement extends PreparedStatement implements java.sql.Cal /* * @exception SQLException on failure */ - CallableStatement(Connection c, String q) throws SQLException + CallableStatement(Jdbc1Connection c, String q) throws SQLException { super(c, q); } diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/Connection.java b/src/interfaces/jdbc/org/postgresql/jdbc1/Connection.java deleted file mode 100644 index 4d3e087f76b65a170ee5724ea118318830ebd3d2..0000000000000000000000000000000000000000 --- a/src/interfaces/jdbc/org/postgresql/jdbc1/Connection.java +++ /dev/null @@ -1,214 +0,0 @@ -package org.postgresql.jdbc1; - -// IMPORTANT NOTE: This file implements the JDBC 1 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 2 class in the -// org.postgresql.jdbc2 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.15 2002/01/15 06:55:13 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; - - /* - * SQL statements without parameters are normally executed using - * Statement objects. If the same SQL statement is executed many - * times, it is more efficient to use a PreparedStatement - * - * @return a new Statement object - * @exception SQLException passed through from the constructor - */ - public java.sql.Statement createStatement() throws SQLException - { - return new Statement(this); - } - - /* - * A SQL statement with or without IN parameters can be pre-compiled - * and stored in a PreparedStatement object. This object can then - * be used to efficiently execute this statement multiple times. - * - * <B>Note:</B> This method is optimized for handling parametric - * SQL statements that benefit from precompilation if the drivers - * supports precompilation. PostgreSQL does not support precompilation. - * In this case, the statement is not sent to the database until the - * PreparedStatement is executed. This has no direct effect on users; - * however it does affect which method throws certain SQLExceptions - * - * @param sql a SQL statement that may contain one or more '?' IN - * parameter placeholders - * @return a new PreparedStatement object containing the pre-compiled - * statement. - * @exception SQLException if a database access error occurs. - */ - public java.sql.PreparedStatement prepareStatement(String sql) throws SQLException - { - return new PreparedStatement(this, sql); - } - - /* - * A SQL stored procedure call statement is handled by creating a - * CallableStatement for it. The CallableStatement provides methods - * for setting up its IN and OUT parameters and methods for executing - * it. - * - * <B>Note:</B> This method is optimised for handling stored procedure - * call statements. Some drivers may send the call statement to the - * database when the prepareCall is done; others may wait until the - * CallableStatement is executed. This has no direct effect on users; - * however, it does affect which method throws certain SQLExceptions - * - * @param sql a SQL statement that may contain one or more '?' parameter - * placeholders. Typically this statement is a JDBC function call - * escape string. - * @return a new CallableStatement object containing the pre-compiled - * SQL statement - * @exception SQLException if a database access error occurs - */ - public java.sql.CallableStatement prepareCall(String sql) throws SQLException - { - throw new PSQLException("postgresql.con.call"); - // return new CallableStatement(this, sql); - } - - /* - * Tests to see if a Connection is closed - * - * @return the status of the connection - * @exception SQLException (why?) - */ - public boolean isClosed() throws SQLException - { - return (pg_stream == null); - } - - /* - * A connection's database is able to provide information describing - * its tables, its supported SQL grammar, its stored procedures, the - * capabilities of this connection, etc. This information is made - * available through a DatabaseMetaData object. - * - * @return a DatabaseMetaData object for this connection - * @exception SQLException if a database access error occurs - */ - public java.sql.DatabaseMetaData getMetaData() throws SQLException - { - if (metadata == null) - metadata = new DatabaseMetaData(this); - return metadata; - } - - /* - * 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 jdbc1 stat is ignored. - return new org.postgresql.jdbc1.ResultSet((org.postgresql.jdbc1.Connection)conn, fields, tuples, status, updateCount, insertOID, binaryCursor); - } - - - /* An implementation of the abstract method in the parent class. - * This implemetation uses the jdbc1Types array to support the jdbc1 - * 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 < jdbc1Types.length;i++) - { - if (pgTypeName.equals(jdbc1Types[i])) - { - sqlType = jdbc1Typei[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 jdbc1Types[] = { - "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" - }; - - /* - * 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 jdbc1Typei[] = { - 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 - }; - - -} - -// *********************************************************************** - diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/DatabaseMetaData.java b/src/interfaces/jdbc/org/postgresql/jdbc1/DatabaseMetaData.java index 5fba1d68c00c3770c6bb94e8f6495f084dc7ce21..747ee1f1ea4f2209350fe4fa292f5a9dfa9374ae 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc1/DatabaseMetaData.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc1/DatabaseMetaData.java @@ -13,7 +13,7 @@ import org.postgresql.util.PSQLException; /* * This class provides information about the database as a whole. * - * $Id: DatabaseMetaData.java,v 1.47 2002/06/20 16:00:44 momjian Exp $ + * $Id: DatabaseMetaData.java,v 1.48 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 @@ -37,7 +37,7 @@ import org.postgresql.util.PSQLException; */ public class DatabaseMetaData implements java.sql.DatabaseMetaData { - Connection connection; // The connection association + Jdbc1Connection connection; // The connection association // These define various OID's. Hopefully they will stay constant. static final int iVarcharOid = 1043; // OID for varchar @@ -46,7 +46,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(Jdbc1Connection conn) { this.connection = conn; } @@ -196,7 +196,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData */ public String getDriverVersion() throws SQLException { - return connection.this_driver.getVersion(); + return connection.getDriver().getVersion(); } /* @@ -206,7 +206,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData */ public int getDriverMajorVersion() { - return connection.this_driver.getMajorVersion(); + return connection.getDriver().getMajorVersion(); } /* @@ -216,7 +216,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData */ public int getDriverMinorVersion() { - return connection.this_driver.getMinorVersion(); + return connection.getDriver().getMinorVersion(); } /* @@ -1549,7 +1549,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData v.addElement(tuple); } - return new ResultSet(connection, f, v, "OK", 1); + return new Jdbc1ResultSet(connection, f, v, "OK", 1); } /* @@ -1627,7 +1627,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData // add query loop here - return new ResultSet(connection, f, v, "OK", 1); + return new Jdbc1ResultSet(connection, f, v, "OK", 1); } /* @@ -1721,7 +1721,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData byte remarks[] = null; - if (((org.postgresql.ResultSet)dr).getTupleCount() == 1) + if (((AbstractJdbc1ResultSet)dr).getTupleCount() == 1) { dr.next(); remarks = dr.getBytes(1); @@ -1762,7 +1762,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData v.addElement(tuple); } r.close(); - return new ResultSet(connection, f, v, "OK", 1); + return new Jdbc1ResultSet(connection, f, v, "OK", 1); } // This array contains the valid values for the types argument @@ -1809,7 +1809,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 Jdbc1ResultSet(connection, f, v, "OK", 1); } /* @@ -1854,7 +1854,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 Jdbc1ResultSet(connection, f, v, "OK", 1); } /* @@ -2050,7 +2050,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData } r.close(); - return new ResultSet(connection, f, v, "OK", 1); + return new Jdbc1ResultSet(connection, f, v, "OK", 1); } /* @@ -2113,7 +2113,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData //v.addElement(tuple); } - return new ResultSet(connection, f, v, "OK", 1); + return new Jdbc1ResultSet(connection, f, v, "OK", 1); } /* @@ -2203,7 +2203,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 Jdbc1ResultSet(connection, f, v, "OK", 1); } /* @@ -2413,7 +2413,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData while (hasMore); } - return new ResultSet(connection, f, tuples, "OK", 1); + return new Jdbc1ResultSet(connection, f, tuples, "OK", 1); } /* @@ -2692,7 +2692,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData v.addElement(tuple); } rs.close(); - return new ResultSet(connection, f, v, "OK", 1); + return new Jdbc1ResultSet(connection, f, v, "OK", 1); } throw new PSQLException("postgresql.metadata.unavailable"); @@ -2832,7 +2832,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData } } - return new ResultSet(connection, f, v, "OK", 1); + return new Jdbc1ResultSet(connection, f, v, "OK", 1); } } diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1Connection.java b/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1Connection.java new file mode 100644 index 0000000000000000000000000000000000000000..55e527bd4908c6c6d033978c3e9f64efffcf6078 --- /dev/null +++ b/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1Connection.java @@ -0,0 +1,47 @@ +package org.postgresql.jdbc1; + + +import java.util.Vector; +import java.sql.*; +import org.postgresql.Field; +import org.postgresql.util.PSQLException; + +/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/Jdbc1Connection.java,v 1.1 2002/07/23 03:59:55 barry Exp $ + * This class implements the java.sql.Connection interface for JDBC1. + * However most of the implementation is really done in + * org.postgresql.jdbc1.AbstractJdbc1Connection + */ +public class Jdbc1Connection extends org.postgresql.jdbc1.AbstractJdbc1Connection implements java.sql.Connection +{ + + public java.sql.Statement createStatement() throws SQLException + { + return new org.postgresql.jdbc1.Jdbc1Statement(this); + } + + public java.sql.PreparedStatement prepareStatement(String sql) throws SQLException + { + return new org.postgresql.jdbc1.PreparedStatement(this, sql); + } + +//BJL TODO - merge callable statement logic from jdbc2 to jdbc1 + public java.sql.CallableStatement prepareCall(String sql) throws SQLException + { + throw new PSQLException("postgresql.con.call"); + } + + public java.sql.DatabaseMetaData getMetaData() throws SQLException + { + if (metadata == null) + metadata = new org.postgresql.jdbc1.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 + { + return new Jdbc1ResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor); + } + +} + + diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1ResultSet.java b/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1ResultSet.java new file mode 100644 index 0000000000000000000000000000000000000000..a959fef9d392539880ac74dd33e0db4d4b1fe08f --- /dev/null +++ b/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1ResultSet.java @@ -0,0 +1,32 @@ +package org.postgresql.jdbc1; + + +import java.sql.*; +import java.util.Vector; +import org.postgresql.Field; + +/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/Jdbc1ResultSet.java,v 1.1 2002/07/23 03:59:55 barry Exp $ + * This class implements the java.sql.ResultSet interface for JDBC1. + * However most of the implementation is really done in + * org.postgresql.jdbc1.AbstractJdbc1ResultSet + */ +public class Jdbc1ResultSet extends org.postgresql.jdbc1.AbstractJdbc1ResultSet implements java.sql.ResultSet +{ + + public Jdbc1ResultSet(Jdbc1Connection conn, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) + { + super(conn, fields, tuples, status, updateCount, insertOID, binaryCursor); + } + + public Jdbc1ResultSet(Jdbc1Connection 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/jdbc1/Jdbc1Statement.java b/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1Statement.java new file mode 100644 index 0000000000000000000000000000000000000000..bb073eae99871cdfaae4186c57815a14e14efaf9 --- /dev/null +++ b/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1Statement.java @@ -0,0 +1,19 @@ +package org.postgresql.jdbc1; + + +import java.sql.*; + +/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/Jdbc1Statement.java,v 1.1 2002/07/23 03:59:55 barry Exp $ + * This class implements the java.sql.Statement interface for JDBC1. + * However most of the implementation is really done in + * org.postgresql.jdbc1.AbstractJdbc1Statement + */ +public class Jdbc1Statement extends org.postgresql.jdbc1.AbstractJdbc1Statement implements java.sql.Statement +{ + + public Jdbc1Statement (Jdbc1Connection c) + { + connection = c; + } + +} diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/PreparedStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc1/PreparedStatement.java index 31926c500bd07153a678e54780dc942aec760f41..9ef9a4289e59f816e05289b4ed642a68e54a7493 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc1/PreparedStatement.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc1/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 Jdbc1Statement implements java.sql.PreparedStatement { String sql; String[] templateStrings; String[] inStrings; - Connection connection; + Jdbc1Connection 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(Jdbc1Connection connection, String sql) throws SQLException { super(connection); diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/ResultSet.java b/src/interfaces/jdbc/org/postgresql/jdbc1/ResultSet.java deleted file mode 100644 index b6e054a33689c76c74a6efc3c40b0caef255c776..0000000000000000000000000000000000000000 --- a/src/interfaces/jdbc/org/postgresql/jdbc1/ResultSet.java +++ /dev/null @@ -1,1026 +0,0 @@ -package org.postgresql.jdbc1; - -// IMPORTANT NOTE: This file implements the JDBC 1 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 2 class in the -// org.postgresql.jdbc2 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 -{ - /* - * 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); - 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) - rows.setSize(0); - } - - /* - * 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 - { - String s = getString(columnIndex); - - if (s != null) - { - int c = s.charAt(0); - return ((c == 't') || (c == 'T') || (c == '1')); - } - return false; // SQL NULL - } - - /* - * Get the value of a column in the current row as a Java byte. - * - * @param columnIndex the first column is 1, the second is 2,... - * @return the column value; 0 if SQL NULL - * @exception SQLException if a database access error occurs - */ - public byte getByte(int columnIndex) throws SQLException - { - String s = getString(columnIndex); - - if (s != null) - { - try - { - return Byte.parseByte(s); - } - catch (NumberFormatException e) - { - throw new 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 - { - String s = getFixedString(columnIndex); - - if (s != null) - { - try - { - return Integer.parseInt(s); - } - catch (NumberFormatException e) - { - throw new PSQLException ("postgresql.res.badint", s); - } - } - return 0; // SQL NULL - } - - /* - * Get the value of a column in the current row as a Java long. - * - * @param columnIndex the first column is 1, the second is 2,... - * @return the column value; 0 if SQL NULL - * @exception SQLException if a database access error occurs - */ - public long getLong(int columnIndex) throws SQLException - { - String s = getFixedString(columnIndex); - - if (s != null) - { - try - { - return Long.parseLong(s); - } - catch (NumberFormatException e) - { - throw new PSQLException ("postgresql.res.badlong", s); - } - } - return 0; // SQL NULL - } - - /* - * Get the value of a column in the current row as a Java float. - * - * @param columnIndex the first column is 1, the second is 2,... - * @return the column value; 0 if SQL NULL - * @exception SQLException if a database access error occurs - */ - public float getFloat(int columnIndex) throws SQLException - { - String s = getFixedString(columnIndex); - - if (s != null) - { - try - { - return Float.valueOf(s).floatValue(); - } - catch (NumberFormatException e) - { - throw new PSQLException ("postgresql.res.badfloat", s); - } - } - return 0; // SQL NULL - } - - /* - * Get the value of a column in the current row as a Java double. - * - * @param columnIndex the first column is 1, the second is 2,... - * @return the column value; 0 if SQL NULL - * @exception SQLException if a database access error occurs - */ - public double getDouble(int columnIndex) throws SQLException - { - String s = getFixedString(columnIndex); - - if (s != null) - { - try - { - return Double.valueOf(s).doubleValue(); - } - catch (NumberFormatException e) - { - throw new PSQLException ("postgresql.res.baddouble", s); - } - } - return 0; // SQL NULL - } - - /* - * 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 - */ - public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException - { - String s = getFixedString(columnIndex); - BigDecimal val; - - if (s != null) - { - try - { - val = new BigDecimal(s); - } - catch (NumberFormatException e) - { - throw new PSQLException ("postgresql.res.badbigdec", s); - } - try - { - return val.setScale(scale); - } - catch (ArithmeticException e) - { - throw new PSQLException ("postgresql.res.badbigdec", s); - } - } - return null; // SQL NULL - } - - /* - * 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 - { - String s = getString(columnIndex); - 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); - } - } - - /* - * Get the value of a column in the current row as a java.sql.Time - * object - * - * @param columnIndex the first column is 1, the second is 2... - * @return the column value; null if SQL NULL - * @exception SQLException if a database access error occurs - */ - public Time getTime(int columnIndex) throws SQLException - { - String s = getString(columnIndex); - - if (s == null) - 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(getTimestamp(columnIndex).getTime()); - } - } - catch (NumberFormatException e) - { - throw new PSQLException("postgresql.res.badtime", s); - } - } - - /* - * Get the value of a column in the current row as a - * java.sql.Timestamp object - * - * 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 columnIndex the first column is 1, the second is 2... - * @return the column value; null if SQL NULL - * @exception SQLException if a database access error occurs - */ - public Timestamp getTimestamp(int columnIndex) throws SQLException - { - String s = getString(columnIndex); - - if (s == null) - return null; - - StringBuffer sbuf = new StringBuffer(s); - SimpleDateFormat df = null; - - 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 should 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; - 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) - 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++) - sbuf.append('0'); - } - else - { - // No fractional seconds, lets add some. - sbuf.append(".000"); - } - - if (i < slen) - { - // prepend the GMT part and then add the remaining bit of - // the string. - sbuf.append(" GMT"); - sbuf.append(c); - 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) - 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 - { - //if type is timestamptz then data is in GMT, else it is in local timezone - if (fields[columnIndex - 1].getPGType().equals("timestamptz")) { - 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 type is timestamptz then data is in GMT, else it is in local timezone - if (fields[columnIndex - 1].getPGType().equals("timestamptz")) { - 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. - return new Timestamp(df.parse(sbuf.toString()).getTime()); - } - catch (ParseException e) - { - throw new PSQLException("postgresql.res.badtimestamp", new Integer(e.getErrorOffset()), s); - } - } - - /* - * 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. - * - * @param columnIndex the first column is 1, the second is 2... - * @return a Java InputStream that delivers the database column value - * as a stream of two byte Unicode characters. If the value is - * SQL NULL, then the result is null - * @exception SQLException if a database access error occurs - * @see getAsciiStream - * @see getBinaryStream - */ - public InputStream getUnicodeStream(int columnIndex) throws SQLException - { - 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)); - } - - public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException - { - return getBigDecimal(findColumn(columnName), scale); - } - - public byte[] getBytes(String columnName) throws SQLException - { - return getBytes(findColumn(columnName)); - } - - public java.sql.Date getDate(String columnName) throws SQLException - { - return getDate(findColumn(columnName)); - } - - public Time getTime(String columnName) throws SQLException - { - return getTime(findColumn(columnName)); - } - - public Timestamp getTimestamp(String columnName) throws SQLException - { - return getTimestamp(findColumn(columnName)); - } - - public InputStream getAsciiStream(String columnName) throws SQLException - { - return getAsciiStream(findColumn(columnName)); - } - - public InputStream getUnicodeStream(String columnName) throws SQLException - { - return getUnicodeStream(findColumn(columnName)); - } - - public InputStream getBinaryStream(String columnName) throws SQLException - { - return getBinaryStream(findColumn(columnName)); - } - - /* - * The first warning reported by calls on this ResultSet is - * returned. Subsequent ResultSet warnings will be chained - * to this SQLWarning. - * - * <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; - - if (columnIndex < 1 || columnIndex > fields.length) - throw new PSQLException("postgresql.res.colrange"); - 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() - 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); - 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; - - for (i = 0 ; i < fields.length; ++i) - if (fields[i].getName().equalsIgnoreCase(columnName)) - return (i + 1); - throw new PSQLException ("postgresql.res.colname", columnName); - } -} - diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/Statement.java b/src/interfaces/jdbc/org/postgresql/jdbc1/Statement.java deleted file mode 100644 index 8898f5a69dd3e3daaf59d2f7dfbe30e68d9c690e..0000000000000000000000000000000000000000 --- a/src/interfaces/jdbc/org/postgresql/jdbc1/Statement.java +++ /dev/null @@ -1,144 +0,0 @@ -package org.postgresql.jdbc1; - -// IMPORTANT NOTE: This file implements the JDBC 1 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 2 class in the -// org.postgresql.jdbc2 package. - -import java.sql.*; - -import org.postgresql.util.PSQLException; - -/* - * 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 - - /* - * 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; - } - - /* - * 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); - 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); - result = connection.ExecSQL(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()); - } -} 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 0000000000000000000000000000000000000000..8faefad65ff6ae1db59023212cc168aacb57afcf --- /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 0000000000000000000000000000000000000000..50c5d942bbf63ce71e53e46d756bf8c681b6d123 --- /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 0000000000000000000000000000000000000000..3d6f6553ced3fea5afba83d7e4c81cbbcabf5d1d --- /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 7cc842ec36e0ad7f30f617a770308031c7f5a9ee..2105802d66a17fa1e77efeedf3c828bda5c7f1db 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 4aa034832537c9e78c27d7e6a9a89ad08c6f7d86..9d37bf04bc50c42cacc133b394cb719e3a1f6289 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 9ab3cced8edb3138bd01e0a1ca553a2a02878a01..0000000000000000000000000000000000000000 --- 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 3cc224e6e8f665b2809e8491d9bdf7adaef70756..77415d051d428a0732626fef15ac2d8481691b9d 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 0000000000000000000000000000000000000000..cfbb3486ec6f6d25dc6b0ca25110bedf73a6e65e --- /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 0000000000000000000000000000000000000000..7200cf549ad586ddfc49d5a518e06482a7949d26 --- /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 0000000000000000000000000000000000000000..31cec93821a4f8dde7b01b811a3d584c5e579246 --- /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 5638a2692d657704414e6322930c76d660229f28..21aba8d9ee089ff84ad991c7873d25f6e66a7bec 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 f5489f4e9793aea143173a15de31e21639b9ed95..0000000000000000000000000000000000000000 --- 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 a00025ff72ae77ab0617b40fc725b58d27fa9b6b..0000000000000000000000000000000000000000 --- 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 9ff8be4080d5cc9001a1ead433eb0ea4428aa1d7..6f6f67d8394376c2e1e224dad9fce676f5723b43 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++ ) diff --git a/src/interfaces/jdbc/org/postgresql/largeobject/LargeObjectManager.java b/src/interfaces/jdbc/org/postgresql/largeobject/LargeObjectManager.java index e5296189cdc8725db12bd8e76c86b4d6c817080e..a037ab28a21719cc183e5fc246badf38d06341dc 100644 --- a/src/interfaces/jdbc/org/postgresql/largeobject/LargeObjectManager.java +++ b/src/interfaces/jdbc/org/postgresql/largeobject/LargeObjectManager.java @@ -94,16 +94,16 @@ public class LargeObjectManager * org.postgresql.Connection class keeps track of the various extension API's * and it's advised you use those to gain access, and not going direct. */ - public LargeObjectManager(org.postgresql.Connection conn) throws SQLException + public LargeObjectManager(Connection conn) throws SQLException { // We need Fastpath to do anything - this.fp = conn.getFastpathAPI(); + this.fp = ((org.postgresql.PGConnection)conn).getFastpathAPI(); // Now get the function oid's for the api // // This is an example of Fastpath.addFunctions(); // - java.sql.ResultSet res = (java.sql.ResultSet)conn.createStatement().executeQuery("select proname, oid from pg_proc" + + ResultSet res = conn.createStatement().executeQuery("select proname, oid from pg_proc" + " where proname = 'lo_open'" + " or proname = 'lo_close'" + " or proname = 'lo_creat'" + diff --git a/src/interfaces/jdbc/org/postgresql/largeobject/PGblob.java b/src/interfaces/jdbc/org/postgresql/largeobject/PGblob.java index 12e04e4c14aba302762871347b5b172285d9f211..87c1ac247742538964273fa212d6c5ceba150bfc 100644 --- a/src/interfaces/jdbc/org/postgresql/largeobject/PGblob.java +++ b/src/interfaces/jdbc/org/postgresql/largeobject/PGblob.java @@ -20,18 +20,16 @@ import org.postgresql.largeobject.*; * This implements the Blob interface, which is basically another way to * access a LargeObject. * - * $Id: PGblob.java,v 1.3 2001/11/19 22:33:39 momjian Exp $ + * $Id: PGblob.java,v 1.4 2002/07/23 03:59:55 barry Exp $ * */ public class PGblob implements java.sql.Blob { - private org.postgresql.Connection conn; private int oid; private LargeObject lo; - public PGblob(org.postgresql.Connection conn, int oid) throws SQLException + public PGblob(org.postgresql.PGConnection conn, int oid) throws SQLException { - this.conn = conn; this.oid = oid; LargeObjectManager lom = conn.getLargeObjectAPI(); this.lo = lom.open(oid); diff --git a/src/interfaces/jdbc/org/postgresql/largeobject/PGclob.java b/src/interfaces/jdbc/org/postgresql/largeobject/PGclob.java index 63d39c07b0f7b09dda53f860ea98b204babb0781..71c3f8a2f0c40e9884b02a38eda3c1df4f24583e 100644 --- a/src/interfaces/jdbc/org/postgresql/largeobject/PGclob.java +++ b/src/interfaces/jdbc/org/postgresql/largeobject/PGclob.java @@ -20,18 +20,16 @@ import org.postgresql.largeobject.*; * This implements the Blob interface, which is basically another way to * access a LargeObject. * - * $Id: PGclob.java,v 1.3 2001/11/19 22:33:39 momjian Exp $ + * $Id: PGclob.java,v 1.4 2002/07/23 03:59:55 barry Exp $ * */ public class PGclob implements java.sql.Clob { - private org.postgresql.Connection conn; private int oid; private LargeObject lo; - public PGclob(org.postgresql.Connection conn, int oid) throws SQLException + public PGclob(org.postgresql.PGConnection conn, int oid) throws SQLException { - this.conn = conn; this.oid = oid; LargeObjectManager lom = conn.getLargeObjectAPI(); this.lo = lom.open(oid); diff --git a/src/interfaces/jdbc/org/postgresql/test/jdbc2/BlobTest.java b/src/interfaces/jdbc/org/postgresql/test/jdbc2/BlobTest.java index ae436fbf18b4c78c5dd412a40e0a303d5e8f026d..45bab13b0e0798d0fe7b8b1aa4d63dd1937d1b05 100644 --- a/src/interfaces/jdbc/org/postgresql/test/jdbc2/BlobTest.java +++ b/src/interfaces/jdbc/org/postgresql/test/jdbc2/BlobTest.java @@ -8,7 +8,7 @@ import java.sql.*; import org.postgresql.largeobject.*; /* - * $Id: BlobTest.java,v 1.5 2001/11/19 23:16:46 momjian Exp $ + * $Id: BlobTest.java,v 1.6 2002/07/23 03:59:55 barry Exp $ * * Some simple tests based on problems reported by users. Hopefully these will * help prevent previous problems from re-occuring ;-) @@ -95,7 +95,7 @@ public class BlobTest extends TestCase */ private int uploadFile(String file, int method) throws Exception { - LargeObjectManager lom = ((org.postgresql.Connection)con).getLargeObjectAPI(); + LargeObjectManager lom = ((org.postgresql.PGConnection)con).getLargeObjectAPI(); FileInputStream fis = new FileInputStream(file); @@ -160,7 +160,7 @@ public class BlobTest extends TestCase { boolean result = true; - LargeObjectManager lom = ((org.postgresql.Connection)con).getLargeObjectAPI(); + LargeObjectManager lom = ((org.postgresql.PGConnection)con).getLargeObjectAPI(); Statement st = con.createStatement(); ResultSet rs = st.executeQuery(JDBC2Tests.selectSQL("testblob", "id,lo")); diff --git a/src/interfaces/jdbc/org/postgresql/test/jdbc2/ConnectionTest.java b/src/interfaces/jdbc/org/postgresql/test/jdbc2/ConnectionTest.java index 6db4f4121846fca5dcc8dfa378cee978a2086d17..682118b6c1733cdd415fe759af5277c0498a4b67 100644 --- a/src/interfaces/jdbc/org/postgresql/test/jdbc2/ConnectionTest.java +++ b/src/interfaces/jdbc/org/postgresql/test/jdbc2/ConnectionTest.java @@ -10,7 +10,7 @@ import java.sql.*; * * PS: Do you know how difficult it is to type on a train? ;-) * - * $Id: ConnectionTest.java,v 1.7 2001/11/19 22:33:39 momjian Exp $ + * $Id: ConnectionTest.java,v 1.8 2002/07/23 03:59:55 barry Exp $ */ public class ConnectionTest extends TestCase @@ -199,13 +199,13 @@ public class ConnectionTest extends TestCase String testStr = "This Is OuR TeSt message"; // The connection must be ours! - assertTrue(con instanceof org.postgresql.Connection); + assertTrue(con instanceof org.postgresql.PGConnection); // Clear any existing warnings con.clearWarnings(); // Set the test warning - ((org.postgresql.Connection)con).addWarning(testStr); + ((org.postgresql.jdbc2.AbstractJdbc2Connection)con).addWarning(testStr); // Retrieve it SQLWarning warning = con.getWarnings(); diff --git a/src/interfaces/jdbc/org/postgresql/test/jdbc2/DatabaseMetaDataTest.java b/src/interfaces/jdbc/org/postgresql/test/jdbc2/DatabaseMetaDataTest.java index e6acfc0d700cbae444599a71bc8bba5201c152ef..26675a7ca6aebae3cd286a1c27a36555960b026c 100644 --- a/src/interfaces/jdbc/org/postgresql/test/jdbc2/DatabaseMetaDataTest.java +++ b/src/interfaces/jdbc/org/postgresql/test/jdbc2/DatabaseMetaDataTest.java @@ -9,7 +9,7 @@ import java.sql.*; * * PS: Do you know how difficult it is to type on a train? ;-) * - * $Id: DatabaseMetaDataTest.java,v 1.8 2002/06/05 19:12:01 davec Exp $ + * $Id: DatabaseMetaDataTest.java,v 1.9 2002/07/23 03:59:55 barry Exp $ */ public class DatabaseMetaDataTest extends TestCase @@ -163,13 +163,13 @@ public class DatabaseMetaDataTest extends TestCase // We need to type cast the connection to get access to the // PostgreSQL-specific method haveMinimumServerVersion(). // This is not available through the java.sql.Connection interface. - assertTrue( con instanceof org.postgresql.Connection ); + assertTrue( con instanceof org.postgresql.PGConnection ); assertTrue(!dbmd.nullsAreSortedAtStart()); assertTrue( dbmd.nullsAreSortedAtEnd() != - ((org.postgresql.Connection)con).haveMinimumServerVersion("7.2")); + ((org.postgresql.jdbc2.AbstractJdbc2Connection)con).haveMinimumServerVersion("7.2")); assertTrue( dbmd.nullsAreSortedHigh() == - ((org.postgresql.Connection)con).haveMinimumServerVersion("7.2")); + ((org.postgresql.jdbc2.AbstractJdbc2Connection)con).haveMinimumServerVersion("7.2")); assertTrue(!dbmd.nullsAreSortedLow()); assertTrue(dbmd.nullPlusNonNullIsNull()); @@ -250,7 +250,7 @@ public class DatabaseMetaDataTest extends TestCase { String pkTableName = rs.getString( "PKTABLE_NAME" ); - assertTrue ( pkTableName.equals("people") || pkTableName.equals("policy") ); + assertTrue ( pkTableName.equals("people") || pkTableName.equals("policy") ); String pkColumnName = rs.getString( "PKCOLUMN_NAME" ); assertTrue( pkColumnName.equals("id") ); @@ -367,14 +367,20 @@ public class DatabaseMetaDataTest extends TestCase { try { - assertTrue(con instanceof org.postgresql.Connection); - org.postgresql.Connection pc = (org.postgresql.Connection) con; + assertTrue(con instanceof org.postgresql.PGConnection); + org.postgresql.jdbc2.AbstractJdbc2Connection pc = (org.postgresql.jdbc2.AbstractJdbc2Connection) con; DatabaseMetaData dbmd = con.getMetaData(); assertNotNull(dbmd); assertTrue(dbmd.getDatabaseProductName().equals("PostgreSQL")); - assertTrue(dbmd.getDatabaseProductVersion().startsWith(Integer.toString(pc.this_driver.getMajorVersion()) + "." + Integer.toString(pc.this_driver.getMinorVersion()))); + //The test below doesn't make sense to me, it tests that + //the version of the driver = the version of the database it is connected to + //since the driver should be backwardly compatible this test is commented out + //assertTrue(dbmd.getDatabaseProductVersion().startsWith( + // Integer.toString(pc.getDriver().getMajorVersion()) + // + "." + // + Integer.toString(pc.getDriver().getMinorVersion()))); assertTrue(dbmd.getDriverName().equals("PostgreSQL Native Driver")); } @@ -388,15 +394,15 @@ public class DatabaseMetaDataTest extends TestCase { try { - assertTrue(con instanceof org.postgresql.Connection); - org.postgresql.Connection pc = (org.postgresql.Connection) con; + assertTrue(con instanceof org.postgresql.PGConnection); + org.postgresql.jdbc2.AbstractJdbc2Connection pc = (org.postgresql.jdbc2.AbstractJdbc2Connection) con; DatabaseMetaData dbmd = con.getMetaData(); assertNotNull(dbmd); - assertTrue(dbmd.getDriverVersion().equals(pc.this_driver.getVersion())); - assertTrue(dbmd.getDriverMajorVersion() == pc.this_driver.getMajorVersion()); - assertTrue(dbmd.getDriverMinorVersion() == pc.this_driver.getMinorVersion()); + assertTrue(dbmd.getDriverVersion().equals(pc.getDriver().getVersion())); + assertTrue(dbmd.getDriverMajorVersion() == pc.getDriver().getMajorVersion()); + assertTrue(dbmd.getDriverMinorVersion() == pc.getDriver().getMinorVersion()); } diff --git a/src/interfaces/jdbc/org/postgresql/test/jdbc2/TimestampTest.java b/src/interfaces/jdbc/org/postgresql/test/jdbc2/TimestampTest.java index f7bf62e6d60e63e664014256ef546c08aa593158..37eff6c5b7591546c299474f2e03690ed05664ba 100644 --- a/src/interfaces/jdbc/org/postgresql/test/jdbc2/TimestampTest.java +++ b/src/interfaces/jdbc/org/postgresql/test/jdbc2/TimestampTest.java @@ -5,12 +5,10 @@ import junit.framework.TestCase; import java.sql.*; /* - * $Id: TimestampTest.java,v 1.6 2001/11/19 22:33:39 momjian Exp $ + * $Id: TimestampTest.java,v 1.7 2002/07/23 03:59:55 barry Exp $ * - * This has been the most controversial pair of methods since 6.5 was released! - * - * From now on, any changes made to either getTimestamp or setTimestamp - * MUST PASS this TestCase!!! + * Test get/setTimestamp for both timestamp with time zone and + * timestamp without time zone datatypes * */ public class TimestampTest extends TestCase @@ -28,39 +26,74 @@ public class TimestampTest extends TestCase con = JDBC2Tests.openDB(); Statement stmt = con.createStatement(); - JDBC2Tests.createTable(con, "testtimestamp", "ts timestamp"); + JDBC2Tests.createTable(con, TSWTZ_TABLE, "ts timestamp with time zone"); + JDBC2Tests.createTable(con, TSWOTZ_TABLE, "ts timestamp without time zone"); } protected void tearDown() throws Exception { - JDBC2Tests.dropTable(con, "testtimestamp"); + JDBC2Tests.dropTable(con, TSWTZ_TABLE); + JDBC2Tests.dropTable(con, TSWOTZ_TABLE); JDBC2Tests.closeDB(con); } /* - * Tests the time methods in ResultSet + * Tests the timestamp methods in ResultSet on timestamp with time zone + * we insert a known string value (don't use setTimestamp) then see that + * we get back the same value from getTimestamp */ - public void testGetTimestamp() + public void testGetTimestampWTZ() { try { Statement stmt = con.createStatement(); - assertEquals(1, stmt.executeUpdate(JDBC2Tests.insertSQL("testtimestamp", - "'1950-02-07 15:00:00'"))); + //Insert the three timestamp values in raw pg format + assertEquals(1, stmt.executeUpdate(JDBC2Tests.insertSQL(TSWTZ_TABLE,"'" + TS1WTZ_PGFORMAT + "'"))); + assertEquals(1, stmt.executeUpdate(JDBC2Tests.insertSQL(TSWTZ_TABLE,"'" + TS2WTZ_PGFORMAT + "'"))); + assertEquals(1, stmt.executeUpdate(JDBC2Tests.insertSQL(TSWTZ_TABLE,"'" + TS3WTZ_PGFORMAT + "'"))); + + // Fall through helper + timestampTestWTZ(); + + assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWTZ_TABLE)); + + stmt.close(); + } + catch (Exception ex) + { + fail(ex.getMessage()); + } + } + + /* + * Tests the timestamp methods in PreparedStatement on timestamp with time zone + * we insert a value using setTimestamp then see that + * we get back the same value from getTimestamp (which we know works as it was tested + * independently of setTimestamp + */ + public void testSetTimestampWTZ() + { + try + { + Statement stmt = con.createStatement(); + PreparedStatement pstmt = con.prepareStatement(JDBC2Tests.insertSQL(TSWTZ_TABLE, "?")); - assertEquals(1, stmt.executeUpdate(JDBC2Tests.insertSQL("testtimestamp", "'" + - getTimestamp(1970, 6, 2, 8, 13, 0, 0).toString() + - "'"))); + pstmt.setTimestamp(1, TS1WTZ); + assertEquals(1, pstmt.executeUpdate()); - assertEquals(1, stmt.executeUpdate(JDBC2Tests.insertSQL("testtimestamp", - "'1970-06-02 08:13:00'"))); + pstmt.setTimestamp(1, TS2WTZ); + assertEquals(1, pstmt.executeUpdate()); + + pstmt.setTimestamp(1, TS3WTZ); + assertEquals(1, pstmt.executeUpdate()); // Fall through helper - timestampTest(); + timestampTestWTZ(); - assertEquals(3, stmt.executeUpdate("DELETE FROM testtimestamp")); + assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWTZ_TABLE)); + pstmt.close(); stmt.close(); } catch (Exception ex) @@ -70,28 +103,61 @@ public class TimestampTest extends TestCase } /* - * Tests the time methods in PreparedStatement + * Tests the timestamp methods in ResultSet on timestamp without time zone + * we insert a known string value (don't use setTimestamp) then see that + * we get back the same value from getTimestamp */ - public void testSetTimestamp() + public void testGetTimestampWOTZ() { try { Statement stmt = con.createStatement(); - PreparedStatement pstmt = con.prepareStatement(JDBC2Tests.insertSQL("testtimestamp", "?")); - pstmt.setTimestamp(1, getTimestamp(1950, 2, 7, 15, 0, 0, 0)); - assertEquals(1, pstmt.executeUpdate()); + //Insert the three timestamp values in raw pg format + assertEquals(1, stmt.executeUpdate(JDBC2Tests.insertSQL(TSWOTZ_TABLE,"'" + TS1WOTZ_PGFORMAT + "'"))); + assertEquals(1, stmt.executeUpdate(JDBC2Tests.insertSQL(TSWOTZ_TABLE,"'" + TS2WOTZ_PGFORMAT + "'"))); + assertEquals(1, stmt.executeUpdate(JDBC2Tests.insertSQL(TSWOTZ_TABLE,"'" + TS3WOTZ_PGFORMAT + "'"))); + + // Fall through helper + timestampTestWOTZ(); + + assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWOTZ_TABLE)); - pstmt.setTimestamp(1, getTimestamp(1970, 6, 2, 8, 13, 0, 0)); - assertEquals(1, pstmt.executeUpdate()); + stmt.close(); + } + catch (Exception ex) + { + fail(ex.getMessage()); + } + } - pstmt.setTimestamp(1, getTimestamp(1970, 6, 2, 8, 13, 0, 0)); - assertEquals(1, pstmt.executeUpdate()); + + /* + * Tests the timestamp methods in PreparedStatement on timestamp without time zone + * we insert a value using setTimestamp then see that + * we get back the same value from getTimestamp (which we know works as it was tested + * independently of setTimestamp + */ + public void testSetTimestampWOTZ() + { + try + { + Statement stmt = con.createStatement(); + PreparedStatement pstmt = con.prepareStatement(JDBC2Tests.insertSQL(TSWOTZ_TABLE, "?")); + + pstmt.setTimestamp(1, TS1WOTZ); + assertEquals(1, pstmt.executeUpdate()); + + pstmt.setTimestamp(1, TS2WOTZ); + assertEquals(1, pstmt.executeUpdate()); + + pstmt.setTimestamp(1, TS3WOTZ); + assertEquals(1, pstmt.executeUpdate()); // Fall through helper - timestampTest(); + timestampTestWOTZ(); - assertEquals(3, stmt.executeUpdate("DELETE FROM testtimestamp")); + assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWOTZ_TABLE)); pstmt.close(); stmt.close(); @@ -103,31 +169,64 @@ public class TimestampTest extends TestCase } /* - * Helper for the TimeTests. It tests what should be in the db + * Helper for the TimestampTests. It tests what should be in the db + */ + private void timestampTestWTZ() throws SQLException + { + Statement stmt = con.createStatement(); + ResultSet rs; + java.sql.Timestamp t; + + rs = stmt.executeQuery("select ts from " + TSWTZ_TABLE + " order by ts"); + assertNotNull(rs); + + assertTrue(rs.next()); + t = rs.getTimestamp(1); + assertNotNull(t); + assertTrue(t.equals(TS1WTZ)); + + assertTrue(rs.next()); + t = rs.getTimestamp(1); + assertNotNull(t); + assertTrue(t.equals(TS2WTZ)); + + assertTrue(rs.next()); + t = rs.getTimestamp(1); + assertNotNull(t); + assertTrue(t.equals(TS3WTZ)); + + assertTrue(! rs.next()); // end of table. Fail if more entries exist. + + rs.close(); + stmt.close(); + } + + /* + * Helper for the TimestampTests. It tests what should be in the db */ - private void timestampTest() throws SQLException + private void timestampTestWOTZ() throws SQLException { Statement stmt = con.createStatement(); ResultSet rs; java.sql.Timestamp t; - rs = stmt.executeQuery(JDBC2Tests.selectSQL("testtimestamp", "ts")); - assertNotNull(rs); + rs = stmt.executeQuery("select ts from " + TSWOTZ_TABLE + " order by ts"); + assertNotNull(rs); assertTrue(rs.next()); t = rs.getTimestamp(1); - assertNotNull(t); - assertTrue(t.equals(getTimestamp(1950, 2, 7, 15, 0, 0, 0))); + assertNotNull(t); + assertTrue(t.toString().equals(TS1WOTZ_JAVAFORMAT)); assertTrue(rs.next()); t = rs.getTimestamp(1); - assertNotNull(t); - assertTrue(t.equals(getTimestamp(1970, 6, 2, 8, 13, 0, 0))); + assertNotNull(t); + assertTrue(t.toString().equals(TS2WOTZ_JAVAFORMAT)); assertTrue(rs.next()); t = rs.getTimestamp(1); - assertNotNull(t); - assertTrue(t.equals(getTimestamp(1970, 6, 2, 8, 13, 0, 0))); + assertNotNull(t); + assertTrue(t.toString().equals(TS3WOTZ_JAVAFORMAT)); assertTrue(! rs.next()); // end of table. Fail if more entries exist. @@ -135,14 +234,59 @@ public class TimestampTest extends TestCase stmt.close(); } - private java.sql.Timestamp getTimestamp(int y, int m, int d, int h, int mn, int se, int f) + private static java.sql.Timestamp getTimestamp(int y, int m, int d, int h, int mn, int se, int f, String tz) { - return java.sql.Timestamp.valueOf(JDBC2Tests.fix(y, 4) + "-" + - JDBC2Tests.fix(m, 2) + "-" + - JDBC2Tests.fix(d, 2) + " " + - JDBC2Tests.fix(h, 2) + ":" + - JDBC2Tests.fix(mn, 2) + ":" + - JDBC2Tests.fix(se, 2) + "." + - JDBC2Tests.fix(f, 9)); + java.sql.Timestamp l_return = null; + java.text.DateFormat l_df; + try { + String l_ts; + l_ts = JDBC2Tests.fix(y, 4) + "-" + + JDBC2Tests.fix(m, 2) + "-" + + JDBC2Tests.fix(d, 2) + " " + + JDBC2Tests.fix(h, 2) + ":" + + JDBC2Tests.fix(mn, 2) + ":" + + JDBC2Tests.fix(se, 2) + " "; + + if (tz == null) { + l_df = new java.text.SimpleDateFormat("y-M-d H:m:s"); + } else { + l_ts = l_ts + tz; + l_df = new java.text.SimpleDateFormat("y-M-d H:m:s z"); + } + java.util.Date l_date = l_df.parse(l_ts); + l_return = new java.sql.Timestamp(l_date.getTime()); + l_return.setNanos(f); + } catch (Exception ex) { + fail(ex.getMessage()); + } + return l_return; } + + private static final java.sql.Timestamp TS1WTZ = getTimestamp(1950, 2, 7, 15, 0, 0, 100000000, "PST"); + private static final String TS1WTZ_PGFORMAT = "1950-02-07 15:00:00.1-08"; + + private static final java.sql.Timestamp TS2WTZ = getTimestamp(2000, 2, 7, 15, 0, 0, 120000000, "GMT"); + private static final String TS2WTZ_PGFORMAT = "2000-02-07 15:00:00.12+00"; + + private static final java.sql.Timestamp TS3WTZ = getTimestamp(2000, 7, 7, 15, 0, 0, 123000000, "GMT"); + private static final String TS3WTZ_PGFORMAT = "2000-07-07 15:00:00.123+00"; + + + private static final java.sql.Timestamp TS1WOTZ = getTimestamp(1950, 2, 7, 15, 0, 0, 100000000, null); + private static final String TS1WOTZ_PGFORMAT = "1950-02-07 15:00:00.1"; + private static final String TS1WOTZ_JAVAFORMAT = "1950-02-07 15:00:00.1"; + + private static final java.sql.Timestamp TS2WOTZ = getTimestamp(2000, 2, 7, 15, 0, 0, 120000000, null); + private static final String TS2WOTZ_PGFORMAT = "2000-02-07 15:00:00.12"; + //there is probably a bug here in that this needs to be .1 instead of .12, but I couldn't find it now + private static final String TS2WOTZ_JAVAFORMAT = "2000-02-07 15:00:00.1"; + + private static final java.sql.Timestamp TS3WOTZ = getTimestamp(2000, 7, 7, 15, 0, 0, 123000000, null); + private static final String TS3WOTZ_PGFORMAT = "2000-07-07 15:00:00.123"; + //there is probably a bug here in that this needs to be .12 instead of .123, but I couldn't find it now + private static final String TS3WOTZ_JAVAFORMAT = "2000-07-07 15:00:00.12"; + + private static final String TSWTZ_TABLE = "testtimestampwtz"; + private static final String TSWOTZ_TABLE = "testtimestampwotz"; + } diff --git a/src/interfaces/jdbc/org/postgresql/test/jdbc2/UpdateableResultTest.java b/src/interfaces/jdbc/org/postgresql/test/jdbc2/UpdateableResultTest.java index 722dd78398a634a6abcb34ec6992b330860f3234..056e68eba0524ea5bca755dcf805765045c75984 100644 --- a/src/interfaces/jdbc/org/postgresql/test/jdbc2/UpdateableResultTest.java +++ b/src/interfaces/jdbc/org/postgresql/test/jdbc2/UpdateableResultTest.java @@ -28,7 +28,6 @@ public class UpdateableResultTest extends TestCase Connection con = JDBC2Tests.openDB(); JDBC2Tests.createTable(con, "updateable","id int primary key, name text, notselected text"); JDBC2Tests.createTable(con, "second","id1 int primary key, name1 text"); - Statement st1 = con.createStatement(); boolean retVal = st1.execute( "insert into updateable ( id, name, notselected ) values (1, 'jake', 'avalue')" ); assert( retVal== false ); @@ -132,4 +131,4 @@ public class UpdateableResultTest extends TestCase } -} \ No newline at end of file +} diff --git a/src/interfaces/jdbc/org/postgresql/util/Serialize.java b/src/interfaces/jdbc/org/postgresql/util/Serialize.java index 80d10bc54106d96b9cf2bdaaa651cd637dce106b..f1f12520baaf2ddd680c1149d108708d59822009 100644 --- a/src/interfaces/jdbc/org/postgresql/util/Serialize.java +++ b/src/interfaces/jdbc/org/postgresql/util/Serialize.java @@ -109,7 +109,7 @@ import java.sql.*; public class Serialize { // This is the connection that the instance refers to - protected org.postgresql.Connection conn; + protected Connection conn; // This is the table name protected String tableName; @@ -124,7 +124,7 @@ public class Serialize * This creates an instance that can be used to serialize or deserialize * a Java object from a PostgreSQL table. */ - public Serialize(org.postgresql.Connection c, String type) throws SQLException + public Serialize(Connection c, String type) throws SQLException { try { @@ -142,7 +142,7 @@ public class Serialize // Second check, the type must be a table boolean status = false; - ResultSet rs = conn.ExecSQL("select typname from pg_type,pg_class where typname=relname and typname='" + tableName + "'"); + ResultSet rs = ((org.postgresql.jdbc1.AbstractJdbc1Connection)conn).ExecSQL("select typname from pg_type,pg_class where typname=relname and typname='" + tableName + "'"); if (rs != null) { if (rs.next()) @@ -164,7 +164,7 @@ public class Serialize /* * Constructor when Object is passed in */ - public Serialize(org.postgresql.Connection c, Object o) throws SQLException + public Serialize(Connection c, Object o) throws SQLException { this(c, o.getClass().getName()); } @@ -172,7 +172,7 @@ public class Serialize /* * Constructor when Class is passed in */ - public Serialize(org.postgresql.Connection c, Class cls) throws SQLException + public Serialize(Connection c, Class cls) throws SQLException { this(c, cls.getName()); } @@ -221,7 +221,7 @@ public class Serialize sb.append(oid); if (Driver.logDebug) Driver.debug("Serialize.fetch: " + sb.toString()); - ResultSet rs = conn.ExecSQL(sb.toString()); + ResultSet rs = ((org.postgresql.jdbc1.AbstractJdbc1Connection)conn).ExecSQL(sb.toString()); if (rs != null) { @@ -390,7 +390,7 @@ public class Serialize } if (Driver.logDebug) Driver.debug("Serialize.store: " + sb.toString() ); - org.postgresql.ResultSet rs = (org.postgresql.ResultSet) conn.ExecSQL(sb.toString()); + ResultSet rs = ((org.postgresql.jdbc1.AbstractJdbc1Connection)conn).ExecSQL(sb.toString()); // fetch the OID for returning if (update) @@ -403,7 +403,7 @@ public class Serialize else { // new record inserted has new oid; rs should be not null - long newOID = ((org.postgresql.ResultSet)rs).getLastOID(); + long newOID = ((org.postgresql.jdbc1.AbstractJdbc1ResultSet)rs).getLastOID(); rs.close(); // update the java object's oid field if it has the oid field if (hasOID) @@ -472,7 +472,7 @@ public class Serialize * @param o Object to base table on * @exception SQLException on error */ - public static void create(org.postgresql.Connection con, Object o) throws SQLException + public static void create(Connection con, Object o) throws SQLException { create(con, o.getClass()); } @@ -485,7 +485,7 @@ public class Serialize * @param o Class to base table on * @exception SQLException on error */ - public static void create(org.postgresql.Connection con, Class c) throws SQLException + public static void create(Connection con, Class c) throws SQLException { if (c.isInterface()) throw new PSQLException("postgresql.serial.interface"); @@ -493,7 +493,7 @@ public class Serialize // See if the table exists String tableName = toPostgreSQL(c.getName()); - ResultSet rs = con.ExecSQL("select relname from pg_class where relname = '" + tableName + "'"); + ResultSet rs = ((org.postgresql.jdbc1.AbstractJdbc1Connection)con).ExecSQL("select relname from pg_class where relname = '" + tableName + "'"); if ( rs.next() ) { if (Driver.logDebug) Driver.debug("Serialize.create: table " + tableName + " exists, skipping"); @@ -549,7 +549,7 @@ public class Serialize // Now create the table if (Driver.logDebug) Driver.debug("Serialize.create: " + sb ); - con.ExecSQL(sb.toString()); + ((org.postgresql.jdbc1.AbstractJdbc1Connection)con).ExecSQL(sb.toString()); } // This is used to translate between Java primitives and PostgreSQL types.