diff options
author | Peter Mount <peter@retep.org.uk> | 2001-01-18 14:50:15 +0000 |
---|---|---|
committer | Peter Mount <peter@retep.org.uk> | 2001-01-18 14:50:15 +0000 |
commit | 45b5d792afa60ae24d57cdceaaec0e03cf6abb2a (patch) | |
tree | b16cf82d422f6226b4dd6086e836564ce4e1438b /src/interfaces/jdbc/org/postgresql/Connection.java | |
parent | 89ac643964bff695309b66410205593dec4f1a03 (diff) | |
download | postgresql-45b5d792afa60ae24d57cdceaaec0e03cf6abb2a.tar.gz |
Thu Jan 18 12:24:00 GMT 2001 peter@retep.org.uk
- These methods in org.postgresql.jdbc2.ResultSet are now implemented:
getBigDecimal(int) ie: without a scale (why did this get missed?)
getBlob(int)
getCharacterStream(int)
getConcurrency()
getDate(int,Calendar)
getFetchDirection()
getFetchSize()
getTime(int,Calendar)
getTimestamp(int,Calendar)
getType()
NB: Where int represents the column name, the associated version
taking a String were already implemented by calling the int
version.
- These methods no longer throw the not implemented but the new noupdate
error. This is in preparation for the Updateable ResultSet support
which will overide these methods by extending the existing class to
implement that functionality, but needed to show something other than
notimplemented:
cancelRowUpdates()
deleteRow()
- Added new error message into errors.properties "postgresql.noupdate"
This is used by jdbc2.ResultSet when an update method is called and
the ResultSet is not updateable. A new method notUpdateable() has been
added to that class to throw this exception, keeping the binary size
down.
- Added new error message into errors.properties "postgresql.psqlnotimp"
This is used instead of unimplemented when it's a feature in the
backend that is preventing this method from being implemented.
- Removed getKeysetSize() as its not part of the ResultSet API
Thu Jan 18 09:46:00 GMT 2001 peter@retep.org.uk
- Applied modified patch from Richard Bullington-McGuire
<rbulling@microstate.com>. I had to modify it as some of the code
patched now exists in different classes, and some of it actually
patched obsolete code.
Wed Jan 17 10:19:00 GMT 2001 peter@retep.org.uk
- Updated Implementation to include both ANT & JBuilder
- Updated README to reflect the changes since 7.0
- Created jdbc.jpr file which allows JBuilder to be used to edit the
source. JBuilder _CAN_NOT_ be used to compile. You must use ANT for
that. It's only to allow JBuilders syntax checking to improve the
drivers source. Refer to Implementation for more details
Diffstat (limited to 'src/interfaces/jdbc/org/postgresql/Connection.java')
-rw-r--r-- | src/interfaces/jdbc/org/postgresql/Connection.java | 185 |
1 files changed, 104 insertions, 81 deletions
diff --git a/src/interfaces/jdbc/org/postgresql/Connection.java b/src/interfaces/jdbc/org/postgresql/Connection.java index b828a90b6d..3ca464d3ad 100644 --- a/src/interfaces/jdbc/org/postgresql/Connection.java +++ b/src/interfaces/jdbc/org/postgresql/Connection.java @@ -10,7 +10,7 @@ import org.postgresql.largeobject.*; import org.postgresql.util.*; /** - * $Id: Connection.java,v 1.11 2000/12/22 03:08:52 momjian Exp $ + * $Id: Connection.java,v 1.12 2001/01/18 14:50:14 peter Exp $ * * This abstract class is used by org.postgresql.Driver to open either the JDBC1 or * JDBC2 versions of the Connection class. @@ -20,10 +20,10 @@ public abstract class Connection { // This is the network stream associated with this connection public PG_Stream pg_stream; - + // This is set by org.postgresql.Statement.setMaxRows() public int maxrows = 0; // maximum no. of rows; 0 = unlimited - + private String PG_HOST; private int PG_PORT; private String PG_USER; @@ -38,17 +38,17 @@ public abstract class Connection * used. */ private String encoding; - + public boolean CONNECTION_OK = true; public boolean CONNECTION_BAD = false; - + public boolean autoCommit = true; public boolean readOnly = false; - + public Driver this_driver; private String this_url; private String cursor = null; // The positioned update cursor name - + // These are new for v6.3, they determine the current protocol versions // supported by this version of the driver. They are defined in // src/include/libpq/pqcomm.h @@ -59,41 +59,41 @@ public abstract class Connection private static final int SM_OPTIONS = 64; private static final int SM_UNUSED = 64; private static final int SM_TTY = 64; - + private static final int AUTH_REQ_OK = 0; private static final int AUTH_REQ_KRB4 = 1; private static final int AUTH_REQ_KRB5 = 2; private static final int AUTH_REQ_PASSWORD = 3; private static final int AUTH_REQ_CRYPT = 4; - + // New for 6.3, salt value for crypt authorisation private String salt; - + // This is used by Field to cache oid -> names. // It's here, because it's shared across this connection only. // Hence it cannot be static within the Field class, because it would then // be across all connections, which could be to different backends. public Hashtable fieldCache = new Hashtable(); - + // Now handle notices as warnings, so things like "show" now work public SQLWarning firstWarning = null; - + // The PID an cancellation key we get from the backend process public int pid; public int ckey; // This receive_sbuf should be used by the different methods - // that call pg_stream.ReceiveString() in this Connection, so - // so we avoid uneccesary new allocations. + // that call pg_stream.ReceiveString() in this Connection, so + // so we avoid uneccesary new allocations. byte receive_sbuf[] = new byte[8192]; - + /** * This is called by Class.forName() from within org.postgresql.Driver */ public Connection() { } - + /** * This method actually opens the connection. It is called by Driver. * @@ -115,7 +115,7 @@ public abstract class Connection throw new PSQLException("postgresql.con.user"); if(info.getProperty("password")==null) throw new PSQLException("postgresql.con.pass"); - + this_driver = d; this_url = url; PG_DATABASE = database; @@ -137,7 +137,7 @@ public abstract class Connection } catch (IOException e) { throw new PSQLException ("postgresql.con.failed",e); } - + // Now we need to construct and send a startup packet try { @@ -146,13 +146,13 @@ public abstract class Connection pg_stream.SendInteger(PG_PROTOCOL_LATEST_MAJOR,2); pg_stream.SendInteger(PG_PROTOCOL_LATEST_MINOR,2); pg_stream.Send(database.getBytes(),SM_DATABASE); - + // This last send includes the unused fields pg_stream.Send(PG_USER.getBytes(),SM_USER+SM_OPTIONS+SM_UNUSED+SM_TTY); - + // now flush the startup packets to the backend pg_stream.flush(); - + // Now get the response from the backend, either an error message // or an authentication request int areq = -1; // must have a value here @@ -169,11 +169,11 @@ public abstract class Connection // throw new SQLException(pg_stream.ReceiveString (receive_sbuf, 4096, getEncoding())); - + case 'R': // Get the type of request areq = pg_stream.ReceiveIntegerR(4); - + // Get the password salt if there is one if(areq == AUTH_REQ_CRYPT) { byte[] rst = new byte[2]; @@ -182,21 +182,21 @@ public abstract class Connection salt = new String(rst,0,2); DriverManager.println("Salt="+salt); } - + // now send the auth packet switch(areq) { case AUTH_REQ_OK: break; - + case AUTH_REQ_KRB4: DriverManager.println("postgresql: KRB4"); throw new PSQLException("postgresql.con.kerb4"); - + case AUTH_REQ_KRB5: DriverManager.println("postgresql: KRB5"); throw new PSQLException("postgresql.con.kerb5"); - + case AUTH_REQ_PASSWORD: DriverManager.println("postgresql: PASSWORD"); pg_stream.SendInteger(5+PG_PASSWORD.length(),4); @@ -204,7 +204,7 @@ public abstract class Connection pg_stream.SendInteger(0,1); pg_stream.flush(); break; - + case AUTH_REQ_CRYPT: DriverManager.println("postgresql: CRYPT"); String crypted = UnixCrypt.crypt(salt,PG_PASSWORD); @@ -213,21 +213,21 @@ public abstract class Connection pg_stream.SendInteger(0,1); pg_stream.flush(); break; - + default: throw new PSQLException("postgresql.con.auth",new Integer(areq)); } break; - + default: throw new PSQLException("postgresql.con.authfail"); } } while(areq != AUTH_REQ_OK); - + } catch (IOException e) { throw new PSQLException("postgresql.con.failed",e); } - + // As of protocol version 2.0, we should now receive the cancellation key and the pid int beresp = pg_stream.ReceiveChar(); @@ -266,7 +266,7 @@ public abstract class Connection // We also ask the DB for certain properties (i.e. DatabaseEncoding at this time) // firstWarning = null; - + java.sql.ResultSet initrset = ExecSQL("set datestyle to 'ISO'; select getdatabaseencoding()"); String dbEncoding = null; @@ -341,19 +341,19 @@ public abstract class Connection encoding = null; } } - + // Initialise object handling initObjectTypes(); - + // Mark the connection as ok, and cleanup firstWarning = null; PG_STATUS = CONNECTION_OK; } - + // 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. - + /** * This adds a warning to the warning chain. * @param msg message to add @@ -361,15 +361,15 @@ public abstract class Connection public void addWarning(String msg) { DriverManager.println(msg); - + // Add the warning to the chain if(firstWarning!=null) firstWarning.setNextWarning(new SQLWarning(msg)); else firstWarning = new SQLWarning(msg); - + // Now check for some specific messages - + // This is obsolete in 6.5, but I've left it in here so if we need to use this // technique again, we'll know where to place it. // @@ -377,13 +377,13 @@ public abstract class Connection //if(msg.startsWith("NOTICE:") && msg.indexOf("DateStyle")>0) { //// 13 is the length off "DateStyle is " //msg = msg.substring(msg.indexOf("DateStyle is ")+13); - // + // //for(int i=0;i<dateStyles.length;i+=2) //if(msg.startsWith(dateStyles[i])) //currentDateStyle=i+1; // this is the index of the format //} } - + /** * Send a query to the backend. Returns one of the ResultSet * objects. @@ -404,8 +404,10 @@ public abstract class Connection // This will let the driver reuse byte arrays that has already // been allocated instead of allocating new ones in order // to gain performance improvements. - pg_stream.deallocate(); - + // PM 17/01/01: Commented out due to race bug. See comments in + // PG_Stream + //pg_stream.deallocate(); + Field[] fields = null; Vector tuples = new Vector(); byte[] buf = null; @@ -415,7 +417,7 @@ public abstract class Connection int update_count = 1; int insert_oid = 0; SQLException final_error = null; - + // Commented out as the backend can now handle queries // larger than 8K. Peter June 6 2000 //if (sql.length() > 8192) @@ -441,13 +443,13 @@ public abstract class Connection } catch (IOException e) { throw new PSQLException("postgresql.con.ioerror",e); } - + while (!hfr || fqp > 0) { Object tup=null; // holds rows as they are recieved - + int c = pg_stream.ReceiveChar(); - + switch (c) { case 'A': // Asynchronous Notify @@ -464,7 +466,7 @@ public abstract class Connection break; case 'C': // Command Status recv_status = pg_stream.ReceiveString(receive_sbuf,8192,getEncoding()); - + // Now handle the update count correctly. if(recv_status.startsWith("INSERT") || recv_status.startsWith("UPDATE") || recv_status.startsWith("DELETE")) { try { @@ -511,7 +513,7 @@ public abstract class Connection break; case 'I': // Empty Query int t = pg_stream.ReceiveChar(); - + if (t != 0) throw new PSQLException("postgresql.con.garbled"); if (fqp > 0) @@ -538,7 +540,7 @@ public abstract class Connection } if (final_error != null) throw final_error; - + return getResultSet(this, fields, tuples, recv_status, update_count, insert_oid); } } @@ -553,7 +555,7 @@ public abstract class Connection { int nf = pg_stream.ReceiveIntegerR(2), i; Field[] fields = new Field[nf]; - + for (i = 0 ; i < nf ; ++i) { String typname = pg_stream.ReceiveString(receive_sbuf,8192,getEncoding()); @@ -564,7 +566,7 @@ public abstract class Connection } return fields; } - + /** * In SQL, a result table can be retrieved through a cursor that * is named. The current row of a result can be updated or deleted @@ -582,7 +584,7 @@ public abstract class Connection { this.cursor = cursor; } - + /** * getCursorName gets the cursor name. * @@ -593,7 +595,7 @@ public abstract class Connection { return cursor; } - + /** * We are required to bring back certain information by * the DatabaseMetaData class. These functions do that. @@ -607,7 +609,7 @@ public abstract class Connection { return this_url; } - + /** * Method getUserName() brings back the User Name (again, we * saved it) @@ -622,13 +624,13 @@ public abstract class Connection /** * Get the character encoding to use for this connection. - * @return the encoding to use, or <b>null</b> for the + * @return the encoding to use, or <b>null</b> for the * default encoding. */ public String getEncoding() throws SQLException { return encoding; } - + /** * This returns the Fastpath API for the current connection. * @@ -657,10 +659,10 @@ public abstract class Connection fastpath = new Fastpath(this,pg_stream); return fastpath; } - + // This holds a reference to the Fastpath API if already open private Fastpath fastpath = null; - + /** * This returns the LargeObject API for the current connection. * @@ -686,10 +688,10 @@ public abstract class Connection largeobject = new LargeObjectManager(this); return largeobject; } - + // This holds a reference to the LargeObject API if already open private LargeObjectManager largeobject = null; - + /** * This method is used internally to return an object based around * org.postgresql's more unique data types. @@ -713,7 +715,7 @@ public abstract class Connection { try { Object o = objectTypes.get(type); - + // If o is null, then the type is unknown, so check to see if type // is an actual table name. If it does, see if a Class is known that // can handle it @@ -722,7 +724,7 @@ public abstract class Connection objectTypes.put(type,ser); return ser.fetch(Integer.parseInt(value)); } - + // If o is not null, and it is a String, then its a class name that // extends PGobject. // @@ -748,11 +750,11 @@ public abstract class Connection } catch(Exception ex) { throw new PSQLException("postgresql.con.creobj",type,ex); } - + // should never be reached return null; } - + /** * This stores an object into the database. * @param o Object to store @@ -765,7 +767,7 @@ public abstract class Connection try { String type = o.getClass().getName(); Object x = objectTypes.get(type); - + // If x is null, then the type is unknown, so check to see if type // is an actual table name. If it does, see if a Class is known that // can handle it @@ -774,15 +776,15 @@ public abstract class Connection objectTypes.put(type,ser); return ser.store(o); } - + // If it's an object, it should be an instance of our Serialize class // If so, then call it's fetch method. if(x instanceof Serialize) return ((Serialize)x).store(o); - + // Thow an exception because the type is unknown throw new PSQLException("postgresql.con.strobj"); - + } catch(SQLException sx) { // rethrow the exception. Done because we capture any others next sx.fillInStackTrace(); @@ -791,7 +793,7 @@ public abstract class Connection throw new PSQLException("postgresql.con.strobjex",ex); } } - + /** * This allows client code to add a handler for one of org.postgresql's * more unique data types. @@ -816,10 +818,10 @@ public abstract class Connection { objectTypes.put(type,name); } - + // This holds the available types private Hashtable objectTypes = new Hashtable(); - + // This array contains the types that are supported as standard. // // The first entry is the types name on the database, the second @@ -835,25 +837,25 @@ public abstract class Connection {"polygon", "org.postgresql.geometric.PGpolygon"}, {"money", "org.postgresql.util.PGmoney"} }; - + // This initialises the objectTypes hashtable private void initObjectTypes() { for(int i=0;i<defaultObjectTypes.length;i++) objectTypes.put(defaultObjectTypes[i][0],defaultObjectTypes[i][1]); } - + // These are required by other common classes public abstract java.sql.Statement createStatement() throws SQLException; - + /** * This returns a resultset. It must be overridden, so that the correct * version (from jdbc1 or jdbc2) are returned. */ protected abstract java.sql.ResultSet getResultSet(org.postgresql.Connection conn, Field[] fields, Vector tuples, String status, int updateCount,int insertOID) throws SQLException; - + public abstract void close() throws SQLException; - + /** * Overides finalize(). If called, it closes the connection. * @@ -866,12 +868,33 @@ public abstract class Connection { close(); } - + /** * This is an attempt to implement SQL Escape clauses */ public String EscapeSQL(String sql) { - return sql; + //if (DEBUG) { System.out.println ("parseSQLEscapes called"); } + + // If we find a "{d", assume we have a date escape. + // + // Since the date escape syntax is very close to the + // native Postgres date format, we just remove the escape + // delimiters. + // + // This implementation could use some optimization, but it has + // worked in practice for two years of solid use. + int index = sql.indexOf("{d"); + while (index != -1) { + //System.out.println ("escape found at index: " + index); + StringBuffer buf = new StringBuffer(sql); + buf.setCharAt(index, ' '); + buf.setCharAt(index + 1, ' '); + buf.setCharAt(sql.indexOf('}', index), ' '); + sql = new String(buf); + index = sql.indexOf("{d"); + } + //System.out.println ("modified SQL: " + sql); + return sql; } - + } |