summaryrefslogtreecommitdiff
path: root/src/interfaces/jdbc/postgresql/Connection.java
diff options
context:
space:
mode:
authorMarc G. Fournier1998-01-11 21:14:56 +0000
committerMarc G. Fournier1998-01-11 21:14:56 +0000
commitba977c086c01726affcc96219a79584a11ccc78e (patch)
tree209fc13fa5b540fdaf17711a26338ad6a35e6367 /src/interfaces/jdbc/postgresql/Connection.java
parent4bad5be7bc7fa1ea973e0b83046b82f9fd5984c5 (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.java244
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]);
}
}