diff options
author | Marc G. Fournier | 1998-01-11 21:14:56 +0000 |
---|---|---|
committer | Marc G. Fournier | 1998-01-11 21:14:56 +0000 |
commit | ba977c086c01726affcc96219a79584a11ccc78e (patch) | |
tree | 209fc13fa5b540fdaf17711a26338ad6a35e6367 /src/interfaces/jdbc/postgresql/Connection.java | |
parent | 4bad5be7bc7fa1ea973e0b83046b82f9fd5984c5 (diff) |
Peter's Mega-Patch for JDBC...
see README_6.3 for list of changes
Diffstat (limited to 'src/interfaces/jdbc/postgresql/Connection.java')
-rw-r--r-- | src/interfaces/jdbc/postgresql/Connection.java | 244 |
1 files changed, 219 insertions, 25 deletions
diff --git a/src/interfaces/jdbc/postgresql/Connection.java b/src/interfaces/jdbc/postgresql/Connection.java index 09344e1fe08..1c13b520d5b 100644 --- a/src/interfaces/jdbc/postgresql/Connection.java +++ b/src/interfaces/jdbc/postgresql/Connection.java @@ -5,22 +5,21 @@ import java.lang.*; import java.net.*; import java.util.*; import java.sql.*; -import postgresql.*; +import postgresql.fastpath.*; +import postgresql.largeobject.*; +import postgresql.util.*; /** - * @version 1.0 15-APR-1997 - * @author <A HREF="mailto:[email protected]">Adrian Hall</A> - * * A Connection represents a session with a specific database. Within the * context of a Connection, SQL statements are executed and results are * returned. * - * A Connection's database is able to provide information describing + * <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. * - * <B>Note:</B> By default, the Connection automatically commits changes + * <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. * @@ -28,8 +27,12 @@ import postgresql.*; */ public class Connection implements java.sql.Connection { + // This is the network stream associated with this connection protected PG_Stream pg_stream; + // This is set by postgresql.Statement.setMaxRows() + protected int maxrows = 0; // maximum no. of rows; 0 = unlimited + private String PG_HOST; private int PG_PORT; private String PG_USER; @@ -59,7 +62,39 @@ public class Connection implements java.sql.Connection private String cursor = null; // The positioned update cursor name // This is false for US, true for European date formats - protected boolean europeanDates = false; + //protected boolean europeanDates = false; + + /** + * This is the current date style of the backend + */ + protected int currentDateStyle; + + /** + * This defines the formats for dates, according to the various date styles. + * + * <p>There are two strings for each entry. The first is the string to search + * for in the datestyle message, and the second the format to use. + * + * <p>To add a new date style, work out the format. Then with psql running + * in the date style you wish to add, type: show datestyle; + * + * <p>eg: + * <br><pre> + * => show datestyle; + * NOTICE: Datestyle is SQL with European conventions + * ^^^^^^^^^^^^^^^^^ + * </pre>The marked part of the string is the first string below. The second + * is your format. If a style (like ISO) ignores the US/European variants, + * then you can ignore the "with" part of the string. + */ + protected static final String dateStyles[] = { + "Postgres with European", "dd-MM-yyyy", + "Postgres with US", "MM-dd-yyyy", + "ISO", "yyyy-MM-dd", + "SQL with European", "dd/MM/yyyy", + "SQL with US", "MM/dd/yyyy", + "German", "dd.MM.yyyy" + }; // Now handle notices as warnings, so things like "show" now work protected SQLWarning firstWarning = null; @@ -67,6 +102,13 @@ public class Connection implements java.sql.Connection /** * Connect to a PostgreSQL database back end. * + * <p><b>Important Notice</b> + * + * <br>Although this will connect to the database, user code should open + * the connection via the DriverManager.getConnection() methods only. + * + * <br>This should only be called from the postgresql.Driver class. + * * @param host the hostname of the database back end * @param port the port number of the postmaster process * @param info a Properties[] thing of the user and password @@ -108,6 +150,7 @@ public class Connection implements java.sql.Connection STARTUP_CODE=STARTUP_USER; } + // Now make the initial connection try { pg_stream = new PG_Stream(host, port); @@ -148,6 +191,9 @@ public class Connection implements java.sql.Connection clearWarnings(); ExecSQL("show datestyle"); + // Initialise object handling + initObjectTypes(); + // Mark the connection as ok, and cleanup clearWarnings(); PG_STATUS = CONNECTION_OK; @@ -468,10 +514,15 @@ public class Connection implements java.sql.Connection // ********************************************************** /** - * This adds a warning to the warning chain + * This adds a warning to the warning chain. + * @param msg message to add */ public void addWarning(String msg) { + //PrintStream log = DriverManager.getLogStream(); + //if(log!=null) + DriverManager.println(msg); + // Add the warning to the chain if(firstWarning!=null) firstWarning.setNextWarning(new SQLWarning(msg)); @@ -481,16 +532,25 @@ public class Connection implements java.sql.Connection // Now check for some specific messages // This is generated by the SQL "show datestyle" - if(msg.startsWith("NOTICE:DateStyle")) { - if(msg.indexOf("with US")==-1) - europeanDates=true; - else - europeanDates=false; - System.err.println("europeanDates="+europeanDates); + 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 } } /** + * @return the date format for the current date style of the backend + */ + public String getDateStyle() + { + return dateStyles[currentDateStyle]; + } + + /** * Send a query to the backend. Returns one of the ResultSet * objects. * @@ -525,6 +585,8 @@ public class Connection implements java.sql.Connection while (!hfr || fqp > 0) { + Object tup=null; // holds rows as they are recieved + int c = pg_stream.ReceiveChar(); switch (c) @@ -536,7 +598,10 @@ public class Connection implements java.sql.Connection case 'B': // Binary Data Transfer if (fields == null) throw new SQLException("Tuple received before MetaData"); - tuples.addElement(pg_stream.ReceiveTuple(fields.length, true)); + tup = pg_stream.ReceiveTuple(fields.length, true); + // This implements Statement.setMaxRows() + if(maxrows==0 || tuples.size()<maxrows) + tuples.addElement(tup); break; case 'C': // Command Status recv_status = pg_stream.ReceiveString(8192); @@ -558,7 +623,10 @@ public class Connection implements java.sql.Connection case 'D': // Text Data Transfer if (fields == null) throw new SQLException("Tuple received before MetaData"); - tuples.addElement(pg_stream.ReceiveTuple(fields.length, false)); + tup = pg_stream.ReceiveTuple(fields.length, false); + // This implements Statement.setMaxRows() + if(maxrows==0 || tuples.size()<maxrows) + tuples.addElement(tup); break; case 'E': // Error Message msg = pg_stream.ReceiveString(4096); @@ -576,10 +644,7 @@ public class Connection implements java.sql.Connection hfr = true; break; case 'N': // Error Notification - msg = pg_stream.ReceiveString(4096); - PrintStream log = DriverManager.getLogStream(); - if(log!=null) log.println(msg); - addWarning(msg); + addWarning(pg_stream.ReceiveString(4096)); break; case 'P': // Portal Name String pname = pg_stream.ReceiveString(8192); @@ -675,14 +740,143 @@ public class Connection implements java.sql.Connection } /** - * This method is not part of the Connection interface. Its is an extension - * that allows access to the PostgreSQL Large Object API + * This returns the Fastpath API for the current connection. + * + * <p><b>NOTE:</b> This is not part of JDBC, but allows access to + * functions on the postgresql backend itself. + * + * <p>It is primarily used by the LargeObject API + * + * <p>The best way to use this is as follows: + * + * <p><pre> + * import postgresql.fastpath.*; + * ... + * Fastpath fp = ((postgresql.Connection)myconn).getFastpathAPI(); + * </pre> + * + * <p>where myconn is an open Connection to postgresql. + * + * @return Fastpath object allowing access to functions on the postgresql + * backend. + * @exception SQLException by Fastpath when initialising for first time + */ + public Fastpath getFastpathAPI() throws SQLException + { + if(fastpath==null) + 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. + * + * <p><b>NOTE:</b> This is not part of JDBC, but allows access to + * functions on the postgresql backend itself. + * + * <p>The best way to use this is as follows: + * + * <p><pre> + * import postgresql.largeobject.*; + * ... + * LargeObjectManager lo = ((postgresql.Connection)myconn).getLargeObjectAPI(); + * </pre> + * + * <p>where myconn is an open Connection to postgresql. + * + * @return LargeObject object that implements the API + * @exception SQLException by LargeObject when initialising for first time + */ + public LargeObjectManager getLargeObjectAPI() throws SQLException + { + if(largeobject==null) + 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 + * 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 postgresql.util.PGobject + * is returned. * - * @return PGlobj class that implements the API + * 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 */ - public PGlobj getLargeObjectAPI() throws SQLException + protected PGobject getObject(String type,String value) throws SQLException + { + PGobject obj = null; + try { + String name = (String)objectTypes.get(type); + obj = (PGobject)(Class.forName(name==null?"postgresql.util.PGobject":name).newInstance()); + } catch(Exception ex) { + throw new SQLException("Failed to create object for "+type+": "+ex); + } + if(obj!=null) { + obj.setType(type); + obj.setValue(value); + } + return obj; + } + + /** + * This allows client code to add a handler for one of postgresql's + * more unique data types. + * + * <p><b>NOTE:</b> This is not part of JDBC, but an extension. + * + * <p>The best way to use this is as follows: + * + * <p><pre> + * ... + * ((postgresql.Connection)myconn).addDataType("mytype","my.class.name"); + * ... + * </pre> + * + * <p>where myconn is an open Connection to postgresql. + * + * <p>The handling class must extend postgresql.util.PGobject + * + * @see postgresql.util.PGobject + */ + public void addDataType(String type,String name) + { + 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 + // the full class name of the handling class. + // + private static final String defaultObjectTypes[][] = { + {"box", "postgresql.geometric.PGbox"}, + {"circle", "postgresql.geometric.PGcircle"}, + {"lseg", "postgresql.geometric.PGlseg"}, + {"path", "postgresql.geometric.PGpath"}, + {"point", "postgresql.geometric.PGpoint"}, + {"polygon", "postgresql.geometric.PGpolygon"} + }; + + // This initialises the objectTypes hashtable + private void initObjectTypes() { - return new PGlobj(this); + for(int i=0;i<defaultObjectTypes.length;i++) + objectTypes.put(defaultObjectTypes[i][0],defaultObjectTypes[i][1]); } } |