mirror of
https://github.com/postgres/postgres.git
synced 2025-07-11 10:01:57 +03:00
Peter's Mega-Patch for JDBC...
see README_6.3 for list of changes
This commit is contained in:
@ -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:adrian@hottub.org">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,15 +532,24 @@ 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.
|
||||
*
|
||||
* @return PGlobj class that implements the API
|
||||
* <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 PGlobj getLargeObjectAPI() throws SQLException
|
||||
public Fastpath getFastpathAPI() throws SQLException
|
||||
{
|
||||
return new PGlobj(this);
|
||||
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.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
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()
|
||||
{
|
||||
for(int i=0;i<defaultObjectTypes.length;i++)
|
||||
objectTypes.put(defaultObjectTypes[i][0],defaultObjectTypes[i][1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user