
Modified Files: jdbc/org/postgresql/Driver.java.in jdbc/org/postgresql/jdbc1/AbstractJdbc1Connection.java jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java jdbc/org/postgresql/jdbc1/Jdbc1Connection.java jdbc/org/postgresql/jdbc1/Jdbc1ResultSet.java jdbc/org/postgresql/jdbc2/Jdbc2Connection.java jdbc/org/postgresql/jdbc2/Jdbc2ResultSet.java Added Files: jdbc/org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSetMetaData.java jdbc/org/postgresql/jdbc1/Jdbc1DatabaseMetaData.java jdbc/org/postgresql/jdbc1/Jdbc1ResultSetMetaData.java jdbc/org/postgresql/jdbc2/AbstractJdbc2DatabaseMetaData.java jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSetMetaData.java jdbc/org/postgresql/jdbc2/Jdbc2DatabaseMetaData.java jdbc/org/postgresql/jdbc2/Jdbc2ResultSetMetaData.java Removed Files: jdbc/org/postgresql/jdbc1/DatabaseMetaData.java jdbc/org/postgresql/jdbc1/ResultSetMetaData.java jdbc/org/postgresql/jdbc2/DatabaseMetaData.java jdbc/org/postgresql/jdbc2/ResultSetMetaData.java
448 lines
13 KiB
Java
448 lines
13 KiB
Java
package org.postgresql;
|
|
|
|
import java.sql.*;
|
|
import java.util.*;
|
|
|
|
import org.postgresql.util.PSQLException;
|
|
|
|
/*
|
|
* The Java SQL framework allows for multiple database drivers. Each
|
|
* driver should supply a class that implements the Driver interface
|
|
*
|
|
* <p>The DriverManager will try to load as many drivers as it can find and
|
|
* then for any given connection request, it will ask each driver in turn
|
|
* to try to connect to the target URL.
|
|
*
|
|
* <p>It is strongly recommended that each Driver class should be small and
|
|
* standalone so that the Driver class can be loaded and queried without
|
|
* bringing in vast quantities of supporting code.
|
|
*
|
|
* <p>When a Driver class is loaded, it should create an instance of itself
|
|
* and register it with the DriverManager. This means that a user can load
|
|
* and register a driver by doing Class.forName("foo.bah.Driver")
|
|
*
|
|
* @see org.postgresql.Connection
|
|
* @see java.sql.Driver
|
|
*/
|
|
public class Driver implements java.sql.Driver
|
|
{
|
|
|
|
// make these public so they can be used in setLogLevel below
|
|
|
|
public static final int DEBUG = 2;
|
|
public static final int INFO = 1;
|
|
public static boolean logDebug = false;
|
|
public static boolean logInfo = false;
|
|
|
|
static
|
|
{
|
|
try
|
|
{
|
|
// moved the registerDriver from the constructor to here
|
|
// because some clients call the driver themselves (I know, as
|
|
// my early jdbc work did - and that was based on other examples).
|
|
// Placing it here, means that the driver is registered once only.
|
|
java.sql.DriverManager.registerDriver(new Driver());
|
|
}
|
|
catch (SQLException e)
|
|
{
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Try to make a database connection to the given URL. The driver
|
|
* should return "null" if it realizes it is the wrong kind of
|
|
* driver to connect to the given URL. This will be common, as
|
|
* when the JDBC driverManager is asked to connect to a given URL,
|
|
* it passes the URL to each loaded driver in turn.
|
|
*
|
|
* <p>The driver should raise an SQLException if it is the right driver
|
|
* to connect to the given URL, but has trouble connecting to the
|
|
* database.
|
|
*
|
|
* <p>The java.util.Properties argument can be used to pass arbitrary
|
|
* string tag/value pairs as connection arguments.
|
|
*
|
|
* user - (optional) The user to connect as
|
|
* password - (optional) The password for the user
|
|
* charSet - (optional) The character set to be used for converting
|
|
* to/from the database to unicode. If multibyte is enabled on the
|
|
* server then the character set of the database is used as the default,
|
|
* otherwise the jvm character encoding is used as the default.
|
|
* loglevel - (optional) Enable logging of messages from the driver.
|
|
* The value is an integer from 1 to 2 where:
|
|
* INFO = 1, DEBUG = 2
|
|
* The output is sent to DriverManager.getPrintWriter() if set,
|
|
* otherwise it is sent to System.out.
|
|
* compatible - (optional) This is used to toggle
|
|
* between different functionality as it changes across different releases
|
|
* of the jdbc driver code. The values here are versions of the jdbc
|
|
* client and not server versions. For example in 7.1 get/setBytes
|
|
* worked on LargeObject values, in 7.2 these methods were changed
|
|
* to work on bytea values. This change in functionality could
|
|
* be disabled by setting the compatible level to be "7.1", in
|
|
* which case the driver will revert to the 7.1 functionality.
|
|
*
|
|
* <p>Normally, at least
|
|
* "user" and "password" properties should be included in the
|
|
* properties. For a list of supported
|
|
* character encoding , see
|
|
* http://java.sun.com/products/jdk/1.2/docs/guide/internat/encoding.doc.html
|
|
* Note that you will probably want to have set up the Postgres database
|
|
* itself to use the same encoding, with the "-E <encoding>" argument
|
|
* to createdb.
|
|
*
|
|
* Our protocol takes the forms:
|
|
* <PRE>
|
|
* jdbc:org.postgresql://host:port/database?param1=val1&...
|
|
* </PRE>
|
|
*
|
|
* @param url the URL of the database to connect to
|
|
* @param info a list of arbitrary tag/value pairs as connection
|
|
* arguments
|
|
* @return a connection to the URL or null if it isnt us
|
|
* @exception SQLException if a database access error occurs
|
|
* @see java.sql.Driver#connect
|
|
*/
|
|
public java.sql.Connection connect(String url, Properties info) throws SQLException
|
|
{
|
|
if ((props = parseURL(url, info)) == null)
|
|
{
|
|
if (Driver.logDebug) Driver.debug("Error in url" + url);
|
|
return null;
|
|
}
|
|
try
|
|
{
|
|
if (Driver.logDebug) Driver.debug("connect " + url);
|
|
|
|
@JDBCCONNECTCLASS@ con = (@JDBCCONNECTCLASS@)(Class.forName("@JDBCCONNECTCLASS@").newInstance());
|
|
con.openConnection (host(), port(), props, database(), url, this);
|
|
return (java.sql.Connection)con;
|
|
}
|
|
catch (ClassNotFoundException ex)
|
|
{
|
|
if (Driver.logDebug) Driver.debug("error", ex);
|
|
throw new PSQLException("postgresql.jvm.version", ex);
|
|
}
|
|
catch (PSQLException ex1)
|
|
{
|
|
// re-throw the exception, otherwise it will be caught next, and a
|
|
// org.postgresql.unusual error will be returned instead.
|
|
throw ex1;
|
|
}
|
|
catch (Exception ex2)
|
|
{
|
|
if (Driver.logDebug) Driver.debug("error", ex2);
|
|
throw new PSQLException("postgresql.unusual", ex2);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Returns true if the driver thinks it can open a connection to the
|
|
* given URL. Typically, drivers will return true if they understand
|
|
* the subprotocol specified in the URL and false if they don't. Our
|
|
* protocols start with jdbc:org.postgresql:
|
|
*
|
|
* @see java.sql.Driver#acceptsURL
|
|
* @param url the URL of the driver
|
|
* @return true if this driver accepts the given URL
|
|
* @exception SQLException if a database-access error occurs
|
|
* (Dont know why it would *shrug*)
|
|
*/
|
|
public boolean acceptsURL(String url) throws SQLException
|
|
{
|
|
if (parseURL(url, null) == null)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* The getPropertyInfo method is intended to allow a generic GUI
|
|
* tool to discover what properties it should prompt a human for
|
|
* in order to get enough information to connect to a database.
|
|
*
|
|
* <p>Note that depending on the values the human has supplied so
|
|
* far, additional values may become necessary, so it may be necessary
|
|
* to iterate through several calls to getPropertyInfo
|
|
*
|
|
* @param url the Url of the database to connect to
|
|
* @param info a proposed list of tag/value pairs that will be sent on
|
|
* connect open.
|
|
* @return An array of DriverPropertyInfo objects describing
|
|
* possible properties. This array may be an empty array if
|
|
* no properties are required
|
|
* @exception SQLException if a database-access error occurs
|
|
* @see java.sql.Driver#getPropertyInfo
|
|
*/
|
|
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException
|
|
{
|
|
//This method isn't really implemented
|
|
Properties p = parseURL(url, info);
|
|
return new DriverPropertyInfo[0];
|
|
}
|
|
|
|
/*
|
|
* Gets the drivers major version number
|
|
*
|
|
* @return the drivers major version number
|
|
*/
|
|
public int getMajorVersion()
|
|
{
|
|
return @MAJORVERSION@;
|
|
}
|
|
|
|
/*
|
|
* Get the drivers minor version number
|
|
*
|
|
* @return the drivers minor version number
|
|
*/
|
|
public int getMinorVersion()
|
|
{
|
|
return @MINORVERSION@;
|
|
}
|
|
|
|
/*
|
|
* Returns the VERSION variable from Makefile.global
|
|
*/
|
|
public static String getVersion()
|
|
{
|
|
return "@VERSION@ jdbc driver build " + m_buildNumber;
|
|
}
|
|
|
|
/*
|
|
* Report whether the driver is a genuine JDBC compliant driver. A
|
|
* driver may only report "true" here if it passes the JDBC compliance
|
|
* tests, otherwise it is required to return false. JDBC compliance
|
|
* requires full support for the JDBC API and full support for SQL 92
|
|
* Entry Level.
|
|
*
|
|
* <p>For PostgreSQL, this is not yet possible, as we are not SQL92
|
|
* compliant (yet).
|
|
*/
|
|
public boolean jdbcCompliant()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
private Properties props;
|
|
|
|
static private String[] protocols = { "jdbc", "postgresql" };
|
|
|
|
/*
|
|
* Constructs a new DriverURL, splitting the specified URL into its
|
|
* component parts
|
|
* @param url JDBC URL to parse
|
|
* @param defaults Default properties
|
|
* @return Properties with elements added from the url
|
|
* @exception SQLException
|
|
*/
|
|
Properties parseURL(String url, Properties defaults) throws SQLException
|
|
{
|
|
int state = -1;
|
|
Properties urlProps = new Properties(defaults);
|
|
String key = "";
|
|
String value = "";
|
|
|
|
StringTokenizer st = new StringTokenizer(url, ":/;=&?", true);
|
|
for (int count = 0; (st.hasMoreTokens()); count++)
|
|
{
|
|
String token = st.nextToken();
|
|
|
|
// PM Aug 2 1997 - Modified to allow multiple backends
|
|
if (count <= 3)
|
|
{
|
|
if ((count % 2) == 1 && token.equals(":"))
|
|
;
|
|
else if ((count % 2) == 0)
|
|
{
|
|
boolean found = (count == 0) ? true : false;
|
|
for (int tmp = 0;tmp < protocols.length;tmp++)
|
|
{
|
|
if (token.equals(protocols[tmp]))
|
|
{
|
|
// PM June 29 1997 Added this property to enable the driver
|
|
// to handle multiple backend protocols.
|
|
if (count == 2 && tmp > 0)
|
|
{
|
|
urlProps.put("Protocol", token);
|
|
found = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (found == false)
|
|
return null;
|
|
}
|
|
else
|
|
return null;
|
|
}
|
|
else if (count > 3)
|
|
{
|
|
if (count == 4 && token.equals("/"))
|
|
state = 0;
|
|
else if (count == 4)
|
|
{
|
|
urlProps.put("PGDBNAME", token);
|
|
state = -2;
|
|
}
|
|
else if (count == 5 && state == 0 && token.equals("/"))
|
|
state = 1;
|
|
else if (count == 5 && state == 0)
|
|
return null;
|
|
else if (count == 6 && state == 1)
|
|
urlProps.put("PGHOST", token);
|
|
else if (count == 7 && token.equals(":"))
|
|
state = 2;
|
|
else if (count == 8 && state == 2)
|
|
{
|
|
try
|
|
{
|
|
Integer portNumber = Integer.decode(token);
|
|
urlProps.put("PGPORT", portNumber.toString());
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
else if ((count == 7 || count == 9) &&
|
|
(state == 1 || state == 2) && token.equals("/"))
|
|
state = -1;
|
|
else if (state == -1)
|
|
{
|
|
urlProps.put("PGDBNAME", token);
|
|
state = -2;
|
|
}
|
|
else if (state <= -2 && (count % 2) == 1)
|
|
{
|
|
// PM Aug 2 1997 - added tests for ? and &
|
|
if (token.equals(";") || token.equals("?") || token.equals("&") )
|
|
state = -3;
|
|
else if (token.equals("="))
|
|
state = -5;
|
|
}
|
|
else if (state <= -2 && (count % 2) == 0)
|
|
{
|
|
if (state == -3)
|
|
key = token;
|
|
else if (state == -5)
|
|
{
|
|
value = token;
|
|
urlProps.put(key, value);
|
|
state = -2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return urlProps;
|
|
|
|
}
|
|
|
|
/*
|
|
* @return the hostname portion of the URL
|
|
*/
|
|
public String host()
|
|
{
|
|
return props.getProperty("PGHOST", "localhost");
|
|
}
|
|
|
|
/*
|
|
* @return the port number portion of the URL or the default if no port was specified
|
|
*/
|
|
public int port()
|
|
{
|
|
return Integer.parseInt(props.getProperty("PGPORT", "@DEF_PGPORT@"));
|
|
}
|
|
|
|
/*
|
|
* @return the database name of the URL
|
|
*/
|
|
public String database()
|
|
{
|
|
return props.getProperty("PGDBNAME", "");
|
|
}
|
|
|
|
/*
|
|
* @return the value of any property specified in the URL or properties
|
|
* passed to connect(), or null if not found.
|
|
*/
|
|
public String property(String name)
|
|
{
|
|
return props.getProperty(name);
|
|
}
|
|
|
|
/*
|
|
* This method was added in v6.5, and simply throws an SQLException
|
|
* for an unimplemented method. I decided to do it this way while
|
|
* implementing the JDBC2 extensions to JDBC, as it should help keep the
|
|
* overall driver size down.
|
|
*/
|
|
public static SQLException notImplemented()
|
|
{
|
|
return new PSQLException("postgresql.unimplemented");
|
|
}
|
|
|
|
/**
|
|
* used to turn logging on to a certain level, can be called
|
|
* by specifying fully qualified class ie org.postgresql.Driver.setLogLevel()
|
|
* @param int logLevel sets the level which logging will respond to
|
|
* INFO being almost no messages
|
|
* DEBUG most verbose
|
|
*/
|
|
public static void setLogLevel(int logLevel)
|
|
{
|
|
logDebug = (logLevel >= DEBUG) ? true : false;
|
|
logInfo = (logLevel >= INFO) ? true : false;
|
|
}
|
|
/*
|
|
* logging message at the debug level
|
|
* messages will be printed if the logging level is less or equal to DEBUG
|
|
*/
|
|
public static void debug(String msg)
|
|
{
|
|
if (logDebug)
|
|
{
|
|
DriverManager.println(msg);
|
|
}
|
|
}
|
|
/*
|
|
* logging message at the debug level
|
|
* messages will be printed if the logging level is less or equal to DEBUG
|
|
*/
|
|
public static void debug(String msg, Exception ex)
|
|
{
|
|
if (logDebug)
|
|
{
|
|
DriverManager.println(msg + ex != null ? ex.getMessage() : "null Exception");
|
|
}
|
|
}
|
|
/*
|
|
* logging message at info level
|
|
* messages will be printed if the logging level is less or equal to INFO
|
|
*/
|
|
public static void info(String msg)
|
|
{
|
|
if (logInfo)
|
|
{
|
|
DriverManager.println(msg);
|
|
}
|
|
}
|
|
/*
|
|
* logging message at info level
|
|
* messages will be printed if the logging level is less or equal to INFO
|
|
*/
|
|
public static void info(String msg, Exception ex)
|
|
{
|
|
if (logInfo)
|
|
{
|
|
DriverManager.println(msg + ex != null ? ex.getMessage() : "null Exception");
|
|
}
|
|
}
|
|
|
|
//The build number should be incremented for every new build
|
|
private static int m_buildNumber = 103;
|
|
|
|
}
|