package postgresql; import java.io.*; import java.net.*; import java.sql.*; import java.util.*; import postgresql.Field; import postgresql.fastpath.*; import postgresql.largeobject.*; import postgresql.util.*; /** * $Id: Connection.java,v 1.15 1999/04/11 18:03:00 peter Exp $ * * This abstract class is used by postgresql.Driver to open either the JDBC1 or * JDBC2 versions of the Connection class. * */ public abstract class Connection { // This is the network stream associated with this connection public PG_Stream pg_stream; // This is set by 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; private String PG_PASSWORD; private String PG_DATABASE; private boolean PG_STATUS; 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 protected static final int PG_PROTOCOL_LATEST_MAJOR = 1; protected static final int PG_PROTOCOL_LATEST_MINOR = 0; private static final int SM_DATABASE = 64; private static final int SM_USER = 32; 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(); /** * This is the current date style of the backend */ public int currentDateStyle; /** * This defines the formats for dates, according to the various date styles. * *
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. * *
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; * *
eg:
*
* => show datestyle; * NOTICE: Datestyle is SQL with European conventions * ^^^^^^^^^^^^^^^^^ *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 public SQLWarning firstWarning = null; /** * This is called by Class.forName() from within postgresql.Driver */ public Connection() { } /** * This method actually opens the connection. It is called by Driver. * * @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 * @param database the database to connect to * @param u 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 { // Throw an exception if the user or password properties are missing // This occasionally occurs when the client uses the properties version // of getConnection(), and is a common question on the email lists if(info.getProperty("user")==null) throw new SQLException("The user property is missing. It is mandatory."); if(info.getProperty("password")==null) throw new SQLException("The password property is missing. It is mandatory."); this_driver = d; this_url = new String(url); PG_DATABASE = new String(database); PG_PASSWORD = new String(info.getProperty("password")); PG_USER = new String(info.getProperty("user")); PG_PORT = port; PG_HOST = new String(host); PG_STATUS = CONNECTION_BAD; // Now make the initial connection try { pg_stream = new PG_Stream(host, port); } catch (ConnectException cex) { // Added by Peter Mount
NOTE: This is not part of JDBC, but allows access to * functions on the postgresql backend itself. * *
It is primarily used by the LargeObject API * *
The best way to use this is as follows: * *
* import postgresql.fastpath.*; * ... * Fastpath fp = ((postgresql.Connection)myconn).getFastpathAPI(); ** *
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. * *
NOTE: This is not part of JDBC, but allows access to * functions on the postgresql backend itself. * *
The best way to use this is as follows: * *
* import postgresql.largeobject.*; * ... * LargeObjectManager lo = ((postgresql.Connection)myconn).getLargeObjectAPI(); ** *
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. * *
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. * * In 6.4, this is extended to use the postgresql.util.Serialize class to * allow the Serialization of Java Objects into the database without using * Blobs. Refer to that class for details on how this new feature works. * * @return PGobject for this type, and set to value * @exception SQLException if value is not correct for this type * @see postgresql.util.Serialize */ public Object getObject(String type,String value) throws SQLException { 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 if(o == null) { Serialize ser = new Serialize(this,type); 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. // // This is used to implement the postgresql unique types (like lseg, // point, etc). if(o instanceof String) { // 6.3 style extending PG_Object PGobject obj = null; obj = (PGobject)(Class.forName((String)o).newInstance()); obj.setType(type); obj.setValue(value); return (Object)obj; } else { // If it's an object, it should be an instance of our Serialize class // If so, then call it's fetch method. if(o instanceof Serialize) return ((Serialize)o).fetch(Integer.parseInt(value)); } } catch(SQLException sx) { // rethrow the exception. Done because we capture any others next sx.fillInStackTrace(); throw sx; } catch(Exception ex) { throw new SQLException("Failed to create object for "+type+": "+ex); } // should never be reached return null; } /** * This stores an object into the database. * @param o Object to store * @return OID of the new rectord * @exception SQLException if value is not correct for this type * @see postgresql.util.Serialize */ public int putObject(Object o) throws SQLException { 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 if(x == null) { Serialize ser = new Serialize(this,type); 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 SQLException("The object could not be stored. Check that any tables required have already been created in the database."); } catch(SQLException sx) { // rethrow the exception. Done because we capture any others next sx.fillInStackTrace(); throw sx; } catch(Exception ex) { throw new SQLException("Failed to store object: "+ex); } } /** * This allows client code to add a handler for one of postgresql's * more unique data types. * *
NOTE: This is not part of JDBC, but an extension. * *
The best way to use this is as follows: * *
* ... * ((postgresql.Connection)myconn).addDataType("mytype","my.class.name"); * ... ** *
where myconn is an open Connection to postgresql. * *
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"},
{"line", "postgresql.geometric.PGline"},
{"lseg", "postgresql.geometric.PGlseg"},
{"path", "postgresql.geometric.PGpath"},
{"point", "postgresql.geometric.PGpoint"},
{"polygon", "postgresql.geometric.PGpolygon"},
{"money", "postgresql.util.PGmoney"}
};
// This initialises the objectTypes hashtable
private void initObjectTypes()
{
for(int i=0;i