Commit f37c1c48 authored by Bruce Momjian's avatar Bruce Momjian

Run pgjindent for Java folks.

parent b4295d05
......@@ -233,7 +233,7 @@ public class Unicode
catch (ClassNotFoundException cnfe)
{
log("Unable to load driver", cnfe);
return;
return ;
}
try
{
......
......@@ -6,7 +6,7 @@ import java.text.*;
/*
*
* $Id: basic.java,v 1.12 2002/07/23 03:59:54 barry Exp $
* $Id: basic.java,v 1.13 2002/09/06 21:23:05 momjian Exp $
*
* This example tests the basic components of the JDBC driver, and shows
* how even the simplest of queries can be implemented.
......@@ -137,6 +137,7 @@ public class basic
// result if you don't know what column number a value is in
System.out.println("performing another query");
rs = st.executeQuery("select * from basic where b>1");
if (rs != null)
......@@ -164,6 +165,7 @@ public class basic
// Now test maxrows by setting it to 3 rows
st.setMaxRows(3);
System.out.println("performing a query limited to " + st.getMaxRows());
rs = st.executeQuery("select a, b from basic");
......
......@@ -9,7 +9,7 @@ import org.omg.CosNaming.*;
*
* It has no GUI, just a text frontend to keep it simple.
*
* $Id: StockClient.java,v 1.5 2001/11/19 23:19:20 momjian Exp $
* $Id: StockClient.java,v 1.6 2002/09/06 21:23:05 momjian Exp $
*/
public class StockClient
{
......@@ -35,14 +35,14 @@ public class StockClient
if (nameServiceObj == null)
{
System.err.println("nameServiceObj == null");
return;
return ;
}
nameService = org.omg.CosNaming.NamingContextHelper.narrow(nameServiceObj);
if (nameService == null)
{
System.err.println("nameService == null");
return;
return ;
}
// Resolve the dispenser
......@@ -53,7 +53,7 @@ public class StockClient
if (dispenser == null)
{
System.err.println("dispenser == null");
return;
return ;
}
// Now run the front end.
......
......@@ -5,7 +5,7 @@ import org.omg.CosNaming.*;
/*
* This class implements the server side of the example.
*
* $Id: StockDispenserImpl.java,v 1.4 2001/11/19 23:19:20 momjian Exp $
* $Id: StockDispenserImpl.java,v 1.5 2002/09/06 21:23:05 momjian Exp $
*/
public class StockDispenserImpl extends stock._StockDispenserImplBase
{
......@@ -67,11 +67,11 @@ public class StockDispenserImpl extends stock._StockDispenserImplBase
{
stock[i].inUse = false;
System.out.println("Releasing slot " + i);
return;
return ;
}
}
System.out.println("Reserved object not a member of this dispenser");
return;
return ;
}
/*
......
......@@ -5,7 +5,7 @@ import org.omg.CosNaming.*;
/*
* This class implements the server side of the example.
*
* $Id: StockServer.java,v 1.4 2001/11/19 23:19:20 momjian Exp $
* $Id: StockServer.java,v 1.5 2002/09/06 21:23:05 momjian Exp $
*/
public class StockServer
{
......@@ -29,14 +29,14 @@ public class StockServer
if (nameServiceObj == null)
{
System.err.println("nameServiceObj = null");
return;
return ;
}
org.omg.CosNaming.NamingContext nameService = org.omg.CosNaming.NamingContextHelper.narrow(nameServiceObj);
if (nameService == null)
{
System.err.println("nameService = null");
return;
return ;
}
// bind the dispenser into the naming service
......
......@@ -82,7 +82,7 @@ public class psql
if (line.startsWith("\\"))
{
processSlashCommand(line);
return;
return ;
}
boolean type = st.execute(line);
......
......@@ -31,8 +31,8 @@ public class Driver implements java.sql.Driver
public static final int DEBUG = 2;
public static final int INFO = 1;
public static boolean logDebug = false;
public static boolean logInfo = false;
public static boolean logDebug = false;
public static boolean logInfo = false;
static
{
......@@ -70,11 +70,11 @@ public class Driver implements java.sql.Driver
* 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.
* 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
......@@ -109,12 +109,14 @@ public class Driver implements java.sql.Driver
{
if ((props = parseURL(url, info)) == null)
{
if (Driver.logDebug) Driver.debug("Error in url" + url);
if (Driver.logDebug)
Driver.debug("Error in url" + url);
return null;
}
try
{
if (Driver.logDebug) Driver.debug("connect " + url);
if (Driver.logDebug)
Driver.debug("connect " + url);
@JDBCCONNECTCLASS@ con = (@JDBCCONNECTCLASS@)(Class.forName("@JDBCCONNECTCLASS@").newInstance());
con.openConnection (host(), port(), props, database(), url, this);
......@@ -122,7 +124,8 @@ public class Driver implements java.sql.Driver
}
catch (ClassNotFoundException ex)
{
if (Driver.logDebug) Driver.debug("error", ex);
if (Driver.logDebug)
Driver.debug("error", ex);
throw new PSQLException("postgresql.jvm.version", ex);
}
catch (PSQLException ex1)
......@@ -133,7 +136,8 @@ public class Driver implements java.sql.Driver
}
catch (Exception ex2)
{
if (Driver.logDebug) Driver.debug("error", ex2);
if (Driver.logDebug)
Driver.debug("error", ex2);
throw new PSQLException("postgresql.unusual", ex2);
}
}
......@@ -177,7 +181,7 @@ public class Driver implements java.sql.Driver
*/
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException
{
//This method isn't really implemented
//This method isn't really implemented
Properties p = parseURL(url, info);
return new DriverPropertyInfo[0];
}
......@@ -385,16 +389,16 @@ public class Driver implements java.sql.Driver
}
/**
* used to turn logging on to a certain level, can be called
* 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
* INFO being almost no messages
* DEBUG most verbose
*/
public static void setLogLevel(int logLevel)
{
logDebug = (logLevel >= DEBUG) ? true : false;
logInfo = (logLevel >= INFO) ? true : false;
logDebug = (logLevel >= DEBUG) ? true : false;
logInfo = (logLevel >= INFO) ? true : false;
}
/*
* logging message at the debug level
......@@ -441,7 +445,7 @@ public class Driver implements java.sql.Driver
}
}
//The build number should be incremented for every new build
private static int m_buildNumber = 104;
//The build number should be incremented for every new build
private static int m_buildNumber = 104;
}
......@@ -7,74 +7,74 @@ import org.postgresql.core.Encoding;
import org.postgresql.fastpath.Fastpath;
import org.postgresql.largeobject.LargeObjectManager;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/Attic/PGConnection.java,v 1.2 2002/09/02 03:07:36 barry Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/Attic/PGConnection.java,v 1.3 2002/09/06 21:23:05 momjian Exp $
* This interface defines PostgreSQL extentions to the java.sql.Connection interface.
* Any java.sql.Connection object returned by the driver will also implement this
* Any java.sql.Connection object returned by the driver will also implement this
* interface
*/
public interface PGConnection
{
/*
* Get the character encoding to use for this connection.
*/
public Encoding getEncoding() throws SQLException;
/*
* Get the character encoding to use for this connection.
*/
public Encoding getEncoding() throws SQLException;
/*
* This method returns the java.sql.Types type for a postgres datatype name
*/
public int getSQLType(String pgTypeName) throws SQLException;
/*
* This method returns the java.sql.Types type for a postgres datatype name
*/
public int getSQLType(String pgTypeName) throws SQLException;
/*
* This returns the java.sql.Types type for a postgres datatype OID
*/
public int getSQLType(int oid) throws SQLException;
/*
* This returns the java.sql.Types type for a postgres datatype OID
*/
public int getSQLType(int oid) throws SQLException;
/*
* This returns the postgres datatype name from the
* postgres datatype OID
*/
public String getPGType(int oid) throws SQLException;
/*
* This returns the postgres datatype name from the
* postgres datatype OID
*/
public String getPGType(int oid) throws SQLException;
/*
* This returns the postgres datatype OID from the
* postgres datatype name
*/
public int getPGType(String typeName) throws SQLException;
/*
* This returns the postgres datatype OID from the
* postgres datatype name
*/
public int getPGType(String typeName) throws SQLException;
/*
* This returns the LargeObject API for the current connection.
*/
public LargeObjectManager getLargeObjectAPI() throws SQLException;
/*
* This returns the LargeObject API for the current connection.
*/
public LargeObjectManager getLargeObjectAPI() throws SQLException;
/*
* This returns the Fastpath API for the current connection.
*/
public Fastpath getFastpathAPI() throws SQLException;
/*
* This returns the Fastpath API for the current connection.
*/
public Fastpath getFastpathAPI() throws SQLException;
/*
* This method is used internally to return an object based around
* org.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 org.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
* @see org.postgresql.util.Serialize
*/
public Object getObject(String type, String value) throws SQLException;
/*
* This method is used internally to return an object based around
* org.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 org.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
* @see org.postgresql.util.Serialize
*/
public Object getObject(String type, String value) throws SQLException;
/*
* This method returns any notifications that have been received
* since the last call to this method.
* Returns null if there have been no notifications.
*/
public PGNotification[] getNotifications();
/*
* This method returns any notifications that have been received
* since the last call to this method.
* Returns null if there have been no notifications.
*/
public PGNotification[] getNotifications();
}
......
package org.postgresql;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/Attic/PGNotification.java,v 1.1 2002/09/02 03:07:36 barry Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/Attic/PGNotification.java,v 1.2 2002/09/06 21:23:05 momjian Exp $
* This interface defines PostgreSQL extention for Notifications
*/
public interface PGNotification
{
/*
* Returns name of this notification
*/
public String getName();
/*
* Returns name of this notification
*/
public String getName();
/*
* Returns the process id of the backend process making this notification
*/
public int getPID();
/*
* Returns the process id of the backend process making this notification
*/
public int getPID();
}
......@@ -3,23 +3,23 @@ package org.postgresql;
import java.sql.*;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/Attic/PGStatement.java,v 1.4 2002/09/02 03:07:36 barry Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/Attic/PGStatement.java,v 1.5 2002/09/06 21:23:05 momjian Exp $
* This interface defines PostgreSQL extentions to the java.sql.Statement interface.
* Any java.sql.Statement object returned by the driver will also implement this
* Any java.sql.Statement object returned by the driver will also implement this
* interface
*/
public interface PGStatement
{
/*
* Returns the Last inserted/updated oid.
* Returns the Last inserted/updated oid.
* @return OID of last insert
* @since 7.3
* @since 7.3
*/
public long getLastOID() throws SQLException;
public long getLastOID() throws SQLException;
public void setUseServerPrepare(boolean flag);
public void setUseServerPrepare(boolean flag);
public boolean isUseServerPrepare();
public boolean isUseServerPrepare();
}
......@@ -8,7 +8,7 @@ import org.postgresql.util.*;
/*
* Converts to and from the character encoding used by the backend.
*
* $Id: Encoding.java,v 1.5 2002/03/19 02:48:45 momjian Exp $
* $Id: Encoding.java,v 1.6 2002/09/06 21:23:05 momjian Exp $
*/
public class Encoding
......@@ -42,14 +42,14 @@ public class Encoding
encodings.put("EUC_KR", new String[] { "EUC_KR" });
encodings.put("JOHAB", new String[] { "Johab" });
encodings.put("EUC_TW", new String[] { "EUC_TW" });
encodings.put("SJIS", new String[] { "MS932","SJIS" });
encodings.put("BIG5", new String[] { "Big5","MS950","Cp950" });
encodings.put("GBK", new String[] { "GBK","MS936" });
encodings.put("UHC", new String[] { "MS949","Cp949","Cp949C" });
encodings.put("SJIS", new String[] { "MS932", "SJIS" });
encodings.put("BIG5", new String[] { "Big5", "MS950", "Cp950" });
encodings.put("GBK", new String[] { "GBK", "MS936" });
encodings.put("UHC", new String[] { "MS949", "Cp949", "Cp949C" });
encodings.put("TCVN", new String[] { "Cp1258" });
encodings.put("WIN1256", new String[] { "Cp1256" });
encodings.put("WIN1250", new String[] { "Cp1250" });
encodings.put("WIN874", new String[] { "MS874","Cp874" });
encodings.put("WIN874", new String[] { "MS874", "Cp874" });
encodings.put("WIN", new String[] { "Cp1251" });
encodings.put("ALT", new String[] { "Cp866" });
// We prefer KOI8-U, since it is a superset of KOI8-R.
......
package org.postgresql.core;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/core/Attic/Notification.java,v 1.1 2002/09/02 03:07:36 barry Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/core/Attic/Notification.java,v 1.2 2002/09/06 21:23:05 momjian Exp $
* This is the implementation of the PGNotification interface
*/
public class Notification implements org.postgresql.PGNotification
{
public Notification(String p_name, int p_pid) {
m_name = p_name;
m_pid = p_pid;
}
public Notification(String p_name, int p_pid)
{
m_name = p_name;
m_pid = p_pid;
}
/*
* Returns name of this notification
*/
public String getName() {
return m_name;
}
/*
* Returns name of this notification
*/
public String getName()
{
return m_name;
}
/*
* Returns the process id of the backend process making this notification
*/
public int getPID() {
return m_pid;
}
/*
* Returns the process id of the backend process making this notification
*/
public int getPID()
{
return m_pid;
}
private String m_name;
private int m_pid;
private String m_name;
private int m_pid;
}
......@@ -13,208 +13,209 @@ import org.postgresql.util.PSQLException;
* <p>The lifetime of a QueryExecutor object is from sending the query
* until the response has been received from the backend.
*
* $Id: QueryExecutor.java,v 1.15 2002/09/02 03:07:36 barry Exp $
* $Id: QueryExecutor.java,v 1.16 2002/09/06 21:23:05 momjian Exp $
*/
public class QueryExecutor
{
private final String[] m_sqlFrags;
private final Object[] m_binds;
private final java.sql.Statement statement;
private final PG_Stream pg_stream;
private final org.postgresql.jdbc1.AbstractJdbc1Connection connection;
public QueryExecutor(String[] p_sqlFrags, Object[] p_binds,
java.sql.Statement statement,
PG_Stream pg_stream,
java.sql.Connection connection)
throws SQLException
{
this.m_sqlFrags = p_sqlFrags;
this.m_binds = p_binds;
this.statement = statement;
this.pg_stream = pg_stream;
this.connection = (org.postgresql.jdbc1.AbstractJdbc1Connection)connection;
if (statement != null)
maxRows = statement.getMaxRows();
else
maxRows = 0;
}
private Field[] fields = null;
private Vector tuples = new Vector();
private boolean binaryCursor = false;
private String status = null;
private int update_count = 1;
private long insert_oid = 0;
private int maxRows;
/*
* Execute a query on the backend.
*/
public java.sql.ResultSet execute() throws SQLException
{
StringBuffer errorMessage = null;
synchronized (pg_stream)
{
sendQuery();
int c;
boolean l_endQuery = false;
while (!l_endQuery)
{
c = pg_stream.ReceiveChar();
switch (c)
{
case 'A': // Asynchronous Notify
int pid = pg_stream.ReceiveInteger(4);
String msg = pg_stream.ReceiveString(connection.getEncoding());
private final String[] m_sqlFrags;
private final Object[] m_binds;
private final java.sql.Statement statement;
private final PG_Stream pg_stream;
private final org.postgresql.jdbc1.AbstractJdbc1Connection connection;
public QueryExecutor(String[] p_sqlFrags, Object[] p_binds,
java.sql.Statement statement,
PG_Stream pg_stream,
java.sql.Connection connection)
throws SQLException
{
this.m_sqlFrags = p_sqlFrags;
this.m_binds = p_binds;
this.statement = statement;
this.pg_stream = pg_stream;
this.connection = (org.postgresql.jdbc1.AbstractJdbc1Connection)connection;
if (statement != null)
maxRows = statement.getMaxRows();
else
maxRows = 0;
}
private Field[] fields = null;
private Vector tuples = new Vector();
private boolean binaryCursor = false;
private String status = null;
private int update_count = 1;
private long insert_oid = 0;
private int maxRows;
/*
* Execute a query on the backend.
*/
public java.sql.ResultSet execute() throws SQLException
{
StringBuffer errorMessage = null;
synchronized (pg_stream)
{
sendQuery();
int c;
boolean l_endQuery = false;
while (!l_endQuery)
{
c = pg_stream.ReceiveChar();
switch (c)
{
case 'A': // Asynchronous Notify
int pid = pg_stream.ReceiveInteger(4);
String msg = pg_stream.ReceiveString(connection.getEncoding());
connection.addNotification(new org.postgresql.core.Notification(msg, pid));
break;
case 'B': // Binary Data Transfer
receiveTuple(true);
break;
case 'C': // Command Status
receiveCommandStatus();
break;
case 'D': // Text Data Transfer
receiveTuple(false);
break;
case 'E': // Error Message
// it's possible to get more than one error message for a query
// see libpq comments wrt backend closing a connection
// so, append messages to a string buffer and keep processing
// check at the bottom to see if we need to throw an exception
if ( errorMessage == null )
errorMessage = new StringBuffer();
errorMessage.append(pg_stream.ReceiveString(connection.getEncoding()));
// keep processing
break;
case 'I': // Empty Query
int t = pg_stream.ReceiveChar();
break;
case 'N': // Error Notification
connection.addWarning(pg_stream.ReceiveString(connection.getEncoding()));
break;
case 'P': // Portal Name
String pname = pg_stream.ReceiveString(connection.getEncoding());
break;
case 'T': // MetaData Field Description
receiveFields();
break;
case 'Z':
l_endQuery = true;
break;
default:
throw new PSQLException("postgresql.con.type",
new Character((char) c));
}
}
// did we get an error during this query?
if ( errorMessage != null )
throw new SQLException( errorMessage.toString() );
return connection.getResultSet(statement, fields, tuples, status, update_count, insert_oid, binaryCursor);
}
}
/*
* Send a query to the backend.
*/
private void sendQuery() throws SQLException
{
try
{
pg_stream.SendChar('Q');
for (int i = 0 ; i < m_binds.length ; ++i) {
if (m_binds[i] == null)
throw new PSQLException("postgresql.prep.param", new Integer(i + 1));
pg_stream.Send(connection.getEncoding().encode(m_sqlFrags[i]));
pg_stream.Send(connection.getEncoding().encode(m_binds[i].toString()));
}
pg_stream.Send(connection.getEncoding().encode(m_sqlFrags[m_binds.length]));
pg_stream.SendChar(0);
pg_stream.flush();
}
catch (IOException e)
{
throw new PSQLException("postgresql.con.ioerror", e);
}
}
/*
* Receive a tuple from the backend.
*
* @param isBinary set if the tuple should be treated as binary data
*/
private void receiveTuple(boolean isBinary) throws SQLException
{
if (fields == null)
throw new PSQLException("postgresql.con.tuple");
Object tuple = pg_stream.ReceiveTuple(fields.length, isBinary);
if (isBinary)
binaryCursor = true;
if (maxRows == 0 || tuples.size() < maxRows)
tuples.addElement(tuple);
}
/*
* Receive command status from the backend.
*/
private void receiveCommandStatus() throws SQLException
{
status = pg_stream.ReceiveString(connection.getEncoding());
try
{
// Now handle the update count correctly.
if (status.startsWith("INSERT") || status.startsWith("UPDATE") || status.startsWith("DELETE") || status.startsWith("MOVE"))
{
update_count = Integer.parseInt(status.substring(1 + status.lastIndexOf(' ')));
}
if (status.startsWith("INSERT"))
{
insert_oid = Long.parseLong(status.substring(1 + status.indexOf(' '),
status.lastIndexOf(' ')));
}
}
catch (NumberFormatException nfe)
{
throw new PSQLException("postgresql.con.fathom", status);
}
}
/*
* Receive the field descriptions from the back end.
*/
private void receiveFields() throws SQLException
{
if (fields != null)
throw new PSQLException("postgresql.con.multres");
int size = pg_stream.ReceiveIntegerR(2);
fields = new Field[size];
for (int i = 0; i < fields.length; i++)
{
String typeName = pg_stream.ReceiveString(connection.getEncoding());
int typeOid = pg_stream.ReceiveIntegerR(4);
int typeLength = pg_stream.ReceiveIntegerR(2);
int typeModifier = pg_stream.ReceiveIntegerR(4);
fields[i] = new Field(connection, typeName, typeOid, typeLength, typeModifier);
}
}
break;
case 'B': // Binary Data Transfer
receiveTuple(true);
break;
case 'C': // Command Status
receiveCommandStatus();
break;
case 'D': // Text Data Transfer
receiveTuple(false);
break;
case 'E': // Error Message
// it's possible to get more than one error message for a query
// see libpq comments wrt backend closing a connection
// so, append messages to a string buffer and keep processing
// check at the bottom to see if we need to throw an exception
if ( errorMessage == null )
errorMessage = new StringBuffer();
errorMessage.append(pg_stream.ReceiveString(connection.getEncoding()));
// keep processing
break;
case 'I': // Empty Query
int t = pg_stream.ReceiveChar();
break;
case 'N': // Error Notification
connection.addWarning(pg_stream.ReceiveString(connection.getEncoding()));
break;
case 'P': // Portal Name
String pname = pg_stream.ReceiveString(connection.getEncoding());
break;
case 'T': // MetaData Field Description
receiveFields();
break;
case 'Z':
l_endQuery = true;
break;
default:
throw new PSQLException("postgresql.con.type",
new Character((char) c));
}
}
// did we get an error during this query?
if ( errorMessage != null )
throw new SQLException( errorMessage.toString() );
return connection.getResultSet(statement, fields, tuples, status, update_count, insert_oid, binaryCursor);
}
}
/*
* Send a query to the backend.
*/
private void sendQuery() throws SQLException
{
try
{
pg_stream.SendChar('Q');
for (int i = 0 ; i < m_binds.length ; ++i)
{
if (m_binds[i] == null)
throw new PSQLException("postgresql.prep.param", new Integer(i + 1));
pg_stream.Send(connection.getEncoding().encode(m_sqlFrags[i]));
pg_stream.Send(connection.getEncoding().encode(m_binds[i].toString()));
}
pg_stream.Send(connection.getEncoding().encode(m_sqlFrags[m_binds.length]));
pg_stream.SendChar(0);
pg_stream.flush();
}
catch (IOException e)
{
throw new PSQLException("postgresql.con.ioerror", e);
}
}
/*
* Receive a tuple from the backend.
*
* @param isBinary set if the tuple should be treated as binary data
*/
private void receiveTuple(boolean isBinary) throws SQLException
{
if (fields == null)
throw new PSQLException("postgresql.con.tuple");
Object tuple = pg_stream.ReceiveTuple(fields.length, isBinary);
if (isBinary)
binaryCursor = true;
if (maxRows == 0 || tuples.size() < maxRows)
tuples.addElement(tuple);
}
/*
* Receive command status from the backend.
*/
private void receiveCommandStatus() throws SQLException
{
status = pg_stream.ReceiveString(connection.getEncoding());
try
{
// Now handle the update count correctly.
if (status.startsWith("INSERT") || status.startsWith("UPDATE") || status.startsWith("DELETE") || status.startsWith("MOVE"))
{
update_count = Integer.parseInt(status.substring(1 + status.lastIndexOf(' ')));
}
if (status.startsWith("INSERT"))
{
insert_oid = Long.parseLong(status.substring(1 + status.indexOf(' '),
status.lastIndexOf(' ')));
}
}
catch (NumberFormatException nfe)
{
throw new PSQLException("postgresql.con.fathom", status);
}
}
/*
* Receive the field descriptions from the back end.
*/
private void receiveFields() throws SQLException
{
if (fields != null)
throw new PSQLException("postgresql.con.multres");
int size = pg_stream.ReceiveIntegerR(2);
fields = new Field[size];
for (int i = 0; i < fields.length; i++)
{
String typeName = pg_stream.ReceiveString(connection.getEncoding());
int typeOid = pg_stream.ReceiveIntegerR(4);
int typeLength = pg_stream.ReceiveIntegerR(2);
int typeModifier = pg_stream.ReceiveIntegerR(4);
fields[i] = new Field(connection, typeName, typeOid, typeLength, typeModifier);
}
}
}
......@@ -6,7 +6,7 @@ import java.io.IOException;
/**
* Sent to the backend to initialize a newly created connection.
*
* $Id: StartupPacket.java,v 1.1 2002/03/21 02:40:03 davec Exp $
* $Id: StartupPacket.java,v 1.2 2002/09/06 21:23:05 momjian Exp $
*/
public class StartupPacket
......@@ -22,15 +22,16 @@ public class StartupPacket
private String user;
private String database;
public StartupPacket(int protocolMajor, int protocolMinor, String user, String database) {
public StartupPacket(int protocolMajor, int protocolMinor, String user, String database)
{
this.protocolMajor = protocolMajor;
this.protocolMinor = protocolMinor;
this.user = user;
this.database = database;
}
public void writeTo(PG_Stream stream) throws IOException
{
public void writeTo(PG_Stream stream) throws IOException
{
stream.SendInteger(4 + 4 + SM_DATABASE + SM_USER + SM_OPTIONS + SM_UNUSED + SM_TTY, 4);
stream.SendInteger(protocolMajor, 2);
stream.SendInteger(protocolMinor, 2);
......
......@@ -24,268 +24,272 @@ import org.postgresql.util.*;
*/
public class Fastpath
{
// This maps the functions names to their id's (possible unique just
// to a connection).
protected Hashtable func = new Hashtable();
// This maps the functions names to their id's (possible unique just
// to a connection).
protected Hashtable func = new Hashtable();
protected org.postgresql.PGConnection conn; // our connection
protected org.postgresql.PG_Stream stream; // the network stream
protected org.postgresql.PGConnection conn; // our connection
protected org.postgresql.PG_Stream stream; // the network stream
/*
* Initialises the fastpath system
*
* <p><b>Important Notice</b>
* <br>This is called from org.postgresql.Connection, and should not be called
* from client code.
*
* @param conn org.postgresql.Connection to attach to
* @param stream The network stream to the backend
*/
public Fastpath(org.postgresql.PGConnection conn, org.postgresql.PG_Stream stream)
{
this.conn = conn;
this.stream = stream;
}
/*
* Initialises the fastpath system
*
* <p><b>Important Notice</b>
* <br>This is called from org.postgresql.Connection, and should not be called
* from client code.
*
* @param conn org.postgresql.Connection to attach to
* @param stream The network stream to the backend
*/
public Fastpath(org.postgresql.PGConnection conn, org.postgresql.PG_Stream stream)
{
this.conn = conn;
this.stream = stream;
}
/*
* Send a function call to the PostgreSQL backend
*
* @param fnid Function id
* @param resulttype True if the result is an integer, false for other results
* @param args FastpathArguments to pass to fastpath
* @return null if no data, Integer if an integer result, or byte[] otherwise
* @exception SQLException if a database-access error occurs.
*/
public Object fastpath(int fnid, boolean resulttype, FastpathArg[] args) throws SQLException
{
// added Oct 7 1998 to give us thread safety
synchronized (stream)
{
// send the function call
try
{
// 70 is 'F' in ASCII. Note: don't use SendChar() here as it adds padding
// that confuses the backend. The 0 terminates the command line.
stream.SendInteger(70, 1);
stream.SendInteger(0, 1);
/*
* Send a function call to the PostgreSQL backend
*
* @param fnid Function id
* @param resulttype True if the result is an integer, false for other results
* @param args FastpathArguments to pass to fastpath
* @return null if no data, Integer if an integer result, or byte[] otherwise
* @exception SQLException if a database-access error occurs.
*/
public Object fastpath(int fnid, boolean resulttype, FastpathArg[] args) throws SQLException
{
// added Oct 7 1998 to give us thread safety
synchronized (stream)
{
// send the function call
try
{
// 70 is 'F' in ASCII. Note: don't use SendChar() here as it adds padding
// that confuses the backend. The 0 terminates the command line.
stream.SendInteger(70, 1);
stream.SendInteger(0, 1);
stream.SendInteger(fnid, 4);
stream.SendInteger(args.length, 4);
stream.SendInteger(fnid, 4);
stream.SendInteger(args.length, 4);
for (int i = 0;i < args.length;i++)
args[i].send(stream);
for (int i = 0;i < args.length;i++)
args[i].send(stream);
// This is needed, otherwise data can be lost
stream.flush();
// This is needed, otherwise data can be lost
stream.flush();
}
catch (IOException ioe)
{
throw new PSQLException("postgresql.fp.send", new Integer(fnid), ioe);
}
}
catch (IOException ioe)
{
throw new PSQLException("postgresql.fp.send", new Integer(fnid), ioe);
}
// Now handle the result
// Now handle the result
// Now loop, reading the results
Object result = null; // our result
StringBuffer errorMessage = null;
int c;
boolean l_endQuery = false;
while (!l_endQuery)
{
c = stream.ReceiveChar();
// Now loop, reading the results
Object result = null; // our result
StringBuffer errorMessage = null;
int c;
boolean l_endQuery = false;
while (!l_endQuery)
{
c = stream.ReceiveChar();
switch (c)
{
case 'A': // Asynchronous Notify
int pid = stream.ReceiveInteger(4);
String msg = stream.ReceiveString(conn.getEncoding());
break;
switch (c)
{
case 'A': // Asynchronous Notify
int pid = stream.ReceiveInteger(4);
String msg = stream.ReceiveString(conn.getEncoding());
break;
//------------------------------
// Error message returned
case 'E':
if ( errorMessage == null )
errorMessage = new StringBuffer();
errorMessage.append(stream.ReceiveString(conn.getEncoding()));
break;
//------------------------------
// Error message returned
case 'E':
if ( errorMessage == null )
errorMessage = new StringBuffer();
errorMessage.append(stream.ReceiveString(conn.getEncoding()));
break;
//------------------------------
// Notice from backend
case 'N':
((org.postgresql.jdbc1.AbstractJdbc1Connection)conn).addWarning(stream.ReceiveString(conn.getEncoding()));
break;
//------------------------------
// Notice from backend
case 'N':
((org.postgresql.jdbc1.AbstractJdbc1Connection)conn).addWarning(stream.ReceiveString(conn.getEncoding()));
break;
case 'V':
int l_nextChar = stream.ReceiveChar();
if (l_nextChar == 'G') {
int sz = stream.ReceiveIntegerR(4);
// Return an Integer if
if (resulttype)
result = new Integer(stream.ReceiveIntegerR(sz));
else
{
byte buf[] = new byte[sz];
stream.Receive(buf, 0, sz);
result = buf;
}
//There should be a trailing '0'
int l_endChar = stream.ReceiveChar();
} else {
//it must have been a '0', thus no results
}
break;
case 'V':
int l_nextChar = stream.ReceiveChar();
if (l_nextChar == 'G')
{
int sz = stream.ReceiveIntegerR(4);
// Return an Integer if
if (resulttype)
result = new Integer(stream.ReceiveIntegerR(sz));
else
{
byte buf[] = new byte[sz];
stream.Receive(buf, 0, sz);
result = buf;
}
//There should be a trailing '0'
int l_endChar = stream.ReceiveChar();
}
else
{
//it must have been a '0', thus no results
}
break;
case 'Z':
l_endQuery = true;
break;
case 'Z':
l_endQuery = true;
break;
default:
throw new PSQLException("postgresql.fp.protocol", new Character((char)c));
}
}
default:
throw new PSQLException("postgresql.fp.protocol", new Character((char)c));
}
}
if ( errorMessage != null )
throw new PSQLException("postgresql.fp.error", errorMessage.toString());
if ( errorMessage != null )
throw new PSQLException("postgresql.fp.error", errorMessage.toString());
return result;
}
}
return result;
}
}
/*
* Send a function call to the PostgreSQL backend by name.
*
* Note: the mapping for the procedure name to function id needs to exist,
* usually to an earlier call to addfunction().
*
* This is the prefered method to call, as function id's can/may change
* between versions of the backend.
*
* For an example of how this works, refer to org.postgresql.LargeObject
*
* @param name Function name
* @param resulttype True if the result is an integer, false for other
* results
* @param args FastpathArguments to pass to fastpath
* @return null if no data, Integer if an integer result, or byte[] otherwise
* @exception SQLException if name is unknown or if a database-access error
* occurs.
* @see org.postgresql.LargeObject
*/
public Object fastpath(String name, boolean resulttype, FastpathArg[] args) throws SQLException
{
if (Driver.logDebug) Driver.debug("Fastpath: calling "+name);
return fastpath(getID(name), resulttype, args);
}
/*
* Send a function call to the PostgreSQL backend by name.
*
* Note: the mapping for the procedure name to function id needs to exist,
* usually to an earlier call to addfunction().
*
* This is the prefered method to call, as function id's can/may change
* between versions of the backend.
*
* For an example of how this works, refer to org.postgresql.LargeObject
*
* @param name Function name
* @param resulttype True if the result is an integer, false for other
* results
* @param args FastpathArguments to pass to fastpath
* @return null if no data, Integer if an integer result, or byte[] otherwise
* @exception SQLException if name is unknown or if a database-access error
* occurs.
* @see org.postgresql.LargeObject
*/
public Object fastpath(String name, boolean resulttype, FastpathArg[] args) throws SQLException
{
if (Driver.logDebug)
Driver.debug("Fastpath: calling " + name);
return fastpath(getID(name), resulttype, args);
}
/*
* This convenience method assumes that the return value is an Integer
* @param name Function name
* @param args Function arguments
* @return integer result
* @exception SQLException if a database-access error occurs or no result
*/
public int getInteger(String name, FastpathArg[] args) throws SQLException
{
Integer i = (Integer)fastpath(name, true, args);
if (i == null)
throw new PSQLException("postgresql.fp.expint", name);
return i.intValue();
}
/*
* This convenience method assumes that the return value is an Integer
* @param name Function name
* @param args Function arguments
* @return integer result
* @exception SQLException if a database-access error occurs or no result
*/
public int getInteger(String name, FastpathArg[] args) throws SQLException
{
Integer i = (Integer)fastpath(name, true, args);
if (i == null)
throw new PSQLException("postgresql.fp.expint", name);
return i.intValue();
}
/*
* This convenience method assumes that the return value is an Integer
* @param name Function name
* @param args Function arguments
* @return byte[] array containing result
* @exception SQLException if a database-access error occurs or no result
*/
public byte[] getData(String name, FastpathArg[] args) throws SQLException
{
return (byte[])fastpath(name, false, args);
}
/*
* This convenience method assumes that the return value is an Integer
* @param name Function name
* @param args Function arguments
* @return byte[] array containing result
* @exception SQLException if a database-access error occurs or no result
*/
public byte[] getData(String name, FastpathArg[] args) throws SQLException
{
return (byte[])fastpath(name, false, args);
}
/*
* This adds a function to our lookup table.
*
* <p>User code should use the addFunctions method, which is based upon a
* query, rather than hard coding the oid. The oid for a function is not
* guaranteed to remain static, even on different servers of the same
* version.
*
* @param name Function name
* @param fnid Function id
*/
public void addFunction(String name, int fnid)
{
func.put(name, new Integer(fnid));
}
/*
* This adds a function to our lookup table.
*
* <p>User code should use the addFunctions method, which is based upon a
* query, rather than hard coding the oid. The oid for a function is not
* guaranteed to remain static, even on different servers of the same
* version.
*
* @param name Function name
* @param fnid Function id
*/
public void addFunction(String name, int fnid)
{
func.put(name, new Integer(fnid));
}
/*
* This takes a ResultSet containing two columns. Column 1 contains the
* function name, Column 2 the oid.
*
* <p>It reads the entire ResultSet, loading the values into the function
* table.
*
* <p><b>REMEMBER</b> to close() the resultset after calling this!!
*
* <p><b><em>Implementation note about function name lookups:</em></b>
*
* <p>PostgreSQL stores the function id's and their corresponding names in
* the pg_proc table. To speed things up locally, instead of querying each
* function from that table when required, a Hashtable is used. Also, only
* the function's required are entered into this table, keeping connection
* times as fast as possible.
*
* <p>The org.postgresql.LargeObject class performs a query upon it's startup,
* and passes the returned ResultSet to the addFunctions() method here.
*
* <p>Once this has been done, the LargeObject api refers to the functions by
* name.
*
* <p>Dont think that manually converting them to the oid's will work. Ok,
* they will for now, but they can change during development (there was some
* discussion about this for V7.0), so this is implemented to prevent any
* unwarranted headaches in the future.
*
* @param rs ResultSet
* @exception SQLException if a database-access error occurs.
* @see org.postgresql.LargeObjectManager
*/
public void addFunctions(ResultSet rs) throws SQLException
{
while (rs.next())
{
func.put(rs.getString(1), new Integer(rs.getInt(2)));
}
}
/*
* This takes a ResultSet containing two columns. Column 1 contains the
* function name, Column 2 the oid.
*
* <p>It reads the entire ResultSet, loading the values into the function
* table.
*
* <p><b>REMEMBER</b> to close() the resultset after calling this!!
*
* <p><b><em>Implementation note about function name lookups:</em></b>
*
* <p>PostgreSQL stores the function id's and their corresponding names in
* the pg_proc table. To speed things up locally, instead of querying each
* function from that table when required, a Hashtable is used. Also, only
* the function's required are entered into this table, keeping connection
* times as fast as possible.
*
* <p>The org.postgresql.LargeObject class performs a query upon it's startup,
* and passes the returned ResultSet to the addFunctions() method here.
*
* <p>Once this has been done, the LargeObject api refers to the functions by
* name.
*
* <p>Dont think that manually converting them to the oid's will work. Ok,
* they will for now, but they can change during development (there was some
* discussion about this for V7.0), so this is implemented to prevent any
* unwarranted headaches in the future.
*
* @param rs ResultSet
* @exception SQLException if a database-access error occurs.
* @see org.postgresql.LargeObjectManager
*/
public void addFunctions(ResultSet rs) throws SQLException
{
while (rs.next())
{
func.put(rs.getString(1), new Integer(rs.getInt(2)));
}
}
/*
* This returns the function id associated by its name
*
* <p>If addFunction() or addFunctions() have not been called for this name,
* then an SQLException is thrown.
*
* @param name Function name to lookup
* @return Function ID for fastpath call
* @exception SQLException is function is unknown.
*/
public int getID(String name) throws SQLException
{
Integer id = (Integer)func.get(name);
/*
* This returns the function id associated by its name
*
* <p>If addFunction() or addFunctions() have not been called for this name,
* then an SQLException is thrown.
*
* @param name Function name to lookup
* @return Function ID for fastpath call
* @exception SQLException is function is unknown.
*/
public int getID(String name) throws SQLException
{
Integer id = (Integer)func.get(name);
// may be we could add a lookup to the database here, and store the result
// in our lookup table, throwing the exception if that fails.
// We must, however, ensure that if we do, any existing ResultSet is
// unaffected, otherwise we could break user code.
//
// so, until we know we can do this (needs testing, on the TODO list)
// for now, we throw the exception and do no lookups.
if (id == null)
throw new PSQLException("postgresql.fp.unknown", name);
// may be we could add a lookup to the database here, and store the result
// in our lookup table, throwing the exception if that fails.
// We must, however, ensure that if we do, any existing ResultSet is
// unaffected, otherwise we could break user code.
//
// so, until we know we can do this (needs testing, on the TODO list)
// for now, we throw the exception and do no lookups.
if (id == null)
throw new PSQLException("postgresql.fp.unknown", name);
return id.intValue();
}
return id.intValue();
}
}
......@@ -14,1218 +14,1237 @@ import org.postgresql.largeobject.LargeObjectManager;
import org.postgresql.util.*;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Connection.java,v 1.7 2002/09/02 03:07:36 barry Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Connection.java,v 1.8 2002/09/06 21:23:05 momjian Exp $
* This class defines methods of the jdbc1 specification. This class is
* extended by org.postgresql.jdbc2.AbstractJdbc2Connection which adds the jdbc2
* methods. The real Connection class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Connection
*/
public abstract class AbstractJdbc1Connection implements org.postgresql.PGConnection
{
// This is the network stream associated with this connection
public PG_Stream pg_stream;
protected String PG_HOST;
protected int PG_PORT;
protected String PG_USER;
protected String PG_DATABASE;
protected boolean PG_STATUS;
protected String compatible;
// The PID an cancellation key we get from the backend process
protected int pid;
protected int ckey;
private Vector m_notifications;
/*
The encoding to use for this connection.
*/
private Encoding encoding = Encoding.defaultEncoding();
private String dbVersionNumber;
public boolean CONNECTION_OK = true;
public boolean CONNECTION_BAD = false;
public boolean autoCommit = true;
public boolean readOnly = false;
public org.postgresql.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 = 2;
protected static final int PG_PROTOCOL_LATEST_MINOR = 0;
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;
private static final int AUTH_REQ_MD5 = 5;
// These are used to cache oids, PGTypes and SQLTypes
private static Hashtable sqlTypeCache = new Hashtable(); // oid -> SQLType
private static Hashtable pgTypeCache = new Hashtable(); // oid -> PGType
private static Hashtable typeOidCache = new Hashtable(); //PGType -> oid
// Now handle notices as warnings, so things like "show" now work
public SQLWarning firstWarning = null;
/*
* Cache of the current isolation level
*/
private int isolationLevel = java.sql.Connection.TRANSACTION_READ_COMMITTED;
public abstract java.sql.Statement createStatement() throws SQLException;
/*
* 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 url the URL of the connection
* @param d the Driver instantation of the connection
* @exception SQLException if a database access error occurs
*/
public void openConnection(String host, int port, Properties info, String database, String url, org.postgresql.Driver d) throws SQLException
{
firstWarning = null;
// 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 PSQLException("postgresql.con.user");
this_driver = (org.postgresql.Driver)d;
this_url = url;
PG_DATABASE = database;
PG_USER = info.getProperty("user");
String password = info.getProperty("password", "");
PG_PORT = port;
PG_HOST = host;
PG_STATUS = CONNECTION_BAD;
if (info.getProperty("compatible") == null)
{
compatible = d.getMajorVersion() + "." + d.getMinorVersion();
}
else
{
compatible = info.getProperty("compatible");
}
//Read loglevel arg and set the loglevel based on this value
//in addition to setting the log level enable output to
//standard out if no other printwriter is set
String l_logLevelProp = info.getProperty("loglevel","0");
int l_logLevel = 0;
try {
l_logLevel = Integer.parseInt(l_logLevelProp);
if (l_logLevel > org.postgresql.Driver.DEBUG || l_logLevel < org.postgresql.Driver.INFO) {
l_logLevel = 0;
}
} catch (Exception l_e) {
//invalid value for loglevel ignore
// This is the network stream associated with this connection
public PG_Stream pg_stream;
protected String PG_HOST;
protected int PG_PORT;
protected String PG_USER;
protected String PG_DATABASE;
protected boolean PG_STATUS;
protected String compatible;
// The PID an cancellation key we get from the backend process
protected int pid;
protected int ckey;
private Vector m_notifications;
/*
The encoding to use for this connection.
*/
private Encoding encoding = Encoding.defaultEncoding();
private String dbVersionNumber;
public boolean CONNECTION_OK = true;
public boolean CONNECTION_BAD = false;
public boolean autoCommit = true;
public boolean readOnly = false;
public org.postgresql.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 = 2;
protected static final int PG_PROTOCOL_LATEST_MINOR = 0;
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;
private static final int AUTH_REQ_MD5 = 5;
// These are used to cache oids, PGTypes and SQLTypes
private static Hashtable sqlTypeCache = new Hashtable(); // oid -> SQLType
private static Hashtable pgTypeCache = new Hashtable(); // oid -> PGType
private static Hashtable typeOidCache = new Hashtable(); //PGType -> oid
// Now handle notices as warnings, so things like "show" now work
public SQLWarning firstWarning = null;
/*
* Cache of the current isolation level
*/
private int isolationLevel = java.sql.Connection.TRANSACTION_READ_COMMITTED;
public abstract java.sql.Statement createStatement() throws SQLException;
/*
* 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 url the URL of the connection
* @param d the Driver instantation of the connection
* @exception SQLException if a database access error occurs
*/
public void openConnection(String host, int port, Properties info, String database, String url, org.postgresql.Driver d) throws SQLException
{
firstWarning = null;
// 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 PSQLException("postgresql.con.user");
this_driver = (org.postgresql.Driver)d;
this_url = url;
PG_DATABASE = database;
PG_USER = info.getProperty("user");
String password = info.getProperty("password", "");
PG_PORT = port;
PG_HOST = host;
PG_STATUS = CONNECTION_BAD;
if (info.getProperty("compatible") == null)
{
compatible = d.getMajorVersion() + "." + d.getMinorVersion();
}
else
{
compatible = info.getProperty("compatible");
}
//Read loglevel arg and set the loglevel based on this value
//in addition to setting the log level enable output to
//standard out if no other printwriter is set
String l_logLevelProp = info.getProperty("loglevel", "0");
int l_logLevel = 0;
try
{
l_logLevel = Integer.parseInt(l_logLevelProp);
if (l_logLevel > org.postgresql.Driver.DEBUG || l_logLevel < org.postgresql.Driver.INFO)
{
l_logLevel = 0;
}
}
catch (Exception l_e)
{
//invalid value for loglevel ignore
}
if (l_logLevel > 0)
{
org.postgresql.Driver.setLogLevel(l_logLevel);
enableDriverManagerLogging();
}
//Print out the driver version number
if (org.postgresql.Driver.logInfo)
org.postgresql.Driver.info(org.postgresql.Driver.getVersion());
// Now make the initial connection
try
{
pg_stream = new PG_Stream(host, port);
}
catch (ConnectException cex)
{
// Added by Peter Mount <peter@retep.org.uk>
// ConnectException is thrown when the connection cannot be made.
// we trap this an return a more meaningful message for the end user
throw new PSQLException ("postgresql.con.refused");
}
catch (IOException e)
{
throw new PSQLException ("postgresql.con.failed", e);
}
// Now we need to construct and send a startup packet
try
{
new StartupPacket(PG_PROTOCOL_LATEST_MAJOR,
PG_PROTOCOL_LATEST_MINOR,
PG_USER,
database).writeTo(pg_stream);
// now flush the startup packets to the backend
pg_stream.flush();
// Now get the response from the backend, either an error message
// or an authentication request
int areq = -1; // must have a value here
do
{
int beresp = pg_stream.ReceiveChar();
String salt = null;
byte [] md5Salt = new byte[4];
switch (beresp)
{
case 'E':
// An error occured, so pass the error message to the
// user.
//
// The most common one to be thrown here is:
// "User authentication failed"
//
throw new PSQLException("postgresql.con.misc", pg_stream.ReceiveString(encoding));
case 'R':
// Get the type of request
areq = pg_stream.ReceiveIntegerR(4);
// Get the crypt password salt if there is one
if (areq == AUTH_REQ_CRYPT)
{
byte[] rst = new byte[2];
rst[0] = (byte)pg_stream.ReceiveChar();
rst[1] = (byte)pg_stream.ReceiveChar();
salt = new String(rst, 0, 2);
if (org.postgresql.Driver.logDebug)
org.postgresql.Driver.debug("Crypt salt=" + salt);
}
// Or get the md5 password salt if there is one
if (areq == AUTH_REQ_MD5)
{
md5Salt[0] = (byte)pg_stream.ReceiveChar();
md5Salt[1] = (byte)pg_stream.ReceiveChar();
md5Salt[2] = (byte)pg_stream.ReceiveChar();
md5Salt[3] = (byte)pg_stream.ReceiveChar();
salt = new String(md5Salt, 0, 4);
if (org.postgresql.Driver.logDebug)
org.postgresql.Driver.debug("MD5 salt=" + salt);
}
// now send the auth packet
switch (areq)
{
case AUTH_REQ_OK:
break;
case AUTH_REQ_KRB4:
if (org.postgresql.Driver.logDebug)
org.postgresql.Driver.debug("postgresql: KRB4");
throw new PSQLException("postgresql.con.kerb4");
case AUTH_REQ_KRB5:
if (org.postgresql.Driver.logDebug)
org.postgresql.Driver.debug("postgresql: KRB5");
throw new PSQLException("postgresql.con.kerb5");
case AUTH_REQ_PASSWORD:
if (org.postgresql.Driver.logDebug)
org.postgresql.Driver.debug("postgresql: PASSWORD");
pg_stream.SendInteger(5 + password.length(), 4);
pg_stream.Send(password.getBytes());
pg_stream.SendInteger(0, 1);
pg_stream.flush();
break;
case AUTH_REQ_CRYPT:
if (org.postgresql.Driver.logDebug)
org.postgresql.Driver.debug("postgresql: CRYPT");
String crypted = UnixCrypt.crypt(salt, password);
pg_stream.SendInteger(5 + crypted.length(), 4);
pg_stream.Send(crypted.getBytes());
pg_stream.SendInteger(0, 1);
pg_stream.flush();
break;
case AUTH_REQ_MD5:
if (org.postgresql.Driver.logDebug)
org.postgresql.Driver.debug("postgresql: MD5");
byte[] digest = MD5Digest.encode(PG_USER, password, md5Salt);
pg_stream.SendInteger(5 + digest.length, 4);
pg_stream.Send(digest);
pg_stream.SendInteger(0, 1);
pg_stream.flush();
break;
default:
throw new PSQLException("postgresql.con.auth", new Integer(areq));
}
break;
default:
throw new PSQLException("postgresql.con.authfail");
}
}
while (areq != AUTH_REQ_OK);
}
catch (IOException e)
{
throw new PSQLException("postgresql.con.failed", e);
}
// As of protocol version 2.0, we should now receive the cancellation key and the pid
int beresp;
do
{
beresp = pg_stream.ReceiveChar();
switch (beresp)
{
case 'K':
pid = pg_stream.ReceiveIntegerR(4);
ckey = pg_stream.ReceiveIntegerR(4);
break;
case 'E':
throw new PSQLException("postgresql.con.backend", pg_stream.ReceiveString(encoding));
case 'N':
addWarning(pg_stream.ReceiveString(encoding));
break;
default:
throw new PSQLException("postgresql.con.setup");
}
}
while (beresp == 'N');
// Expect ReadyForQuery packet
do
{
beresp = pg_stream.ReceiveChar();
switch (beresp)
{
case 'Z':
break;
case 'N':
addWarning(pg_stream.ReceiveString(encoding));
break;
case 'E':
throw new PSQLException("postgresql.con.backend", pg_stream.ReceiveString(encoding));
default:
throw new PSQLException("postgresql.con.setup");
}
}
while (beresp == 'N');
// "pg_encoding_to_char(1)" will return 'EUC_JP' for a backend compiled with multibyte,
// otherwise it's hardcoded to 'SQL_ASCII'.
// If the backend doesn't know about multibyte we can't assume anything about the encoding
// used, so we denote this with 'UNKNOWN'.
//Note: begining with 7.2 we should be using pg_client_encoding() which
//is new in 7.2. However it isn't easy to conditionally call this new
//function, since we don't yet have the information as to what server
//version we are talking to. Thus we will continue to call
//getdatabaseencoding() until we drop support for 7.1 and older versions
//or until someone comes up with a conditional way to run one or
//the other function depending on server version that doesn't require
//two round trips to the server per connection
final String encodingQuery =
"case when pg_encoding_to_char(1) = 'SQL_ASCII' then 'UNKNOWN' else getdatabaseencoding() end";
// Set datestyle and fetch db encoding in a single call, to avoid making
// more than one round trip to the backend during connection startup.
java.sql.ResultSet resultSet =
ExecSQL("set datestyle to 'ISO'; select version(), " + encodingQuery + ";");
if (! resultSet.next())
{
throw new PSQLException("postgresql.con.failed", "failed getting backend encoding");
}
String version = resultSet.getString(1);
dbVersionNumber = extractVersionNumber(version);
String dbEncoding = resultSet.getString(2);
encoding = Encoding.getEncoding(dbEncoding, info.getProperty("charSet"));
// Initialise object handling
initObjectTypes();
// Mark the connection as ok, and cleanup
PG_STATUS = CONNECTION_OK;
}
/*
* Return the instance of org.postgresql.Driver
* that created this connection
*/
public org.postgresql.Driver getDriver()
{
return this_driver;
}
// These methods used to be in the main Connection implementation. As they
// are common to all implementations (JDBC1 or 2), they are placed here.
// This should make it easy to maintain the two specifications.
public abstract java.sql.ResultSet getResultSet(Statement statement, org.postgresql.Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException;
public abstract java.sql.ResultSet getResultSet(Statement statement, org.postgresql.Field[] fields, Vector tuples, String status, int updateCount) throws SQLException;
/*
* This adds a warning to the warning chain.
* @param msg message to add
*/
public void addWarning(String msg)
{
// Add the warning to the chain
if (firstWarning != null)
firstWarning.setNextWarning(new SQLWarning(msg));
else
firstWarning = new SQLWarning(msg);
// Now check for some specific messages
// This is obsolete in 6.5, but I've left it in here so if we need to use this
// technique again, we'll know where to place it.
//
// This is generated by the SQL "show datestyle"
//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
//}
}
/*
* Send a query to the backend. Returns one of the ResultSet
* objects.
*
* <B>Note:</B> there does not seem to be any method currently
* in existance to return the update count.
*
* @param sql the SQL statement to be executed
* @return a ResultSet holding the results
* @exception SQLException if a database error occurs
*/
public java.sql.ResultSet ExecSQL(String sql) throws SQLException
{
return ExecSQL(sql, null);
}
/*
* Send a query to the backend. Returns one of the ResultSet
* objects.
*
* <B>Note:</B> there does not seem to be any method currently
* in existance to return the update count.
*
* @param sql the SQL statement to be executed
* @param stat The Statement associated with this query (may be null)
* @return a ResultSet holding the results
* @exception SQLException if a database error occurs
*/
public java.sql.ResultSet ExecSQL(String sql, java.sql.Statement stat) throws SQLException
{
return new QueryExecutor(new String[] {sql}, EMPTY_OBJECT_ARRAY, stat, pg_stream, (java.sql.Connection)this).execute();
}
private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
/*
* Send a query to the backend. Returns one of the ResultSet
* objects.
*
* <B>Note:</B> there does not seem to be any method currently
* in existance to return the update count.
*
* @param p_sqlFragmentss the SQL statement parts to be executed
* @param p_binds the SQL bind values
* @param stat The Statement associated with this query (may be null)
* @return a ResultSet holding the results
* @exception SQLException if a database error occurs
*/
public java.sql.ResultSet ExecSQL(String[] p_sqlFragments, Object[] p_binds, java.sql.Statement stat) throws SQLException
{
return new QueryExecutor(p_sqlFragments, p_binds, stat, pg_stream, (java.sql.Connection)this).execute();
}
/*
* In SQL, a result table can be retrieved through a cursor that
* is named. The current row of a result can be updated or deleted
* using a positioned update/delete statement that references the
* cursor name.
*
* We support one cursor per connection.
*
* setCursorName sets the cursor name.
*
* @param cursor the cursor name
* @exception SQLException if a database access error occurs
*/
public void setCursorName(String cursor) throws SQLException
{
this.cursor = cursor;
}
/*
* getCursorName gets the cursor name.
*
* @return the current cursor name
* @exception SQLException if a database access error occurs
*/
public String getCursorName() throws SQLException
{
return cursor;
}
/*
* We are required to bring back certain information by
* the DatabaseMetaData class. These functions do that.
*
* Method getURL() brings back the URL (good job we saved it)
*
* @return the url
* @exception SQLException just in case...
*/
public String getURL() throws SQLException
{
return this_url;
}
/*
* Method getUserName() brings back the User Name (again, we
* saved it)
*
* @return the user name
* @exception SQLException just in case...
*/
int lastMessage = 0;
public String getUserName() throws SQLException
{
return PG_USER;
}
/*
* Get the character encoding to use for this connection.
*/
public Encoding getEncoding() throws SQLException
{
return encoding;
}
/*
* 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 org.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 org.postgresql.fastpath.*;
* ...
* Fastpath fp = ((org.postgresql.Connection)myconn).getFastpathAPI();
* </pre>
*
* <p>where myconn is an open Connection to org.postgresql.
*
* @return Fastpath object allowing access to functions on the org.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 org.postgresql backend itself.
*
* <p>The best way to use this is as follows:
*
* <p><pre>
* import org.postgresql.largeobject.*;
* ...
* LargeObjectManager lo = ((org.postgresql.Connection)myconn).getLargeObjectAPI();
* </pre>
*
* <p>where myconn is an open Connection to org.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((java.sql.Connection)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
* org.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 org.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 org.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 org.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((java.sql.Connection)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 org.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 PSQLException("postgresql.con.creobj", type, ex);
}
// should never be reached
return null;
}
/*
* This stores an object into the database. This method was
* deprecated in 7.2 bacause an OID can be larger than the java signed
* int returned by this method.
* @deprecated Replaced by storeObject() in 7.2
*/
public int putObject(Object o) throws SQLException
{
return (int) storeObject(o);
}
/*
* 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 org.postgresql.util.Serialize
* @since 7.2
*/
public long storeObject(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((java.sql.Connection)this, type);
objectTypes.put(type, ser);
return ser.storeObject(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).storeObject(o);
// Thow an exception because the type is unknown
throw new PSQLException("postgresql.con.strobj");
}
catch (SQLException sx)
{
// rethrow the exception. Done because we capture any others next
sx.fillInStackTrace();
throw sx;
}
if (l_logLevel > 0) {
org.postgresql.Driver.setLogLevel(l_logLevel);
enableDriverManagerLogging();
catch (Exception ex)
{
throw new PSQLException("postgresql.con.strobjex", ex);
}
}
//Print out the driver version number
if (org.postgresql.Driver.logInfo) org.postgresql.Driver.info(org.postgresql.Driver.getVersion());
// Now make the initial connection
try
{
pg_stream = new PG_Stream(host, port);
}
catch (ConnectException cex)
{
// Added by Peter Mount <peter@retep.org.uk>
// ConnectException is thrown when the connection cannot be made.
// we trap this an return a more meaningful message for the end user
throw new PSQLException ("postgresql.con.refused");
}
catch (IOException e)
{
throw new PSQLException ("postgresql.con.failed", e);
}
// Now we need to construct and send a startup packet
try
{
new StartupPacket(PG_PROTOCOL_LATEST_MAJOR,
PG_PROTOCOL_LATEST_MINOR,
PG_USER,
database).writeTo(pg_stream);
// now flush the startup packets to the backend
pg_stream.flush();
// Now get the response from the backend, either an error message
// or an authentication request
int areq = -1; // must have a value here
do
{
int beresp = pg_stream.ReceiveChar();
String salt = null;
byte [] md5Salt = new byte[4];
switch (beresp)
{
case 'E':
// An error occured, so pass the error message to the
// user.
//
// The most common one to be thrown here is:
// "User authentication failed"
//
throw new PSQLException("postgresql.con.misc", pg_stream.ReceiveString(encoding));
case 'R':
// Get the type of request
areq = pg_stream.ReceiveIntegerR(4);
// Get the crypt password salt if there is one
if (areq == AUTH_REQ_CRYPT)
{
byte[] rst = new byte[2];
rst[0] = (byte)pg_stream.ReceiveChar();
rst[1] = (byte)pg_stream.ReceiveChar();
salt = new String(rst, 0, 2);
if (org.postgresql.Driver.logDebug) org.postgresql.Driver.debug("Crypt salt=" + salt);
}
// Or get the md5 password salt if there is one
if (areq == AUTH_REQ_MD5)
{
md5Salt[0] = (byte)pg_stream.ReceiveChar();
md5Salt[1] = (byte)pg_stream.ReceiveChar();
md5Salt[2] = (byte)pg_stream.ReceiveChar();
md5Salt[3] = (byte)pg_stream.ReceiveChar();
salt = new String(md5Salt, 0, 4);
if (org.postgresql.Driver.logDebug) org.postgresql.Driver.debug("MD5 salt=" + salt);
}
// now send the auth packet
switch (areq)
{
case AUTH_REQ_OK:
break;
case AUTH_REQ_KRB4:
if (org.postgresql.Driver.logDebug) org.postgresql.Driver.debug("postgresql: KRB4");
throw new PSQLException("postgresql.con.kerb4");
case AUTH_REQ_KRB5:
if (org.postgresql.Driver.logDebug) org.postgresql.Driver.debug("postgresql: KRB5");
throw new PSQLException("postgresql.con.kerb5");
case AUTH_REQ_PASSWORD:
if (org.postgresql.Driver.logDebug) org.postgresql.Driver.debug("postgresql: PASSWORD");
pg_stream.SendInteger(5 + password.length(), 4);
pg_stream.Send(password.getBytes());
pg_stream.SendInteger(0, 1);
pg_stream.flush();
break;
case AUTH_REQ_CRYPT:
if (org.postgresql.Driver.logDebug) org.postgresql.Driver.debug("postgresql: CRYPT");
String crypted = UnixCrypt.crypt(salt, password);
pg_stream.SendInteger(5 + crypted.length(), 4);
pg_stream.Send(crypted.getBytes());
pg_stream.SendInteger(0, 1);
pg_stream.flush();
break;
case AUTH_REQ_MD5:
if (org.postgresql.Driver.logDebug) org.postgresql.Driver.debug("postgresql: MD5");
byte[] digest = MD5Digest.encode(PG_USER, password, md5Salt);
pg_stream.SendInteger(5 + digest.length, 4);
pg_stream.Send(digest);
pg_stream.SendInteger(0, 1);
pg_stream.flush();
break;
default:
throw new PSQLException("postgresql.con.auth", new Integer(areq));
}
break;
default:
throw new PSQLException("postgresql.con.authfail");
}
}
while (areq != AUTH_REQ_OK);
}
catch (IOException e)
{
throw new PSQLException("postgresql.con.failed", e);
}
// As of protocol version 2.0, we should now receive the cancellation key and the pid
int beresp;
do {
beresp = pg_stream.ReceiveChar();
switch (beresp)
{
case 'K':
pid = pg_stream.ReceiveIntegerR(4);
ckey = pg_stream.ReceiveIntegerR(4);
break;
case 'E':
throw new PSQLException("postgresql.con.backend", pg_stream.ReceiveString(encoding));
case 'N':
addWarning(pg_stream.ReceiveString(encoding));
break;
default:
throw new PSQLException("postgresql.con.setup");
}
} while (beresp == 'N');
// Expect ReadyForQuery packet
do {
beresp = pg_stream.ReceiveChar();
switch (beresp)
{
case 'Z':
break;
case 'N':
addWarning(pg_stream.ReceiveString(encoding));
break;
case 'E':
throw new PSQLException("postgresql.con.backend", pg_stream.ReceiveString(encoding));
default:
throw new PSQLException("postgresql.con.setup");
}
} while (beresp == 'N');
// "pg_encoding_to_char(1)" will return 'EUC_JP' for a backend compiled with multibyte,
// otherwise it's hardcoded to 'SQL_ASCII'.
// If the backend doesn't know about multibyte we can't assume anything about the encoding
// used, so we denote this with 'UNKNOWN'.
//Note: begining with 7.2 we should be using pg_client_encoding() which
//is new in 7.2. However it isn't easy to conditionally call this new
//function, since we don't yet have the information as to what server
//version we are talking to. Thus we will continue to call
//getdatabaseencoding() until we drop support for 7.1 and older versions
//or until someone comes up with a conditional way to run one or
//the other function depending on server version that doesn't require
//two round trips to the server per connection
final String encodingQuery =
"case when pg_encoding_to_char(1) = 'SQL_ASCII' then 'UNKNOWN' else getdatabaseencoding() end";
// Set datestyle and fetch db encoding in a single call, to avoid making
// more than one round trip to the backend during connection startup.
java.sql.ResultSet resultSet =
ExecSQL("set datestyle to 'ISO'; select version(), " + encodingQuery + ";");
if (! resultSet.next())
{
throw new PSQLException("postgresql.con.failed", "failed getting backend encoding");
}
String version = resultSet.getString(1);
dbVersionNumber = extractVersionNumber(version);
String dbEncoding = resultSet.getString(2);
encoding = Encoding.getEncoding(dbEncoding, info.getProperty("charSet"));
// Initialise object handling
initObjectTypes();
// Mark the connection as ok, and cleanup
PG_STATUS = CONNECTION_OK;
}
/*
* Return the instance of org.postgresql.Driver
* that created this connection
*/
public org.postgresql.Driver getDriver()
{
return this_driver;
/*
* This allows client code to add a handler for one of org.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>
* ...
* ((org.postgresql.Connection)myconn).addDataType("mytype","my.class.name");
* ...
* </pre>
*
* <p>where myconn is an open Connection to org.postgresql.
*
* <p>The handling class must extend org.postgresql.util.PGobject
*
* @see org.postgresql.util.PGobject
*/
public void addDataType(String type, String name)
{
objectTypes.put(type, name);
}
// These methods used to be in the main Connection implementation. As they
// are common to all implementations (JDBC1 or 2), they are placed here.
// This should make it easy to maintain the two specifications.
public abstract java.sql.ResultSet getResultSet(Statement statement, org.postgresql.Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException;
public abstract java.sql.ResultSet getResultSet(Statement statement, org.postgresql.Field[] fields, Vector tuples, String status, int updateCount) throws SQLException;
/*
* This adds a warning to the warning chain.
* @param msg message to add
*/
public void addWarning(String msg)
{
// Add the warning to the chain
if (firstWarning != null)
firstWarning.setNextWarning(new SQLWarning(msg));
else
firstWarning = new SQLWarning(msg);
// Now check for some specific messages
// This is obsolete in 6.5, but I've left it in here so if we need to use this
// technique again, we'll know where to place it.
//
// This is generated by the SQL "show datestyle"
//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
//}
}
/*
* Send a query to the backend. Returns one of the ResultSet
* objects.
*
* <B>Note:</B> there does not seem to be any method currently
* in existance to return the update count.
*
* @param sql the SQL statement to be executed
* @return a ResultSet holding the results
* @exception SQLException if a database error occurs
*/
public java.sql.ResultSet ExecSQL(String sql) throws SQLException
{
return ExecSQL(sql, null);
}
/*
* Send a query to the backend. Returns one of the ResultSet
* objects.
*
* <B>Note:</B> there does not seem to be any method currently
* in existance to return the update count.
*
* @param sql the SQL statement to be executed
* @param stat The Statement associated with this query (may be null)
* @return a ResultSet holding the results
* @exception SQLException if a database error occurs
*/
public java.sql.ResultSet ExecSQL(String sql, java.sql.Statement stat) throws SQLException
{
return new QueryExecutor(new String[] {sql}, EMPTY_OBJECT_ARRAY, stat, pg_stream, (java.sql.Connection)this).execute();
}
private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
/*
* Send a query to the backend. Returns one of the ResultSet
* objects.
*
* <B>Note:</B> there does not seem to be any method currently
* in existance to return the update count.
*
* @param p_sqlFragmentss the SQL statement parts to be executed
* @param p_binds the SQL bind values
* @param stat The Statement associated with this query (may be null)
* @return a ResultSet holding the results
* @exception SQLException if a database error occurs
*/
public java.sql.ResultSet ExecSQL(String[] p_sqlFragments, Object[] p_binds, java.sql.Statement stat) throws SQLException
{
return new QueryExecutor(p_sqlFragments, p_binds, stat, pg_stream, (java.sql.Connection)this).execute();
}
/*
* In SQL, a result table can be retrieved through a cursor that
* is named. The current row of a result can be updated or deleted
* using a positioned update/delete statement that references the
* cursor name.
*
* We support one cursor per connection.
*
* setCursorName sets the cursor name.
*
* @param cursor the cursor name
* @exception SQLException if a database access error occurs
*/
public void setCursorName(String cursor) throws SQLException
{
this.cursor = cursor;
}
/*
* getCursorName gets the cursor name.
*
* @return the current cursor name
* @exception SQLException if a database access error occurs
*/
public String getCursorName() throws SQLException
{
return cursor;
}
/*
* We are required to bring back certain information by
* the DatabaseMetaData class. These functions do that.
*
* Method getURL() brings back the URL (good job we saved it)
*
* @return the url
* @exception SQLException just in case...
*/
public String getURL() throws SQLException
{
return this_url;
}
/*
* Method getUserName() brings back the User Name (again, we
* saved it)
*
* @return the user name
* @exception SQLException just in case...
*/
int lastMessage = 0;
public String getUserName() throws SQLException
{
return PG_USER;
}
/*
* Get the character encoding to use for this connection.
*/
public Encoding getEncoding() throws SQLException
{
return encoding;
}
/*
* 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 org.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 org.postgresql.fastpath.*;
* ...
* Fastpath fp = ((org.postgresql.Connection)myconn).getFastpathAPI();
* </pre>
*
* <p>where myconn is an open Connection to org.postgresql.
*
* @return Fastpath object allowing access to functions on the org.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 org.postgresql backend itself.
*
* <p>The best way to use this is as follows:
*
* <p><pre>
* import org.postgresql.largeobject.*;
* ...
* LargeObjectManager lo = ((org.postgresql.Connection)myconn).getLargeObjectAPI();
* </pre>
*
* <p>where myconn is an open Connection to org.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((java.sql.Connection)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
* org.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 org.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 org.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 org.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((java.sql.Connection)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 org.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 PSQLException("postgresql.con.creobj", type, ex);
}
// should never be reached
return null;
}
/*
* This stores an object into the database. This method was
* deprecated in 7.2 bacause an OID can be larger than the java signed
* int returned by this method.
* @deprecated Replaced by storeObject() in 7.2
*/
public int putObject(Object o) throws SQLException
{
return (int) storeObject(o);
}
/*
* 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 org.postgresql.util.Serialize
* @since 7.2
*/
public long storeObject(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((java.sql.Connection)this, type);
objectTypes.put(type, ser);
return ser.storeObject(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).storeObject(o);
// Thow an exception because the type is unknown
throw new PSQLException("postgresql.con.strobj");
}
catch (SQLException sx)
{
// rethrow the exception. Done because we capture any others next
sx.fillInStackTrace();
throw sx;
}
catch (Exception ex)
{
throw new PSQLException("postgresql.con.strobjex", ex);
}
}
/*
* This allows client code to add a handler for one of org.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>
* ...
* ((org.postgresql.Connection)myconn).addDataType("mytype","my.class.name");
* ...
* </pre>
*
* <p>where myconn is an open Connection to org.postgresql.
*
* <p>The handling class must extend org.postgresql.util.PGobject
*
* @see org.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", "org.postgresql.geometric.PGbox"},
{"circle", "org.postgresql.geometric.PGcircle"},
{"line", "org.postgresql.geometric.PGline"},
{"lseg", "org.postgresql.geometric.PGlseg"},
{"path", "org.postgresql.geometric.PGpath"},
{"point", "org.postgresql.geometric.PGpoint"},
{"polygon", "org.postgresql.geometric.PGpolygon"},
{"money", "org.postgresql.util.PGmoney"}
};
// This initialises the objectTypes hashtable
private void initObjectTypes()
{
for (int i = 0;i < defaultObjectTypes.length;i++)
objectTypes.put(defaultObjectTypes[i][0], defaultObjectTypes[i][1]);
}
/*
* In some cases, it is desirable to immediately release a Connection's
* database and JDBC resources instead of waiting for them to be
* automatically released (cant think why off the top of my head)
*
* <B>Note:</B> A Connection is automatically closed when it is
* garbage collected. Certain fatal errors also result in a closed
* connection.
*
* @exception SQLException if a database access error occurs
*/
public void close() throws SQLException
{
if (pg_stream != null)
{
try
{
pg_stream.SendChar('X');
pg_stream.flush();
pg_stream.close();
}
catch (IOException e)
{}
// 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", "org.postgresql.geometric.PGbox"},
{"circle", "org.postgresql.geometric.PGcircle"},
{"line", "org.postgresql.geometric.PGline"},
{"lseg", "org.postgresql.geometric.PGlseg"},
{"path", "org.postgresql.geometric.PGpath"},
{"point", "org.postgresql.geometric.PGpoint"},
{"polygon", "org.postgresql.geometric.PGpolygon"},
{"money", "org.postgresql.util.PGmoney"}
};
// This initialises the objectTypes hashtable
private void initObjectTypes()
{
for (int i = 0;i < defaultObjectTypes.length;i++)
objectTypes.put(defaultObjectTypes[i][0], defaultObjectTypes[i][1]);
}
/*
* In some cases, it is desirable to immediately release a Connection's
* database and JDBC resources instead of waiting for them to be
* automatically released (cant think why off the top of my head)
*
* <B>Note:</B> A Connection is automatically closed when it is
* garbage collected. Certain fatal errors also result in a closed
* connection.
*
* @exception SQLException if a database access error occurs
*/
public void close() throws SQLException
{
if (pg_stream != null)
{
try
{
pg_stream.SendChar('X');
pg_stream.flush();
pg_stream.close();
}
catch (IOException e)
{}
finally
{
pg_stream = null;
pg_stream = null;
}
}
}
/*
* A driver may convert the JDBC sql grammar into its system's
* native SQL grammar prior to sending it; nativeSQL returns the
* native form of the statement that the driver would have sent.
*
* @param sql a SQL statement that may contain one or more '?'
* parameter placeholders
* @return the native form of this statement
* @exception SQLException if a database access error occurs
*/
public String nativeSQL(String sql) throws SQLException
{
return sql;
}
/*
* The first warning reported by calls on this Connection is
* returned.
*
* <B>Note:</B> Sebsequent warnings will be changed to this
* SQLWarning
*
* @return the first SQLWarning or null
* @exception SQLException if a database access error occurs
*/
public SQLWarning getWarnings() throws SQLException
{
return firstWarning;
}
/*
* After this call, getWarnings returns null until a new warning
* is reported for this connection.
*
* @exception SQLException if a database access error occurs
*/
public void clearWarnings() throws SQLException
{
firstWarning = null;
}
/*
* You can put a connection in read-only mode as a hunt to enable
* database optimizations
*
* <B>Note:</B> setReadOnly cannot be called while in the middle
* of a transaction
*
* @param readOnly - true enables read-only mode; false disables it
* @exception SQLException if a database access error occurs
*/
public void setReadOnly(boolean readOnly) throws SQLException
{
this.readOnly = readOnly;
}
/*
* Tests to see if the connection is in Read Only Mode. Note that
* we cannot really put the database in read only mode, but we pretend
* we can by returning the value of the readOnly flag
*
* @return true if the connection is read only
* @exception SQLException if a database access error occurs
*/
public boolean isReadOnly() throws SQLException
{
return readOnly;
}
/*
* If a connection is in auto-commit mode, than all its SQL
* statements will be executed and committed as individual
* transactions. Otherwise, its SQL statements are grouped
* into transactions that are terminated by either commit()
* or rollback(). By default, new connections are in auto-
* commit mode. The commit occurs when the statement completes
* or the next execute occurs, whichever comes first. In the
* case of statements returning a ResultSet, the statement
* completes when the last row of the ResultSet has been retrieved
* or the ResultSet has been closed. In advanced cases, a single
* statement may return multiple results as well as output parameter
* values. Here the commit occurs when all results and output param
* values have been retrieved.
*
* @param autoCommit - true enables auto-commit; false disables it
* @exception SQLException if a database access error occurs
*/
public void setAutoCommit(boolean autoCommit) throws SQLException
{
if (this.autoCommit == autoCommit)
return;
if (autoCommit)
ExecSQL("end");
else
{
if (haveMinimumServerVersion("7.1"))
{
ExecSQL("begin;" + getIsolationLevelSQL());
}
else
{
ExecSQL("begin");
ExecSQL(getIsolationLevelSQL());
}
}
this.autoCommit = autoCommit;
}
/*
* gets the current auto-commit state
*
* @return Current state of the auto-commit mode
* @exception SQLException (why?)
* @see setAutoCommit
*/
public boolean getAutoCommit() throws SQLException
{
return this.autoCommit;
}
/*
* The method commit() makes all changes made since the previous
* commit/rollback permanent and releases any database locks currently
* held by the Connection. This method should only be used when
* auto-commit has been disabled. (If autoCommit == true, then we
* just return anyhow)
*
* @exception SQLException if a database access error occurs
* @see setAutoCommit
*/
public void commit() throws SQLException
{
if (autoCommit)
return;
if (haveMinimumServerVersion("7.1"))
{
ExecSQL("commit;begin;" + getIsolationLevelSQL());
}
else
{
ExecSQL("commit");
ExecSQL("begin");
ExecSQL(getIsolationLevelSQL());
}
}
/*
* The method rollback() drops all changes made since the previous
* commit/rollback and releases any database locks currently held by
* the Connection.
*
* @exception SQLException if a database access error occurs
* @see commit
*/
public void rollback() throws SQLException
{
if (autoCommit)
return;
if (haveMinimumServerVersion("7.1"))
{
ExecSQL("rollback; begin;" + getIsolationLevelSQL());
}
else
{
ExecSQL("rollback");
ExecSQL("begin");
ExecSQL(getIsolationLevelSQL());
}
}
/*
* Get this Connection's current transaction isolation mode.
*
* @return the current TRANSACTION_* mode value
* @exception SQLException if a database access error occurs
*/
public int getTransactionIsolation() throws SQLException
{
clearWarnings();
ExecSQL("show transaction isolation level");
SQLWarning warning = getWarnings();
if (warning != null)
{
String message = warning.getMessage();
clearWarnings();
if (message.indexOf("READ COMMITTED") != -1)
return java.sql.Connection.TRANSACTION_READ_COMMITTED;
else if (message.indexOf("READ UNCOMMITTED") != -1)
return java.sql.Connection.TRANSACTION_READ_UNCOMMITTED;
else if (message.indexOf("REPEATABLE READ") != -1)
return java.sql.Connection.TRANSACTION_REPEATABLE_READ;
else if (message.indexOf("SERIALIZABLE") != -1)
return java.sql.Connection.TRANSACTION_SERIALIZABLE;
}
return java.sql.Connection.TRANSACTION_READ_COMMITTED;
}
/*
* You can call this method to try to change the transaction
* isolation level using one of the TRANSACTION_* values.
*
* <B>Note:</B> setTransactionIsolation cannot be called while
* in the middle of a transaction
*
* @param level one of the TRANSACTION_* isolation values with
* the exception of TRANSACTION_NONE; some databases may
* not support other values
* @exception SQLException if a database access error occurs
* @see java.sql.DatabaseMetaData#supportsTransactionIsolationLevel
*/
public void setTransactionIsolation(int level) throws SQLException
{
//In 7.1 and later versions of the server it is possible using
//the "set session" command to set this once for all future txns
//however in 7.0 and prior versions it is necessary to set it in
//each transaction, thus adding complexity below.
//When we decide to drop support for servers older than 7.1
//this can be simplified
isolationLevel = level;
String isolationLevelSQL;
if (!haveMinimumServerVersion("7.1"))
{
isolationLevelSQL = getIsolationLevelSQL();
}
else
{
isolationLevelSQL = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL ";
switch (isolationLevel)
{
case java.sql.Connection.TRANSACTION_READ_COMMITTED:
isolationLevelSQL += "READ COMMITTED";
break;
case java.sql.Connection.TRANSACTION_SERIALIZABLE:
isolationLevelSQL += "SERIALIZABLE";
break;
default:
throw new PSQLException("postgresql.con.isolevel",
new Integer(isolationLevel));
}
}
ExecSQL(isolationLevelSQL);
}
/*
* Helper method used by setTransactionIsolation(), commit(), rollback()
* and setAutoCommit(). This returns the SQL string needed to
* set the isolation level for a transaction. In 7.1 and later it
* is possible to set a default isolation level that applies to all
* future transactions, this method is only necesary for 7.0 and older
* servers, and should be removed when support for these older
* servers are dropped
*/
protected String getIsolationLevelSQL() throws SQLException
{
//7.1 and higher servers have a default specified so
//no additional SQL is required to set the isolation level
if (haveMinimumServerVersion("7.1"))
{
return "";
}
StringBuffer sb = new StringBuffer("SET TRANSACTION ISOLATION LEVEL");
switch (isolationLevel)
{
case java.sql.Connection.TRANSACTION_READ_COMMITTED:
sb.append(" READ COMMITTED");
break;
case java.sql.Connection.TRANSACTION_SERIALIZABLE:
sb.append(" SERIALIZABLE");
break;
default:
throw new PSQLException("postgresql.con.isolevel", new Integer(isolationLevel));
}
return sb.toString();
}
/*
* A sub-space of this Connection's database may be selected by
* setting a catalog name. If the driver does not support catalogs,
* it will silently ignore this request
*
* @exception SQLException if a database access error occurs
*/
public void setCatalog(String catalog) throws SQLException
{
//no-op
}
/*
* Return the connections current catalog name, or null if no
* catalog name is set, or we dont support catalogs.
*
* @return the current catalog name or null
* @exception SQLException if a database access error occurs
*/
public String getCatalog() throws SQLException
{
return PG_DATABASE;
}
/*
* Overides finalize(). If called, it closes the connection.
*
* This was done at the request of Rachel Greenham
* <rachel@enlarion.demon.co.uk> who hit a problem where multiple
* clients didn't close the connection, and once a fortnight enough
* clients were open to kill the org.postgres server.
*/
public void finalize() throws Throwable
{
close();
}
private static String extractVersionNumber(String fullVersionString)
{
StringTokenizer versionParts = new StringTokenizer(fullVersionString);
versionParts.nextToken(); /* "PostgreSQL" */
return versionParts.nextToken(); /* "X.Y.Z" */
}
/*
* Get server version number
*/
public String getDBVersionNumber()
{
return dbVersionNumber;
}
public boolean haveMinimumServerVersion(String ver) throws SQLException
{
return (getDBVersionNumber().compareTo(ver) >= 0);
}
/*
* This method returns true if the compatible level set in the connection
* (which can be passed into the connection or specified in the URL)
* is at least the value passed to this method. 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.
*/
public boolean haveMinimumCompatibleVersion(String ver) throws SQLException
{
return (compatible.compareTo(ver) >= 0);
}
/*
* This returns the java.sql.Types type for a PG type oid
*
* @param oid PostgreSQL type oid
* @return the java.sql.Types type
* @exception SQLException if a database access error occurs
*/
public int getSQLType(int oid) throws SQLException
{
Integer sqlType = (Integer)sqlTypeCache.get(new Integer(oid));
// it's not in the cache, so perform a query, and add the result to the cache
if (sqlType == null)
{
ResultSet result = ExecSQL("select typname from pg_type where oid = " + oid);
if (((AbstractJdbc1ResultSet)result).getColumnCount() != 1 || ((AbstractJdbc1ResultSet)result).getTupleCount() != 1)
throw new PSQLException("postgresql.unexpected");
result.next();
String pgType = result.getString(1);
Integer iOid = new Integer(oid);
sqlType = new Integer(getSQLType(result.getString(1)));
sqlTypeCache.put(iOid, sqlType);
pgTypeCache.put(iOid, pgType);
result.close();
}
return sqlType.intValue();
}
/*
* This returns the oid for a given PG data type
* @param typeName PostgreSQL type name
* @return PostgreSQL oid value for a field of this type
*/
public int getPGType(String typeName) throws SQLException
{
int oid = -1;
if (typeName != null)
{
Integer oidValue = (Integer) typeOidCache.get(typeName);
if (oidValue != null)
{
oid = oidValue.intValue();
}
else
{
// it's not in the cache, so perform a query, and add the result to the cache
ResultSet result = ExecSQL("select oid from pg_type where typname='"
+ typeName + "'");
if (((AbstractJdbc1ResultSet)result).getColumnCount() != 1 || ((AbstractJdbc1ResultSet)result).getTupleCount() != 1)
throw new PSQLException("postgresql.unexpected");
result.next();
oid = Integer.parseInt(result.getString(1));
typeOidCache.put(typeName, new Integer(oid));
result.close();
}
}
return oid;
}
/*
* We also need to get the PG type name as returned by the back end.
*
* @return the String representation of the type of this field
* @exception SQLException if a database access error occurs
*/
public String getPGType(int oid) throws SQLException
{
String pgType = (String) pgTypeCache.get(new Integer(oid));
if (pgType == null)
{
getSQLType(oid);
pgType = (String) pgTypeCache.get(new Integer(oid));
}
return pgType;
}
//Because the get/setLogStream methods are deprecated in JDBC2
//we use them for JDBC1 here and override this method in the jdbc2
//version of this class
protected void enableDriverManagerLogging() {
if (DriverManager.getLogStream() == null) {
DriverManager.setLogStream(System.out);
}
}
}
/*
* A driver may convert the JDBC sql grammar into its system's
* native SQL grammar prior to sending it; nativeSQL returns the
* native form of the statement that the driver would have sent.
*
* @param sql a SQL statement that may contain one or more '?'
* parameter placeholders
* @return the native form of this statement
* @exception SQLException if a database access error occurs
*/
public String nativeSQL(String sql) throws SQLException
{
return sql;
}
/*
* The first warning reported by calls on this Connection is
* returned.
*
* <B>Note:</B> Sebsequent warnings will be changed to this
* SQLWarning
*
* @return the first SQLWarning or null
* @exception SQLException if a database access error occurs
*/
public SQLWarning getWarnings() throws SQLException
{
return firstWarning;
}
/*
* After this call, getWarnings returns null until a new warning
* is reported for this connection.
*
* @exception SQLException if a database access error occurs
*/
public void clearWarnings() throws SQLException
{
firstWarning = null;
}
/*
* You can put a connection in read-only mode as a hunt to enable
* database optimizations
*
* <B>Note:</B> setReadOnly cannot be called while in the middle
* of a transaction
*
* @param readOnly - true enables read-only mode; false disables it
* @exception SQLException if a database access error occurs
*/
public void setReadOnly(boolean readOnly) throws SQLException
{
this.readOnly = readOnly;
}
/*
* Tests to see if the connection is in Read Only Mode. Note that
* we cannot really put the database in read only mode, but we pretend
* we can by returning the value of the readOnly flag
*
* @return true if the connection is read only
* @exception SQLException if a database access error occurs
*/
public boolean isReadOnly() throws SQLException
{
return readOnly;
}
/*
* If a connection is in auto-commit mode, than all its SQL
* statements will be executed and committed as individual
* transactions. Otherwise, its SQL statements are grouped
* into transactions that are terminated by either commit()
* or rollback(). By default, new connections are in auto-
* commit mode. The commit occurs when the statement completes
* or the next execute occurs, whichever comes first. In the
* case of statements returning a ResultSet, the statement
* completes when the last row of the ResultSet has been retrieved
* or the ResultSet has been closed. In advanced cases, a single
* statement may return multiple results as well as output parameter
* values. Here the commit occurs when all results and output param
* values have been retrieved.
*
* @param autoCommit - true enables auto-commit; false disables it
* @exception SQLException if a database access error occurs
*/
public void setAutoCommit(boolean autoCommit) throws SQLException
{
if (this.autoCommit == autoCommit)
return ;
if (autoCommit)
ExecSQL("end");
else
{
if (haveMinimumServerVersion("7.1"))
{
ExecSQL("begin;" + getIsolationLevelSQL());
}
else
{
ExecSQL("begin");
ExecSQL(getIsolationLevelSQL());
}
}
this.autoCommit = autoCommit;
}
/*
* gets the current auto-commit state
*
* @return Current state of the auto-commit mode
* @exception SQLException (why?)
* @see setAutoCommit
*/
public boolean getAutoCommit() throws SQLException
{
return this.autoCommit;
}
/*
* The method commit() makes all changes made since the previous
* commit/rollback permanent and releases any database locks currently
* held by the Connection. This method should only be used when
* auto-commit has been disabled. (If autoCommit == true, then we
* just return anyhow)
*
* @exception SQLException if a database access error occurs
* @see setAutoCommit
*/
public void commit() throws SQLException
{
if (autoCommit)
return ;
if (haveMinimumServerVersion("7.1"))
{
ExecSQL("commit;begin;" + getIsolationLevelSQL());
}
else
{
ExecSQL("commit");
ExecSQL("begin");
ExecSQL(getIsolationLevelSQL());
}
}
/*
* The method rollback() drops all changes made since the previous
* commit/rollback and releases any database locks currently held by
* the Connection.
*
* @exception SQLException if a database access error occurs
* @see commit
*/
public void rollback() throws SQLException
{
if (autoCommit)
return ;
if (haveMinimumServerVersion("7.1"))
{
ExecSQL("rollback; begin;" + getIsolationLevelSQL());
}
else
{
ExecSQL("rollback");
ExecSQL("begin");
ExecSQL(getIsolationLevelSQL());
}
}
/*
* Get this Connection's current transaction isolation mode.
*
* @return the current TRANSACTION_* mode value
* @exception SQLException if a database access error occurs
*/
public int getTransactionIsolation() throws SQLException
{
clearWarnings();
ExecSQL("show transaction isolation level");
SQLWarning warning = getWarnings();
if (warning != null)
{
String message = warning.getMessage();
clearWarnings();
if (message.indexOf("READ COMMITTED") != -1)
return java.sql.Connection.TRANSACTION_READ_COMMITTED;
else if (message.indexOf("READ UNCOMMITTED") != -1)
return java.sql.Connection.TRANSACTION_READ_UNCOMMITTED;
else if (message.indexOf("REPEATABLE READ") != -1)
return java.sql.Connection.TRANSACTION_REPEATABLE_READ;
else if (message.indexOf("SERIALIZABLE") != -1)
return java.sql.Connection.TRANSACTION_SERIALIZABLE;
}
return java.sql.Connection.TRANSACTION_READ_COMMITTED;
}
/*
* You can call this method to try to change the transaction
* isolation level using one of the TRANSACTION_* values.
*
* <B>Note:</B> setTransactionIsolation cannot be called while
* in the middle of a transaction
*
* @param level one of the TRANSACTION_* isolation values with
* the exception of TRANSACTION_NONE; some databases may
* not support other values
* @exception SQLException if a database access error occurs
* @see java.sql.DatabaseMetaData#supportsTransactionIsolationLevel
*/
public void setTransactionIsolation(int level) throws SQLException
{
//In 7.1 and later versions of the server it is possible using
//the "set session" command to set this once for all future txns
//however in 7.0 and prior versions it is necessary to set it in
//each transaction, thus adding complexity below.
//When we decide to drop support for servers older than 7.1
//this can be simplified
isolationLevel = level;
String isolationLevelSQL;
if (!haveMinimumServerVersion("7.1"))
{
isolationLevelSQL = getIsolationLevelSQL();
}
else
{
isolationLevelSQL = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL ";
switch (isolationLevel)
{
case java.sql.Connection.TRANSACTION_READ_COMMITTED:
isolationLevelSQL += "READ COMMITTED";
break;
case java.sql.Connection.TRANSACTION_SERIALIZABLE:
isolationLevelSQL += "SERIALIZABLE";
break;
default:
throw new PSQLException("postgresql.con.isolevel",
new Integer(isolationLevel));
}
}
ExecSQL(isolationLevelSQL);
}
/*
* Helper method used by setTransactionIsolation(), commit(), rollback()
* and setAutoCommit(). This returns the SQL string needed to
* set the isolation level for a transaction. In 7.1 and later it
* is possible to set a default isolation level that applies to all
* future transactions, this method is only necesary for 7.0 and older
* servers, and should be removed when support for these older
* servers are dropped
*/
protected String getIsolationLevelSQL() throws SQLException
{
//7.1 and higher servers have a default specified so
//no additional SQL is required to set the isolation level
if (haveMinimumServerVersion("7.1"))
{
return "";
}
StringBuffer sb = new StringBuffer("SET TRANSACTION ISOLATION LEVEL");
switch (isolationLevel)
{
case java.sql.Connection.TRANSACTION_READ_COMMITTED:
sb.append(" READ COMMITTED");
break;
case java.sql.Connection.TRANSACTION_SERIALIZABLE:
sb.append(" SERIALIZABLE");
break;
default:
throw new PSQLException("postgresql.con.isolevel", new Integer(isolationLevel));
}
return sb.toString();
}
/*
* A sub-space of this Connection's database may be selected by
* setting a catalog name. If the driver does not support catalogs,
* it will silently ignore this request
*
* @exception SQLException if a database access error occurs
*/
public void setCatalog(String catalog) throws SQLException
{
//no-op
}
/*
* Return the connections current catalog name, or null if no
* catalog name is set, or we dont support catalogs.
*
* @return the current catalog name or null
* @exception SQLException if a database access error occurs
*/
public String getCatalog() throws SQLException
{
return PG_DATABASE;
}
/*
* Overides finalize(). If called, it closes the connection.
*
* This was done at the request of Rachel Greenham
* <rachel@enlarion.demon.co.uk> who hit a problem where multiple
* clients didn't close the connection, and once a fortnight enough
* clients were open to kill the org.postgres server.
*/
public void finalize() throws Throwable
{
close();
}
private static String extractVersionNumber(String fullVersionString)
{
StringTokenizer versionParts = new StringTokenizer(fullVersionString);
versionParts.nextToken(); /* "PostgreSQL" */
return versionParts.nextToken(); /* "X.Y.Z" */
}
/*
* Get server version number
*/
public String getDBVersionNumber()
{
return dbVersionNumber;
}
public boolean haveMinimumServerVersion(String ver) throws SQLException
{
return (getDBVersionNumber().compareTo(ver) >= 0);
}
/*
* This method returns true if the compatible level set in the connection
* (which can be passed into the connection or specified in the URL)
* is at least the value passed to this method. 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.
*/
public boolean haveMinimumCompatibleVersion(String ver) throws SQLException
{
return (compatible.compareTo(ver) >= 0);
}
/*
* This returns the java.sql.Types type for a PG type oid
*
* @param oid PostgreSQL type oid
* @return the java.sql.Types type
* @exception SQLException if a database access error occurs
*/
public int getSQLType(int oid) throws SQLException
{
Integer sqlType = (Integer)sqlTypeCache.get(new Integer(oid));
// it's not in the cache, so perform a query, and add the result to the cache
if (sqlType == null)
{
ResultSet result = ExecSQL("select typname from pg_type where oid = " + oid);
if (((AbstractJdbc1ResultSet)result).getColumnCount() != 1 || ((AbstractJdbc1ResultSet)result).getTupleCount() != 1)
throw new PSQLException("postgresql.unexpected");
result.next();
String pgType = result.getString(1);
Integer iOid = new Integer(oid);
sqlType = new Integer(getSQLType(result.getString(1)));
sqlTypeCache.put(iOid, sqlType);
pgTypeCache.put(iOid, pgType);
result.close();
}
return sqlType.intValue();
}
/*
* This returns the oid for a given PG data type
* @param typeName PostgreSQL type name
* @return PostgreSQL oid value for a field of this type
*/
public int getPGType(String typeName) throws SQLException
{
int oid = -1;
if (typeName != null)
{
Integer oidValue = (Integer) typeOidCache.get(typeName);
if (oidValue != null)
{
oid = oidValue.intValue();
}
else
{
// it's not in the cache, so perform a query, and add the result to the cache
ResultSet result = ExecSQL("select oid from pg_type where typname='"
+ typeName + "'");
if (((AbstractJdbc1ResultSet)result).getColumnCount() != 1 || ((AbstractJdbc1ResultSet)result).getTupleCount() != 1)
throw new PSQLException("postgresql.unexpected");
result.next();
oid = Integer.parseInt(result.getString(1));
typeOidCache.put(typeName, new Integer(oid));
result.close();
}
}
return oid;
}
/*
* We also need to get the PG type name as returned by the back end.
*
* @return the String representation of the type of this field
* @exception SQLException if a database access error occurs
*/
public String getPGType(int oid) throws SQLException
{
String pgType = (String) pgTypeCache.get(new Integer(oid));
if (pgType == null)
{
getSQLType(oid);
pgType = (String) pgTypeCache.get(new Integer(oid));
}
return pgType;
}
//Because the get/setLogStream methods are deprecated in JDBC2
//we use them for JDBC1 here and override this method in the jdbc2
//version of this class
protected void enableDriverManagerLogging()
{
if (DriverManager.getLogStream() == null)
{
DriverManager.setLogStream(System.out);
}
}
// This is a cache of the DatabaseMetaData instance for this connection
......@@ -1312,22 +1331,25 @@ public abstract class AbstractJdbc1Connection implements org.postgresql.PGConnec
Types.TIMESTAMP, Types.TIMESTAMP, Types.TIMESTAMP
};
//Methods to support postgres notifications
public void addNotification(org.postgresql.PGNotification p_notification) {
if (m_notifications == null)
m_notifications = new Vector();
m_notifications.addElement(p_notification);
}
public PGNotification[] getNotifications() {
PGNotification[] l_return = null;
if (m_notifications != null) {
l_return = new PGNotification[m_notifications.size()];
m_notifications.copyInto(l_return);
//Methods to support postgres notifications
public void addNotification(org.postgresql.PGNotification p_notification)
{
if (m_notifications == null)
m_notifications = new Vector();
m_notifications.addElement(p_notification);
}
public PGNotification[] getNotifications()
{
PGNotification[] l_return = null;
if (m_notifications != null)
{
l_return = new PGNotification[m_notifications.size()];
m_notifications.copyInto(l_return);
}
m_notifications = null;
return l_return;
}
m_notifications = null;
return l_return;
}
}
......@@ -10,14 +10,14 @@ import org.postgresql.Driver;
public abstract class AbstractJdbc1DatabaseMetaData
{
private static final String keywords = "abort,acl,add,aggregate,append,archive," +
"arch_store,backward,binary,change,cluster,"+
"copy,database,delimiter,delimiters,do,extend,"+
"explain,forward,heavy,index,inherits,isnull,"+
"light,listen,load,merge,nothing,notify,"+
"notnull,oids,purge,rename,replace,retrieve,"+
"returns,rule,recipe,setof,stdin,stdout,store,"+
"vacuum,verbose,version";
private static final String keywords = "abort,acl,add,aggregate,append,archive," +
"arch_store,backward,binary,change,cluster," +
"copy,database,delimiter,delimiters,do,extend," +
"explain,forward,heavy,index,inherits,isnull," +
"light,listen,load,merge,nothing,notify," +
"notnull,oids,purge,rename,replace,retrieve," +
"returns,rule,recipe,setof,stdin,stdout,store," +
"vacuum,verbose,version";
protected AbstractJdbc1Connection connection; // The connection association
......@@ -30,7 +30,7 @@ public abstract class AbstractJdbc1DatabaseMetaData
public AbstractJdbc1DatabaseMetaData(AbstractJdbc1Connection conn)
{
this.connection = conn;
this.connection = conn;
}
/*
......@@ -42,8 +42,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean allProceduresAreCallable() throws SQLException
{
if (Driver.logDebug) Driver.debug("allProceduresAreCallable");
return true; // For now...
if (Driver.logDebug)
Driver.debug("allProceduresAreCallable");
return true; // For now...
}
/*
......@@ -55,7 +56,8 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean allTablesAreSelectable() throws SQLException
{
if (Driver.logDebug) Driver.debug("allTablesAreSelectable");
if (Driver.logDebug)
Driver.debug("allTablesAreSelectable");
return true; // For now...
}
......@@ -67,9 +69,10 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public String getURL() throws SQLException
{
String url = connection.getURL();
if (Driver.logDebug) Driver.debug("getURL " + url);
return url;
String url = connection.getURL();
if (Driver.logDebug)
Driver.debug("getURL " + url);
return url;
}
/*
......@@ -80,9 +83,10 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public String getUserName() throws SQLException
{
String userName = connection.getUserName();
if (Driver.logDebug) Driver.debug("getUserName " + userName);
return userName;
String userName = connection.getUserName();
if (Driver.logDebug)
Driver.debug("getUserName " + userName);
return userName;
}
/*
......@@ -93,9 +97,10 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean isReadOnly() throws SQLException
{
boolean isReadOnly = connection.isReadOnly();
if (Driver.logDebug) Driver.debug("isReadOnly " + isReadOnly);
return isReadOnly;
boolean isReadOnly = connection.isReadOnly();
if (Driver.logDebug)
Driver.debug("isReadOnly " + isReadOnly);
return isReadOnly;
}
/*
......@@ -106,9 +111,10 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean nullsAreSortedHigh() throws SQLException
{
boolean nullSortedHigh = connection.haveMinimumServerVersion("7.2");
if (Driver.logDebug) Driver.debug("nullsAreSortedHigh " + nullSortedHigh);
return nullSortedHigh;
boolean nullSortedHigh = connection.haveMinimumServerVersion("7.2");
if (Driver.logDebug)
Driver.debug("nullsAreSortedHigh " + nullSortedHigh);
return nullSortedHigh;
}
/*
......@@ -119,8 +125,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean nullsAreSortedLow() throws SQLException
{
if (Driver.logDebug) Driver.debug("nullsAreSortedLow false");
return false;
if (Driver.logDebug)
Driver.debug("nullsAreSortedLow false");
return false;
}
/*
......@@ -131,8 +138,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean nullsAreSortedAtStart() throws SQLException
{
if (Driver.logDebug) Driver.debug("nullsAreSortedAtStart false");
return false;
if (Driver.logDebug)
Driver.debug("nullsAreSortedAtStart false");
return false;
}
/*
......@@ -143,9 +151,10 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean nullsAreSortedAtEnd() throws SQLException
{
boolean nullsAreSortedAtEnd = ! connection.haveMinimumServerVersion("7.2");
if (Driver.logDebug) Driver.debug("nullsAreSortedAtEnd " + nullsAreSortedAtEnd);
return nullsAreSortedAtEnd;
boolean nullsAreSortedAtEnd = ! connection.haveMinimumServerVersion("7.2");
if (Driver.logDebug)
Driver.debug("nullsAreSortedAtEnd " + nullsAreSortedAtEnd);
return nullsAreSortedAtEnd;
}
/*
......@@ -157,8 +166,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public String getDatabaseProductName() throws SQLException
{
if (Driver.logDebug) Driver.debug("getDatabaseProductName PostgresSQL");
return "PostgreSQL";
if (Driver.logDebug)
Driver.debug("getDatabaseProductName PostgresSQL");
return "PostgreSQL";
}
/*
......@@ -169,9 +179,10 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public String getDatabaseProductVersion() throws SQLException
{
String versionNumber = connection.getDBVersionNumber();
if (Driver.logDebug) Driver.debug("getDatabaseProductVersion " + versionNumber);
return versionNumber;
String versionNumber = connection.getDBVersionNumber();
if (Driver.logDebug)
Driver.debug("getDatabaseProductVersion " + versionNumber);
return versionNumber;
}
/*
......@@ -183,9 +194,10 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public String getDriverName() throws SQLException
{
String driverName = "PostgreSQL Native Driver";
if (Driver.logDebug) Driver.debug("getDriverName" + driverName);
return driverName;
String driverName = "PostgreSQL Native Driver";
if (Driver.logDebug)
Driver.debug("getDriverName" + driverName);
return driverName;
}
/*
......@@ -197,9 +209,10 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public String getDriverVersion() throws SQLException
{
String driverVersion = connection.this_driver.getVersion();
if (Driver.logDebug) Driver.debug("getDriverVersion " + driverVersion);
return driverVersion;
String driverVersion = connection.this_driver.getVersion();
if (Driver.logDebug)
Driver.debug("getDriverVersion " + driverVersion);
return driverVersion;
}
/*
......@@ -209,9 +222,10 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public int getDriverMajorVersion()
{
int majorVersion = connection.this_driver.getMajorVersion();
if (Driver.logDebug) Driver.debug("getMajorVersion " + majorVersion);
return majorVersion;
int majorVersion = connection.this_driver.getMajorVersion();
if (Driver.logDebug)
Driver.debug("getMajorVersion " + majorVersion);
return majorVersion;
}
/*
......@@ -221,9 +235,10 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public int getDriverMinorVersion()
{
int minorVersion = connection.this_driver.getMinorVersion();
if (Driver.logDebug) Driver.debug("getMinorVersion " + minorVersion);
return minorVersion;
int minorVersion = connection.this_driver.getMinorVersion();
if (Driver.logDebug)
Driver.debug("getMinorVersion " + minorVersion);
return minorVersion;
}
/*
......@@ -235,8 +250,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean usesLocalFiles() throws SQLException
{
if (Driver.logDebug) Driver.debug("usesLocalFiles " + false);
return false;
if (Driver.logDebug)
Driver.debug("usesLocalFiles " + false);
return false;
}
/*
......@@ -248,8 +264,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean usesLocalFilePerTable() throws SQLException
{
if (Driver.logDebug) Driver.debug("usesLocalFilePerTable " + false);
return false;
if (Driver.logDebug)
Driver.debug("usesLocalFilePerTable " + false);
return false;
}
/*
......@@ -266,8 +283,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsMixedCaseIdentifiers() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsMixedCaseIdentifiers " + false);
return false;
if (Driver.logDebug)
Driver.debug("supportsMixedCaseIdentifiers " + false);
return false;
}
/*
......@@ -278,8 +296,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean storesUpperCaseIdentifiers() throws SQLException
{
if (Driver.logDebug) Driver.debug("storesUpperCaseIdentifiers " + false);
return false;
if (Driver.logDebug)
Driver.debug("storesUpperCaseIdentifiers " + false);
return false;
}
/*
......@@ -290,8 +309,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean storesLowerCaseIdentifiers() throws SQLException
{
if (Driver.logDebug) Driver.debug("storesLowerCaseIdentifiers " + true);
return true;
if (Driver.logDebug)
Driver.debug("storesLowerCaseIdentifiers " + true);
return true;
}
/*
......@@ -302,8 +322,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean storesMixedCaseIdentifiers() throws SQLException
{
if (Driver.logDebug) Driver.debug("storesMixedCaseIdentifiers " + false);
return false;
if (Driver.logDebug)
Driver.debug("storesMixedCaseIdentifiers " + false);
return false;
}
/*
......@@ -316,8 +337,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsMixedCaseQuotedIdentifiers " + true);
return true;
if (Driver.logDebug)
Driver.debug("supportsMixedCaseQuotedIdentifiers " + true);
return true;
}
/*
......@@ -328,8 +350,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean storesUpperCaseQuotedIdentifiers() throws SQLException
{
if (Driver.logDebug) Driver.debug("storesUpperCaseQuotedIdentifiers " + false);
return false;
if (Driver.logDebug)
Driver.debug("storesUpperCaseQuotedIdentifiers " + false);
return false;
}
/*
......@@ -340,8 +363,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean storesLowerCaseQuotedIdentifiers() throws SQLException
{
if (Driver.logDebug) Driver.debug("storesLowerCaseQuotedIdentifiers " + false);
return false;
if (Driver.logDebug)
Driver.debug("storesLowerCaseQuotedIdentifiers " + false);
return false;
}
/*
......@@ -352,8 +376,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean storesMixedCaseQuotedIdentifiers() throws SQLException
{
if (Driver.logDebug) Driver.debug("storesMixedCaseQuotedIdentifiers " + false);
return false;
if (Driver.logDebug)
Driver.debug("storesMixedCaseQuotedIdentifiers " + false);
return false;
}
/*
......@@ -366,8 +391,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public String getIdentifierQuoteString() throws SQLException
{
if (Driver.logDebug) Driver.debug("getIdentifierQuoteString \"" );
return "\"";
if (Driver.logDebug)
Driver.debug("getIdentifierQuoteString \"" );
return "\"";
}
/*
......@@ -393,26 +419,30 @@ public abstract class AbstractJdbc1DatabaseMetaData
public String getNumericFunctions() throws SQLException
{
if (Driver.logDebug) Driver.debug("getNumericFunctions");
return "";
if (Driver.logDebug)
Driver.debug("getNumericFunctions");
return "";
}
public String getStringFunctions() throws SQLException
{
if (Driver.logDebug) Driver.debug("getStringFunctions");
return "";
if (Driver.logDebug)
Driver.debug("getStringFunctions");
return "";
}
public String getSystemFunctions() throws SQLException
{
if (Driver.logDebug) Driver.debug("getSystemFunctions");
return "";
if (Driver.logDebug)
Driver.debug("getSystemFunctions");
return "";
}
public String getTimeDateFunctions() throws SQLException
{
if (Driver.logDebug) Driver.debug("getTimeDateFunctions");
return "";
if (Driver.logDebug)
Driver.debug("getTimeDateFunctions");
return "";
}
/*
......@@ -424,8 +454,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public String getSearchStringEscape() throws SQLException
{
if (Driver.logDebug) Driver.debug("getSearchStringEscape");
return "\\";
if (Driver.logDebug)
Driver.debug("getSearchStringEscape");
return "\\";
}
/*
......@@ -441,8 +472,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public String getExtraNameCharacters() throws SQLException
{
if (Driver.logDebug) Driver.debug("getExtraNameCharacters");
return "";
if (Driver.logDebug)
Driver.debug("getExtraNameCharacters");
return "";
}
/*
......@@ -454,8 +486,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsAlterTableWithAddColumn() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsAlterTableWithAddColumn " + true);
return true;
if (Driver.logDebug)
Driver.debug("supportsAlterTableWithAddColumn " + true);
return true;
}
/*
......@@ -467,7 +500,8 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsAlterTableWithDropColumn() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsAlterTableWithDropColumn " + false);
if (Driver.logDebug)
Driver.debug("supportsAlterTableWithDropColumn " + false);
return false;
}
......@@ -491,8 +525,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsColumnAliasing() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsColumnAliasing " + true);
return true;
if (Driver.logDebug)
Driver.debug("supportsColumnAliasing " + true);
return true;
}
/*
......@@ -504,20 +539,23 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean nullPlusNonNullIsNull() throws SQLException
{
if (Driver.logDebug) Driver.debug("nullPlusNonNullIsNull " + true);
return true;
if (Driver.logDebug)
Driver.debug("nullPlusNonNullIsNull " + true);
return true;
}
public boolean supportsConvert() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsConvert " + false);
return false;
if (Driver.logDebug)
Driver.debug("supportsConvert " + false);
return false;
}
public boolean supportsConvert(int fromType, int toType) throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsConvert " + false);
return false;
if (Driver.logDebug)
Driver.debug("supportsConvert " + false);
return false;
}
/*
......@@ -529,8 +567,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsTableCorrelationNames() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsTableCorrelationNames " + true);
return true;
if (Driver.logDebug)
Driver.debug("supportsTableCorrelationNames " + true);
return true;
}
/*
......@@ -542,8 +581,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsDifferentTableCorrelationNames() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsDifferentTableCorrelationNames " + false);
return false;
if (Driver.logDebug)
Driver.debug("supportsDifferentTableCorrelationNames " + false);
return false;
}
/*
......@@ -556,8 +596,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsExpressionsInOrderBy() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsExpressionsInOrderBy " + true);
return true;
if (Driver.logDebug)
Driver.debug("supportsExpressionsInOrderBy " + true);
return true;
}
/*
......@@ -568,9 +609,10 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsOrderByUnrelated() throws SQLException
{
boolean supportsOrderByUnrelated = connection.haveMinimumServerVersion("6.4");
if (Driver.logDebug) Driver.debug("supportsOrderByUnrelated " + supportsOrderByUnrelated);
return supportsOrderByUnrelated;
boolean supportsOrderByUnrelated = connection.haveMinimumServerVersion("6.4");
if (Driver.logDebug)
Driver.debug("supportsOrderByUnrelated " + supportsOrderByUnrelated);
return supportsOrderByUnrelated;
}
/*
......@@ -582,8 +624,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsGroupBy() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsGroupBy " + true);
return true;
if (Driver.logDebug)
Driver.debug("supportsGroupBy " + true);
return true;
}
/*
......@@ -594,9 +637,10 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsGroupByUnrelated() throws SQLException
{
boolean supportsGroupByUnrelated = connection.haveMinimumServerVersion("6.4");
if (Driver.logDebug) Driver.debug("supportsGroupByUnrelated " + supportsGroupByUnrelated);
return supportsGroupByUnrelated;
boolean supportsGroupByUnrelated = connection.haveMinimumServerVersion("6.4");
if (Driver.logDebug)
Driver.debug("supportsGroupByUnrelated " + supportsGroupByUnrelated);
return supportsGroupByUnrelated;
}
/*
......@@ -611,9 +655,10 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsGroupByBeyondSelect() throws SQLException
{
boolean supportsGroupByBeyondSelect = connection.haveMinimumServerVersion("6.4");
if (Driver.logDebug) Driver.debug("supportsGroupByUnrelated " + supportsGroupByBeyondSelect);
return supportsGroupByBeyondSelect;
boolean supportsGroupByBeyondSelect = connection.haveMinimumServerVersion("6.4");
if (Driver.logDebug)
Driver.debug("supportsGroupByUnrelated " + supportsGroupByBeyondSelect);
return supportsGroupByBeyondSelect;
}
/*
......@@ -625,9 +670,10 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsLikeEscapeClause() throws SQLException
{
boolean supportsLikeEscapeClause = connection.haveMinimumServerVersion("7.1");
if (Driver.logDebug) Driver.debug("supportsLikeEscapeClause " + supportsLikeEscapeClause);
return supportsLikeEscapeClause;
boolean supportsLikeEscapeClause = connection.haveMinimumServerVersion("7.1");
if (Driver.logDebug)
Driver.debug("supportsLikeEscapeClause " + supportsLikeEscapeClause);
return supportsLikeEscapeClause;
}
/*
......@@ -640,8 +686,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsMultipleResultSets() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsMultipleResultSets " + false);
return false;
if (Driver.logDebug)
Driver.debug("supportsMultipleResultSets " + false);
return false;
}
/*
......@@ -654,8 +701,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsMultipleTransactions() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsMultipleTransactions " + true);
return true;
if (Driver.logDebug)
Driver.debug("supportsMultipleTransactions " + true);
return true;
}
/*
......@@ -670,8 +718,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsNonNullableColumns() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsNonNullableColumns true");
return true;
if (Driver.logDebug)
Driver.debug("supportsNonNullableColumns true");
return true;
}
/*
......@@ -688,8 +737,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsMinimumSQLGrammar() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsMinimumSQLGrammar TRUE");
return true;
if (Driver.logDebug)
Driver.debug("supportsMinimumSQLGrammar TRUE");
return true;
}
/*
......@@ -701,8 +751,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsCoreSQLGrammar() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsCoreSQLGrammar FALSE ");
return false;
if (Driver.logDebug)
Driver.debug("supportsCoreSQLGrammar FALSE ");
return false;
}
/*
......@@ -715,8 +766,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsExtendedSQLGrammar() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsExtendedSQLGrammar FALSE");
return false;
if (Driver.logDebug)
Driver.debug("supportsExtendedSQLGrammar FALSE");
return false;
}
/*
......@@ -733,9 +785,10 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsANSI92EntryLevelSQL() throws SQLException
{
boolean schemas = connection.haveMinimumServerVersion("7.3");
if (Driver.logDebug) Driver.debug("supportsANSI92EntryLevelSQL " + schemas);
return schemas;
boolean schemas = connection.haveMinimumServerVersion("7.3");
if (Driver.logDebug)
Driver.debug("supportsANSI92EntryLevelSQL " + schemas);
return schemas;
}
/*
......@@ -747,8 +800,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsANSI92IntermediateSQL() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsANSI92IntermediateSQL false ");
return false;
if (Driver.logDebug)
Driver.debug("supportsANSI92IntermediateSQL false ");
return false;
}
/*
......@@ -759,8 +813,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsANSI92FullSQL() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsANSI92FullSQL false ");
return false;
if (Driver.logDebug)
Driver.debug("supportsANSI92FullSQL false ");
return false;
}
/*
......@@ -772,8 +827,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsIntegrityEnhancementFacility() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsIntegrityEnhancementFacility false ");
return false;
if (Driver.logDebug)
Driver.debug("supportsIntegrityEnhancementFacility false ");
return false;
}
/*
......@@ -784,9 +840,10 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsOuterJoins() throws SQLException
{
boolean supportsOuterJoins = connection.haveMinimumServerVersion("7.1");
if (Driver.logDebug) Driver.debug("supportsOuterJoins " + supportsOuterJoins);
return supportsOuterJoins;
boolean supportsOuterJoins = connection.haveMinimumServerVersion("7.1");
if (Driver.logDebug)
Driver.debug("supportsOuterJoins " + supportsOuterJoins);
return supportsOuterJoins;
}
/*
......@@ -797,9 +854,10 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsFullOuterJoins() throws SQLException
{
boolean supportsFullOuterJoins = connection.haveMinimumServerVersion("7.1");
if (Driver.logDebug) Driver.debug("supportsFullOuterJoins " + supportsFullOuterJoins);
return supportsFullOuterJoins;
boolean supportsFullOuterJoins = connection.haveMinimumServerVersion("7.1");
if (Driver.logDebug)
Driver.debug("supportsFullOuterJoins " + supportsFullOuterJoins);
return supportsFullOuterJoins;
}
/*
......@@ -810,9 +868,10 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsLimitedOuterJoins() throws SQLException
{
boolean supportsLimitedOuterJoins = connection.haveMinimumServerVersion("7.1");
if (Driver.logDebug) Driver.debug("supportsFullOuterJoins " + supportsLimitedOuterJoins);
return supportsLimitedOuterJoins;
boolean supportsLimitedOuterJoins = connection.haveMinimumServerVersion("7.1");
if (Driver.logDebug)
Driver.debug("supportsFullOuterJoins " + supportsLimitedOuterJoins);
return supportsLimitedOuterJoins;
}
/*
......@@ -825,8 +884,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public String getSchemaTerm() throws SQLException
{
if (Driver.logDebug) Driver.debug("getSchemaTerm schema");
return "schema";
if (Driver.logDebug)
Driver.debug("getSchemaTerm schema");
return "schema";
}
/*
......@@ -838,8 +898,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public String getProcedureTerm() throws SQLException
{
if (Driver.logDebug) Driver.debug("getProcedureTerm function ");
return "function";
if (Driver.logDebug)
Driver.debug("getProcedureTerm function ");
return "function";
}
/*
......@@ -850,8 +911,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public String getCatalogTerm() throws SQLException
{
if (Driver.logDebug) Driver.debug("getCatalogTerm database ");
return "database";
if (Driver.logDebug)
Driver.debug("getCatalogTerm database ");
return "database";
}
/*
......@@ -863,10 +925,11 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean isCatalogAtStart() throws SQLException
{
// return true here; we return false for every other catalog function
// so it won't matter what we return here D.C.
if (Driver.logDebug) Driver.debug("isCatalogAtStart not implemented");
return true;
// return true here; we return false for every other catalog function
// so it won't matter what we return here D.C.
if (Driver.logDebug)
Driver.debug("isCatalogAtStart not implemented");
return true;
}
/*
......@@ -877,10 +940,11 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public String getCatalogSeparator() throws SQLException
{
// Give them something to work with here
// everything else returns false so it won't matter what we return here D.C.
if (Driver.logDebug) Driver.debug("getCatalogSeparator not implemented ");
return ".";
// Give them something to work with here
// everything else returns false so it won't matter what we return here D.C.
if (Driver.logDebug)
Driver.debug("getCatalogSeparator not implemented ");
return ".";
}
/*
......@@ -891,8 +955,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsSchemasInDataManipulation() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsSchemasInDataManipulation false");
return false;
if (Driver.logDebug)
Driver.debug("supportsSchemasInDataManipulation false");
return false;
}
/*
......@@ -903,8 +968,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsSchemasInProcedureCalls() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsSchemasInProcedureCalls false");
return false;
if (Driver.logDebug)
Driver.debug("supportsSchemasInProcedureCalls false");
return false;
}
/*
......@@ -915,10 +981,11 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsSchemasInTableDefinitions() throws SQLException
{
boolean schemas = connection.haveMinimumServerVersion("7.3");
boolean schemas = connection.haveMinimumServerVersion("7.3");
if (Driver.logDebug) Driver.debug("supportsSchemasInTableDefinitions " + schemas);
return schemas;
if (Driver.logDebug)
Driver.debug("supportsSchemasInTableDefinitions " + schemas);
return schemas;
}
/*
......@@ -929,8 +996,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsSchemasInIndexDefinitions() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsSchemasInIndexDefinitions false");
return false;
if (Driver.logDebug)
Driver.debug("supportsSchemasInIndexDefinitions false");
return false;
}
/*
......@@ -941,8 +1009,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsSchemasInPrivilegeDefinitions false");
return false;
if (Driver.logDebug)
Driver.debug("supportsSchemasInPrivilegeDefinitions false");
return false;
}
/*
......@@ -953,8 +1022,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsCatalogsInDataManipulation() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsCatalogsInDataManipulation false");
return false;
if (Driver.logDebug)
Driver.debug("supportsCatalogsInDataManipulation false");
return false;
}
/*
......@@ -965,8 +1035,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsCatalogsInProcedureCalls() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsCatalogsInDataManipulation false");
return false;
if (Driver.logDebug)
Driver.debug("supportsCatalogsInDataManipulation false");
return false;
}
/*
......@@ -977,8 +1048,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsCatalogsInTableDefinitions() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsCatalogsInTableDefinitions false");
return false;
if (Driver.logDebug)
Driver.debug("supportsCatalogsInTableDefinitions false");
return false;
}
/*
......@@ -989,8 +1061,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsCatalogsInIndexDefinitions() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsCatalogsInIndexDefinitions false");
return false;
if (Driver.logDebug)
Driver.debug("supportsCatalogsInIndexDefinitions false");
return false;
}
/*
......@@ -1001,8 +1074,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsCatalogsInPrivilegeDefinitions false");
return false;
if (Driver.logDebug)
Driver.debug("supportsCatalogsInPrivilegeDefinitions false");
return false;
}
/*
......@@ -1014,8 +1088,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsPositionedDelete() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsPositionedDelete false");
return false; // For now...
if (Driver.logDebug)
Driver.debug("supportsPositionedDelete false");
return false; // For now...
}
/*
......@@ -1026,8 +1101,9 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsPositionedUpdate() throws SQLException
{
if (Driver.logDebug) Driver.debug("supportsPositionedUpdate false");
return false; // For now...
if (Driver.logDebug)
Driver.debug("supportsPositionedUpdate false");
return false; // For now...
}
/*
......@@ -1038,7 +1114,7 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsSelectForUpdate() throws SQLException
{
return connection.haveMinimumServerVersion("6.5");
return connection.haveMinimumServerVersion("6.5");
}
/*
......@@ -1050,7 +1126,7 @@ public abstract class AbstractJdbc1DatabaseMetaData
*/
public boolean supportsStoredProcedures() throws SQLException
{
return false;
return false;
}
/*
......@@ -1809,14 +1885,14 @@ public abstract class AbstractJdbc1DatabaseMetaData
{
case (byte) 'r':
if ( r.getString(1).startsWith("pg_") )
{
relKind = "SYSTEM TABLE";
}
else
{
relKind = "TABLE";
}
break;
{
relKind = "SYSTEM TABLE";
}
else
{
relKind = "TABLE";
}
break;
case (byte) 'i':
relKind = "INDEX";
break;
......@@ -2100,7 +2176,7 @@ public abstract class AbstractJdbc1DatabaseMetaData
// from the typmod value.
if (typname.equals("numeric") || typname.equals("decimal"))
{
int attypmod = r.getInt(8) - VARHDRSZ;
int attypmod = r.getInt(8) - VARHDRSZ;
tuple[8] =
Integer.toString(attypmod & 0xffff).getBytes();
tuple[9] =
......@@ -2184,7 +2260,8 @@ public abstract class AbstractJdbc1DatabaseMetaData
{
byte[][] tuple = new byte[8][0];
tuple[0] = tuple[1] = "".getBytes();
if (Driver.logDebug) Driver.debug("relname=\"" + r.getString(1) + "\" relacl=\"" + r.getString(2) + "\"");
if (Driver.logDebug)
Driver.debug("relname=\"" + r.getString(1) + "\" relacl=\"" + r.getString(2) + "\"");
// For now, don't add to the result as relacl needs to be processed.
//v.addElement(tuple);
......@@ -2193,68 +2270,69 @@ public abstract class AbstractJdbc1DatabaseMetaData
return connection.getResultSet(null, f, v, "OK", 1);
}
/*
* Get a description of the access rights for each table available
* in a catalog.
*
* This method is currently unimplemented.
*
* <P>Only privileges matching the schema and table name
* criteria are returned. They are ordered by TABLE_SCHEM,
* TABLE_NAME, and PRIVILEGE.
*
* <P>Each privilige description has the following columns:
* <OL>
* <LI><B>TABLE_CAT</B> String => table catalog (may be null)
* <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
* <LI><B>TABLE_NAME</B> String => table name
* <LI><B>COLUMN_NAME</B> String => column name
* <LI><B>GRANTOR</B> => grantor of access (may be null)
* <LI><B>GRANTEE</B> String => grantee of access
* <LI><B>PRIVILEGE</B> String => name of access (SELECT,
* INSERT, UPDATE, REFRENCES, ...)
* <LI><B>IS_GRANTABLE</B> String => "YES" if grantee is permitted
* to grant to others; "NO" if not; null if unknown
* </OL>
*
* @param catalog a catalog name; "" retrieves those without a catalog
* @param schemaPattern a schema name pattern; "" retrieves those
* without a schema
* @param tableNamePattern a table name pattern
* @return ResultSet each row is a table privilege description
* @see #getSearchStringEscape
*/
public java.sql.ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) throws SQLException
{
Field f[] = new Field[8];
Vector v = new Vector();
if (tableNamePattern == null)
tableNamePattern = "%";
f[0] = new Field(connection, "TABLE_CAT", iVarcharOid, 32);
f[1] = new Field(connection, "TABLE_SCHEM", iVarcharOid, 32);
f[2] = new Field(connection, "TABLE_NAME", iVarcharOid, 32);
f[3] = new Field(connection, "COLUMN_NAME", iVarcharOid, 32);
f[4] = new Field(connection, "GRANTOR", iVarcharOid, 32);
f[5] = new Field(connection, "GRANTEE", iVarcharOid, 32);
f[6] = new Field(connection, "PRIVILEGE", iVarcharOid, 32);
f[7] = new Field(connection, "IS_GRANTABLE", iVarcharOid, 32);
// This is taken direct from the psql source
java.sql.ResultSet r = connection.ExecSQL("SELECT relname, relacl FROM pg_class, pg_user WHERE ( relkind = 'r' OR relkind = 'i') and relname !~ '^pg_' and relname !~ '^xin[vx][0-9]+' and usesysid = relowner and relname like '" + tableNamePattern.toLowerCase() + "' ORDER BY relname");
while (r.next())
{
byte[][] tuple = new byte[8][0];
tuple[0] = tuple[1] = "".getBytes();
if (Driver.logDebug) Driver.debug("relname=\"" + r.getString(1) + "\" relacl=\"" + r.getString(2) + "\"");
// For now, don't add to the result as relacl needs to be processed.
//v.addElement(tuple);
}
return connection.getResultSet(null, f, v, "OK", 1);
}
/*
* Get a description of the access rights for each table available
* in a catalog.
*
* This method is currently unimplemented.
*
* <P>Only privileges matching the schema and table name
* criteria are returned. They are ordered by TABLE_SCHEM,
* TABLE_NAME, and PRIVILEGE.
*
* <P>Each privilige description has the following columns:
* <OL>
* <LI><B>TABLE_CAT</B> String => table catalog (may be null)
* <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
* <LI><B>TABLE_NAME</B> String => table name
* <LI><B>COLUMN_NAME</B> String => column name
* <LI><B>GRANTOR</B> => grantor of access (may be null)
* <LI><B>GRANTEE</B> String => grantee of access
* <LI><B>PRIVILEGE</B> String => name of access (SELECT,
* INSERT, UPDATE, REFRENCES, ...)
* <LI><B>IS_GRANTABLE</B> String => "YES" if grantee is permitted
* to grant to others; "NO" if not; null if unknown
* </OL>
*
* @param catalog a catalog name; "" retrieves those without a catalog
* @param schemaPattern a schema name pattern; "" retrieves those
* without a schema
* @param tableNamePattern a table name pattern
* @return ResultSet each row is a table privilege description
* @see #getSearchStringEscape
*/
public java.sql.ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) throws SQLException
{
Field f[] = new Field[8];
Vector v = new Vector();
if (tableNamePattern == null)
tableNamePattern = "%";
f[0] = new Field(connection, "TABLE_CAT", iVarcharOid, 32);
f[1] = new Field(connection, "TABLE_SCHEM", iVarcharOid, 32);
f[2] = new Field(connection, "TABLE_NAME", iVarcharOid, 32);
f[3] = new Field(connection, "COLUMN_NAME", iVarcharOid, 32);
f[4] = new Field(connection, "GRANTOR", iVarcharOid, 32);
f[5] = new Field(connection, "GRANTEE", iVarcharOid, 32);
f[6] = new Field(connection, "PRIVILEGE", iVarcharOid, 32);
f[7] = new Field(connection, "IS_GRANTABLE", iVarcharOid, 32);
// This is taken direct from the psql source
java.sql.ResultSet r = connection.ExecSQL("SELECT relname, relacl FROM pg_class, pg_user WHERE ( relkind = 'r' OR relkind = 'i') and relname !~ '^pg_' and relname !~ '^xin[vx][0-9]+' and usesysid = relowner and relname like '" + tableNamePattern.toLowerCase() + "' ORDER BY relname");
while (r.next())
{
byte[][] tuple = new byte[8][0];
tuple[0] = tuple[1] = "".getBytes();
if (Driver.logDebug)
Driver.debug("relname=\"" + r.getString(1) + "\" relacl=\"" + r.getString(2) + "\"");
// For now, don't add to the result as relacl needs to be processed.
//v.addElement(tuple);
}
return connection.getResultSet(null, f, v, "OK", 1);
}
/*
* Get a description of a table's optimal set of columns that
......@@ -2375,7 +2453,7 @@ public abstract class AbstractJdbc1DatabaseMetaData
"a.attnum as KEY_SEQ," +
"ic.relname as PK_NAME " +
" FROM pg_class bc, pg_class ic, pg_index i, pg_attribute a" +
" WHERE bc.relkind = 'r' " + // -- not indices
" WHERE bc.relkind = 'r' " + // -- not indices
" and upper(bc.relname) = upper('" + table + "')" +
" and i.indrelid = bc.oid" +
" and i.indexrelid = ic.oid" +
......@@ -2385,274 +2463,275 @@ public abstract class AbstractJdbc1DatabaseMetaData
);
}
/*
SELECT
c.relname as primary,
c2.relname as foreign,
t.tgconstrname,
ic.relname as fkeyname,
af.attnum as fkeyseq,
ipc.relname as pkeyname,
ap.attnum as pkeyseq,
t.tgdeferrable,
t.tginitdeferred,
t.tgnargs,t.tgargs,
p1.proname as updaterule,
p2.proname as deleterule
FROM
pg_trigger t,
pg_trigger t1,
pg_class c,
pg_class c2,
pg_class ic,
pg_class ipc,
pg_proc p1,
pg_proc p2,
pg_index if,
pg_index ip,
pg_attribute af,
pg_attribute ap
WHERE
(t.tgrelid=c.oid
AND t.tgisconstraint
AND t.tgconstrrelid=c2.oid
AND t.tgfoid=p1.oid
and p1.proname like '%%upd')
and
(t1.tgrelid=c.oid
and t1.tgisconstraint
and t1.tgconstrrelid=c2.oid
AND t1.tgfoid=p2.oid
and p2.proname like '%%del')
AND c2.relname='users'
AND
(if.indrelid=c.oid
AND if.indexrelid=ic.oid
and ic.oid=af.attrelid
AND if.indisprimary)
and
(ip.indrelid=c2.oid
and ip.indexrelid=ipc.oid
and ipc.oid=ap.attrelid
and ip.indisprimary)
*/
/**
*
* @param catalog
* @param schema
* @param primaryTable if provided will get the keys exported by this table
* @param foreignTable if provided will get the keys imported by this table
* @return ResultSet
* @throws SQLException
*/
protected java.sql.ResultSet getImportedExportedKeys(String catalog, String schema, String primaryTable, String foreignTable) throws SQLException
{
Field f[] = new Field[14];
f[0] = new Field(connection, "PKTABLE_CAT", iVarcharOid, 32);
f[1] = new Field(connection, "PKTABLE_SCHEM", iVarcharOid, 32);
f[2] = new Field(connection, "PKTABLE_NAME", iVarcharOid, 32);
f[3] = new Field(connection, "PKCOLUMN_NAME", iVarcharOid, 32);
f[4] = new Field(connection, "FKTABLE_CAT", iVarcharOid, 32);
f[5] = new Field(connection, "FKTABLE_SCHEM", iVarcharOid, 32);
f[6] = new Field(connection, "FKTABLE_NAME", iVarcharOid, 32);
f[7] = new Field(connection, "FKCOLUMN_NAME", iVarcharOid, 32);
f[8] = new Field(connection, "KEY_SEQ", iInt2Oid, 2);
f[9] = new Field(connection, "UPDATE_RULE", iInt2Oid, 2);
f[10] = new Field(connection, "DELETE_RULE", iInt2Oid, 2);
f[11] = new Field(connection, "FK_NAME", iVarcharOid, 32);
f[12] = new Field(connection, "PK_NAME", iVarcharOid, 32);
f[13] = new Field(connection, "DEFERRABILITY", iInt2Oid, 2);
java.sql.ResultSet rs = connection.ExecSQL(
"SELECT distinct "
+ "c.relname as prelname, "
+ "c2.relname as frelname, "
+ "t.tgconstrname, "
+ "a.attnum as keyseq, "
+ "ic.relname as fkeyname, "
+ "t.tgdeferrable, "
+ "t.tginitdeferred, "
+ "t.tgnargs,t.tgargs, "
+ "p1.proname as updaterule, "
+ "p2.proname as deleterule "
+ "FROM "
+ "pg_trigger t, "
+ "pg_trigger t1, "
+ "pg_class c, "
+ "pg_class c2, "
+ "pg_class ic, "
+ "pg_proc p1, "
+ "pg_proc p2, "
+ "pg_index i, "
+ "pg_attribute a "
+ "WHERE "
// isolate the update rule
+ "(t.tgrelid=c.oid "
+ "AND t.tgisconstraint "
+ "AND t.tgconstrrelid=c2.oid "
+ "AND t.tgfoid=p1.oid "
+ "and p1.proname like '%%upd') "
+ "and "
// isolate the delete rule
+ "(t1.tgrelid=c.oid "
+ "and t1.tgisconstraint "
+ "and t1.tgconstrrelid=c2.oid "
+ "AND t1.tgfoid=p2.oid "
+ "and p2.proname like '%%del') "
// if we are looking for exported keys then primary table will be used
+ ((primaryTable != null) ? "AND c.relname='" + primaryTable + "' " : "")
// if we are looking for imported keys then the foreign table will be used
+ ((foreignTable != null) ? "AND c2.relname='" + foreignTable + "' " : "")
+ "AND i.indrelid=c.oid "
+ "AND i.indexrelid=ic.oid "
+ "AND ic.oid=a.attrelid "
+ "AND i.indisprimary "
+ "ORDER BY "
// orderby is as follows getExported, orders by FKTABLE,
// getImported orders by PKTABLE
// getCrossReference orders by FKTABLE, so this should work for both,
// since when getting crossreference, primaryTable will be defined
+ (primaryTable != null ? "frelname" : "prelname") + ",keyseq");
// returns the following columns
// and some example data with a table defined as follows
// create table people ( id int primary key);
// create table policy ( id int primary key);
// create table users ( id int primary key, people_id int references people(id), policy_id int references policy(id))
// prelname | frelname | tgconstrname | keyseq | fkeyName | tgdeferrable | tginitdeferred
// 1 | 2 | 3 | 4 | 5 | 6 | 7
// people | users | <unnamed> | 1 | people_pkey | f | f
// | tgnargs | tgargs | updaterule | deleterule
// | 8 | 9 | 10 | 11
// | 6 | <unnamed>\000users\000people\000UNSPECIFIED\000people_id\000id\000 | RI_FKey_noaction_upd | RI_FKey_noaction_del
Vector tuples = new Vector();
while ( rs.next() )
{
byte tuple[][] = new byte[14][];
tuple[2] = rs.getBytes(1); //PKTABLE_NAME
tuple[6] = rs.getBytes(2); //FKTABLE_NAME
String fKeyName = rs.getString(3);
String updateRule = rs.getString(10);
if (updateRule != null )
{
// Rules look like this RI_FKey_noaction_del so we want to pull out the part between the 'Key_' and the last '_' s
String rule = updateRule.substring(8, updateRule.length() - 4);
int action = java.sql.DatabaseMetaData.importedKeyNoAction;
if ( rule == null || "noaction".equals(rule) )
action = java.sql.DatabaseMetaData.importedKeyNoAction;
if ("cascade".equals(rule))
action = java.sql.DatabaseMetaData.importedKeyCascade;
else if ("setnull".equals(rule))
action = java.sql.DatabaseMetaData.importedKeySetNull;
else if ("setdefault".equals(rule))
action = java.sql.DatabaseMetaData.importedKeySetDefault;
else if ("restrict".equals(rule))
action = java.sql.DatabaseMetaData.importedKeyRestrict;
tuple[9] = Integer.toString(action).getBytes();
}
String deleteRule = rs.getString(11);
if ( deleteRule != null )
{
String rule = updateRule.substring(8, updateRule.length() - 4);
int action = java.sql.DatabaseMetaData.importedKeyNoAction;
if ("cascade".equals(rule))
action = java.sql.DatabaseMetaData.importedKeyCascade;
else if ("setnull".equals(rule))
action = java.sql.DatabaseMetaData.importedKeySetNull;
else if ("setdefault".equals(rule))
action = java.sql.DatabaseMetaData.importedKeySetDefault;
tuple[10] = Integer.toString(action).getBytes();
}
/*
SELECT
c.relname as primary,
c2.relname as foreign,
t.tgconstrname,
ic.relname as fkeyname,
af.attnum as fkeyseq,
ipc.relname as pkeyname,
ap.attnum as pkeyseq,
t.tgdeferrable,
t.tginitdeferred,
t.tgnargs,t.tgargs,
p1.proname as updaterule,
p2.proname as deleterule
FROM
pg_trigger t,
pg_trigger t1,
pg_class c,
pg_class c2,
pg_class ic,
pg_class ipc,
pg_proc p1,
pg_proc p2,
pg_index if,
pg_index ip,
pg_attribute af,
pg_attribute ap
WHERE
(t.tgrelid=c.oid
AND t.tgisconstraint
AND t.tgconstrrelid=c2.oid
AND t.tgfoid=p1.oid
and p1.proname like '%%upd')
and
(t1.tgrelid=c.oid
and t1.tgisconstraint
and t1.tgconstrrelid=c2.oid
AND t1.tgfoid=p2.oid
and p2.proname like '%%del')
AND c2.relname='users'
AND
(if.indrelid=c.oid
AND if.indexrelid=ic.oid
and ic.oid=af.attrelid
AND if.indisprimary)
and
(ip.indrelid=c2.oid
and ip.indexrelid=ipc.oid
and ipc.oid=ap.attrelid
and ip.indisprimary)
*/
/**
*
* @param catalog
* @param schema
* @param primaryTable if provided will get the keys exported by this table
* @param foreignTable if provided will get the keys imported by this table
* @return ResultSet
* @throws SQLException
*/
protected java.sql.ResultSet getImportedExportedKeys(String catalog, String schema, String primaryTable, String foreignTable) throws SQLException
{
Field f[] = new Field[14];
f[0] = new Field(connection, "PKTABLE_CAT", iVarcharOid, 32);
f[1] = new Field(connection, "PKTABLE_SCHEM", iVarcharOid, 32);
f[2] = new Field(connection, "PKTABLE_NAME", iVarcharOid, 32);
f[3] = new Field(connection, "PKCOLUMN_NAME", iVarcharOid, 32);
f[4] = new Field(connection, "FKTABLE_CAT", iVarcharOid, 32);
f[5] = new Field(connection, "FKTABLE_SCHEM", iVarcharOid, 32);
f[6] = new Field(connection, "FKTABLE_NAME", iVarcharOid, 32);
f[7] = new Field(connection, "FKCOLUMN_NAME", iVarcharOid, 32);
f[8] = new Field(connection, "KEY_SEQ", iInt2Oid, 2);
f[9] = new Field(connection, "UPDATE_RULE", iInt2Oid, 2);
f[10] = new Field(connection, "DELETE_RULE", iInt2Oid, 2);
f[11] = new Field(connection, "FK_NAME", iVarcharOid, 32);
f[12] = new Field(connection, "PK_NAME", iVarcharOid, 32);
f[13] = new Field(connection, "DEFERRABILITY", iInt2Oid, 2);
java.sql.ResultSet rs = connection.ExecSQL(
"SELECT distinct "
+ "c.relname as prelname, "
+ "c2.relname as frelname, "
+ "t.tgconstrname, "
+ "a.attnum as keyseq, "
+ "ic.relname as fkeyname, "
+ "t.tgdeferrable, "
+ "t.tginitdeferred, "
+ "t.tgnargs,t.tgargs, "
+ "p1.proname as updaterule, "
+ "p2.proname as deleterule "
+ "FROM "
+ "pg_trigger t, "
+ "pg_trigger t1, "
+ "pg_class c, "
+ "pg_class c2, "
+ "pg_class ic, "
+ "pg_proc p1, "
+ "pg_proc p2, "
+ "pg_index i, "
+ "pg_attribute a "
+ "WHERE "
// isolate the update rule
+ "(t.tgrelid=c.oid "
+ "AND t.tgisconstraint "
+ "AND t.tgconstrrelid=c2.oid "
+ "AND t.tgfoid=p1.oid "
+ "and p1.proname like '%%upd') "
+ "and "
// isolate the delete rule
+ "(t1.tgrelid=c.oid "
+ "and t1.tgisconstraint "
+ "and t1.tgconstrrelid=c2.oid "
+ "AND t1.tgfoid=p2.oid "
+ "and p2.proname like '%%del') "
// if we are looking for exported keys then primary table will be used
+ ((primaryTable != null) ? "AND c.relname='" + primaryTable + "' " : "")
// if we are looking for imported keys then the foreign table will be used
+ ((foreignTable != null) ? "AND c2.relname='" + foreignTable + "' " : "")
+ "AND i.indrelid=c.oid "
+ "AND i.indexrelid=ic.oid "
+ "AND ic.oid=a.attrelid "
+ "AND i.indisprimary "
+ "ORDER BY "
// orderby is as follows getExported, orders by FKTABLE,
// getImported orders by PKTABLE
// getCrossReference orders by FKTABLE, so this should work for both,
// since when getting crossreference, primaryTable will be defined
+ (primaryTable != null ? "frelname" : "prelname") + ",keyseq");
// returns the following columns
// and some example data with a table defined as follows
// create table people ( id int primary key);
// create table policy ( id int primary key);
// create table users ( id int primary key, people_id int references people(id), policy_id int references policy(id))
// prelname | frelname | tgconstrname | keyseq | fkeyName | tgdeferrable | tginitdeferred
// 1 | 2 | 3 | 4 | 5 | 6 | 7
// people | users | <unnamed> | 1 | people_pkey | f | f
// | tgnargs | tgargs | updaterule | deleterule
// | 8 | 9 | 10 | 11
// | 6 | <unnamed>\000users\000people\000UNSPECIFIED\000people_id\000id\000 | RI_FKey_noaction_upd | RI_FKey_noaction_del
Vector tuples = new Vector();
while ( rs.next() )
{
byte tuple[][] = new byte[14][];
// Parse the tgargs data
String fkeyColumn="";
String pkeyColumn="";
tuple[2] = rs.getBytes(1); //PKTABLE_NAME
tuple[6] = rs.getBytes(2); //FKTABLE_NAME
String fKeyName = rs.getString(3);
String updateRule = rs.getString(10);
if (updateRule != null )
{
// Rules look like this RI_FKey_noaction_del so we want to pull out the part between the 'Key_' and the last '_' s
// Note, I am guessing at most of this, but it should be close
// if not, please correct
// the keys are in pairs and start after the first four arguments
// the arguments are seperated by \000
String rule = updateRule.substring(8, updateRule.length() - 4);
int keySequence = rs.getInt(4); //KEY_SEQ
int action = java.sql.DatabaseMetaData.importedKeyNoAction;
// get the args
String targs = rs.getString(9);
if ( rule == null || "noaction".equals(rule) )
action = java.sql.DatabaseMetaData.importedKeyNoAction;
if ("cascade".equals(rule))
action = java.sql.DatabaseMetaData.importedKeyCascade;
else if ("setnull".equals(rule))
action = java.sql.DatabaseMetaData.importedKeySetNull;
else if ("setdefault".equals(rule))
action = java.sql.DatabaseMetaData.importedKeySetDefault;
else if ("restrict".equals(rule))
action = java.sql.DatabaseMetaData.importedKeyRestrict;
// args look like this
//<unnamed>\000ww\000vv\000UNSPECIFIED\000m\000a\000n\000b\000
// we are primarily interested in the column names which are the last items in the string
tuple[9] = Integer.toString(action).getBytes();
StringTokenizer st = new StringTokenizer(targs, "\\000");
}
String deleteRule = rs.getString(11);
if ( deleteRule != null )
{
String rule = updateRule.substring(8, updateRule.length() - 4);
int action = java.sql.DatabaseMetaData.importedKeyNoAction;
if ("cascade".equals(rule))
action = java.sql.DatabaseMetaData.importedKeyCascade;
else if ("setnull".equals(rule))
action = java.sql.DatabaseMetaData.importedKeySetNull;
else if ("setdefault".equals(rule))
action = java.sql.DatabaseMetaData.importedKeySetDefault;
tuple[10] = Integer.toString(action).getBytes();
}
// Parse the tgargs data
String fkeyColumn = "";
String pkeyColumn = "";
// Note, I am guessing at most of this, but it should be close
// if not, please correct
// the keys are in pairs and start after the first four arguments
// the arguments are seperated by \000
int keySequence = rs.getInt(4); //KEY_SEQ
int advance = 4 + (keySequence-1) * 2;
for( int i=0; st.hasMoreTokens() && i < advance ; i++ ) st.nextToken(); // advance to the key column of interest
// get the args
String targs = rs.getString(9);
if ( st.hasMoreTokens() )
{
fkeyColumn = st.nextToken();
}
if ( st.hasMoreTokens() )
{
pkeyColumn = st.nextToken();
}
// args look like this
//<unnamed>\000ww\000vv\000UNSPECIFIED\000m\000a\000n\000b\000
// we are primarily interested in the column names which are the last items in the string
tuple[3] = pkeyColumn.getBytes(); //PKCOLUMN_NAME
tuple[7] = fkeyColumn.getBytes(); //FKCOLUMN_NAME
StringTokenizer st = new StringTokenizer(targs, "\\000");
tuple[8] = rs.getBytes(4); //KEY_SEQ
tuple[11] = targs.getBytes(); //FK_NAME this will give us a unique name for the foreign key
tuple[12] = rs.getBytes(5); //PK_NAME
int advance = 4 + (keySequence - 1) * 2;
for ( int i = 0; st.hasMoreTokens() && i < advance ; i++ )
st.nextToken(); // advance to the key column of interest
// DEFERRABILITY
int deferrability = java.sql.DatabaseMetaData.importedKeyNotDeferrable;
boolean deferrable = rs.getBoolean(6);
boolean initiallyDeferred = rs.getBoolean(7);
if (deferrable)
{
if (initiallyDeferred)
deferrability = java.sql.DatabaseMetaData.importedKeyInitiallyDeferred;
else
deferrability = java.sql.DatabaseMetaData.importedKeyInitiallyImmediate;
}
tuple[13] = Integer.toString(deferrability).getBytes();
if ( st.hasMoreTokens() )
{
fkeyColumn = st.nextToken();
}
if ( st.hasMoreTokens() )
{
pkeyColumn = st.nextToken();
}
tuple[3] = pkeyColumn.getBytes(); //PKCOLUMN_NAME
tuple[7] = fkeyColumn.getBytes(); //FKCOLUMN_NAME
tuple[8] = rs.getBytes(4); //KEY_SEQ
tuple[11] = targs.getBytes(); //FK_NAME this will give us a unique name for the foreign key
tuple[12] = rs.getBytes(5); //PK_NAME
tuples.addElement(tuple);
}
// DEFERRABILITY
int deferrability = java.sql.DatabaseMetaData.importedKeyNotDeferrable;
boolean deferrable = rs.getBoolean(6);
boolean initiallyDeferred = rs.getBoolean(7);
if (deferrable)
{
if (initiallyDeferred)
deferrability = java.sql.DatabaseMetaData.importedKeyInitiallyDeferred;
else
deferrability = java.sql.DatabaseMetaData.importedKeyInitiallyImmediate;
}
tuple[13] = Integer.toString(deferrability).getBytes();
return connection.getResultSet(null, f, tuples, "OK", 1);
}
tuples.addElement(tuple);
}
return connection.getResultSet(null, f, tuples, "OK", 1);
}
/*
* Get a description of the primary key columns that are
......
......@@ -13,7 +13,7 @@ import org.postgresql.largeobject.*;
import org.postgresql.util.PGbytea;
import org.postgresql.util.PSQLException;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1ResultSet.java,v 1.5 2002/09/02 03:07:36 barry Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1ResultSet.java,v 1.6 2002/09/06 21:23:06 momjian Exp $
* This class defines methods of the jdbc1 specification. This class is
* extended by org.postgresql.jdbc2.AbstractJdbc2ResultSet which adds the jdbc2
* methods. The real ResultSet class (for jdbc1) is org.postgresql.jdbc1.Jdbc1ResultSet
......@@ -22,7 +22,7 @@ public abstract class AbstractJdbc1ResultSet
{
protected Vector rows; // The results
protected Statement statement;
protected Statement statement;
protected Field fields[]; // The field descriptions
protected String status; // Status of the result
protected boolean binaryCursor = false; // is the data binary or Strings
......@@ -39,13 +39,13 @@ public abstract class AbstractJdbc1ResultSet
protected ResultSet next = null;
protected StringBuffer sbuf = null;
public byte[][] rowBuffer=null;
public byte[][] rowBuffer = null;
public AbstractJdbc1ResultSet(org.postgresql.PGConnection conn, Statement statement, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor)
{
this.connection = conn;
this.statement = statement;
this.statement = statement;
this.fields = fields;
this.rows = tuples;
this.status = status;
......@@ -59,16 +59,16 @@ public abstract class AbstractJdbc1ResultSet
public boolean next() throws SQLException
{
if (rows == null)
throw new PSQLException("postgresql.con.closed");
if (rows == null)
throw new PSQLException("postgresql.con.closed");
if (++current_row >= rows.size())
return false;
this_row = (byte [][])rows.elementAt(current_row);
rowBuffer=new byte[this_row.length][];
System.arraycopy(this_row,0,rowBuffer,0,this_row.length);
rowBuffer = new byte[this_row.length][];
System.arraycopy(this_row, 0, rowBuffer, 0, this_row.length);
return true;
}
......@@ -230,12 +230,12 @@ public abstract class AbstractJdbc1ResultSet
public Time getTime(int columnIndex) throws SQLException
{
return toTime( getString(columnIndex), (java.sql.ResultSet)this, fields[columnIndex-1].getPGType() );
return toTime( getString(columnIndex), (java.sql.ResultSet)this, fields[columnIndex - 1].getPGType() );
}
public Timestamp getTimestamp(int columnIndex) throws SQLException
{
return toTimestamp( getString(columnIndex), (java.sql.ResultSet)this, fields[columnIndex-1].getPGType() );
return toTimestamp( getString(columnIndex), (java.sql.ResultSet)this, fields[columnIndex - 1].getPGType() );
}
public InputStream getAsciiStream(int columnIndex) throws SQLException
......@@ -423,11 +423,12 @@ public abstract class AbstractJdbc1ResultSet
warnings = null;
}
public void addWarnings(SQLWarning warnings) {
if ( this.warnings != null )
this.warnings.setNextWarning(warnings);
else
this.warnings = warnings;
public void addWarnings(SQLWarning warnings)
{
if ( this.warnings != null )
this.warnings.setNextWarning(warnings);
else
this.warnings = warnings;
}
public String getCursorName() throws SQLException
......@@ -612,18 +613,18 @@ public abstract class AbstractJdbc1ResultSet
/*
* returns the OID of the last inserted row. Deprecated in 7.2 because
* range for OID values is greater than java signed int.
* range for OID values is greater than java signed int.
* @deprecated Replaced by getLastOID() in 7.2
*/
public int getInsertedOID()
{
return (int) getLastOID();
return (int) getLastOID();
}
/*
* returns the OID of the last inserted row
* @since 7.2
* @since 7.2
*/
public long getLastOID()
{
......@@ -660,8 +661,10 @@ public abstract class AbstractJdbc1ResultSet
protected void checkResultSet( int column ) throws SQLException
{
if ( this_row == null ) throw new PSQLException("postgresql.res.nextrequired");
if ( column < 1 || column > fields.length ) throw new PSQLException("postgresql.res.colrange" );
if ( this_row == null )
throw new PSQLException("postgresql.res.nextrequired");
if ( column < 1 || column > fields.length )
throw new PSQLException("postgresql.res.colrange" );
}
//----------------- Formatting Methods -------------------
......@@ -789,26 +792,34 @@ public abstract class AbstractJdbc1ResultSet
return null; // SQL NULL
try
{
if (s.length() == 8) {
//value is a time value
return java.sql.Time.valueOf(s);
} else if (s.indexOf(".") == 8) {
//value is a time value with fractional seconds
java.sql.Time l_time = java.sql.Time.valueOf(s.substring(0,8));
String l_strMillis = s.substring(9);
if (l_strMillis.length() > 3)
l_strMillis = l_strMillis.substring(0,3);
int l_millis = Integer.parseInt(l_strMillis);
if (l_millis < 10) {
l_millis = l_millis * 100;
} else if (l_millis < 100) {
l_millis = l_millis * 10;
}
return new java.sql.Time(l_time.getTime() + l_millis);
} else {
//value is a timestamp
return new java.sql.Time(toTimestamp(s, resultSet, pgDataType).getTime());
}
if (s.length() == 8)
{
//value is a time value
return java.sql.Time.valueOf(s);
}
else if (s.indexOf(".") == 8)
{
//value is a time value with fractional seconds
java.sql.Time l_time = java.sql.Time.valueOf(s.substring(0, 8));
String l_strMillis = s.substring(9);
if (l_strMillis.length() > 3)
l_strMillis = l_strMillis.substring(0, 3);
int l_millis = Integer.parseInt(l_strMillis);
if (l_millis < 10)
{
l_millis = l_millis * 100;
}
else if (l_millis < 100)
{
l_millis = l_millis * 10;
}
return new java.sql.Time(l_time.getTime() + l_millis);
}
else
{
//value is a timestamp
return new java.sql.Time(toTimestamp(s, resultSet, pgDataType).getTime());
}
}
catch (NumberFormatException e)
{
......@@ -827,7 +838,7 @@ public abstract class AbstractJdbc1ResultSet
* From version 7.2 postgres returns fractional seconds to 6 places.
* If available, we drop the last 3 digits.
*
* @param s The ISO formated date string to parse.
* @param s The ISO formated date string to parse.
* @param resultSet The ResultSet this date is part of.
*
* @return null if s is null or a timestamp of the parsed string s.
......@@ -837,7 +848,7 @@ public abstract class AbstractJdbc1ResultSet
public static Timestamp toTimestamp(String s, java.sql.ResultSet resultSet, String pgDataType)
throws SQLException
{
AbstractJdbc1ResultSet rs = (AbstractJdbc1ResultSet)resultSet;
AbstractJdbc1ResultSet rs = (AbstractJdbc1ResultSet)resultSet;
if (s == null)
return null;
......@@ -847,12 +858,14 @@ public abstract class AbstractJdbc1ResultSet
synchronized (rs)
{
SimpleDateFormat df = null;
if ( org.postgresql.Driver.logDebug ) org.postgresql.Driver.debug("the data from the DB is "+s);
if ( org.postgresql.Driver.logDebug )
org.postgresql.Driver.debug("the data from the DB is " + s);
// If first time, create the buffer, otherwise clear it.
if (rs.sbuf == null)
rs.sbuf = new StringBuffer(32);
else {
else
{
rs.sbuf.setLength(0);
}
......@@ -880,7 +893,8 @@ public abstract class AbstractJdbc1ResultSet
if (i < 24)
rs.sbuf.append(c);
c = s.charAt(i++);
} while (i < slen && Character.isDigit(c));
}
while (i < slen && Character.isDigit(c));
// If there wasn't at least 3 digits we should add some zeros
// to make up the 3 digits we tell java to expect.
......@@ -911,37 +925,43 @@ public abstract class AbstractJdbc1ResultSet
}
else
{
// Just found fractional seconds but no timezone.
//If timestamptz then we use GMT, else local timezone
if (pgDataType.equals("timestamptz")) {
rs.sbuf.append(" GMT");
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS z");
} else {
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
}
// Just found fractional seconds but no timezone.
//If timestamptz then we use GMT, else local timezone
if (pgDataType.equals("timestamptz"))
{
rs.sbuf.append(" GMT");
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS z");
}
else
{
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
}
}
}
else if (slen == 19)
{
// No tz or fractional second info.
//If timestamptz then we use GMT, else local timezone
if (pgDataType.equals("timestamptz")) {
rs.sbuf.append(" GMT");
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
} else {
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
// No tz or fractional second info.
//If timestamptz then we use GMT, else local timezone
if (pgDataType.equals("timestamptz"))
{
rs.sbuf.append(" GMT");
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
}
else
{
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
}
else
{
if (slen == 8 && s.equals("infinity"))
//java doesn't have a concept of postgres's infinity
//so set to an arbitrary future date
s = "9999-01-01";
if (slen == 8 && s.equals("infinity"))
//java doesn't have a concept of postgres's infinity
//so set to an arbitrary future date
s = "9999-01-01";
if (slen == 9 && s.equals("-infinity"))
//java doesn't have a concept of postgres's infinity
//so set to an arbitrary old date
s = "0001-01-01";
//java doesn't have a concept of postgres's infinity
//so set to an arbitrary old date
s = "0001-01-01";
// We must just have a date. This case is
// needed if this method is called on a date
......@@ -952,7 +972,8 @@ public abstract class AbstractJdbc1ResultSet
try
{
// All that's left is to parse the string and return the ts.
if ( org.postgresql.Driver.logDebug ) org.postgresql.Driver.debug( "" + df.parse(rs.sbuf.toString()).getTime() );
if ( org.postgresql.Driver.logDebug )
org.postgresql.Driver.debug( "" + df.parse(rs.sbuf.toString()).getTime() );
return new Timestamp(df.parse(rs.sbuf.toString()).getTime());
}
......
......@@ -8,7 +8,7 @@ import org.postgresql.util.*;
import java.sql.SQLException;
import java.sql.Types;
public abstract class AbstractJdbc1ResultSetMetaData
public abstract class AbstractJdbc1ResultSetMetaData
{
protected Vector rows;
......
......@@ -8,7 +8,7 @@ import java.util.Vector;
import org.postgresql.largeobject.*;
import org.postgresql.util.*;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.6 2002/09/02 03:07:36 barry Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.7 2002/09/06 21:23:06 momjian Exp $
* This class defines methods of the jdbc1 specification. This class is
* extended by org.postgresql.jdbc2.AbstractJdbc2Statement which adds the jdbc2
* methods. The real Statement class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Statement
......@@ -16,8 +16,8 @@ import org.postgresql.util.*;
public abstract class AbstractJdbc1Statement implements org.postgresql.PGStatement
{
// The connection who created us
protected AbstractJdbc1Connection connection;
// The connection who created us
protected AbstractJdbc1Connection connection;
/** The warnings chain. */
protected SQLWarning warnings = null;
......@@ -42,15 +42,15 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
// Some performance caches
private StringBuffer sbuf = new StringBuffer(32);
//Used by the preparedstatement style methods
//Used by the preparedstatement style methods
protected String[] m_sqlFragments;
private String[] m_origSqlFragments;
private String[] m_executeSqlFragments;
protected Object[] m_binds = new Object[0];
private String[] m_bindTypes = new String[0];
private String m_statementName = null;
private boolean m_useServerPrepare = false;
private static int m_preparedCount = 1;
private String[] m_bindTypes = new String[0];
private String m_statementName = null;
private boolean m_useServerPrepare = false;
private static int m_preparedCount = 1;
//Used by the callablestatement style methods
private static final String JDBC_SYNTAX = "{[? =] call <some_function> ([? [,?]*]) }";
......@@ -58,7 +58,7 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
private String originalSql = "";
private boolean isFunction;
// functionReturnType contains the user supplied value to check
// testReturn contains a modified version to make it easier to
// testReturn contains a modified version to make it easier to
// check the getXXX methods..
private int functionReturnType;
private int testReturn;
......@@ -76,17 +76,19 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
public AbstractJdbc1Statement (AbstractJdbc1Connection connection, String p_sql) throws SQLException
{
this.connection = connection;
parseSqlStmt(p_sql); // this allows Callable stmt to override
parseSqlStmt(p_sql); // this allows Callable stmt to override
}
protected void parseSqlStmt (String p_sql) throws SQLException {
String l_sql = p_sql;
protected void parseSqlStmt (String p_sql) throws SQLException
{
String l_sql = p_sql;
l_sql = replaceProcessing(l_sql);
l_sql = replaceProcessing(l_sql);
if (this instanceof CallableStatement) {
l_sql = modifyJdbcCall(l_sql);
}
if (this instanceof CallableStatement)
{
l_sql = modifyJdbcCall(l_sql);
}
Vector v = new Vector();
boolean inQuotes = false;
......@@ -108,8 +110,8 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
m_sqlFragments = new String[v.size()];
m_binds = new String[v.size() - 1];
m_bindTypes = new String[v.size() - 1];
//BJL why if binds is new???
m_bindTypes = new String[v.size() - 1];
//BJL why if binds is new???
clearParameters();
for (i = 0 ; i < m_sqlFragments.length; ++i)
......@@ -127,9 +129,9 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
*/
public java.sql.ResultSet executeQuery(String p_sql) throws SQLException
{
String l_sql = replaceProcessing(p_sql);
m_sqlFragments = new String[] {l_sql};
return executeQuery();
String l_sql = replaceProcessing(p_sql);
m_sqlFragments = new String[] {l_sql};
return executeQuery();
}
/*
......@@ -160,9 +162,9 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
*/
public int executeUpdate(String p_sql) throws SQLException
{
String l_sql = replaceProcessing(p_sql);
m_sqlFragments = new String[] {l_sql};
return executeUpdate();
String l_sql = replaceProcessing(p_sql);
m_sqlFragments = new String[] {l_sql};
return executeUpdate();
}
/*
......@@ -195,9 +197,9 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
*/
public boolean execute(String p_sql) throws SQLException
{
String l_sql = replaceProcessing(p_sql);
m_sqlFragments = new String[] {l_sql};
return execute();
String l_sql = replaceProcessing(p_sql);
m_sqlFragments = new String[] {l_sql};
return execute();
}
/*
......@@ -213,15 +215,17 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
{
if (isFunction && !returnTypeSet)
throw new PSQLException("postgresql.call.noreturntype");
if (isFunction) { // set entry 1 to dummy entry..
if (isFunction)
{ // set entry 1 to dummy entry..
m_binds[0] = ""; // dummy entry which ensured that no one overrode
m_bindTypes[0] = PG_TEXT;
m_bindTypes[0] = PG_TEXT;
// and calls to setXXX (2,..) really went to first arg in a function call..
}
// New in 7.1, if we have a previous resultset then force it to close
// This brings us nearer to compliance, and helps memory management.
// Internal stuff will call ExecSQL directly, bypassing this.
if (result != null)
{
java.sql.ResultSet rs = getResultSet();
......@@ -229,73 +233,86 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
rs.close();
}
//Use server prepared statements if directed
if (m_useServerPrepare) {
if (m_statementName == null) {
m_statementName = "JDBC_STATEMENT_" + m_preparedCount++;
m_origSqlFragments = new String[m_sqlFragments.length];
m_executeSqlFragments = new String[m_sqlFragments.length];
System.arraycopy(m_sqlFragments, 0, m_origSqlFragments, 0, m_sqlFragments.length);
m_executeSqlFragments[0] = "EXECUTE " + m_statementName;
if (m_sqlFragments.length > 1) {
m_executeSqlFragments[0] = m_executeSqlFragments[0] + "(";
for(int i = 1; i < m_bindTypes.length; i++) {
m_executeSqlFragments[i] = ", ";
}
m_executeSqlFragments[m_bindTypes.length] = ")";
}
synchronized (sbuf) {
sbuf.setLength(0);
sbuf.append("PREPARE ");
sbuf.append(m_statementName);
if (m_origSqlFragments.length > 1) {
sbuf.append("(");
for(int i = 0; i < m_bindTypes.length - 1; i++) {
sbuf.append(m_bindTypes[i]);
sbuf.append(", ");
}
sbuf.append(m_bindTypes[m_bindTypes.length - 1]);
sbuf.append(")");
}
sbuf.append(" AS ");
sbuf.append(m_origSqlFragments[0]);
for(int i = 1; i < m_origSqlFragments.length; i++) {
sbuf.append(" $");
sbuf.append(i);
sbuf.append(" ");
sbuf.append(m_origSqlFragments[i]);
}
sbuf.append("; ");
sbuf.append(m_executeSqlFragments[0]);
m_sqlFragments[0] = sbuf.toString();
System.arraycopy(m_executeSqlFragments, 1, m_sqlFragments, 1, m_sqlFragments.length - 1);
}
//Use server prepared statements if directed
if (m_useServerPrepare)
{
if (m_statementName == null)
{
m_statementName = "JDBC_STATEMENT_" + m_preparedCount++;
m_origSqlFragments = new String[m_sqlFragments.length];
m_executeSqlFragments = new String[m_sqlFragments.length];
System.arraycopy(m_sqlFragments, 0, m_origSqlFragments, 0, m_sqlFragments.length);
m_executeSqlFragments[0] = "EXECUTE " + m_statementName;
if (m_sqlFragments.length > 1)
{
m_executeSqlFragments[0] = m_executeSqlFragments[0] + "(";
for (int i = 1; i < m_bindTypes.length; i++)
{
m_executeSqlFragments[i] = ", ";
}
m_executeSqlFragments[m_bindTypes.length] = ")";
}
synchronized (sbuf)
{
sbuf.setLength(0);
sbuf.append("PREPARE ");
sbuf.append(m_statementName);
if (m_origSqlFragments.length > 1)
{
sbuf.append("(");
for (int i = 0; i < m_bindTypes.length - 1; i++)
{
sbuf.append(m_bindTypes[i]);
sbuf.append(", ");
}
sbuf.append(m_bindTypes[m_bindTypes.length - 1]);
sbuf.append(")");
}
sbuf.append(" AS ");
sbuf.append(m_origSqlFragments[0]);
for (int i = 1; i < m_origSqlFragments.length; i++)
{
sbuf.append(" $");
sbuf.append(i);
sbuf.append(" ");
sbuf.append(m_origSqlFragments[i]);
}
sbuf.append("; ");
sbuf.append(m_executeSqlFragments[0]);
m_sqlFragments[0] = sbuf.toString();
System.arraycopy(m_executeSqlFragments, 1, m_sqlFragments, 1, m_sqlFragments.length - 1);
}
} else {
m_sqlFragments = m_executeSqlFragments;
}
}
else
{
m_sqlFragments = m_executeSqlFragments;
}
}
// New in 7.1, pass Statement so that ExecSQL can customise to it
result = ((AbstractJdbc1Connection)connection).ExecSQL(m_sqlFragments, m_binds, (java.sql.Statement)this);
//If we are executing a callable statement function set the return data
if (isFunction) {
if (!((AbstractJdbc1ResultSet)result).reallyResultSet())
throw new PSQLException("postgresql.call.noreturnval");
//If we are executing a callable statement function set the return data
if (isFunction)
{
if (!((AbstractJdbc1ResultSet)result).reallyResultSet())
throw new PSQLException("postgresql.call.noreturnval");
if (!result.next ())
throw new PSQLException ("postgresql.call.noreturnval");
callResult = result.getObject(1);
int columnType = result.getMetaData().getColumnType(1);
if (columnType != functionReturnType)
if (columnType != functionReturnType)
throw new PSQLException ("postgresql.call.wrongrtntype",
new Object[]{
"java.sql.Types=" + columnType, "java.sql.Types="+functionReturnType });
result.close ();
return true;
} else {
return (result != null && ((AbstractJdbc1ResultSet)result).reallyResultSet());
"java.sql.Types=" + columnType, "java.sql.Types=" + functionReturnType });
result.close ();
return true;
}
else
{
return (result != null && ((AbstractJdbc1ResultSet)result).reallyResultSet());
}
}
......@@ -336,8 +353,8 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
{
if (result == null)
return -1;
if (isFunction)
return 1;
if (isFunction)
return 1;
if (((AbstractJdbc1ResultSet)result).reallyResultSet())
return -1;
return ((AbstractJdbc1ResultSet)result).getResultCount();
......@@ -437,11 +454,11 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
* @param msg message to add
*/
public void addWarning(String msg)
{
if (warnings != null)
warnings.setNextWarning(new SQLWarning(msg));
else
warnings = new SQLWarning(msg);
{
if (warnings != null)
warnings.setNextWarning(new SQLWarning(msg));
else
warnings = new SQLWarning(msg);
}
/*
......@@ -513,7 +530,7 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
*/
public void cancel() throws SQLException
{
throw new PSQLException("postgresql.unimplemented");
throw new PSQLException("postgresql.unimplemented");
}
/*
......@@ -565,82 +582,85 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
*/
protected String replaceProcessing(String p_sql)
{
if (replaceProcessingEnabled) {
// Since escape codes can only appear in SQL CODE, we keep track
// of if we enter a string or not.
StringBuffer newsql = new StringBuffer(p_sql.length());
short state = IN_SQLCODE;
int i = -1;
int len = p_sql.length();
while (++i < len)
if (replaceProcessingEnabled)
{
char c = p_sql.charAt(i);
switch (state)
// Since escape codes can only appear in SQL CODE, we keep track
// of if we enter a string or not.
StringBuffer newsql = new StringBuffer(p_sql.length());
short state = IN_SQLCODE;
int i = -1;
int len = p_sql.length();
while (++i < len)
{
case IN_SQLCODE:
if (c == '\'') // start of a string?
state = IN_STRING;
else if (c == '{') // start of an escape code?
if (i + 1 < len)
{
char next = p_sql.charAt(i + 1);
if (next == 'd')
{
state = ESC_TIMEDATE;
i++;
break;
}
else if (next == 't')
char c = p_sql.charAt(i);
switch (state)
{
case IN_SQLCODE:
if (c == '\'') // start of a string?
state = IN_STRING;
else if (c == '{') // start of an escape code?
if (i + 1 < len)
{
state = ESC_TIMEDATE;
i += (i + 2 < len && p_sql.charAt(i + 2) == 's') ? 2 : 1;
break;
char next = p_sql.charAt(i + 1);
if (next == 'd')
{
state = ESC_TIMEDATE;
i++;
break;
}
else if (next == 't')
{
state = ESC_TIMEDATE;
i += (i + 2 < len && p_sql.charAt(i + 2) == 's') ? 2 : 1;
break;
}
}
}
newsql.append(c);
break;
case IN_STRING:
if (c == '\'') // end of string?
state = IN_SQLCODE;
else if (c == '\\') // a backslash?
state = BACKSLASH;
newsql.append(c);
break;
newsql.append(c);
break;
case IN_STRING:
if (c == '\'') // end of string?
state = IN_SQLCODE;
else if (c == '\\') // a backslash?
state = BACKSLASH;
case BACKSLASH:
state = IN_STRING;
newsql.append(c);
break;
newsql.append(c);
break;
case BACKSLASH:
state = IN_STRING;
case ESC_TIMEDATE:
if (c == '}')
state = IN_SQLCODE; // end of escape code.
else
newsql.append(c);
break;
} // end switch
}
break;
case ESC_TIMEDATE:
if (c == '}')
state = IN_SQLCODE; // end of escape code.
else
newsql.append(c);
break;
} // end switch
}
return newsql.toString();
} else {
return p_sql;
}
return newsql.toString();
}
else
{
return p_sql;
}
}
/*
*
* The following methods are postgres extensions and are defined
* in the interface org.postgresql.Statement
*
*/
/*
*
* The following methods are postgres extensions and are defined
* in the interface org.postgresql.Statement
*
*/
/*
* Returns the Last inserted/updated oid. Deprecated in 7.2 because
* range of OID values is greater than a java signed int.
* range of OID values is greater than a java signed int.
* @deprecated Replaced by getLastOID in 7.2
*/
public int getInsertedOID() throws SQLException
......@@ -651,9 +671,9 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
}
/*
* Returns the Last inserted/updated oid.
* Returns the Last inserted/updated oid.
* @return OID of last insert
* @since 7.2
* @since 7.2
*/
public long getLastOID() throws SQLException
{
......@@ -713,10 +733,10 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
*/
public void setShort(int parameterIndex, short x) throws SQLException
{
//Note this should be fixed
//as soon as the backend correctly supports int8 type
//comparisons
bind(parameterIndex,"'" + Integer.toString(x) +"'", PG_INT2);
//Note this should be fixed
//as soon as the backend correctly supports int8 type
//comparisons
bind(parameterIndex, "'" + Integer.toString(x) + "'", PG_INT2);
}
/*
......@@ -742,10 +762,10 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
*/
public void setLong(int parameterIndex, long x) throws SQLException
{
//Note this should be fixed
//as soon as the backend correctly supports int8 type
//comparisons
bind(parameterIndex, "'"+Long.toString(x)+"'", PG_INT8);
//Note this should be fixed
//as soon as the backend correctly supports int8 type
//comparisons
bind(parameterIndex, "'" + Long.toString(x) + "'", PG_INT8);
}
/*
......@@ -758,10 +778,10 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
*/
public void setFloat(int parameterIndex, float x) throws SQLException
{
//Note this should be fixed
//as soon as the backend correctly supports int8 type
//comparisons
bind(parameterIndex, "'"+Float.toString(x)+"'", PG_FLOAT);
//Note this should be fixed
//as soon as the backend correctly supports int8 type
//comparisons
bind(parameterIndex, "'" + Float.toString(x) + "'", PG_FLOAT);
}
/*
......@@ -774,10 +794,10 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
*/
public void setDouble(int parameterIndex, double x) throws SQLException
{
//Note this should be fixed
//as soon as the backend correctly supports int8 type
//comparisons
bind(parameterIndex, "'"+Double.toString(x)+"'", PG_DOUBLE);
//Note this should be fixed
//as soon as the backend correctly supports int8 type
//comparisons
bind(parameterIndex, "'" + Double.toString(x) + "'", PG_DOUBLE);
}
/*
......@@ -795,10 +815,10 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
setNull(parameterIndex, Types.OTHER);
else
{
//Note this should be fixed
//as soon as the backend correctly supports int8 type
//comparisons
bind(parameterIndex, "'"+x.toString()+"'", PG_NUMERIC);
//Note this should be fixed
//as soon as the backend correctly supports int8 type
//comparisons
bind(parameterIndex, "'" + x.toString() + "'", PG_NUMERIC);
}
}
......@@ -814,7 +834,7 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
*/
public void setString(int parameterIndex, String x) throws SQLException
{
setString(parameterIndex, x, PG_TEXT);
setString(parameterIndex, x, PG_TEXT);
}
public void setString(int parameterIndex, String x, String type) throws SQLException
......@@ -829,7 +849,7 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
synchronized (sbuf)
{
sbuf.setLength(0);
sbuf.ensureCapacity(x.length());
sbuf.ensureCapacity(x.length());
int i;
sbuf.append('\'');
......@@ -941,72 +961,89 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
setNull(parameterIndex, Types.OTHER);
}
else
{
{
// Use the shared StringBuffer
synchronized (sbuf)
{
sbuf.setLength(0);
sbuf.ensureCapacity(32);
sbuf.ensureCapacity(32);
sbuf.append("'");
//format the timestamp
//we do our own formating so that we can get a format
//that works with both timestamp with time zone and
//timestamp without time zone datatypes.
//The format is '2002-01-01 23:59:59.123456-0130'
//we need to include the local time and timezone offset
//so that timestamp without time zone works correctly
int l_year = x.getYear() + 1900;
sbuf.append(l_year);
sbuf.append('-');
int l_month = x.getMonth() + 1;
if (l_month < 10) sbuf.append('0');
sbuf.append(l_month);
sbuf.append('-');
int l_day = x.getDate();
if (l_day < 10) sbuf.append('0');
sbuf.append(l_day);
sbuf.append(' ');
int l_hours = x.getHours();
if (l_hours < 10) sbuf.append('0');
sbuf.append(l_hours);
sbuf.append(':');
int l_minutes = x.getMinutes();
if (l_minutes < 10) sbuf.append('0');
sbuf.append(l_minutes);
sbuf.append(':');
int l_seconds = x.getSeconds();
if (l_seconds < 10) sbuf.append('0');
sbuf.append(l_seconds);
// Make decimal from nanos.
char[] l_decimal = {'0','0','0','0','0','0','0','0','0'};
char[] l_nanos = Integer.toString(x.getNanos()).toCharArray();
System.arraycopy(l_nanos, 0, l_decimal, l_decimal.length - l_nanos.length, l_nanos.length);
sbuf.append('.');
if (connection.haveMinimumServerVersion("7.2")) {
sbuf.append(l_decimal,0,6);
} else {
// Because 7.1 include bug that "hh:mm:59.999" becomes "hh:mm:60.00".
sbuf.append(l_decimal,0,2);
}
//add timezone offset
int l_offset = -(x.getTimezoneOffset());
int l_houros = l_offset/60;
if (l_houros >= 0) {
sbuf.append('+');
} else {
sbuf.append('-');
}
if (l_houros > -10 && l_houros < 10) sbuf.append('0');
if (l_houros >= 0) {
sbuf.append(l_houros);
} else {
sbuf.append(-l_houros);
}
int l_minos = l_offset - (l_houros *60);
if (l_minos != 0) {
if (l_minos < 10) sbuf.append('0');
sbuf.append(l_minos);
}
//format the timestamp
//we do our own formating so that we can get a format
//that works with both timestamp with time zone and
//timestamp without time zone datatypes.
//The format is '2002-01-01 23:59:59.123456-0130'
//we need to include the local time and timezone offset
//so that timestamp without time zone works correctly
int l_year = x.getYear() + 1900;
sbuf.append(l_year);
sbuf.append('-');
int l_month = x.getMonth() + 1;
if (l_month < 10)
sbuf.append('0');
sbuf.append(l_month);
sbuf.append('-');
int l_day = x.getDate();
if (l_day < 10)
sbuf.append('0');
sbuf.append(l_day);
sbuf.append(' ');
int l_hours = x.getHours();
if (l_hours < 10)
sbuf.append('0');
sbuf.append(l_hours);
sbuf.append(':');
int l_minutes = x.getMinutes();
if (l_minutes < 10)
sbuf.append('0');
sbuf.append(l_minutes);
sbuf.append(':');
int l_seconds = x.getSeconds();
if (l_seconds < 10)
sbuf.append('0');
sbuf.append(l_seconds);
// Make decimal from nanos.
char[] l_decimal = {'0', '0', '0', '0', '0', '0', '0', '0', '0'};
char[] l_nanos = Integer.toString(x.getNanos()).toCharArray();
System.arraycopy(l_nanos, 0, l_decimal, l_decimal.length - l_nanos.length, l_nanos.length);
sbuf.append('.');
if (connection.haveMinimumServerVersion("7.2"))
{
sbuf.append(l_decimal, 0, 6);
}
else
{
// Because 7.1 include bug that "hh:mm:59.999" becomes "hh:mm:60.00".
sbuf.append(l_decimal, 0, 2);
}
//add timezone offset
int l_offset = -(x.getTimezoneOffset());
int l_houros = l_offset / 60;
if (l_houros >= 0)
{
sbuf.append('+');
}
else
{
sbuf.append('-');
}
if (l_houros > -10 && l_houros < 10)
sbuf.append('0');
if (l_houros >= 0)
{
sbuf.append(l_houros);
}
else
{
sbuf.append( -l_houros);
}
int l_minos = l_offset - (l_houros * 60);
if (l_minos != 0)
{
if (l_minos < 10)
sbuf.append('0');
sbuf.append(l_minos);
}
sbuf.append("'");
bind(parameterIndex, sbuf.toString(), PG_TIMESTAMPTZ);
}
......@@ -1206,9 +1243,10 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
{
int i;
for (i = 0 ; i < m_binds.length ; i++) {
for (i = 0 ; i < m_binds.length ; i++)
{
m_binds[i] = null;
m_bindTypes[i] = null;
m_bindTypes[i] = null;
}
}
......@@ -1236,12 +1274,12 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
if (x == null)
{
setNull(parameterIndex, Types.OTHER);
return;
return ;
}
switch (targetSqlType)
{
case Types.INTEGER:
bind(parameterIndex, x.toString(), PG_INTEGER);
bind(parameterIndex, x.toString(), PG_INTEGER);
break;
case Types.TINYINT:
case Types.SMALLINT:
......@@ -1254,10 +1292,10 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
if (x instanceof Boolean)
bind(parameterIndex, ((Boolean)x).booleanValue() ? "1" : "0", PG_BOOLEAN);
else
//Note this should be fixed
//as soon as the backend correctly supports int8 type
//comparisons
bind(parameterIndex, "'"+x.toString()+"'", PG_NUMERIC);
//Note this should be fixed
//as soon as the backend correctly supports int8 type
//comparisons
bind(parameterIndex, "'" + x.toString() + "'", PG_NUMERIC);
break;
case Types.CHAR:
case Types.VARCHAR:
......@@ -1311,7 +1349,7 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
if (x == null)
{
setNull(parameterIndex, Types.OTHER);
return;
return ;
}
if (x instanceof String)
setString(parameterIndex, (String)x);
......@@ -1362,24 +1400,24 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
* @exception SQLException if a database-access error occurs.
*/
public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException
{
if (parameterIndex != 1)
throw new PSQLException ("postgresql.call.noinout");
if (!isFunction)
throw new PSQLException ("postgresql.call.procasfunc", originalSql);
// functionReturnType contains the user supplied value to check
// testReturn contains a modified version to make it easier to
// check the getXXX methods..
functionReturnType = sqlType;
testReturn = sqlType;
if (functionReturnType == Types.CHAR ||
{
if (parameterIndex != 1)
throw new PSQLException ("postgresql.call.noinout");
if (!isFunction)
throw new PSQLException ("postgresql.call.procasfunc", originalSql);
// functionReturnType contains the user supplied value to check
// testReturn contains a modified version to make it easier to
// check the getXXX methods..
functionReturnType = sqlType;
testReturn = sqlType;
if (functionReturnType == Types.CHAR ||
functionReturnType == Types.LONGVARCHAR)
testReturn = Types.VARCHAR;
else if (functionReturnType == Types.FLOAT)
testReturn = Types.REAL; // changes to streamline later error checking
returnTypeSet = true;
}
testReturn = Types.VARCHAR;
else if (functionReturnType == Types.FLOAT)
testReturn = Types.REAL; // changes to streamline later error checking
returnTypeSet = true;
}
/*
* You must also specify the scale for numeric/decimal types:
......@@ -1396,9 +1434,9 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
*/
public void registerOutParameter(int parameterIndex, int sqlType,
int scale) throws SQLException
{
registerOutParameter (parameterIndex, sqlType); // ignore for now..
}
{
registerOutParameter (parameterIndex, sqlType); // ignore for now..
}
/*
* An OUT parameter may have the value of SQL NULL; wasNull
......@@ -1440,7 +1478,8 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
public boolean getBoolean(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.BIT, "Boolean");
if (callResult == null) return false;
if (callResult == null)
return false;
return ((Boolean)callResult).booleanValue ();
}
......@@ -1454,7 +1493,8 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
public byte getByte(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.TINYINT, "Byte");
if (callResult == null) return 0;
if (callResult == null)
return 0;
return (byte)((Integer)callResult).intValue ();
}
......@@ -1468,10 +1508,11 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
public short getShort(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.SMALLINT, "Short");
if (callResult == null) return 0;
if (callResult == null)
return 0;
return (short)((Integer)callResult).intValue ();
}
/*
* Get the value of an INTEGER parameter as a Java int.
......@@ -1483,7 +1524,8 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
public int getInt(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.INTEGER, "Int");
if (callResult == null) return 0;
if (callResult == null)
return 0;
return ((Integer)callResult).intValue ();
}
......@@ -1497,7 +1539,8 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
public long getLong(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.BIGINT, "Long");
if (callResult == null) return 0;
if (callResult == null)
return 0;
return ((Long)callResult).longValue ();
}
......@@ -1511,7 +1554,8 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
public float getFloat(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.REAL, "Float");
if (callResult == null) return 0;
if (callResult == null)
return 0;
return ((Float)callResult).floatValue ();
}
......@@ -1525,7 +1569,8 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
public double getDouble(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.DOUBLE, "Double");
if (callResult == null) return 0;
if (callResult == null)
return 0;
return ((Double)callResult).doubleValue ();
}
......@@ -1625,7 +1670,7 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
public Object getObject(int parameterIndex)
throws SQLException
{
checkIndex (parameterIndex);
checkIndex (parameterIndex);
return callResult;
}
......@@ -1667,9 +1712,9 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
if (paramIndex < 1 || paramIndex > m_binds.length)
throw new PSQLException("postgresql.prep.range");
if (paramIndex == 1 && isFunction) // need to registerOut instead
throw new PSQLException ("postgresql.call.funcover");
throw new PSQLException ("postgresql.call.funcover");
m_binds[paramIndex - 1] = s;
m_bindTypes[paramIndex - 1] = type;
m_bindTypes[paramIndex - 1] = type;
}
/*
......@@ -1694,92 +1739,101 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
bind(parameterIndex, Long.toString(x) + "::" + tablename, PG_TEXT );
}
/**
/**
* this method will turn a string of the form
* {? = call <some_function> (?, [?,..]) }
* into the PostgreSQL format which is
* into the PostgreSQL format which is
* select <some_function> (?, [?, ...]) as result
*
*
*/
private String modifyJdbcCall(String p_sql) throws SQLException {
private String modifyJdbcCall(String p_sql) throws SQLException
{
// syntax checking is not complete only a few basics :(
originalSql = p_sql; // save for error msgs..
String l_sql = p_sql;
String l_sql = p_sql;
int index = l_sql.indexOf ("="); // is implied func or proc?
boolean isValid = true;
if (index != -1) {
if (index != -1)
{
isFunction = true;
isValid = l_sql.indexOf ("?") < index; // ? before =
isValid = l_sql.indexOf ("?") < index; // ? before =
}
l_sql = l_sql.trim ();
if (l_sql.startsWith ("{") && l_sql.endsWith ("}")) {
l_sql = l_sql.substring (1, l_sql.length() -1);
} else isValid = false;
index = l_sql.indexOf ("call");
if (l_sql.startsWith ("{") && l_sql.endsWith ("}"))
{
l_sql = l_sql.substring (1, l_sql.length() - 1);
}
else
isValid = false;
index = l_sql.indexOf ("call");
if (index == -1 || !isValid)
throw new PSQLException ("postgresql.call.malformed",
throw new PSQLException ("postgresql.call.malformed",
new Object[]{l_sql, JDBC_SYNTAX});
l_sql = l_sql.replace ('{', ' '); // replace these characters
l_sql = l_sql.replace ('}', ' ');
l_sql = l_sql.replace (';', ' ');
// this removes the 'call' string and also puts a hidden '?'
// at the front of the line for functions, this will
// allow the registerOutParameter to work correctly
// because in the source sql there was one more ? for the return
// value that is not needed by the postgres syntax. But to make
// sure that the parameter numbers are the same as in the original
// sql we add a dummy parameter in this case
// because in the source sql there was one more ? for the return
// value that is not needed by the postgres syntax. But to make
// sure that the parameter numbers are the same as in the original
// sql we add a dummy parameter in this case
l_sql = (isFunction ? "?" : "") + l_sql.substring (index + 4);
l_sql = "select " + l_sql + " as " + RESULT_COLUMN + ";";
return l_sql;
return l_sql;
}
/** helperfunction for the getXXX calls to check isFunction and index == 1
*/
protected void checkIndex (int parameterIndex, int type, String getName)
throws SQLException {
protected void checkIndex (int parameterIndex, int type, String getName)
throws SQLException
{
checkIndex (parameterIndex);
if (type != this.testReturn)
if (type != this.testReturn)
throw new PSQLException("postgresql.call.wrongget",
new Object[]{"java.sql.Types="+testReturn,
getName,
"java.sql.Types="+type});
new Object[]{"java.sql.Types=" + testReturn,
getName,
"java.sql.Types=" + type});
}
/** helperfunction for the getXXX calls to check isFunction and index == 1
* @param parameterIndex index of getXXX (index)
* check to make sure is a function and index == 1
*/
private void checkIndex (int parameterIndex) throws SQLException {
private void checkIndex (int parameterIndex) throws SQLException
{
if (!isFunction)
throw new PSQLException("postgresql.call.noreturntype");
if (parameterIndex != 1)
throw new PSQLException("postgresql.call.noinout");
}
public void setUseServerPrepare(boolean flag) {
m_useServerPrepare = flag;
}
public boolean isUseServerPrepare() {
return m_useServerPrepare;
}
public void setUseServerPrepare(boolean flag)
{
m_useServerPrepare = flag;
}
public boolean isUseServerPrepare()
{
return m_useServerPrepare;
}
private static final String PG_TEXT = "text";
private static final String PG_INTEGER = "integer";
private static final String PG_INT2 = "int2";
private static final String PG_INT8 = "int8";
private static final String PG_NUMERIC = "numeric";
private static final String PG_FLOAT = "float";
private static final String PG_DOUBLE = "double";
private static final String PG_BOOLEAN = "boolean";
private static final String PG_DATE = "date";
private static final String PG_TIME = "time";
private static final String PG_TIMESTAMPTZ = "timestamptz";
private static final String PG_TEXT = "text";
private static final String PG_INTEGER = "integer";
private static final String PG_INT2 = "int2";
private static final String PG_INT8 = "int8";
private static final String PG_NUMERIC = "numeric";
private static final String PG_FLOAT = "float";
private static final String PG_DOUBLE = "double";
private static final String PG_BOOLEAN = "boolean";
private static final String PG_DATE = "date";
private static final String PG_TIME = "time";
private static final String PG_TIMESTAMPTZ = "timestamptz";
}
......@@ -6,9 +6,9 @@ import java.sql.*;
import org.postgresql.Field;
import org.postgresql.util.PSQLException;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/Jdbc1Connection.java,v 1.4 2002/07/26 05:29:35 barry Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/Jdbc1Connection.java,v 1.5 2002/09/06 21:23:06 momjian Exp $
* This class implements the java.sql.Connection interface for JDBC1.
* However most of the implementation is really done in
* However most of the implementation is really done in
* org.postgresql.jdbc1.AbstractJdbc1Connection
*/
public class Jdbc1Connection extends org.postgresql.jdbc1.AbstractJdbc1Connection implements java.sql.Connection
......
......@@ -5,9 +5,9 @@ import java.sql.*;
import java.util.Vector;
import org.postgresql.Field;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/Jdbc1ResultSet.java,v 1.3 2002/07/26 05:29:35 barry Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/Jdbc1ResultSet.java,v 1.4 2002/09/06 21:23:06 momjian Exp $
* This class implements the java.sql.ResultSet interface for JDBC1.
* However most of the implementation is really done in
* However most of the implementation is really done in
* org.postgresql.jdbc1.AbstractJdbc1ResultSet
*/
public class Jdbc1ResultSet extends org.postgresql.jdbc1.AbstractJdbc1ResultSet implements java.sql.ResultSet
......
......@@ -4,7 +4,7 @@ public class Jdbc1ResultSetMetaData extends AbstractJdbc1ResultSetMetaData imple
{
public Jdbc1ResultSetMetaData(java.util.Vector rows, org.postgresql.Field[] fields)
{
super(rows, fields);
super(rows, fields);
}
}
......
......@@ -3,9 +3,9 @@ package org.postgresql.jdbc1;
import java.sql.*;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/Jdbc1Statement.java,v 1.2 2002/07/24 22:08:40 barry Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/Jdbc1Statement.java,v 1.3 2002/09/06 21:23:06 momjian Exp $
* This class implements the java.sql.Statement interface for JDBC1.
* However most of the implementation is really done in
* However most of the implementation is really done in
* org.postgresql.jdbc1.AbstractJdbc1Statement
*/
public class Jdbc1Statement extends org.postgresql.jdbc1.AbstractJdbc1Statement implements java.sql.Statement
......@@ -13,7 +13,7 @@ public class Jdbc1Statement extends org.postgresql.jdbc1.AbstractJdbc1Statement
public Jdbc1Statement (Jdbc1Connection c)
{
super(c);
super(c);
}
}
......@@ -6,194 +6,206 @@ import java.net.ConnectException;
import java.sql.*;
import org.postgresql.util.PSQLException;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2Connection.java,v 1.1 2002/07/23 03:59:55 barry Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2Connection.java,v 1.2 2002/09/06 21:23:06 momjian Exp $
* This class defines methods of the jdbc2 specification. This class extends
* org.postgresql.jdbc1.AbstractJdbc1Connection which provides the jdbc1
* methods. The real Connection class (for jdbc2) is org.postgresql.jdbc2.Jdbc2Connection
*/
public abstract class AbstractJdbc2Connection extends org.postgresql.jdbc1.AbstractJdbc1Connection
{
/*
* The current type mappings
*/
protected java.util.Map typemap;
public java.sql.Statement createStatement() throws SQLException
{
// The spec says default of TYPE_FORWARD_ONLY but everyone is used to
// using TYPE_SCROLL_INSENSITIVE
return createStatement(java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_READ_ONLY);
}
public abstract java.sql.Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException;
public java.sql.PreparedStatement prepareStatement(String sql) throws SQLException
{
return prepareStatement(sql, java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_READ_ONLY);
}
public abstract java.sql.PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException;
public java.sql.CallableStatement prepareCall(String sql) throws SQLException
{
return prepareCall(sql, java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_READ_ONLY);
}
public abstract java.sql.CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException;
public java.util.Map getTypeMap() throws SQLException
{
return typemap;
}
public void setTypeMap(java.util.Map map) throws SQLException
{
typemap = map;
}
public void cancelQuery() throws SQLException
{
org.postgresql.PG_Stream cancelStream = null;
try {
cancelStream = new org.postgresql.PG_Stream(PG_HOST, PG_PORT);
} catch (ConnectException cex) {
// Added by Peter Mount <peter@retep.org.uk>
// ConnectException is thrown when the connection cannot be made.
// we trap this an return a more meaningful message for the end user
throw new PSQLException ("postgresql.con.refused");
} catch (IOException e) {
throw new PSQLException ("postgresql.con.failed",e);
}
// Now we need to construct and send a cancel packet
try {
cancelStream.SendInteger(16, 4);
cancelStream.SendInteger(80877102, 4);
cancelStream.SendInteger(pid, 4);
cancelStream.SendInteger(ckey, 4);
cancelStream.flush();
}
catch(IOException e) {
throw new PSQLException("postgresql.con.failed",e);
}
finally {
try {
if(cancelStream != null)
cancelStream.close();
}
catch(IOException e) {} // Ignore
}
}
/*
* This overides the standard internal getObject method so that we can
* check the jdbc2 type map first
*/
public Object getObject(String type, String value) throws SQLException
{
if (typemap != null)
{
SQLData d = (SQLData) typemap.get(type);
if (d != null)
{
// Handle the type (requires SQLInput & SQLOutput classes to be implemented)
throw org.postgresql.Driver.notImplemented();
}
}
// Default to the original method
return super.getObject(type, value);
}
//Because the get/setLogStream methods are deprecated in JDBC2
//we use the get/setLogWriter methods here for JDBC2 by overriding
//the base version of this method
protected void enableDriverManagerLogging() {
if (DriverManager.getLogWriter() == null) {
DriverManager.setLogWriter(new PrintWriter(System.out));
}
/*
* The current type mappings
*/
protected java.util.Map typemap;
public java.sql.Statement createStatement() throws SQLException
{
// The spec says default of TYPE_FORWARD_ONLY but everyone is used to
// using TYPE_SCROLL_INSENSITIVE
return createStatement(java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_READ_ONLY);
}
public abstract java.sql.Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException;
/*
* This implemetation uses the jdbc2Types array to support the jdbc2
* datatypes. Basically jdbc1 and jdbc2 are the same, except that
* jdbc2 adds the Array types.
*/
public int getSQLType(String pgTypeName)
{
int sqlType = Types.OTHER; // default value
for (int i = 0;i < jdbc2Types.length;i++)
{
if (pgTypeName.equals(jdbc2Types[i]))
{
sqlType = jdbc2Typei[i];
break;
}
}
return sqlType;
}
/*
* This table holds the org.postgresql names for the types supported.
* Any types that map to Types.OTHER (eg POINT) don't go into this table.
* They default automatically to Types.OTHER
*
* Note: This must be in the same order as below.
*
* Tip: keep these grouped together by the Types. value
*/
private static final String jdbc2Types[] = {
"int2",
"int4", "oid",
"int8",
"cash", "money",
"numeric",
"float4",
"float8",
"bpchar", "char", "char2", "char4", "char8", "char16",
"varchar", "text", "name", "filename",
"bytea",
"bool",
"date",
"time",
"abstime", "timestamp", "timestamptz",
"_bool", "_char", "_int2", "_int4", "_text",
"_oid", "_varchar", "_int8", "_float4", "_float8",
"_abstime", "_date", "_time", "_timestamp", "_numeric",
"_bytea"
};
/*
* This table holds the JDBC type for each entry above.
*
* Note: This must be in the same order as above
*
* Tip: keep these grouped together by the Types. value
*/
private static final int jdbc2Typei[] = {
Types.SMALLINT,
Types.INTEGER, Types.INTEGER,
Types.BIGINT,
Types.DOUBLE, Types.DOUBLE,
Types.NUMERIC,
Types.REAL,
Types.DOUBLE,
Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR,
Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
Types.BINARY,
Types.BIT,
Types.DATE,
Types.TIME,
Types.TIMESTAMP, Types.TIMESTAMP, Types.TIMESTAMP,
Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY,
Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY,
Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY,
Types.ARRAY
};
public java.sql.PreparedStatement prepareStatement(String sql) throws SQLException
{
return prepareStatement(sql, java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_READ_ONLY);
}
public abstract java.sql.PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException;
public java.sql.CallableStatement prepareCall(String sql) throws SQLException
{
return prepareCall(sql, java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_READ_ONLY);
}
public abstract java.sql.CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException;
public java.util.Map getTypeMap() throws SQLException
{
return typemap;
}
public void setTypeMap(java.util.Map map) throws SQLException
{
typemap = map;
}
public void cancelQuery() throws SQLException
{
org.postgresql.PG_Stream cancelStream = null;
try
{
cancelStream = new org.postgresql.PG_Stream(PG_HOST, PG_PORT);
}
catch (ConnectException cex)
{
// Added by Peter Mount <peter@retep.org.uk>
// ConnectException is thrown when the connection cannot be made.
// we trap this an return a more meaningful message for the end user
throw new PSQLException ("postgresql.con.refused");
}
catch (IOException e)
{
throw new PSQLException ("postgresql.con.failed", e);
}
// Now we need to construct and send a cancel packet
try
{
cancelStream.SendInteger(16, 4);
cancelStream.SendInteger(80877102, 4);
cancelStream.SendInteger(pid, 4);
cancelStream.SendInteger(ckey, 4);
cancelStream.flush();
}
catch (IOException e)
{
throw new PSQLException("postgresql.con.failed", e);
}
finally
{
try
{
if (cancelStream != null)
cancelStream.close();
}
catch (IOException e)
{} // Ignore
}
}
/*
* This overides the standard internal getObject method so that we can
* check the jdbc2 type map first
*/
public Object getObject(String type, String value) throws SQLException
{
if (typemap != null)
{
SQLData d = (SQLData) typemap.get(type);
if (d != null)
{
// Handle the type (requires SQLInput & SQLOutput classes to be implemented)
throw org.postgresql.Driver.notImplemented();
}
}
// Default to the original method
return super.getObject(type, value);
}
//Because the get/setLogStream methods are deprecated in JDBC2
//we use the get/setLogWriter methods here for JDBC2 by overriding
//the base version of this method
protected void enableDriverManagerLogging()
{
if (DriverManager.getLogWriter() == null)
{
DriverManager.setLogWriter(new PrintWriter(System.out));
}
}
/*
* This implemetation uses the jdbc2Types array to support the jdbc2
* datatypes. Basically jdbc1 and jdbc2 are the same, except that
* jdbc2 adds the Array types.
*/
public int getSQLType(String pgTypeName)
{
int sqlType = Types.OTHER; // default value
for (int i = 0;i < jdbc2Types.length;i++)
{
if (pgTypeName.equals(jdbc2Types[i]))
{
sqlType = jdbc2Typei[i];
break;
}
}
return sqlType;
}
/*
* This table holds the org.postgresql names for the types supported.
* Any types that map to Types.OTHER (eg POINT) don't go into this table.
* They default automatically to Types.OTHER
*
* Note: This must be in the same order as below.
*
* Tip: keep these grouped together by the Types. value
*/
private static final String jdbc2Types[] = {
"int2",
"int4", "oid",
"int8",
"cash", "money",
"numeric",
"float4",
"float8",
"bpchar", "char", "char2", "char4", "char8", "char16",
"varchar", "text", "name", "filename",
"bytea",
"bool",
"date",
"time",
"abstime", "timestamp", "timestamptz",
"_bool", "_char", "_int2", "_int4", "_text",
"_oid", "_varchar", "_int8", "_float4", "_float8",
"_abstime", "_date", "_time", "_timestamp", "_numeric",
"_bytea"
};
/*
* This table holds the JDBC type for each entry above.
*
* Note: This must be in the same order as above
*
* Tip: keep these grouped together by the Types. value
*/
private static final int jdbc2Typei[] = {
Types.SMALLINT,
Types.INTEGER, Types.INTEGER,
Types.BIGINT,
Types.DOUBLE, Types.DOUBLE,
Types.NUMERIC,
Types.REAL,
Types.DOUBLE,
Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR,
Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
Types.BINARY,
Types.BIT,
Types.DATE,
Types.TIME,
Types.TIMESTAMP, Types.TIMESTAMP, Types.TIMESTAMP,
Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY,
Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY,
Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY,
Types.ARRAY
};
......
......@@ -13,7 +13,7 @@ public abstract class AbstractJdbc2DatabaseMetaData extends org.postgresql.jdbc1
public AbstractJdbc2DatabaseMetaData(AbstractJdbc2Connection conn)
{
super(conn);
super(conn);
}
......@@ -61,18 +61,18 @@ public abstract class AbstractJdbc2DatabaseMetaData extends org.postgresql.jdbc1
/* lots of unsupported stuff... */
public boolean ownUpdatesAreVisible(int type) throws SQLException
{
return true;
return true;
}
public boolean ownDeletesAreVisible(int type) throws SQLException
{
return true;
return true;
}
public boolean ownInsertsAreVisible(int type) throws SQLException
{
// indicates that
return true;
// indicates that
return true;
}
public boolean othersUpdatesAreVisible(int type) throws SQLException
......@@ -117,10 +117,10 @@ public abstract class AbstractJdbc2DatabaseMetaData extends org.postgresql.jdbc1
* Return user defined types in a schema
*/
public java.sql.ResultSet getUDTs(String catalog,
String schemaPattern,
String typeNamePattern,
int[] types
) throws SQLException
String schemaPattern,
String typeNamePattern,
int[] types
) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
......
......@@ -15,1339 +15,1578 @@ import org.postgresql.util.PGbytea;
import org.postgresql.util.PSQLException;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2ResultSet.java,v 1.6 2002/09/01 23:40:36 davec Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2ResultSet.java,v 1.7 2002/09/06 21:23:06 momjian Exp $
* This class defines methods of the jdbc2 specification. This class extends
* org.postgresql.jdbc1.AbstractJdbc1ResultSet which provides the jdbc1
* methods. The real Statement class (for jdbc2) is org.postgresql.jdbc2.Jdbc2ResultSet
*/
public abstract class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.AbstractJdbc1ResultSet {
public abstract class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.AbstractJdbc1ResultSet
{
//needed for updateable result set support
protected boolean updateable = false;
protected boolean doingUpdates = false;
protected boolean onInsertRow = false;
protected Hashtable updateValues = new Hashtable();
private boolean usingOID = false; // are we using the OID for the primary key?
private Vector primaryKeys; // list of primary keys
private int numKeys = 0;
private boolean singleTable = false;
protected String tableName = null;
protected PreparedStatement updateStatement = null;
protected PreparedStatement insertStatement = null;
protected PreparedStatement deleteStatement = null;
private PreparedStatement selectStatement = null;
public AbstractJdbc2ResultSet(org.postgresql.PGConnection conn, Statement statement, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor)
{
super (conn, statement, fields, tuples, status, updateCount, insertOID, binaryCursor);
}
public java.net.URL getURL(int columnIndex) throws SQLException
{
return null;
}
public java.net.URL getURL(String columnName) throws SQLException
{
return null;
}
/*
* Get the value of a column in the current row as a Java object
*
* <p>This method will return the value of the given column as a
* Java object. The type of the Java object will be the default
* Java Object type corresponding to the column's SQL type, following
* the mapping specified in the JDBC specification.
*
* <p>This method may also be used to read database specific abstract
* data types.
*
* @param columnIndex the first column is 1, the second is 2...
* @return a Object holding the column value
* @exception SQLException if a database access error occurs
*/
public Object getObject(int columnIndex) throws SQLException
{
Field field;
checkResultSet( columnIndex );
wasNullFlag = (this_row[columnIndex - 1] == null);
if (wasNullFlag)
return null;
field = fields[columnIndex - 1];
// some fields can be null, mainly from those returned by MetaData methods
if (field == null)
{
wasNullFlag = true;
return null;
}
switch (field.getSQLType())
{
case Types.BIT:
return getBoolean(columnIndex) ? Boolean.TRUE : Boolean.FALSE;
case Types.SMALLINT:
return new Short(getShort(columnIndex));
case Types.INTEGER:
return new Integer(getInt(columnIndex));
case Types.BIGINT:
return new Long(getLong(columnIndex));
case Types.NUMERIC:
return getBigDecimal
(columnIndex, (field.getMod() == -1) ? -1 : ((field.getMod() - 4) & 0xffff));
case Types.REAL:
return new Float(getFloat(columnIndex));
case Types.DOUBLE:
return new Double(getDouble(columnIndex));
case Types.CHAR:
case Types.VARCHAR:
return getString(columnIndex);
case Types.DATE:
return getDate(columnIndex);
case Types.TIME:
return getTime(columnIndex);
case Types.TIMESTAMP:
return getTimestamp(columnIndex);
case Types.BINARY:
case Types.VARBINARY:
return getBytes(columnIndex);
case Types.ARRAY:
return getArray(columnIndex);
default:
String type = field.getPGType();
// if the backend doesn't know the type then coerce to String
if (type.equals("unknown"))
{
return getString(columnIndex);
}
else
{
return connection.getObject(field.getPGType(), getString(columnIndex));
}
}
}
public boolean absolute(int index) throws SQLException
{
// index is 1-based, but internally we use 0-based indices
int internalIndex;
if (index == 0)
throw new SQLException("Cannot move to index of 0");
final int rows_size = rows.size();
//if index<0, count from the end of the result set, but check
//to be sure that it is not beyond the first index
if (index < 0)
{
if (index >= -rows_size)
internalIndex = rows_size + index;
else
{
beforeFirst();
return false;
}
}
else
{
//must be the case that index>0,
//find the correct place, assuming that
//the index is not too large
if (index <= rows_size)
internalIndex = index - 1;
else
{
afterLast();
return false;
}
}
current_row = internalIndex;
this_row = (byte[][]) rows.elementAt(internalIndex);
return true;
}
public void afterLast() throws SQLException
{
final int rows_size = rows.size();
if (rows_size > 0)
current_row = rows_size;
}
public void beforeFirst() throws SQLException
{
if (rows.size() > 0)
current_row = -1;
}
public boolean first() throws SQLException
{
if (rows.size() <= 0)
return false;
onInsertRow = false;
current_row = 0;
this_row = (byte[][]) rows.elementAt(current_row);
rowBuffer = new byte[this_row.length][];
System.arraycopy(this_row, 0, rowBuffer, 0, this_row.length);
return true;
}
public java.sql.Array getArray(String colName) throws SQLException
{
return getArray(findColumn(colName));
}
public java.sql.Array getArray(int i) throws SQLException
{
wasNullFlag = (this_row[i - 1] == null);
if (wasNullFlag)
return null;
if (i < 1 || i > fields.length)
throw new PSQLException("postgresql.res.colrange");
return (java.sql.Array) new org.postgresql.jdbc2.Array( connection, i, fields[i - 1], (java.sql.ResultSet) this );
}
public java.math.BigDecimal getBigDecimal(int columnIndex) throws SQLException
{
return getBigDecimal(columnIndex, -1);
}
public java.math.BigDecimal getBigDecimal(String columnName) throws SQLException
{
return getBigDecimal(findColumn(columnName));
}
public Blob getBlob(String columnName) throws SQLException
{
return getBlob(findColumn(columnName));
}
//needed for updateable result set support
protected boolean updateable = false;
protected boolean doingUpdates = false;
protected boolean onInsertRow = false;
protected Hashtable updateValues = new Hashtable();
private boolean usingOID = false; // are we using the OID for the primary key?
private Vector primaryKeys; // list of primary keys
private int numKeys = 0;
private boolean singleTable = false;
protected String tableName = null;
protected PreparedStatement updateStatement = null;
protected PreparedStatement insertStatement = null;
protected PreparedStatement deleteStatement = null;
private PreparedStatement selectStatement = null;
public AbstractJdbc2ResultSet(org.postgresql.PGConnection conn, Statement statement, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) {
super (conn, statement, fields, tuples, status, updateCount, insertOID, binaryCursor);
}
public java.net.URL getURL(int columnIndex) throws SQLException {
return null;
}
public java.net.URL getURL(String columnName) throws SQLException {
return null;
}
/*
* Get the value of a column in the current row as a Java object
*
* <p>This method will return the value of the given column as a
* Java object. The type of the Java object will be the default
* Java Object type corresponding to the column's SQL type, following
* the mapping specified in the JDBC specification.
*
* <p>This method may also be used to read database specific abstract
* data types.
*
* @param columnIndex the first column is 1, the second is 2...
* @return a Object holding the column value
* @exception SQLException if a database access error occurs
*/
public Object getObject(int columnIndex) throws SQLException {
Field field;
checkResultSet( columnIndex );
wasNullFlag = (this_row[columnIndex - 1] == null);
if (wasNullFlag)
return null;
field = fields[columnIndex - 1];
// some fields can be null, mainly from those returned by MetaData methods
if (field == null) {
wasNullFlag = true;
return null;
}
switch (field.getSQLType()) {
case Types.BIT:
return getBoolean(columnIndex) ? Boolean.TRUE : Boolean.FALSE;
case Types.SMALLINT:
return new Short(getShort(columnIndex));
case Types.INTEGER:
return new Integer(getInt(columnIndex));
case Types.BIGINT:
return new Long(getLong(columnIndex));
case Types.NUMERIC:
return getBigDecimal
(columnIndex, (field.getMod() == -1) ? -1 : ((field.getMod() - 4) & 0xffff));
case Types.REAL:
return new Float(getFloat(columnIndex));
case Types.DOUBLE:
return new Double(getDouble(columnIndex));
case Types.CHAR:
case Types.VARCHAR:
return getString(columnIndex);
case Types.DATE:
return getDate(columnIndex);
case Types.TIME:
return getTime(columnIndex);
case Types.TIMESTAMP:
return getTimestamp(columnIndex);
case Types.BINARY:
case Types.VARBINARY:
return getBytes(columnIndex);
case Types.ARRAY:
return getArray(columnIndex);
default:
String type = field.getPGType();
// if the backend doesn't know the type then coerce to String
if (type.equals("unknown")) {
return getString(columnIndex);
}
else {
return connection.getObject(field.getPGType(), getString(columnIndex));
}
}
}
public abstract Blob getBlob(int i) throws SQLException;
public java.io.Reader getCharacterStream(String columnName) throws SQLException
{
return getCharacterStream(findColumn(columnName));
}
public java.io.Reader getCharacterStream(int i) throws SQLException
{
checkResultSet( i );
wasNullFlag = (this_row[i - 1] == null);
if (wasNullFlag)
return null;
public boolean absolute(int index) throws SQLException {
// index is 1-based, but internally we use 0-based indices
int internalIndex;
if (((AbstractJdbc2Connection) connection).haveMinimumCompatibleVersion("7.2"))
{
//Version 7.2 supports AsciiStream for all the PG text types
//As the spec/javadoc for this method indicate this is to be used for
//large text values (i.e. LONGVARCHAR) PG doesn't have a separate
//long string datatype, but with toast the text datatype is capable of
//handling very large values. Thus the implementation ends up calling
//getString() since there is no current way to stream the value from the server
return new CharArrayReader(getString(i).toCharArray());
}
else
{
// In 7.1 Handle as BLOBS so return the LargeObject input stream
Encoding encoding = connection.getEncoding();
InputStream input = getBinaryStream(i);
return encoding.getDecodingReader(input);
}
}
if (index == 0)
throw new SQLException("Cannot move to index of 0");
final int rows_size = rows.size();
public Clob getClob(String columnName) throws SQLException
{
return getClob(findColumn(columnName));
}
//if index<0, count from the end of the result set, but check
//to be sure that it is not beyond the first index
if (index < 0) {
if (index >= -rows_size)
internalIndex = rows_size + index;
else {
beforeFirst();
return false;
}
}
else {
//must be the case that index>0,
//find the correct place, assuming that
//the index is not too large
if (index <= rows_size)
internalIndex = index - 1;
else {
afterLast();
return false;
}
}
current_row = internalIndex;
this_row = (byte[][]) rows.elementAt(internalIndex);
return true;
}
public abstract Clob getClob(int i) throws SQLException;
public void afterLast() throws SQLException {
final int rows_size = rows.size();
if (rows_size > 0)
current_row = rows_size;
}
public int getConcurrency() throws SQLException
{
if (statement == null)
return java.sql.ResultSet.CONCUR_READ_ONLY;
return statement.getResultSetConcurrency();
}
public void beforeFirst() throws SQLException {
if (rows.size() > 0)
current_row = -1;
}
public java.sql.Date getDate(int i, java.util.Calendar cal) throws SQLException
{
// If I read the specs, this should use cal only if we don't
// store the timezone, and if we do, then act just like getDate()?
// for now...
return getDate(i);
}
public boolean first() throws SQLException
{
if (rows.size() <= 0)
return false;
public Time getTime(int i, java.util.Calendar cal) throws SQLException
{
// If I read the specs, this should use cal only if we don't
// store the timezone, and if we do, then act just like getTime()?
// for now...
return getTime(i);
}
onInsertRow = false;
current_row = 0;
this_row = (byte[][]) rows.elementAt(current_row);
rowBuffer = new byte[this_row.length][];
System.arraycopy(this_row, 0, rowBuffer, 0, this_row.length);
public Timestamp getTimestamp(int i, java.util.Calendar cal) throws SQLException
{
// If I read the specs, this should use cal only if we don't
// store the timezone, and if we do, then act just like getDate()?
// for now...
return getTimestamp(i);
}
return true;
}
public java.sql.Date getDate(String c, java.util.Calendar cal) throws SQLException
{
return getDate(findColumn(c), cal);
}
public java.sql.Array getArray(String colName) throws SQLException {
return getArray(findColumn(colName));
}
public Time getTime(String c, java.util.Calendar cal) throws SQLException
{
return getTime(findColumn(c), cal);
}
public java.sql.Array getArray(int i) throws SQLException {
wasNullFlag = (this_row[i - 1] == null);
if (wasNullFlag)
return null;
if (i < 1 || i > fields.length)
throw new PSQLException("postgresql.res.colrange");
return (java.sql.Array) new org.postgresql.jdbc2.Array( connection, i, fields[i - 1], (java.sql.ResultSet) this );
}
public Timestamp getTimestamp(String c, java.util.Calendar cal) throws SQLException
{
return getTimestamp(findColumn(c), cal);
}
public java.math.BigDecimal getBigDecimal(int columnIndex) throws SQLException {
return getBigDecimal(columnIndex, -1);
}
public int getFetchDirection() throws SQLException
{
//PostgreSQL normally sends rows first->last
return java.sql.ResultSet.FETCH_FORWARD;
}
public java.math.BigDecimal getBigDecimal(String columnName) throws SQLException {
return getBigDecimal(findColumn(columnName));
}
public int getFetchSize() throws SQLException
{
// In this implementation we return the entire result set, so
// here return the number of rows we have. Sub-classes can return a proper
// value
return rows.size();
}
public Blob getBlob(String columnName) throws SQLException {
return getBlob(findColumn(columnName));
}
public Object getObject(String columnName, java.util.Map map) throws SQLException
{
return getObject(findColumn(columnName), map);
}
public abstract Blob getBlob(int i) throws SQLException;
/*
* This checks against map for the type of column i, and if found returns
* an object based on that mapping. The class must implement the SQLData
* interface.
*/
public Object getObject(int i, java.util.Map map) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public java.io.Reader getCharacterStream(String columnName) throws SQLException {
return getCharacterStream(findColumn(columnName));
}
public Ref getRef(String columnName) throws SQLException
{
return getRef(findColumn(columnName));
}
public java.io.Reader getCharacterStream(int i) throws SQLException {
checkResultSet( i );
wasNullFlag = (this_row[i - 1] == null);
if (wasNullFlag)
return null;
public Ref getRef(int i) throws SQLException
{
//The backend doesn't yet have SQL3 REF types
throw new PSQLException("postgresql.psqlnotimp");
}
if (((AbstractJdbc2Connection) connection).haveMinimumCompatibleVersion("7.2")) {
//Version 7.2 supports AsciiStream for all the PG text types
//As the spec/javadoc for this method indicate this is to be used for
//large text values (i.e. LONGVARCHAR) PG doesn't have a separate
//long string datatype, but with toast the text datatype is capable of
//handling very large values. Thus the implementation ends up calling
//getString() since there is no current way to stream the value from the server
return new CharArrayReader(getString(i).toCharArray());
}
else {
// In 7.1 Handle as BLOBS so return the LargeObject input stream
Encoding encoding = connection.getEncoding();
InputStream input = getBinaryStream(i);
return encoding.getDecodingReader(input);
}
}
public int getRow() throws SQLException
{
final int rows_size = rows.size();
public Clob getClob(String columnName) throws SQLException {
return getClob(findColumn(columnName));
}
if (current_row < 0 || current_row >= rows_size)
return 0;
return current_row + 1;
}
public abstract Clob getClob(int i) throws SQLException;
// This one needs some thought, as not all ResultSets come from a statement
public Statement getStatement() throws SQLException
{
return statement;
}
public int getConcurrency() throws SQLException {
if (statement == null)
return java.sql.ResultSet.CONCUR_READ_ONLY;
return statement.getResultSetConcurrency();
}
public int getType() throws SQLException
{
// This implementation allows scrolling but is not able to
// see any changes. Sub-classes may overide this to return a more
// meaningful result.
return java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE;
}
public java.sql.Date getDate(int i, java.util.Calendar cal) throws SQLException {
// If I read the specs, this should use cal only if we don't
// store the timezone, and if we do, then act just like getDate()?
// for now...
return getDate(i);
}
public boolean isAfterLast() throws SQLException
{
final int rows_size = rows.size();
return (current_row >= rows_size && rows_size > 0);
}
public Time getTime(int i, java.util.Calendar cal) throws SQLException {
// If I read the specs, this should use cal only if we don't
// store the timezone, and if we do, then act just like getTime()?
// for now...
return getTime(i);
}
public boolean isBeforeFirst() throws SQLException
{
return (current_row < 0 && rows.size() > 0);
}
public Timestamp getTimestamp(int i, java.util.Calendar cal) throws SQLException {
// If I read the specs, this should use cal only if we don't
// store the timezone, and if we do, then act just like getDate()?
// for now...
return getTimestamp(i);
}
public boolean isFirst() throws SQLException
{
return (current_row == 0 && rows.size() >= 0);
}
public java.sql.Date getDate(String c, java.util.Calendar cal) throws SQLException {
return getDate(findColumn(c), cal);
}
public boolean isLast() throws SQLException
{
final int rows_size = rows.size();
return (current_row == rows_size - 1 && rows_size > 0);
}
public Time getTime(String c, java.util.Calendar cal) throws SQLException {
return getTime(findColumn(c), cal);
}
public boolean last() throws SQLException
{
final int rows_size = rows.size();
if (rows_size <= 0)
return false;
public Timestamp getTimestamp(String c, java.util.Calendar cal) throws SQLException {
return getTimestamp(findColumn(c), cal);
}
current_row = rows_size - 1;
this_row = (byte[][]) rows.elementAt(current_row);
rowBuffer = new byte[this_row.length][];
System.arraycopy(this_row, 0, rowBuffer, 0, this_row.length);
public int getFetchDirection() throws SQLException {
//PostgreSQL normally sends rows first->last
return java.sql.ResultSet.FETCH_FORWARD;
}
return true;
}
public int getFetchSize() throws SQLException {
// In this implementation we return the entire result set, so
// here return the number of rows we have. Sub-classes can return a proper
// value
return rows.size();
}
public boolean previous() throws SQLException
{
if (--current_row < 0)
return false;
this_row = (byte[][]) rows.elementAt(current_row);
System.arraycopy(this_row, 0, rowBuffer, 0, this_row.length);
return true;
}
public Object getObject(String columnName, java.util.Map map) throws SQLException {
return getObject(findColumn(columnName), map);
}
public boolean relative(int rows) throws SQLException
{
//have to add 1 since absolute expects a 1-based index
return absolute(current_row + 1 + rows);
}
/*
* This checks against map for the type of column i, and if found returns
* an object based on that mapping. The class must implement the SQLData
* interface.
*/
public Object getObject(int i, java.util.Map map) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
public void setFetchDirection(int direction) throws SQLException
{
throw new PSQLException("postgresql.psqlnotimp");
}
public Ref getRef(String columnName) throws SQLException {
return getRef(findColumn(columnName));
}
public void setFetchSize(int rows) throws SQLException
{
// Sub-classes should implement this as part of their cursor support
throw org.postgresql.Driver.notImplemented();
}
public Ref getRef(int i) throws SQLException {
//The backend doesn't yet have SQL3 REF types
throw new PSQLException("postgresql.psqlnotimp");
}
public synchronized void cancelRowUpdates()
throws SQLException
{
if (doingUpdates)
{
doingUpdates = false;
clearRowBuffer();
}
}
public int getRow() throws SQLException {
final int rows_size = rows.size();
if (current_row < 0 || current_row >= rows_size)
return 0;
public synchronized void deleteRow()
throws SQLException
{
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
return current_row + 1;
}
if (onInsertRow)
{
throw new PSQLException( "postgresql.updateable.oninsertrow" );
}
if (rows.size() == 0)
{
throw new PSQLException( "postgresql.updateable.emptydelete" );
}
if (isBeforeFirst())
{
throw new PSQLException( "postgresql.updateable.beforestartdelete" );
}
if (isAfterLast())
{
throw new PSQLException( "postgresql.updateable.afterlastdelete" );
}
// This one needs some thought, as not all ResultSets come from a statement
public Statement getStatement() throws SQLException {
return statement;
}
int numKeys = primaryKeys.size();
if ( deleteStatement == null )
{
public int getType() throws SQLException {
// This implementation allows scrolling but is not able to
// see any changes. Sub-classes may overide this to return a more
// meaningful result.
return java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE;
}
StringBuffer deleteSQL = new StringBuffer("DELETE FROM " ).append(tableName).append(" where " );
public boolean isAfterLast() throws SQLException {
final int rows_size = rows.size();
return (current_row >= rows_size && rows_size > 0);
}
for ( int i = 0; i < numKeys; i++ )
{
deleteSQL.append( ((PrimaryKey) primaryKeys.get(i)).name ).append( " = ? " );
if ( i < numKeys - 1 )
{
deleteSQL.append( " and " );
}
}
deleteStatement = ((java.sql.Connection) connection).prepareStatement(deleteSQL.toString());
}
deleteStatement.clearParameters();
public boolean isBeforeFirst() throws SQLException {
return (current_row < 0 && rows.size() > 0);
}
for ( int i = 0; i < numKeys; i++ )
{
deleteStatement.setObject(i + 1, ((PrimaryKey) primaryKeys.get(i)).getValue());
}
public boolean isFirst() throws SQLException {
return (current_row == 0 && rows.size() >= 0);
}
deleteStatement.executeUpdate();
rows.removeElementAt(current_row);
}
public boolean isLast() throws SQLException {
final int rows_size = rows.size();
return (current_row == rows_size - 1 && rows_size > 0);
}
public synchronized void insertRow()
throws SQLException
{
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
public boolean last() throws SQLException {
final int rows_size = rows.size();
if (rows_size <= 0)
return false;
if (!onInsertRow)
{
throw new PSQLException( "postgresql.updateable.notoninsertrow" );
}
else
{
current_row = rows_size - 1;
this_row = (byte[][]) rows.elementAt(current_row);
// loop through the keys in the insertTable and create the sql statement
// we have to create the sql every time since the user could insert different
// columns each time
rowBuffer = new byte[this_row.length][];
System.arraycopy(this_row, 0, rowBuffer, 0, this_row.length);
StringBuffer insertSQL = new StringBuffer("INSERT INTO ").append(tableName).append(" (");
StringBuffer paramSQL = new StringBuffer(") values (" );
return true;
}
Enumeration columnNames = updateValues.keys();
int numColumns = updateValues.size();
for ( int i = 0; columnNames.hasMoreElements(); i++ )
{
String columnName = (String) columnNames.nextElement();
public boolean previous() throws SQLException {
if (--current_row < 0)
return false;
this_row = (byte[][]) rows.elementAt(current_row);
System.arraycopy(this_row, 0, rowBuffer, 0, this_row.length);
return true;
}
insertSQL.append( columnName );
if ( i < numColumns - 1 )
{
insertSQL.append(", ");
paramSQL.append("?,");
}
else
{
paramSQL.append("?)");
}
}
public boolean relative(int rows) throws SQLException {
//have to add 1 since absolute expects a 1-based index
return absolute(current_row + 1 + rows);
}
insertSQL.append(paramSQL.toString());
insertStatement = ((java.sql.Connection) connection).prepareStatement(insertSQL.toString());
Enumeration keys = updateValues.keys();
public void setFetchDirection(int direction) throws SQLException {
throw new PSQLException("postgresql.psqlnotimp");
}
for ( int i = 1; keys.hasMoreElements(); i++)
{
String key = (String) keys.nextElement();
insertStatement.setObject(i, updateValues.get( key ) );
}
insertStatement.executeUpdate();
public void setFetchSize(int rows) throws SQLException {
// Sub-classes should implement this as part of their cursor support
throw org.postgresql.Driver.notImplemented();
}
if ( usingOID )
{
// we have to get the last inserted OID and put it in the resultset
long insertedOID = ((AbstractJdbc2Statement) insertStatement).getLastOID();
public synchronized void cancelRowUpdates() throws SQLException
{
if (doingUpdates)
{
doingUpdates = false;
updateValues.put("oid", new Long(insertedOID) );
clearRowBuffer();
}
}
}
// update the underlying row to the new inserted data
updateRowBuffer();
public synchronized void deleteRow() throws SQLException
{
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
rows.addElement(rowBuffer);
if (onInsertRow) {
throw new PSQLException( "postgresql.updateable.oninsertrow" );
}
// we should now reflect the current data in this_row
// that way getXXX will get the newly inserted data
this_row = rowBuffer;
if (rows.size() == 0) {
throw new PSQLException( "postgresql.updateable.emptydelete" );
}
if (isBeforeFirst()) {
throw new PSQLException( "postgresql.updateable.beforestartdelete" );
}
if (isAfterLast()) {
throw new PSQLException( "postgresql.updateable.afterlastdelete" );
}
// need to clear this in case of another insert
clearRowBuffer();
int numKeys = primaryKeys.size();
if ( deleteStatement == null ) {
}
}
StringBuffer deleteSQL = new StringBuffer("DELETE FROM " ).append(tableName).append(" where " );
public synchronized void moveToCurrentRow()
throws SQLException
{
if (!updateable)
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
for ( int i = 0; i < numKeys; i++ ) {
deleteSQL.append( ((PrimaryKey) primaryKeys.get(i)).name ).append( " = ? " );
if ( i < numKeys - 1 ) {
deleteSQL.append( " and " );
}
}
this_row = (byte[][]) rows.elementAt(current_row);
deleteStatement = ((java.sql.Connection) connection).prepareStatement(deleteSQL.toString());
}
deleteStatement.clearParameters();
rowBuffer = new byte[this_row.length][];
System.arraycopy(this_row, 0, rowBuffer, 0, this_row.length);
for ( int i = 0; i < numKeys; i++ ) {
deleteStatement.setObject(i + 1, ((PrimaryKey) primaryKeys.get(i)).getValue());
}
onInsertRow = false;
doingUpdates = false;
}
deleteStatement.executeUpdate();
public synchronized void moveToInsertRow()
throws SQLException
{
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
rows.removeElementAt(current_row);
}
if (insertStatement != null)
{
insertStatement = null;
}
public synchronized void insertRow() throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
// make sure the underlying data is null
clearRowBuffer();
if (!onInsertRow) {
throw new PSQLException( "postgresql.updateable.notoninsertrow" );
}
else {
onInsertRow = true;
doingUpdates = false;
// loop through the keys in the insertTable and create the sql statement
// we have to create the sql every time since the user could insert different
// columns each time
}
StringBuffer insertSQL = new StringBuffer("INSERT INTO ").append(tableName).append(" (");
StringBuffer paramSQL = new StringBuffer(") values (" );
Enumeration columnNames = updateValues.keys();
int numColumns = updateValues.size();
private synchronized void clearRowBuffer()
throws SQLException
{
// rowBuffer is the temporary storage for the row
rowBuffer = new byte[fields.length][];
for ( int i = 0; columnNames.hasMoreElements(); i++ ) {
String columnName = (String) columnNames.nextElement();
// clear the updateValues hashTable for the next set of updates
updateValues.clear();
insertSQL.append( columnName );
if ( i < numColumns - 1 ) {
insertSQL.append(", ");
paramSQL.append("?,");
}
else {
paramSQL.append("?)");
}
}
}
insertSQL.append(paramSQL.toString());
insertStatement = ((java.sql.Connection) connection).prepareStatement(insertSQL.toString());
public boolean rowDeleted() throws SQLException
{
// only sub-classes implement CONCURuPDATEABLE
throw Driver.notImplemented();
}
Enumeration keys = updateValues.keys();
for ( int i = 1; keys.hasMoreElements(); i++) {
String key = (String) keys.nextElement();
insertStatement.setObject(i, updateValues.get( key ) );
}
public boolean rowInserted() throws SQLException
{
// only sub-classes implement CONCURuPDATEABLE
throw Driver.notImplemented();
}
insertStatement.executeUpdate();
if ( usingOID ) {
// we have to get the last inserted OID and put it in the resultset
public boolean rowUpdated() throws SQLException
{
// only sub-classes implement CONCURuPDATEABLE
throw Driver.notImplemented();
}
long insertedOID = ((AbstractJdbc2Statement) insertStatement).getLastOID();
updateValues.put("oid", new Long(insertedOID) );
public synchronized void updateAsciiStream(int columnIndex,
java.io.InputStream x,
int length
)
throws SQLException
{
}
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
// update the underlying row to the new inserted data
updateRowBuffer();
byte[] theData = null;
rows.addElement(rowBuffer);
try
{
x.read(theData, 0, length);
}
catch (NullPointerException ex )
{
throw new PSQLException("postgresql.updateable.inputstream");
}
catch (IOException ie)
{
throw new PSQLException("postgresql.updateable.ioerror" + ie);
}
// we should now reflect the current data in this_row
// that way getXXX will get the newly inserted data
this_row = rowBuffer;
doingUpdates = !onInsertRow;
// need to clear this in case of another insert
clearRowBuffer();
updateValues.put( fields[columnIndex - 1].getName(), theData );
}
}
}
public synchronized void updateBigDecimal(int columnIndex,
java.math.BigDecimal x )
throws SQLException
{
public synchronized void moveToCurrentRow() throws SQLException {
if (!updateable) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
this_row = (byte[][]) rows.elementAt(current_row);
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), x );
rowBuffer = new byte[this_row.length][];
System.arraycopy(this_row, 0, rowBuffer, 0, this_row.length);
}
onInsertRow = false;
doingUpdates = false;
}
public synchronized void updateBinaryStream(int columnIndex,
java.io.InputStream x,
int length
)
throws SQLException
{
public synchronized void moveToInsertRow() throws SQLException
{
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
if (insertStatement != null)
{
insertStatement = null;
}
byte[] theData = null;
try
{
x.read(theData, 0, length);
// make sure the underlying data is null
clearRowBuffer();
}
catch ( NullPointerException ex )
{
throw new PSQLException("postgresql.updateable.inputstream");
}
catch (IOException ie)
{
throw new PSQLException("postgresql.updateable.ioerror" + ie);
}
onInsertRow = true;
doingUpdates = false;
doingUpdates = !onInsertRow;
}
updateValues.put( fields[columnIndex - 1].getName(), theData );
}
private synchronized void clearRowBuffer() throws SQLException
{
// rowBuffer is the temporary storage for the row
rowBuffer = new byte[fields.length][];
// clear the updateValues hashTable for the next set of updates
updateValues.clear();
public synchronized void updateBoolean(int columnIndex, boolean x)
throws SQLException
{
}
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
if ( Driver.logDebug )
Driver.debug("updating boolean " + fields[columnIndex - 1].getName() + "=" + x);
public boolean rowDeleted() throws SQLException {
// only sub-classes implement CONCURuPDATEABLE
throw Driver.notImplemented();
}
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), new Boolean(x) );
}
public boolean rowInserted() throws SQLException {
// only sub-classes implement CONCURuPDATEABLE
throw Driver.notImplemented();
}
public synchronized void updateByte(int columnIndex, byte x)
throws SQLException
{
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
public boolean rowUpdated() throws SQLException {
// only sub-classes implement CONCURuPDATEABLE
throw Driver.notImplemented();
}
doingUpdates = true;
updateValues.put( fields[columnIndex - 1].getName(), String.valueOf(x) );
}
public synchronized void updateAsciiStream(int columnIndex,
java.io.InputStream x,
int length
) throws SQLException {
public synchronized void updateBytes(int columnIndex, byte[] x)
throws SQLException
{
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
byte[] theData = null;
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), x );
try {
x.read(theData, 0, length);
}
catch (NullPointerException ex ) {
throw new PSQLException("postgresql.updateable.inputstream");
}
catch (IOException ie) {
throw new PSQLException("postgresql.updateable.ioerror" + ie);
}
}
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), theData );
public synchronized void updateCharacterStream(int columnIndex,
java.io.Reader x,
int length
)
throws SQLException
{
}
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
char[] theData = null;
public synchronized void updateBigDecimal(int columnIndex,
java.math.BigDecimal x )
throws SQLException {
try
{
x.read(theData, 0, length);
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
}
catch (NullPointerException ex)
{
throw new PSQLException("postgresql.updateable.inputstream");
}
catch (IOException ie)
{
throw new PSQLException("postgresql.updateable.ioerror" + ie);
}
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), x );
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), theData);
}
}
public synchronized void updateBinaryStream(int columnIndex,
java.io.InputStream x,
int length
) throws SQLException {
public synchronized void updateDate(int columnIndex, java.sql.Date x)
throws SQLException
{
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
byte[] theData = null;
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), x );
}
try {
x.read(theData, 0, length);
}
catch ( NullPointerException ex ) {
throw new PSQLException("postgresql.updateable.inputstream");
}
catch (IOException ie) {
throw new PSQLException("postgresql.updateable.ioerror" + ie);
}
public synchronized void updateDouble(int columnIndex, double x)
throws SQLException
{
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
doingUpdates = !onInsertRow;
if ( Driver.logDebug )
Driver.debug("updating double " + fields[columnIndex - 1].getName() + "=" + x);
updateValues.put( fields[columnIndex - 1].getName(), theData );
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), new Double(x) );
}
}
public synchronized void updateBoolean(int columnIndex, boolean x) throws SQLException {
public synchronized void updateFloat(int columnIndex, float x)
throws SQLException
{
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
if ( Driver.logDebug )
Driver.debug("updating float " + fields[columnIndex - 1].getName() + "=" + x);
if ( Driver.logDebug ) Driver.debug("updating boolean " + fields[columnIndex - 1].getName() + "=" + x);
doingUpdates = !onInsertRow;
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), new Boolean(x) );
updateValues.put( fields[columnIndex - 1].getName(), new Float(x) );
}
}
public synchronized void updateByte(int columnIndex, byte x) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
public synchronized void updateInt(int columnIndex, int x)
throws SQLException
{
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
doingUpdates = true;
updateValues.put( fields[columnIndex - 1].getName(), String.valueOf(x) );
}
if ( Driver.logDebug )
Driver.debug("updating int " + fields[columnIndex - 1].getName() + "=" + x);
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), new Integer(x) );
public synchronized void updateBytes(int columnIndex, byte[] x) throws SQLException {
}
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), x );
public synchronized void updateLong(int columnIndex, long x)
throws SQLException
{
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
}
if ( Driver.logDebug )
Driver.debug("updating long " + fields[columnIndex - 1].getName() + "=" + x);
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), new Long(x) );
public synchronized void updateCharacterStream(int columnIndex,
java.io.Reader x,
int length
) throws SQLException {
}
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
char[] theData = null;
public synchronized void updateNull(int columnIndex)
throws SQLException
{
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
try {
x.read(theData, 0, length);
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), null);
}
catch (NullPointerException ex) {
throw new PSQLException("postgresql.updateable.inputstream");
}
catch (IOException ie) {
throw new PSQLException("postgresql.updateable.ioerror" + ie);
}
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), theData);
}
}
public synchronized void updateObject(int columnIndex, Object x)
throws SQLException
{
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
public synchronized void updateDate(int columnIndex, java.sql.Date x) throws SQLException {
if ( Driver.logDebug )
Driver.debug("updating object " + fields[columnIndex - 1].getName() + " = " + x);
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), x );
}
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), x );
}
public synchronized void updateObject(int columnIndex, Object x, int scale)
throws SQLException
{
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
public synchronized void updateDouble(int columnIndex, double x) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
this.updateObject(columnIndex, x);
if ( Driver.logDebug ) Driver.debug("updating double " + fields[columnIndex - 1].getName() + "=" + x);
}
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), new Double(x) );
}
public void refreshRow() throws SQLException
{
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
try
{
StringBuffer selectSQL = new StringBuffer( "select ");
public synchronized void updateFloat(int columnIndex, float x) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
final int numColumns = java.lang.reflect.Array.getLength(fields);
if ( Driver.logDebug ) Driver.debug("updating float " + fields[columnIndex - 1].getName() + "=" + x);
for (int i = 0; i < numColumns; i++ )
{
doingUpdates = !onInsertRow;
selectSQL.append( fields[i].getName() );
updateValues.put( fields[columnIndex - 1].getName(), new Float(x) );
if ( i < numColumns - 1 )
{
}
selectSQL.append(", ");
}
}
selectSQL.append(" from " ).append(tableName).append(" where ");
public synchronized void updateInt(int columnIndex, int x) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
int numKeys = primaryKeys.size();
if ( Driver.logDebug ) Driver.debug("updating int " + fields[columnIndex - 1].getName() + "=" + x);
for ( int i = 0; i < numKeys; i++ )
{
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), new Integer(x) );
PrimaryKey primaryKey = ((PrimaryKey) primaryKeys.get(i));
selectSQL.append(primaryKey.name).append("= ?");
}
if ( i < numKeys - 1 )
{
selectSQL.append(" and ");
}
}
if ( Driver.logDebug )
Driver.debug("selecting " + selectSQL.toString());
selectStatement = ((java.sql.Connection) connection).prepareStatement(selectSQL.toString());
public synchronized void updateLong(int columnIndex, long x) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
for ( int j = 0, i = 1; j < numKeys; j++, i++)
{
selectStatement.setObject( i, ((PrimaryKey) primaryKeys.get(j)).getValue() );
}
if ( Driver.logDebug ) Driver.debug("updating long " + fields[columnIndex - 1].getName() + "=" + x);
AbstractJdbc2ResultSet rs = (AbstractJdbc2ResultSet) selectStatement.executeQuery();
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), new Long(x) );
if ( rs.first() )
{
rowBuffer = rs.rowBuffer;
}
}
rows.setElementAt( rowBuffer, current_row );
if ( Driver.logDebug )
Driver.debug("done updates");
rs.close();
selectStatement.close();
selectStatement = null;
public synchronized void updateNull(int columnIndex) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
}
catch (Exception e)
{
if ( Driver.logDebug )
Driver.debug(e.getClass().getName() + e);
throw new SQLException( e.getMessage() );
}
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), null);
}
}
public synchronized void updateRow()
throws SQLException
{
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
if (doingUpdates)
{
public synchronized void updateObject(int columnIndex, Object x) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
try
{
if ( Driver.logDebug ) Driver.debug("updating object " + fields[columnIndex - 1].getName() + " = " + x);
StringBuffer updateSQL = new StringBuffer("UPDATE " + tableName + " SET ");
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), x );
}
int numColumns = updateValues.size();
Enumeration columns = updateValues.keys();
for (int i = 0; columns.hasMoreElements(); i++ )
{
public synchronized void updateObject(int columnIndex, Object x, int scale) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
String column = (String) columns.nextElement();
updateSQL.append( column + "= ?");
this.updateObject(columnIndex, x);
if ( i < numColumns - 1 )
{
}
updateSQL.append(", ");
}
}
updateSQL.append( " WHERE " );
public void refreshRow() throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
int numKeys = primaryKeys.size();
try {
StringBuffer selectSQL = new StringBuffer( "select ");
for ( int i = 0; i < numKeys; i++ )
{
final int numColumns = java.lang.reflect.Array.getLength(fields);
PrimaryKey primaryKey = ((PrimaryKey) primaryKeys.get(i));
updateSQL.append(primaryKey.name).append("= ?");
for (int i = 0; i < numColumns; i++ ) {
if ( i < numKeys - 1 )
{
updateSQL.append(" and ");
}
}
if ( Driver.logDebug )
Driver.debug("updating " + updateSQL.toString());
updateStatement = ((java.sql.Connection) connection).prepareStatement(updateSQL.toString());
selectSQL.append( fields[i].getName() );
int i = 0;
Iterator iterator = updateValues.values().iterator();
for (; iterator.hasNext(); i++)
{
updateStatement.setObject( i + 1, iterator.next() );
if ( i < numColumns - 1 ) {
}
for ( int j = 0; j < numKeys; j++, i++)
{
updateStatement.setObject( i + 1, ((PrimaryKey) primaryKeys.get(j)).getValue() );
}
selectSQL.append(", ");
}
updateStatement.executeUpdate();
updateStatement.close();
}
selectSQL.append(" from " ).append(tableName).append(" where ");
updateStatement = null;
updateRowBuffer();
int numKeys = primaryKeys.size();
for ( int i = 0; i < numKeys; i++ ) {
if ( Driver.logDebug )
Driver.debug("copying data");
System.arraycopy(rowBuffer, 0, this_row, 0, rowBuffer.length);
PrimaryKey primaryKey = ((PrimaryKey) primaryKeys.get(i));
selectSQL.append(primaryKey.name).append("= ?");
rows.setElementAt( rowBuffer, current_row );
if ( Driver.logDebug )
Driver.debug("done updates");
if ( i < numKeys - 1 ) {
selectSQL.append(" and ");
}
}
if ( Driver.logDebug ) Driver.debug("selecting " + selectSQL.toString());
selectStatement = ((java.sql.Connection) connection).prepareStatement(selectSQL.toString());
doingUpdates = false;
}
catch (Exception e)
{
if ( Driver.logDebug )
Driver.debug(e.getClass().getName() + e);
throw new SQLException( e.getMessage() );
}
}
for ( int j = 0, i = 1; j < numKeys; j++, i++) {
selectStatement.setObject( i, ((PrimaryKey) primaryKeys.get(j)).getValue() );
}
}
AbstractJdbc2ResultSet rs = (AbstractJdbc2ResultSet) selectStatement.executeQuery();
if ( rs.first() ) {
rowBuffer = rs.rowBuffer;
}
public synchronized void updateShort(int columnIndex, short x)
throws SQLException
{
if ( Driver.logDebug )
Driver.debug("in update Short " + fields[columnIndex - 1].getName() + " = " + x);
rows.setElementAt( rowBuffer, current_row );
if ( Driver.logDebug ) Driver.debug("done updates");
rs.close();
selectStatement.close();
selectStatement = null;
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), new Short(x) );
}
catch (Exception e) {
if ( Driver.logDebug ) Driver.debug(e.getClass().getName() + e);
throw new SQLException( e.getMessage() );
}
}
}
public synchronized void updateString(int columnIndex, String x)
throws SQLException
{
if ( Driver.logDebug )
Driver.debug("in update String " + fields[columnIndex - 1].getName() + " = " + x);
public synchronized void updateRow() throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), x );
if (doingUpdates) {
}
try {
StringBuffer updateSQL = new StringBuffer("UPDATE " + tableName + " SET ");
public synchronized void updateTime(int columnIndex, Time x)
throws SQLException
{
if ( Driver.logDebug )
Driver.debug("in update Time " + fields[columnIndex - 1].getName() + " = " + x);
int numColumns = updateValues.size();
Enumeration columns = updateValues.keys();
for (int i = 0; columns.hasMoreElements(); i++ ) {
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), x );
String column = (String) columns.nextElement();
updateSQL.append( column + "= ?");
}
if ( i < numColumns - 1 ) {
updateSQL.append(", ");
}
public synchronized void updateTimestamp(int columnIndex, Timestamp x)
throws SQLException
{
if ( Driver.logDebug )
Driver.debug("updating Timestamp " + fields[columnIndex - 1].getName() + " = " + x);
}
updateSQL.append( " WHERE " );
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), x );
int numKeys = primaryKeys.size();
for ( int i = 0; i < numKeys; i++ ) {
}
PrimaryKey primaryKey = ((PrimaryKey) primaryKeys.get(i));
updateSQL.append(primaryKey.name).append("= ?");
if ( i < numKeys - 1 ) {
updateSQL.append(" and ");
}
}
if ( Driver.logDebug ) Driver.debug("updating " + updateSQL.toString());
updateStatement = ((java.sql.Connection) connection).prepareStatement(updateSQL.toString());
public synchronized void updateNull(String columnName)
throws SQLException
{
updateNull(findColumn(columnName));
}
int i = 0;
Iterator iterator = updateValues.values().iterator();
for (; iterator.hasNext(); i++) {
updateStatement.setObject( i + 1, iterator.next() );
}
for ( int j = 0; j < numKeys; j++, i++) {
updateStatement.setObject( i + 1, ((PrimaryKey) primaryKeys.get(j)).getValue() );
}
public synchronized void updateBoolean(String columnName, boolean x)
throws SQLException
{
updateBoolean(findColumn(columnName), x);
}
updateStatement.executeUpdate();
updateStatement.close();
updateStatement = null;
updateRowBuffer();
public synchronized void updateByte(String columnName, byte x)
throws SQLException
{
updateByte(findColumn(columnName), x);
}
if ( Driver.logDebug ) Driver.debug("copying data");
System.arraycopy(rowBuffer, 0, this_row, 0, rowBuffer.length);
public synchronized void updateShort(String columnName, short x)
throws SQLException
{
updateShort(findColumn(columnName), x);
}
rows.setElementAt( rowBuffer, current_row );
if ( Driver.logDebug ) Driver.debug("done updates");
doingUpdates = false;
}
catch (Exception e) {
if ( Driver.logDebug ) Driver.debug(e.getClass().getName() + e);
throw new SQLException( e.getMessage() );
}
public synchronized void updateInt(String columnName, int x)
throws SQLException
{
updateInt(findColumn(columnName), x);
}
}
}
public synchronized void updateLong(String columnName, long x)
throws SQLException
{
updateLong(findColumn(columnName), x);
}
public synchronized void updateShort(int columnIndex, short x) throws SQLException {
if ( Driver.logDebug ) Driver.debug("in update Short " + fields[columnIndex - 1].getName() + " = " + x);
public synchronized void updateFloat(String columnName, float x)
throws SQLException
{
updateFloat(findColumn(columnName), x);
}
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), new Short(x) );
public synchronized void updateDouble(String columnName, double x)
throws SQLException
{
updateDouble(findColumn(columnName), x);
}
}
public synchronized void updateBigDecimal(String columnName, BigDecimal x)
throws SQLException
{
updateBigDecimal(findColumn(columnName), x);
}
public synchronized void updateString(int columnIndex, String x) throws SQLException {
if ( Driver.logDebug ) Driver.debug("in update String " + fields[columnIndex - 1].getName() + " = " + x);
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), x );
public synchronized void updateString(String columnName, String x)
throws SQLException
{
updateString(findColumn(columnName), x);
}
}
public synchronized void updateBytes(String columnName, byte x[])
throws SQLException
{
updateBytes(findColumn(columnName), x);
}
public synchronized void updateTime(int columnIndex, Time x) throws SQLException {
if ( Driver.logDebug ) Driver.debug("in update Time " + fields[columnIndex - 1].getName() + " = " + x);
public synchronized void updateDate(String columnName, java.sql.Date x)
throws SQLException
{
updateDate(findColumn(columnName), x);
}
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), x );
}
public synchronized void updateTime(String columnName, java.sql.Time x)
throws SQLException
{
updateTime(findColumn(columnName), x);
}
public synchronized void updateTimestamp(int columnIndex, Timestamp x) throws SQLException {
if ( Driver.logDebug ) Driver.debug("updating Timestamp " + fields[columnIndex - 1].getName() + " = " + x);
public synchronized void updateTimestamp(String columnName, java.sql.Timestamp x)
throws SQLException
{
updateTimestamp(findColumn(columnName), x);
}
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), x );
public synchronized void updateAsciiStream(
String columnName,
java.io.InputStream x,
int length)
throws SQLException
{
updateAsciiStream(findColumn(columnName), x, length);
}
}
public synchronized void updateBinaryStream(
String columnName,
java.io.InputStream x,
int length)
throws SQLException
{
updateBinaryStream(findColumn(columnName), x, length);
}
public synchronized void updateNull(String columnName) throws SQLException {
updateNull(findColumn(columnName));
}
public synchronized void updateCharacterStream(
String columnName,
java.io.Reader reader,
int length)
throws SQLException
{
updateCharacterStream(findColumn(columnName), reader, length);
}
public synchronized void updateBoolean(String columnName, boolean x) throws SQLException {
updateBoolean(findColumn(columnName), x);
}
public synchronized void updateObject(String columnName, Object x, int scale)
throws SQLException
{
updateObject(findColumn(columnName), x);
}
public synchronized void updateByte(String columnName, byte x) throws SQLException {
updateByte(findColumn(columnName), x);
}
public synchronized void updateObject(String columnName, Object x)
throws SQLException
{
updateObject(findColumn(columnName), x);
}
public synchronized void updateShort(String columnName, short x) throws SQLException {
updateShort(findColumn(columnName), x);
}
private int _findColumn( String columnName )
{
int i;
public synchronized void updateInt(String columnName, int x) throws SQLException {
updateInt(findColumn(columnName), x);
}
final int flen = fields.length;
for (i = 0; i < flen; ++i)
{
if (fields[i].getName().equalsIgnoreCase(columnName))
{
return (i + 1);
}
}
return -1;
}
public synchronized void updateLong(String columnName, long x) throws SQLException {
updateLong(findColumn(columnName), x);
}
/**
* Is this ResultSet updateable?
*/
boolean isUpdateable() throws SQLException
{
public synchronized void updateFloat(String columnName, float x) throws SQLException {
updateFloat(findColumn(columnName), x);
}
if (updateable)
return true;
if ( Driver.logDebug )
Driver.debug("checking if rs is updateable");
public synchronized void updateDouble(String columnName, double x) throws SQLException {
updateDouble(findColumn(columnName), x);
}
parseQuery();
if ( singleTable == false )
{
if ( Driver.logDebug )
Driver.debug("not a single table");
return false;
}
public synchronized void updateBigDecimal(String columnName, BigDecimal x)
throws SQLException {
updateBigDecimal(findColumn(columnName), x);
}
if ( Driver.logDebug )
Driver.debug("getting primary keys");
//
// Contains the primary key?
//
public synchronized void updateString(String columnName, String x) throws SQLException {
updateString(findColumn(columnName), x);
}
primaryKeys = new Vector();
// this is not stricty jdbc spec, but it will make things much faster if used
// the user has to select oid, * from table and then we will just use oid
public synchronized void updateBytes(String columnName, byte x[]) throws SQLException {
updateBytes(findColumn(columnName), x);
}
usingOID = false;
int oidIndex = _findColumn( "oid" );
int i = 0;
public synchronized void updateDate(String columnName, java.sql.Date x)
throws SQLException {
updateDate(findColumn(columnName), x);
}
// if we find the oid then just use it
if ( oidIndex > 0 )
{
i++;
primaryKeys.add( new PrimaryKey( oidIndex, "oid" ) );
usingOID = true;
}
else
{
// otherwise go and get the primary keys and create a hashtable of keys
java.sql.ResultSet rs = ((java.sql.Connection) connection).getMetaData().getPrimaryKeys("", "", tableName);
for (; rs.next(); i++ )
{
String columnName = rs.getString(4); // get the columnName
int index = findColumn( columnName );
if ( index > 0 )
{
primaryKeys.add( new PrimaryKey(index, columnName ) ); // get the primary key information
}
}
rs.close();
}
numKeys = primaryKeys.size();
if ( Driver.logDebug )
Driver.debug( "no of keys=" + i );
public synchronized void updateTime(String columnName, java.sql.Time x)
throws SQLException {
updateTime(findColumn(columnName), x);
}
public synchronized void updateTimestamp(String columnName, java.sql.Timestamp x)
throws SQLException {
updateTimestamp(findColumn(columnName), x);
}
public synchronized void updateAsciiStream(
String columnName,
java.io.InputStream x,
int length)
throws SQLException {
updateAsciiStream(findColumn(columnName), x, length);
}
public synchronized void updateBinaryStream(
String columnName,
java.io.InputStream x,
int length)
throws SQLException {
updateBinaryStream(findColumn(columnName), x, length);
}
public synchronized void updateCharacterStream(
String columnName,
java.io.Reader reader,
int length)
throws SQLException {
updateCharacterStream(findColumn(columnName), reader, length);
}
public synchronized void updateObject(String columnName, Object x, int scale)
throws SQLException {
updateObject(findColumn(columnName), x);
}
public synchronized void updateObject(String columnName, Object x) throws SQLException {
updateObject(findColumn(columnName), x);
}
private int _findColumn( String columnName ) {
int i;
final int flen = fields.length;
for (i = 0; i < flen; ++i) {
if (fields[i].getName().equalsIgnoreCase(columnName)) {
return (i + 1);
}
}
return -1;
}
/**
* Is this ResultSet updateable?
*/
boolean isUpdateable() throws SQLException
{
if (updateable) return true;
if ( Driver.logDebug ) Driver.debug("checking if rs is updateable");
parseQuery();
if ( singleTable == false ) {
if ( Driver.logDebug ) Driver.debug("not a single table");
return false;
}
if ( Driver.logDebug ) Driver.debug("getting primary keys");
//
// Contains the primary key?
//
primaryKeys = new Vector();
// this is not stricty jdbc spec, but it will make things much faster if used
// the user has to select oid, * from table and then we will just use oid
usingOID = false;
int oidIndex = _findColumn( "oid" );
int i = 0;
// if we find the oid then just use it
if ( oidIndex > 0 ) {
i++;
primaryKeys.add( new PrimaryKey( oidIndex, "oid" ) );
usingOID = true;
}
else {
// otherwise go and get the primary keys and create a hashtable of keys
java.sql.ResultSet rs = ((java.sql.Connection) connection).getMetaData().getPrimaryKeys("", "", tableName);
for (; rs.next(); i++ ) {
String columnName = rs.getString(4); // get the columnName
int index = findColumn( columnName );
if ( index > 0 ) {
primaryKeys.add( new PrimaryKey(index, columnName ) ); // get the primary key information
}
}
rs.close();
}
numKeys = primaryKeys.size();
if ( Driver.logDebug ) Driver.debug( "no of keys=" + i );
if ( i < 1 ) {
throw new SQLException("No Primary Keys");
}
updateable = primaryKeys.size() > 0;
if ( Driver.logDebug ) Driver.debug( "checking primary key " + updateable );
return updateable;
}
public void parseQuery() {
String[] l_sqlFragments = ((AbstractJdbc2Statement)statement).getSqlFragments();
String l_sql = l_sqlFragments[0];
StringTokenizer st = new StringTokenizer(l_sql, " \r\t");
boolean tableFound = false, tablesChecked = false;
String name = "";
singleTable = true;
while ( !tableFound && !tablesChecked && st.hasMoreTokens() ) {
name = st.nextToken();
if ( !tableFound ) {
if (name.toLowerCase().equals("from")) {
tableName = st.nextToken();
tableFound = true;
}
}
else {
tablesChecked = true;
// if the very next token is , then there are multiple tables
singleTable = !name.equalsIgnoreCase(",");
}
}
}
private void updateRowBuffer() throws SQLException {
Enumeration columns = updateValues.keys();
while ( columns.hasMoreElements() ) {
String columnName = (String) columns.nextElement();
int columnIndex = _findColumn( columnName ) - 1;
switch ( connection.getSQLType( fields[columnIndex].getPGType() ) ) {
case Types.DECIMAL:
case Types.BIGINT:
case Types.DOUBLE:
case Types.BIT:
case Types.VARCHAR:
case Types.DATE:
case Types.TIME:
case Types.TIMESTAMP:
case Types.SMALLINT:
case Types.FLOAT:
case Types.INTEGER:
case Types.CHAR:
case Types.NUMERIC:
case Types.REAL:
case Types.TINYINT:
try {
rowBuffer[columnIndex] = String.valueOf( updateValues.get( columnName ) ).getBytes(connection.getEncoding().name() );
}
catch ( UnsupportedEncodingException ex) {
throw new SQLException("Unsupported Encoding " + connection.getEncoding().name());
}
case Types.NULL:
continue;
default:
rowBuffer[columnIndex] = (byte[]) updateValues.get( columnName );
}
}
}
public void setStatement(Statement statement) {
this.statement = statement;
}
private class PrimaryKey {
int index; // where in the result set is this primaryKey
String name; // what is the columnName of this primary Key
PrimaryKey( int index, String name) {
this.index = index;
this.name = name;
}
Object getValue() throws SQLException {
return getObject(index);
}
};
if ( i < 1 )
{
throw new SQLException("No Primary Keys");
}
updateable = primaryKeys.size() > 0;
if ( Driver.logDebug )
Driver.debug( "checking primary key " + updateable );
return updateable;
}
public void parseQuery()
{
String[] l_sqlFragments = ((AbstractJdbc2Statement)statement).getSqlFragments();
String l_sql = l_sqlFragments[0];
StringTokenizer st = new StringTokenizer(l_sql, " \r\t");
boolean tableFound = false, tablesChecked = false;
String name = "";
singleTable = true;
while ( !tableFound && !tablesChecked && st.hasMoreTokens() )
{
name = st.nextToken();
if ( !tableFound )
{
if (name.toLowerCase().equals("from"))
{
tableName = st.nextToken();
tableFound = true;
}
}
else
{
tablesChecked = true;
// if the very next token is , then there are multiple tables
singleTable = !name.equalsIgnoreCase(",");
}
}
}
private void updateRowBuffer() throws SQLException
{
Enumeration columns = updateValues.keys();
while ( columns.hasMoreElements() )
{
String columnName = (String) columns.nextElement();
int columnIndex = _findColumn( columnName ) - 1;
switch ( connection.getSQLType( fields[columnIndex].getPGType() ) )
{
case Types.DECIMAL:
case Types.BIGINT:
case Types.DOUBLE:
case Types.BIT:
case Types.VARCHAR:
case Types.DATE:
case Types.TIME:
case Types.TIMESTAMP:
case Types.SMALLINT:
case Types.FLOAT:
case Types.INTEGER:
case Types.CHAR:
case Types.NUMERIC:
case Types.REAL:
case Types.TINYINT:
try
{
rowBuffer[columnIndex] = String.valueOf( updateValues.get( columnName ) ).getBytes(connection.getEncoding().name() );
}
catch ( UnsupportedEncodingException ex)
{
throw new SQLException("Unsupported Encoding " + connection.getEncoding().name());
}
case Types.NULL:
continue;
default:
rowBuffer[columnIndex] = (byte[]) updateValues.get( columnName );
}
}
}
public void setStatement(Statement statement)
{
this.statement = statement;
}
private class PrimaryKey
{
int index; // where in the result set is this primaryKey
String name; // what is the columnName of this primary Key
PrimaryKey( int index, String name)
{
this.index = index;
this.name = name;
}
Object getValue() throws SQLException
{
return getObject(index);
}
};
......
......@@ -19,7 +19,7 @@ public abstract class AbstractJdbc2ResultSetMetaData extends org.postgresql.jdbc
*/
public AbstractJdbc2ResultSetMetaData(Vector rows, Field[] fields)
{
super(rows, fields);
super(rows, fields);
}
/*
......@@ -459,53 +459,53 @@ public abstract class AbstractJdbc2ResultSetMetaData extends org.postgresql.jdbc
// This can hook into our PG_Object mechanism
/**
* Returns the fully-qualified name of the Java class whose instances
* Returns the fully-qualified name of the Java class whose instances
* are manufactured if the method <code>ResultSet.getObject</code>
* is called to retrieve a value from the column.
*
*
* <code>ResultSet.getObject</code> may return a subclass of the class
* returned by this method.
*
* @param column the first column is 1, the second is 2, ...
* @return the fully-qualified name of the class in the Java programming
* language that would be used by the method
* <code>ResultSet.getObject</code> to retrieve the value in the specified
* column. This is the class name used for custom mapping.
* language that would be used by the method
* <code>ResultSet.getObject</code> to retrieve the value in the specified
* column. This is the class name used for custom mapping.
* @exception SQLException if a database access error occurs
*/
public String getColumnClassName(int column) throws SQLException
{
/*
The following data type mapping came from ../Field.java.
"int2",
"int4","oid",
"int8",
"cash","money",
"numeric",
"float4",
"float8",
"bpchar","char","char2","char4","char8","char16",
"varchar","text","name","filename",
"bool",
"date",
"time",
"abstime","timestamp"
Types.SMALLINT,
Types.INTEGER,Types.INTEGER,
Types.BIGINT,
Types.DOUBLE,Types.DOUBLE,
Types.NUMERIC,
Types.REAL,
Types.DOUBLE,
Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,
Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,
Types.BIT,
Types.DATE,
Types.TIME,
Types.TIMESTAMP,Types.TIMESTAMP
*/
/*
The following data type mapping came from ../Field.java.
"int2",
"int4","oid",
"int8",
"cash","money",
"numeric",
"float4",
"float8",
"bpchar","char","char2","char4","char8","char16",
"varchar","text","name","filename",
"bool",
"date",
"time",
"abstime","timestamp"
Types.SMALLINT,
Types.INTEGER,Types.INTEGER,
Types.BIGINT,
Types.DOUBLE,Types.DOUBLE,
Types.NUMERIC,
Types.REAL,
Types.DOUBLE,
Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,
Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,
Types.BIT,
Types.DATE,
Types.TIME,
Types.TIMESTAMP,Types.TIMESTAMP
*/
Field field = getField(column);
int sql_type = field.getSQLType();
......@@ -513,40 +513,40 @@ public abstract class AbstractJdbc2ResultSetMetaData extends org.postgresql.jdbc
switch (sql_type)
{
case Types.BIT:
return("java.lang.Boolean");
return ("java.lang.Boolean");
case Types.SMALLINT:
return("java.lang.Short");
return ("java.lang.Short");
case Types.INTEGER:
return("java.lang.Integer");
return ("java.lang.Integer");
case Types.BIGINT:
return("java.lang.Long");
return ("java.lang.Long");
case Types.NUMERIC:
return("java.math.BigDecimal");
return ("java.math.BigDecimal");
case Types.REAL:
return("java.lang.Float");
return ("java.lang.Float");
case Types.DOUBLE:
return("java.lang.Double");
return ("java.lang.Double");
case Types.CHAR:
case Types.VARCHAR:
return("java.lang.String");
return ("java.lang.String");
case Types.DATE:
return("java.sql.Date");
return ("java.sql.Date");
case Types.TIME:
return("java.sql.Time");
return ("java.sql.Time");
case Types.TIMESTAMP:
return("java.sql.Timestamp");
return ("java.sql.Timestamp");
case Types.BINARY:
case Types.VARBINARY:
return("[B");
return ("[B");
case Types.ARRAY:
return("java.sql.Array");
return ("java.sql.Array");
default:
String type = field.getPGType();
if ("unknown".equals(type))
{
return("java.lang.String");
return ("java.lang.String");
}
return("java.lang.Object");
return ("java.lang.Object");
}
}
}
......
......@@ -8,7 +8,7 @@ import java.util.Vector;
import org.postgresql.largeobject.*;
import org.postgresql.util.PSQLException;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2Statement.java,v 1.5 2002/09/02 03:07:36 barry Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2Statement.java,v 1.6 2002/09/06 21:23:06 momjian Exp $
* This class defines methods of the jdbc2 specification. This class extends
* org.postgresql.jdbc1.AbstractJdbc1Statement which provides the jdbc1
* methods. The real Statement class (for jdbc2) is org.postgresql.jdbc2.Jdbc2Statement
......@@ -45,8 +45,8 @@ public abstract class AbstractJdbc2Statement extends org.postgresql.jdbc1.Abstra
*/
public boolean execute() throws SQLException
{
boolean l_return = super.execute();
//Now do the jdbc2 specific stuff
boolean l_return = super.execute();
//Now do the jdbc2 specific stuff
//required for ResultSet.getStatement() to work and updateable resultsets
((AbstractJdbc2ResultSet)result).setStatement((Statement)this);
......@@ -64,7 +64,7 @@ public abstract class AbstractJdbc2Statement extends org.postgresql.jdbc1.Abstra
public void clearBatch() throws SQLException
{
batch = null;
batch = null;
}
public int[] executeBatch() throws SQLException
......@@ -86,7 +86,7 @@ public abstract class AbstractJdbc2Statement extends org.postgresql.jdbc1.Abstra
PBatchUpdateException updex =
new PBatchUpdateException("postgresql.stat.batch.error",
new Integer(i), batch.elementAt(i), resultSucceeded);
new Integer(i), batch.elementAt(i), resultSucceeded);
updex.setNextException(e);
throw updex;
......@@ -183,12 +183,12 @@ public abstract class AbstractJdbc2Statement extends org.postgresql.jdbc1.Abstra
// is buffered internally anyhow, so there would be no performance
// boost gained, if anything it would be worse!
int bytesRemaining = (int)x.length();
int numRead = l_inStream.read(buf,0,Math.min(buf.length,bytesRemaining));
int numRead = l_inStream.read(buf, 0, Math.min(buf.length, bytesRemaining));
while (numRead != -1 && bytesRemaining > 0)
{
bytesRemaining -= numRead;
los.write(buf,0,numRead);
numRead = l_inStream.read(buf,0,Math.min(buf.length,bytesRemaining));
bytesRemaining -= numRead;
los.write(buf, 0, numRead);
numRead = l_inStream.read(buf, 0, Math.min(buf.length, bytesRemaining));
}
los.close();
}
......@@ -384,9 +384,10 @@ public abstract class AbstractJdbc2Statement extends org.postgresql.jdbc1.Abstra
}
//This is needed by AbstractJdbc2ResultSet to determine if the query is updateable or not
protected String[] getSqlFragments() {
return m_sqlFragments;
}
//This is needed by AbstractJdbc2ResultSet to determine if the query is updateable or not
protected String[] getSqlFragments()
{
return m_sqlFragments;
}
}
......@@ -27,7 +27,7 @@ public class Array implements java.sql.Array
{
private org.postgresql.PGConnection conn = null;
private org.postgresql.Field field = null;
private ResultSet rs;
private ResultSet rs;
private int idx = 0;
private String rawString = null;
......@@ -44,7 +44,7 @@ public class Array implements java.sql.Array
{
this.conn = conn;
this.field = field;
this.rs = rs;
this.rs = rs;
this.idx = idx;
this.rawString = ((AbstractJdbc2ResultSet)rs).getFixedString(idx);
}
......@@ -76,9 +76,9 @@ public class Array implements java.sql.Array
ArrayList array = new ArrayList();
/* Check if the String is also not an empty array
* otherwise there will be an exception thrown below
* in the ResultSet.toX with an empty string.
* -- Doug Fields <dfields-pg-jdbc@pexicom.com> Feb 20, 2002 */
* otherwise there will be an exception thrown below
* in the ResultSet.toX with an empty string.
* -- Doug Fields <dfields-pg-jdbc@pexicom.com> Feb 20, 2002 */
if ( rawString != null && !rawString.equals("{}") )
{
......@@ -88,9 +88,9 @@ public class Array implements java.sql.Array
boolean insideString = false;
for ( int i = 0; i < chars.length; i++ )
{
if ( chars[i] == '\\' )
//escape character that we need to skip
i++;
if ( chars[i] == '\\' )
//escape character that we need to skip
i++;
if ( chars[i] == '{' )
{
if ( foundOpen ) // Only supports 1-D arrays for now
......
......@@ -6,55 +6,55 @@ import java.util.Vector;
import java.util.Hashtable;
import org.postgresql.Field;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/Jdbc2Connection.java,v 1.4 2002/07/26 05:29:35 barry Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/Jdbc2Connection.java,v 1.5 2002/09/06 21:23:06 momjian Exp $
* This class implements the java.sql.Connection interface for JDBC2.
* However most of the implementation is really done in
* However most of the implementation is really done in
* org.postgresql.jdbc2.AbstractJdbc2Connection or one of it's parents
*/
public class Jdbc2Connection extends org.postgresql.jdbc2.AbstractJdbc2Connection implements java.sql.Connection
{
public java.sql.Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException
{
Jdbc2Statement s = new Jdbc2Statement(this);
s.setResultSetType(resultSetType);
s.setResultSetConcurrency(resultSetConcurrency);
return s;
}
public java.sql.PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{
Jdbc2PreparedStatement s = new Jdbc2PreparedStatement(this, sql);
s.setResultSetType(resultSetType);
s.setResultSetConcurrency(resultSetConcurrency);
return s;
}
public java.sql.CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{
Jdbc2CallableStatement s = new org.postgresql.jdbc2.Jdbc2CallableStatement(this,sql);
public java.sql.Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException
{
Jdbc2Statement s = new Jdbc2Statement(this);
s.setResultSetType(resultSetType);
s.setResultSetConcurrency(resultSetConcurrency);
return s;
}
public java.sql.DatabaseMetaData getMetaData() throws SQLException
{
if (metadata == null)
metadata = new org.postgresql.jdbc2.Jdbc2DatabaseMetaData(this);
return metadata;
}
public java.sql.ResultSet getResultSet(Statement statement, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException
{
return new Jdbc2ResultSet(this, statement, fields, tuples, status, updateCount, insertOID, binaryCursor);
}
public java.sql.ResultSet getResultSet(Statement statement, Field[] fields, Vector tuples, String status, int updateCount) throws SQLException
{
return new Jdbc2ResultSet(this, statement, fields, tuples, status, updateCount, 0, false);
}
s.setResultSetConcurrency(resultSetConcurrency);
return s;
}
public java.sql.PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{
Jdbc2PreparedStatement s = new Jdbc2PreparedStatement(this, sql);
s.setResultSetType(resultSetType);
s.setResultSetConcurrency(resultSetConcurrency);
return s;
}
public java.sql.CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{
Jdbc2CallableStatement s = new org.postgresql.jdbc2.Jdbc2CallableStatement(this, sql);
s.setResultSetType(resultSetType);
s.setResultSetConcurrency(resultSetConcurrency);
return s;
}
public java.sql.DatabaseMetaData getMetaData() throws SQLException
{
if (metadata == null)
metadata = new org.postgresql.jdbc2.Jdbc2DatabaseMetaData(this);
return metadata;
}
public java.sql.ResultSet getResultSet(Statement statement, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException
{
return new Jdbc2ResultSet(this, statement, fields, tuples, status, updateCount, insertOID, binaryCursor);
}
public java.sql.ResultSet getResultSet(Statement statement, Field[] fields, Vector tuples, String status, int updateCount) throws SQLException
{
return new Jdbc2ResultSet(this, statement, fields, tuples, status, updateCount, 0, false);
}
}
......
......@@ -5,9 +5,9 @@ import java.sql.*;
import java.util.Vector;
import org.postgresql.Field;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/Jdbc2ResultSet.java,v 1.4 2002/08/14 20:35:39 barry Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/Jdbc2ResultSet.java,v 1.5 2002/09/06 21:23:06 momjian Exp $
* This class implements the java.sql.ResultSet interface for JDBC2.
* However most of the implementation is really done in
* However most of the implementation is really done in
* org.postgresql.jdbc2.AbstractJdbc2ResultSet or one of it's parents
*/
public class Jdbc2ResultSet extends org.postgresql.jdbc2.AbstractJdbc2ResultSet implements java.sql.ResultSet
......@@ -23,13 +23,15 @@ public class Jdbc2ResultSet extends org.postgresql.jdbc2.AbstractJdbc2ResultSet
return new Jdbc2ResultSetMetaData(rows, fields);
}
public java.sql.Clob getClob(int i) throws SQLException {
return new org.postgresql.jdbc2.Jdbc2Clob(connection, getInt(i));
}
public java.sql.Clob getClob(int i) throws SQLException
{
return new org.postgresql.jdbc2.Jdbc2Clob(connection, getInt(i));
}
public java.sql.Blob getBlob(int i) throws SQLException {
return new org.postgresql.jdbc2.Jdbc2Blob(connection, getInt(i));
}
public java.sql.Blob getBlob(int i) throws SQLException
{
return new org.postgresql.jdbc2.Jdbc2Blob(connection, getInt(i));
}
}
......@@ -4,7 +4,7 @@ public class Jdbc2ResultSetMetaData extends AbstractJdbc2ResultSetMetaData imple
{
public Jdbc2ResultSetMetaData(java.util.Vector rows, org.postgresql.Field[] fields)
{
super(rows, fields);
super(rows, fields);
}
}
......@@ -3,9 +3,9 @@ package org.postgresql.jdbc2;
import java.sql.*;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/Jdbc2Statement.java,v 1.2 2002/07/24 22:08:43 barry Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/Jdbc2Statement.java,v 1.3 2002/09/06 21:23:06 momjian Exp $
* This class implements the java.sql.Statement interface for JDBC2.
* However most of the implementation is really done in
* However most of the implementation is really done in
* org.postgresql.jdbc2.AbstractJdbc2Statement or one of it's parents
*/
public class Jdbc2Statement extends org.postgresql.jdbc2.AbstractJdbc2Statement implements java.sql.Statement
......
......@@ -8,217 +8,249 @@ import java.sql.*;
* Base class for data sources and related classes.
*
* @author Aaron Mulder (ammulder@chariotsolutions.com)
* @version $Revision: 1.1 $
* @version $Revision: 1.2 $
*/
public abstract class BaseDataSource implements Referenceable {
// Load the normal driver, since we'll use it to actually connect to the
// database. That way we don't have to maintain the connecting code in
// multiple places.
static {
try {
Class.forName("org.postgresql.Driver");
} catch (ClassNotFoundException e) {
System.err.println("PostgreSQL DataSource unable to load PostgreSQL JDBC Driver");
}
}
// Needed to implement the DataSource/ConnectionPoolDataSource interfaces
private transient PrintWriter logger;
// Don't track loginTimeout, since we'd just ignore it anyway
// Standard properties, defined in the JDBC 2.0 Optional Package spec
private String serverName = "localhost";
private String databaseName;
private String user;
private String password;
private int portNumber;
/**
* Gets a connection to the PostgreSQL database. The database is identified by the
* DataSource properties serverName, databaseName, and portNumber. The user to
* connect as is identified by the DataSource properties user and password.
*
* @return A valid database connection.
* @throws SQLException
* Occurs when the database connection cannot be established.
*/
public Connection getConnection() throws SQLException {
return getConnection(user, password);
}
/**
* Gets a connection to the PostgreSQL database. The database is identified by the
* DataAource properties serverName, databaseName, and portNumber. The user to
* connect as is identified by the arguments user and password, which override
* the DataSource properties by the same name.
*
* @return A valid database connection.
* @throws SQLException
* Occurs when the database connection cannot be established.
*/
public Connection getConnection(String user, String password) throws SQLException {
try {
Connection con = DriverManager.getConnection(getUrl(), user, password);
if (logger != null) {
logger.println("Created a non-pooled connection for " + user + " at " + getUrl());
}
return con;
} catch (SQLException e) {
if (logger != null) {
logger.println("Failed to create a non-pooled connection for " + user + " at " + getUrl() + ": " + e);
}
throw e;
}
}
/**
* This DataSource does not support a configurable login timeout.
* @return 0
*/
public int getLoginTimeout() throws SQLException {
return 0;
}
/**
* This DataSource does not support a configurable login timeout. Any value
* provided here will be ignored.
*/
public void setLoginTimeout(int i) throws SQLException {
}
/**
* Gets the log writer used to log connections opened.
*/
public PrintWriter getLogWriter() throws SQLException {
return logger;
}
/**
* The DataSource will note every connection opened to the provided log writer.
*/
public void setLogWriter(PrintWriter printWriter) throws SQLException {
logger = printWriter;
}
/**
* Gets the name of the host the PostgreSQL database is running on.
*/
public String getServerName() {
return serverName;
}
/**
* Sets the name of the host the PostgreSQL database is running on. If this
* is changed, it will only affect future calls to getConnection. The default
* value is <tt>localhost</tt>.
*/
public void setServerName(String serverName) {
if(serverName == null || serverName.equals("")) {
this.serverName = "localhost";
} else {
this.serverName = serverName;
}
}
/**
* Gets the name of the PostgreSQL database, running on the server identified
* by the serverName property.
*/
public String getDatabaseName() {
return databaseName;
}
/**
* Sets the name of the PostgreSQL database, running on the server identified
* by the serverName property. If this is changed, it will only affect
* future calls to getConnection.
*/
public void setDatabaseName(String databaseName) {
this.databaseName = databaseName;
}
/**
* Gets a description of this DataSource-ish thing. Must be customized by
* subclasses.
*/
public abstract String getDescription();
/**
* Gets the user to connect as by default. If this is not specified, you must
* use the getConnection method which takes a user and password as parameters.
*/
public String getUser() {
return user;
}
/**
* Sets the user to connect as by default. If this is not specified, you must
* use the getConnection method which takes a user and password as parameters.
* If this is changed, it will only affect future calls to getConnection.
*/
public void setUser(String user) {
this.user = user;
}
/**
* Gets the password to connect with by default. If this is not specified but a
* password is needed to log in, you must use the getConnection method which takes
* a user and password as parameters.
*/
public String getPassword() {
return password;
}
/**
* Sets the password to connect with by default. If this is not specified but a
* password is needed to log in, you must use the getConnection method which takes
* a user and password as parameters. If this is changed, it will only affect
* future calls to getConnection.
*/
public void setPassword(String password) {
this.password = password;
}
/**
* Gets the port which the PostgreSQL server is listening on for TCP/IP
* connections.
*
* @return The port, or 0 if the default port will be used.
*/
public int getPortNumber() {
return portNumber;
}
/**
* Gets the port which the PostgreSQL server is listening on for TCP/IP
* connections. Be sure the -i flag is passed to postmaster when PostgreSQL
* is started. If this is not set, or set to 0, the default port will be used.
*/
public void setPortNumber(int portNumber) {
this.portNumber = portNumber;
}
/**
* Generates a DriverManager URL from the other properties supplied.
*/
private String getUrl() {
return "jdbc:postgresql://"+serverName+(portNumber == 0 ? "" : ":"+portNumber)+"/"+databaseName;
}
public Reference getReference() throws NamingException {
Reference ref = new Reference(getClass().getName(), PGObjectFactory.class.getName(), null);
ref.add(new StringRefAddr("serverName", serverName));
if (portNumber != 0) {
ref.add(new StringRefAddr("portNumber", Integer.toString(portNumber)));
}
ref.add(new StringRefAddr("databaseName", databaseName));
if (user != null) {
ref.add(new StringRefAddr("user", user));
}
if (password != null) {
ref.add(new StringRefAddr("password", password));
}
return ref;
}
public abstract class BaseDataSource implements Referenceable
{
// Load the normal driver, since we'll use it to actually connect to the
// database. That way we don't have to maintain the connecting code in
// multiple places.
static {
try
{
Class.forName("org.postgresql.Driver");
}
catch (ClassNotFoundException e)
{
System.err.println("PostgreSQL DataSource unable to load PostgreSQL JDBC Driver");
}
}
// Needed to implement the DataSource/ConnectionPoolDataSource interfaces
private transient PrintWriter logger;
// Don't track loginTimeout, since we'd just ignore it anyway
// Standard properties, defined in the JDBC 2.0 Optional Package spec
private String serverName = "localhost";
private String databaseName;
private String user;
private String password;
private int portNumber;
/**
* Gets a connection to the PostgreSQL database. The database is identified by the
* DataSource properties serverName, databaseName, and portNumber. The user to
* connect as is identified by the DataSource properties user and password.
*
* @return A valid database connection.
* @throws SQLException
* Occurs when the database connection cannot be established.
*/
public Connection getConnection() throws SQLException
{
return getConnection(user, password);
}
/**
* Gets a connection to the PostgreSQL database. The database is identified by the
* DataAource properties serverName, databaseName, and portNumber. The user to
* connect as is identified by the arguments user and password, which override
* the DataSource properties by the same name.
*
* @return A valid database connection.
* @throws SQLException
* Occurs when the database connection cannot be established.
*/
public Connection getConnection(String user, String password) throws SQLException
{
try
{
Connection con = DriverManager.getConnection(getUrl(), user, password);
if (logger != null)
{
logger.println("Created a non-pooled connection for " + user + " at " + getUrl());
}
return con;
}
catch (SQLException e)
{
if (logger != null)
{
logger.println("Failed to create a non-pooled connection for " + user + " at " + getUrl() + ": " + e);
}
throw e;
}
}
/**
* This DataSource does not support a configurable login timeout.
* @return 0
*/
public int getLoginTimeout() throws SQLException
{
return 0;
}
/**
* This DataSource does not support a configurable login timeout. Any value
* provided here will be ignored.
*/
public void setLoginTimeout(int i) throws SQLException
{}
/**
* Gets the log writer used to log connections opened.
*/
public PrintWriter getLogWriter() throws SQLException
{
return logger;
}
/**
* The DataSource will note every connection opened to the provided log writer.
*/
public void setLogWriter(PrintWriter printWriter) throws SQLException
{
logger = printWriter;
}
/**
* Gets the name of the host the PostgreSQL database is running on.
*/
public String getServerName()
{
return serverName;
}
/**
* Sets the name of the host the PostgreSQL database is running on. If this
* is changed, it will only affect future calls to getConnection. The default
* value is <tt>localhost</tt>.
*/
public void setServerName(String serverName)
{
if (serverName == null || serverName.equals(""))
{
this.serverName = "localhost";
}
else
{
this.serverName = serverName;
}
}
/**
* Gets the name of the PostgreSQL database, running on the server identified
* by the serverName property.
*/
public String getDatabaseName()
{
return databaseName;
}
/**
* Sets the name of the PostgreSQL database, running on the server identified
* by the serverName property. If this is changed, it will only affect
* future calls to getConnection.
*/
public void setDatabaseName(String databaseName)
{
this.databaseName = databaseName;
}
/**
* Gets a description of this DataSource-ish thing. Must be customized by
* subclasses.
*/
public abstract String getDescription();
/**
* Gets the user to connect as by default. If this is not specified, you must
* use the getConnection method which takes a user and password as parameters.
*/
public String getUser()
{
return user;
}
/**
* Sets the user to connect as by default. If this is not specified, you must
* use the getConnection method which takes a user and password as parameters.
* If this is changed, it will only affect future calls to getConnection.
*/
public void setUser(String user)
{
this.user = user;
}
/**
* Gets the password to connect with by default. If this is not specified but a
* password is needed to log in, you must use the getConnection method which takes
* a user and password as parameters.
*/
public String getPassword()
{
return password;
}
/**
* Sets the password to connect with by default. If this is not specified but a
* password is needed to log in, you must use the getConnection method which takes
* a user and password as parameters. If this is changed, it will only affect
* future calls to getConnection.
*/
public void setPassword(String password)
{
this.password = password;
}
/**
* Gets the port which the PostgreSQL server is listening on for TCP/IP
* connections.
*
* @return The port, or 0 if the default port will be used.
*/
public int getPortNumber()
{
return portNumber;
}
/**
* Gets the port which the PostgreSQL server is listening on for TCP/IP
* connections. Be sure the -i flag is passed to postmaster when PostgreSQL
* is started. If this is not set, or set to 0, the default port will be used.
*/
public void setPortNumber(int portNumber)
{
this.portNumber = portNumber;
}
/**
* Generates a DriverManager URL from the other properties supplied.
*/
private String getUrl()
{
return "jdbc:postgresql://" + serverName + (portNumber == 0 ? "" : ":" + portNumber) + "/" + databaseName;
}
public Reference getReference() throws NamingException
{
Reference ref = new Reference(getClass().getName(), PGObjectFactory.class.getName(), null);
ref.add(new StringRefAddr("serverName", serverName));
if (portNumber != 0)
{
ref.add(new StringRefAddr("portNumber", Integer.toString(portNumber)));
}
ref.add(new StringRefAddr("databaseName", databaseName));
if (user != null)
{
ref.add(new StringRefAddr("user", user));
}
if (password != null)
{
ref.add(new StringRefAddr("password", password));
}
return ref;
}
}
......@@ -21,56 +21,62 @@ import java.io.Serializable;
* <p>This implementation supports JDK 1.3 and higher.</p>
*
* @author Aaron Mulder (ammulder@chariotsolutions.com)
* @version $Revision: 1.1 $
* @version $Revision: 1.2 $
*/
public class ConnectionPool extends BaseDataSource implements Serializable, ConnectionPoolDataSource {
private boolean defaultAutoCommit = false;
public class ConnectionPool extends BaseDataSource implements Serializable, ConnectionPoolDataSource
{
private boolean defaultAutoCommit = false;
/**
* Gets a description of this DataSource.
*/
public String getDescription() {
return "ConnectionPoolDataSource from "+org.postgresql.Driver.getVersion();
}
/**
* Gets a description of this DataSource.
*/
public String getDescription()
{
return "ConnectionPoolDataSource from " + org.postgresql.Driver.getVersion();
}
/**
* Gets a connection which may be pooled by the app server or middleware
* implementation of DataSource.
*
* @throws java.sql.SQLException
* Occurs when the physical database connection cannot be established.
*/
public PooledConnection getPooledConnection() throws SQLException {
return new PooledConnectionImpl(getConnection(), defaultAutoCommit);
}
/**
* Gets a connection which may be pooled by the app server or middleware
* implementation of DataSource.
*
* @throws java.sql.SQLException
* Occurs when the physical database connection cannot be established.
*/
public PooledConnection getPooledConnection() throws SQLException
{
return new PooledConnectionImpl(getConnection(), defaultAutoCommit);
}
/**
* Gets a connection which may be pooled by the app server or middleware
* implementation of DataSource.
*
* @throws java.sql.SQLException
* Occurs when the physical database connection cannot be established.
*/
public PooledConnection getPooledConnection(String user, String password) throws SQLException {
return new PooledConnectionImpl(getConnection(user, password), defaultAutoCommit);
}
/**
* Gets a connection which may be pooled by the app server or middleware
* implementation of DataSource.
*
* @throws java.sql.SQLException
* Occurs when the physical database connection cannot be established.
*/
public PooledConnection getPooledConnection(String user, String password) throws SQLException
{
return new PooledConnectionImpl(getConnection(user, password), defaultAutoCommit);
}
/**
* Gets whether connections supplied by this pool will have autoCommit
* turned on by default. The default value is <tt>false</tt>, so that
* autoCommit will be turned off by default.
*/
public boolean isDefaultAutoCommit() {
return defaultAutoCommit;
}
/**
* Gets whether connections supplied by this pool will have autoCommit
* turned on by default. The default value is <tt>false</tt>, so that
* autoCommit will be turned off by default.
*/
public boolean isDefaultAutoCommit()
{
return defaultAutoCommit;
}
/**
* Sets whether connections supplied by this pool will have autoCommit
* turned on by default. The default value is <tt>false</tt>, so that
* autoCommit will be turned off by default.
*/
public void setDefaultAutoCommit(boolean defaultAutoCommit) {
this.defaultAutoCommit = defaultAutoCommit;
}
/**
* Sets whether connections supplied by this pool will have autoCommit
* turned on by default. The default value is <tt>false</tt>, so that
* autoCommit will be turned off by default.
*/
public void setDefaultAutoCommit(boolean defaultAutoCommit)
{
this.defaultAutoCommit = defaultAutoCommit;
}
}
......@@ -13,77 +13,96 @@ import java.util.Hashtable;
* consistent.
*
* @author Aaron Mulder (ammulder@chariotsolutions.com)
* @version $Revision: 1.1 $
* @version $Revision: 1.2 $
*/
public class PGObjectFactory implements ObjectFactory {
/**
* Dereferences a PostgreSQL DataSource. Other types of references are
* ignored.
*/
public Object getObjectInstance(Object obj, Name name, Context nameCtx,
Hashtable environment) throws Exception {
Reference ref = (Reference)obj;
if(ref.getClassName().equals(SimpleDataSource.class.getName())) {
return loadSimpleDataSource(ref);
} else if (ref.getClassName().equals(ConnectionPool.class.getName())) {
return loadConnectionPool(ref);
} else if (ref.getClassName().equals(PoolingDataSource.class.getName())) {
return loadPoolingDataSource(ref);
} else {
return null;
}
}
public class PGObjectFactory implements ObjectFactory
{
/**
* Dereferences a PostgreSQL DataSource. Other types of references are
* ignored.
*/
public Object getObjectInstance(Object obj, Name name, Context nameCtx,
Hashtable environment) throws Exception
{
Reference ref = (Reference)obj;
if (ref.getClassName().equals(SimpleDataSource.class.getName()))
{
return loadSimpleDataSource(ref);
}
else if (ref.getClassName().equals(ConnectionPool.class.getName()))
{
return loadConnectionPool(ref);
}
else if (ref.getClassName().equals(PoolingDataSource.class.getName()))
{
return loadPoolingDataSource(ref);
}
else
{
return null;
}
}
private Object loadPoolingDataSource(Reference ref) {
// If DataSource exists, return it
String name = getProperty(ref, "dataSourceName");
PoolingDataSource pds = PoolingDataSource.getDataSource(name);
if(pds != null) {
return pds;
}
// Otherwise, create a new one
pds = new PoolingDataSource();
pds.setDataSourceName(name);
loadBaseDataSource(pds, ref);
String min = getProperty(ref, "initialConnections");
if (min != null) {
pds.setInitialConnections(Integer.parseInt(min));
}
String max = getProperty(ref, "maxConnections");
if (max != null) {
pds.setMaxConnections(Integer.parseInt(max));
}
return pds;
}
private Object loadPoolingDataSource(Reference ref)
{
// If DataSource exists, return it
String name = getProperty(ref, "dataSourceName");
PoolingDataSource pds = PoolingDataSource.getDataSource(name);
if (pds != null)
{
return pds;
}
// Otherwise, create a new one
pds = new PoolingDataSource();
pds.setDataSourceName(name);
loadBaseDataSource(pds, ref);
String min = getProperty(ref, "initialConnections");
if (min != null)
{
pds.setInitialConnections(Integer.parseInt(min));
}
String max = getProperty(ref, "maxConnections");
if (max != null)
{
pds.setMaxConnections(Integer.parseInt(max));
}
return pds;
}
private Object loadSimpleDataSource(Reference ref) {
SimpleDataSource ds = new SimpleDataSource();
return loadBaseDataSource(ds, ref);
}
private Object loadSimpleDataSource(Reference ref)
{
SimpleDataSource ds = new SimpleDataSource();
return loadBaseDataSource(ds, ref);
}
private Object loadConnectionPool(Reference ref) {
ConnectionPool cp = new ConnectionPool();
return loadBaseDataSource(cp, ref);
}
private Object loadConnectionPool(Reference ref)
{
ConnectionPool cp = new ConnectionPool();
return loadBaseDataSource(cp, ref);
}
private Object loadBaseDataSource(BaseDataSource ds, Reference ref) {
ds.setDatabaseName(getProperty(ref, "databaseName"));
ds.setPassword(getProperty(ref, "password"));
String port = getProperty(ref, "portNumber");
if(port != null) {
ds.setPortNumber(Integer.parseInt(port));
}
ds.setServerName(getProperty(ref, "serverName"));
ds.setUser(getProperty(ref, "user"));
return ds;
}
private Object loadBaseDataSource(BaseDataSource ds, Reference ref)
{
ds.setDatabaseName(getProperty(ref, "databaseName"));
ds.setPassword(getProperty(ref, "password"));
String port = getProperty(ref, "portNumber");
if (port != null)
{
ds.setPortNumber(Integer.parseInt(port));
}
ds.setServerName(getProperty(ref, "serverName"));
ds.setUser(getProperty(ref, "user"));
return ds;
}
private String getProperty(Reference ref, String s) {
RefAddr addr = ref.get(s);
if(addr == null) {
return null;
}
return (String)addr.getContent();
}
private String getProperty(Reference ref, String s)
{
RefAddr addr = ref.get(s);
if (addr == null)
{
return null;
}
return (String)addr.getContent();
}
}
......@@ -13,187 +13,244 @@ import java.lang.reflect.*;
* @see ConnectionPool
*
* @author Aaron Mulder (ammulder@chariotsolutions.com)
* @version $Revision: 1.1 $
* @version $Revision: 1.2 $
*/
public class PooledConnectionImpl implements PooledConnection {
private List listeners = new LinkedList();
private Connection con;
private ConnectionHandler last;
private boolean autoCommit;
public class PooledConnectionImpl implements PooledConnection
{
private List listeners = new LinkedList();
private Connection con;
private ConnectionHandler last;
private boolean autoCommit;
/**
* Creates a new PooledConnection representing the specified physical
* connection.
*/
PooledConnectionImpl(Connection con, boolean autoCommit) {
this.con = con;
this.autoCommit = autoCommit;
}
/**
* Creates a new PooledConnection representing the specified physical
* connection.
*/
PooledConnectionImpl(Connection con, boolean autoCommit)
{
this.con = con;
this.autoCommit = autoCommit;
}
/**
* Adds a listener for close or fatal error events on the connection
* handed out to a client.
*/
public void addConnectionEventListener(ConnectionEventListener connectionEventListener) {
listeners.add(connectionEventListener);
}
/**
* Adds a listener for close or fatal error events on the connection
* handed out to a client.
*/
public void addConnectionEventListener(ConnectionEventListener connectionEventListener)
{
listeners.add(connectionEventListener);
}
/**
* Removes a listener for close or fatal error events on the connection
* handed out to a client.
*/
public void removeConnectionEventListener(ConnectionEventListener connectionEventListener) {
listeners.remove(connectionEventListener);
}
/**
* Removes a listener for close or fatal error events on the connection
* handed out to a client.
*/
public void removeConnectionEventListener(ConnectionEventListener connectionEventListener)
{
listeners.remove(connectionEventListener);
}
/**
* Closes the physical database connection represented by this
* PooledConnection. If any client has a connection based on
* this PooledConnection, it is forcibly closed as well.
*/
public void close() throws SQLException {
if(last != null) {
last.close();
if(!con.getAutoCommit()) {
try {con.rollback();} catch (SQLException e) {}
}
}
try {
con.close();
} finally {
con = null;
}
}
/**
* Closes the physical database connection represented by this
* PooledConnection. If any client has a connection based on
* this PooledConnection, it is forcibly closed as well.
*/
public void close() throws SQLException
{
if (last != null)
{
last.close();
if (!con.getAutoCommit())
{
try
{
con.rollback();
}
catch (SQLException e)
{}
}
}
try
{
con.close();
}
finally
{
con = null;
}
}
/**
* Gets a handle for a client to use. This is a wrapper around the
* physical connection, so the client can call close and it will just
* return the connection to the pool without really closing the
* pgysical connection.
*
* <p>According to the JDBC 2.0 Optional Package spec (6.2.3), only one
* client may have an active handle to the connection at a time, so if
* there is a previous handle active when this is called, the previous
* one is forcibly closed and its work rolled back.</p>
*/
public Connection getConnection() throws SQLException {
if(con == null) {
throw new SQLException("This PooledConnection has already been closed!");
}
// Only one connection can be open at a time from this PooledConnection. See JDBC 2.0 Optional Package spec section 6.2.3
if(last != null) {
last.close();
if(!con.getAutoCommit()) {
try {con.rollback();} catch(SQLException e) {}
}
con.clearWarnings();
}
con.setAutoCommit(autoCommit);
ConnectionHandler handler = new ConnectionHandler(con);
last = handler;
return (Connection)Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{Connection.class}, handler);
}
/**
* Gets a handle for a client to use. This is a wrapper around the
* physical connection, so the client can call close and it will just
* return the connection to the pool without really closing the
* pgysical connection.
*
* <p>According to the JDBC 2.0 Optional Package spec (6.2.3), only one
* client may have an active handle to the connection at a time, so if
* there is a previous handle active when this is called, the previous
* one is forcibly closed and its work rolled back.</p>
*/
public Connection getConnection() throws SQLException
{
if (con == null)
{
throw new SQLException("This PooledConnection has already been closed!");
}
// Only one connection can be open at a time from this PooledConnection. See JDBC 2.0 Optional Package spec section 6.2.3
if (last != null)
{
last.close();
if (!con.getAutoCommit())
{
try
{
con.rollback();
}
catch (SQLException e)
{}
}
con.clearWarnings();
}
con.setAutoCommit(autoCommit);
ConnectionHandler handler = new ConnectionHandler(con);
last = handler;
return (Connection)Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{Connection.class}, handler);
}
/**
* Used to fire a connection event to all listeners.
*/
void fireConnectionClosed() {
ConnectionEvent evt = null;
// Copy the listener list so the listener can remove itself during this method call
ConnectionEventListener[] local = (ConnectionEventListener[]) listeners.toArray(new ConnectionEventListener[listeners.size()]);
for (int i = 0; i < local.length; i++) {
ConnectionEventListener listener = local[i];
if (evt == null) {
evt = new ConnectionEvent(this);
}
listener.connectionClosed(evt);
}
}
/**
* Used to fire a connection event to all listeners.
*/
void fireConnectionClosed()
{
ConnectionEvent evt = null;
// Copy the listener list so the listener can remove itself during this method call
ConnectionEventListener[] local = (ConnectionEventListener[]) listeners.toArray(new ConnectionEventListener[listeners.size()]);
for (int i = 0; i < local.length; i++)
{
ConnectionEventListener listener = local[i];
if (evt == null)
{
evt = new ConnectionEvent(this);
}
listener.connectionClosed(evt);
}
}
/**
* Used to fire a connection event to all listeners.
*/
void fireConnectionFatalError(SQLException e) {
ConnectionEvent evt = null;
// Copy the listener list so the listener can remove itself during this method call
ConnectionEventListener[] local = (ConnectionEventListener[])listeners.toArray(new ConnectionEventListener[listeners.size()]);
for (int i=0; i<local.length; i++) {
ConnectionEventListener listener = local[i];
if (evt == null) {
evt = new ConnectionEvent(this, e);
}
listener.connectionErrorOccurred(evt);
}
}
/**
* Used to fire a connection event to all listeners.
*/
void fireConnectionFatalError(SQLException e)
{
ConnectionEvent evt = null;
// Copy the listener list so the listener can remove itself during this method call
ConnectionEventListener[] local = (ConnectionEventListener[])listeners.toArray(new ConnectionEventListener[listeners.size()]);
for (int i = 0; i < local.length; i++)
{
ConnectionEventListener listener = local[i];
if (evt == null)
{
evt = new ConnectionEvent(this, e);
}
listener.connectionErrorOccurred(evt);
}
}
/**
* Instead of declaring a class implementing Connection, which would have
* to be updated for every JDK rev, use a dynamic proxy to handle all
* calls through the Connection interface. This is the part that
* requires JDK 1.3 or higher, though JDK 1.2 could be supported with a
* 3rd-party proxy package.
*/
private class ConnectionHandler implements InvocationHandler {
private Connection con;
private boolean automatic = false;
/**
* Instead of declaring a class implementing Connection, which would have
* to be updated for every JDK rev, use a dynamic proxy to handle all
* calls through the Connection interface. This is the part that
* requires JDK 1.3 or higher, though JDK 1.2 could be supported with a
* 3rd-party proxy package.
*/
private class ConnectionHandler implements InvocationHandler
{
private Connection con;
private boolean automatic = false;
public ConnectionHandler(Connection con) {
this.con = con;
}
public ConnectionHandler(Connection con)
{
this.con = con;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// From Object
if(method.getDeclaringClass().getName().equals("java.lang.Object")) {
if(method.getName().equals("toString")) {
return "Pooled connection wrapping physical connection "+con;
}
if(method.getName().equals("hashCode")) {
return new Integer(con.hashCode());
}
if(method.getName().equals("equals")) {
if(args[0] == null) {
return Boolean.FALSE;
}
try {
return Proxy.isProxyClass(args[0].getClass()) && ((ConnectionHandler) Proxy.getInvocationHandler(args[0])).con == con ? Boolean.TRUE : Boolean.FALSE;
} catch(ClassCastException e) {
return Boolean.FALSE;
}
}
return method.invoke(con, args);
}
// All the rest is from the Connection interface
if(method.getName().equals("isClosed")) {
return con == null ? Boolean.TRUE : Boolean.FALSE;
}
if(con == null) {
throw new SQLException(automatic ? "Connection has been closed automatically because a new connection was opened for the same PooledConnection or the PooledConnection has been closed" : "Connection has been closed");
}
if(method.getName().equals("close")) {
SQLException ex = null;
if(!con.getAutoCommit()) {
try {con.rollback();} catch(SQLException e) {ex = e;}
}
con.clearWarnings();
con = null;
last = null;
fireConnectionClosed();
if(ex != null) {
throw ex;
}
return null;
} else {
return method.invoke(con, args);
}
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
// From Object
if (method.getDeclaringClass().getName().equals("java.lang.Object"))
{
if (method.getName().equals("toString"))
{
return "Pooled connection wrapping physical connection " + con;
}
if (method.getName().equals("hashCode"))
{
return new Integer(con.hashCode());
}
if (method.getName().equals("equals"))
{
if (args[0] == null)
{
return Boolean.FALSE;
}
try
{
return Proxy.isProxyClass(args[0].getClass()) && ((ConnectionHandler) Proxy.getInvocationHandler(args[0])).con == con ? Boolean.TRUE : Boolean.FALSE;
}
catch (ClassCastException e)
{
return Boolean.FALSE;
}
}
return method.invoke(con, args);
}
// All the rest is from the Connection interface
if (method.getName().equals("isClosed"))
{
return con == null ? Boolean.TRUE : Boolean.FALSE;
}
if (con == null)
{
throw new SQLException(automatic ? "Connection has been closed automatically because a new connection was opened for the same PooledConnection or the PooledConnection has been closed" : "Connection has been closed");
}
if (method.getName().equals("close"))
{
SQLException ex = null;
if (!con.getAutoCommit())
{
try
{
con.rollback();
}
catch (SQLException e)
{
ex = e;
}
}
con.clearWarnings();
con = null;
last = null;
fireConnectionClosed();
if (ex != null)
{
throw ex;
}
return null;
}
else
{
return method.invoke(con, args);
}
}
public void close() {
if(con != null) {
automatic = true;
}
con = null;
// No close event fired here: see JDBC 2.0 Optional Package spec section 6.3
}
}
public void close()
{
if (con != null)
{
automatic = true;
}
con = null;
// No close event fired here: see JDBC 2.0 Optional Package spec section 6.3
}
}
}
......@@ -26,388 +26,454 @@ import java.sql.SQLException;
*
* <p>If you put this DataSource in JNDI, and access it from different JVMs (or
* otherwise load this class from different ClassLoaders), you'll end up with one
* pool per ClassLoader or VM. This is another area where a server-specific
* pool per ClassLoader or VM. This is another area where a server-specific
* implementation may provide advanced features, such as using a single pool
* across all VMs in a cluster.</p>
*
* <p>This implementation supports JDK 1.3 and higher.</p>
*
* @author Aaron Mulder (ammulder@chariotsolutions.com)
* @version $Revision: 1.1 $
* @version $Revision: 1.2 $
*/
public class PoolingDataSource extends BaseDataSource implements DataSource {
private static Map dataSources = new HashMap();
public class PoolingDataSource extends BaseDataSource implements DataSource
{
private static Map dataSources = new HashMap();
static PoolingDataSource getDataSource(String name) {
return (PoolingDataSource)dataSources.get(name);
}
static PoolingDataSource getDataSource(String name)
{
return (PoolingDataSource)dataSources.get(name);
}
// Additional Data Source properties
private String dataSourceName;
private int initialConnections = 0;
private int maxConnections = 0;
// State variables
private boolean initialized = false;
private Stack available = new Stack();
private Stack used = new Stack();
private Object lock = new Object();
private ConnectionPool source;
// Additional Data Source properties
private String dataSourceName;
private int initialConnections = 0;
private int maxConnections = 0;
// State variables
private boolean initialized = false;
private Stack available = new Stack();
private Stack used = new Stack();
private Object lock = new Object();
private ConnectionPool source;
/**
* Gets a description of this DataSource.
*/
public String getDescription() {
return "Pooling DataSource '"+dataSourceName+" from "+org.postgresql.Driver.getVersion();
}
/**
* Gets a description of this DataSource.
*/
public String getDescription()
{
return "Pooling DataSource '" + dataSourceName + " from " + org.postgresql.Driver.getVersion();
}
/**
* Ensures the DataSource properties are not changed after the DataSource has
* been used.
*
* @throws java.lang.IllegalStateException
* The Server Name cannot be changed after the DataSource has been
* used.
*/
public void setServerName(String serverName) {
if (initialized) {
throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used");
}
super.setServerName(serverName);
}
/**
* Ensures the DataSource properties are not changed after the DataSource has
* been used.
*
* @throws java.lang.IllegalStateException
* The Server Name cannot be changed after the DataSource has been
* used.
*/
public void setServerName(String serverName)
{
if (initialized)
{
throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used");
}
super.setServerName(serverName);
}
/**
* Ensures the DataSource properties are not changed after the DataSource has
* been used.
*
* @throws java.lang.IllegalStateException
* The Database Name cannot be changed after the DataSource has been
* used.
*/
public void setDatabaseName(String databaseName) {
if (initialized) {
throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used");
}
super.setDatabaseName(databaseName);
}
/**
* Ensures the DataSource properties are not changed after the DataSource has
* been used.
*
* @throws java.lang.IllegalStateException
* The Database Name cannot be changed after the DataSource has been
* used.
*/
public void setDatabaseName(String databaseName)
{
if (initialized)
{
throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used");
}
super.setDatabaseName(databaseName);
}
/**
* Ensures the DataSource properties are not changed after the DataSource has
* been used.
*
* @throws java.lang.IllegalStateException
* The User cannot be changed after the DataSource has been
* used.
*/
public void setUser(String user) {
if (initialized) {
throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used");
}
super.setUser(user);
}
/**
* Ensures the DataSource properties are not changed after the DataSource has
* been used.
*
* @throws java.lang.IllegalStateException
* The User cannot be changed after the DataSource has been
* used.
*/
public void setUser(String user)
{
if (initialized)
{
throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used");
}
super.setUser(user);
}
/**
* Ensures the DataSource properties are not changed after the DataSource has
* been used.
*
* @throws java.lang.IllegalStateException
* The Password cannot be changed after the DataSource has been
* used.
*/
public void setPassword(String password) {
if (initialized) {
throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used");
}
super.setPassword(password);
}
/**
* Ensures the DataSource properties are not changed after the DataSource has
* been used.
*
* @throws java.lang.IllegalStateException
* The Password cannot be changed after the DataSource has been
* used.
*/
public void setPassword(String password)
{
if (initialized)
{
throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used");
}
super.setPassword(password);
}
/**
* Ensures the DataSource properties are not changed after the DataSource has
* been used.
*
* @throws java.lang.IllegalStateException
* The Port Number cannot be changed after the DataSource has been
* used.
*/
public void setPortNumber(int portNumber) {
if (initialized) {
throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used");
}
super.setPortNumber(portNumber);
}
/**
* Ensures the DataSource properties are not changed after the DataSource has
* been used.
*
* @throws java.lang.IllegalStateException
* The Port Number cannot be changed after the DataSource has been
* used.
*/
public void setPortNumber(int portNumber)
{
if (initialized)
{
throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used");
}
super.setPortNumber(portNumber);
}
/**
* Gets the number of connections that will be created when this DataSource
* is initialized. If you do not call initialize explicitly, it will be
* initialized the first time a connection is drawn from it.
*/
public int getInitialConnections() {
return initialConnections;
}
/**
* Gets the number of connections that will be created when this DataSource
* is initialized. If you do not call initialize explicitly, it will be
* initialized the first time a connection is drawn from it.
*/
public int getInitialConnections()
{
return initialConnections;
}
/**
* Sets the number of connections that will be created when this DataSource
* is initialized. If you do not call initialize explicitly, it will be
* initialized the first time a connection is drawn from it.
*
* @throws java.lang.IllegalStateException
* The Initial Connections cannot be changed after the DataSource has been
* used.
*/
public void setInitialConnections(int initialConnections) {
if (initialized) {
throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used");
}
this.initialConnections = initialConnections;
}
/**
* Sets the number of connections that will be created when this DataSource
* is initialized. If you do not call initialize explicitly, it will be
* initialized the first time a connection is drawn from it.
*
* @throws java.lang.IllegalStateException
* The Initial Connections cannot be changed after the DataSource has been
* used.
*/
public void setInitialConnections(int initialConnections)
{
if (initialized)
{
throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used");
}
this.initialConnections = initialConnections;
}
/**
* Gets the maximum number of connections that the pool will allow. If a request
* comes in and this many connections are in use, the request will block until a
* connection is available. Note that connections for a user other than the
* default user will not be pooled and don't count against this limit.
*
* @return The maximum number of pooled connection allowed, or 0 for no maximum.
*/
public int getMaxConnections() {
return maxConnections;
}
/**
* Gets the maximum number of connections that the pool will allow. If a request
* comes in and this many connections are in use, the request will block until a
* connection is available. Note that connections for a user other than the
* default user will not be pooled and don't count against this limit.
*
* @return The maximum number of pooled connection allowed, or 0 for no maximum.
*/
public int getMaxConnections()
{
return maxConnections;
}
/**
* Sets the maximum number of connections that the pool will allow. If a request
* comes in and this many connections are in use, the request will block until a
* connection is available. Note that connections for a user other than the
* default user will not be pooled and don't count against this limit.
*
* @param maxConnections The maximum number of pooled connection to allow, or
* 0 for no maximum.
*
* @throws java.lang.IllegalStateException
* The Maximum Connections cannot be changed after the DataSource has been
* used.
*/
public void setMaxConnections(int maxConnections) {
if (initialized) {
throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used");
}
this.maxConnections = maxConnections;
}
/**
* Sets the maximum number of connections that the pool will allow. If a request
* comes in and this many connections are in use, the request will block until a
* connection is available. Note that connections for a user other than the
* default user will not be pooled and don't count against this limit.
*
* @param maxConnections The maximum number of pooled connection to allow, or
* 0 for no maximum.
*
* @throws java.lang.IllegalStateException
* The Maximum Connections cannot be changed after the DataSource has been
* used.
*/
public void setMaxConnections(int maxConnections)
{
if (initialized)
{
throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used");
}
this.maxConnections = maxConnections;
}
/**
* Gets the name of this DataSource. This uniquely identifies the DataSource.
* You cannot use more than one DataSource in the same VM with the same name.
*/
public String getDataSourceName() {
return dataSourceName;
}
/**
* Gets the name of this DataSource. This uniquely identifies the DataSource.
* You cannot use more than one DataSource in the same VM with the same name.
*/
public String getDataSourceName()
{
return dataSourceName;
}
/**
* Sets the name of this DataSource. This is required, and uniquely identifies
* the DataSource. You cannot create or use more than one DataSource in the
* same VM with the same name.
*
* @throws java.lang.IllegalStateException
* The Data Source Name cannot be changed after the DataSource has been
* used.
* @throws java.lang.IllegalArgumentException
* Another PoolingDataSource with the same dataSourceName already
* exists.
*/
public void setDataSourceName(String dataSourceName) {
if(initialized) {
throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used");
}
if(this.dataSourceName != null && dataSourceName != null && dataSourceName.equals(this.dataSourceName)) {
return;
}
synchronized(dataSources) {
if(getDataSource(dataSourceName) != null) {
throw new IllegalArgumentException("DataSource with name '"+dataSourceName+"' already exists!");
}
if (this.dataSourceName != null) {
dataSources.remove(this.dataSourceName);
}
this.dataSourceName = dataSourceName;
dataSources.put(dataSourceName, this);
}
}
/**
* Sets the name of this DataSource. This is required, and uniquely identifies
* the DataSource. You cannot create or use more than one DataSource in the
* same VM with the same name.
*
* @throws java.lang.IllegalStateException
* The Data Source Name cannot be changed after the DataSource has been
* used.
* @throws java.lang.IllegalArgumentException
* Another PoolingDataSource with the same dataSourceName already
* exists.
*/
public void setDataSourceName(String dataSourceName)
{
if (initialized)
{
throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used");
}
if (this.dataSourceName != null && dataSourceName != null && dataSourceName.equals(this.dataSourceName))
{
return ;
}
synchronized (dataSources)
{
if (getDataSource(dataSourceName) != null)
{
throw new IllegalArgumentException("DataSource with name '" + dataSourceName + "' already exists!");
}
if (this.dataSourceName != null)
{
dataSources.remove(this.dataSourceName);
}
this.dataSourceName = dataSourceName;
dataSources.put(dataSourceName, this);
}
}
/**
* Initializes this DataSource. If the initialConnections is greater than zero,
* that number of connections will be created. After this method is called,
* the DataSource properties cannot be changed. If you do not call this
* explicitly, it will be called the first time you get a connection from the
* Datasource.
* @throws java.sql.SQLException
* Occurs when the initialConnections is greater than zero, but the
* DataSource is not able to create enough physical connections.
*/
public void initialize() throws SQLException {
synchronized (lock) {
source = new ConnectionPool();
source.setDatabaseName(getDatabaseName());
source.setPassword(getPassword());
source.setPortNumber(getPortNumber());
source.setServerName(getServerName());
source.setUser(getUser());
while (available.size() < initialConnections) {
available.push(source.getPooledConnection());
}
initialized = true;
}
}
/**
* Initializes this DataSource. If the initialConnections is greater than zero,
* that number of connections will be created. After this method is called,
* the DataSource properties cannot be changed. If you do not call this
* explicitly, it will be called the first time you get a connection from the
* Datasource.
* @throws java.sql.SQLException
* Occurs when the initialConnections is greater than zero, but the
* DataSource is not able to create enough physical connections.
*/
public void initialize() throws SQLException
{
synchronized (lock)
{
source = new ConnectionPool();
source.setDatabaseName(getDatabaseName());
source.setPassword(getPassword());
source.setPortNumber(getPortNumber());
source.setServerName(getServerName());
source.setUser(getUser());
while (available.size() < initialConnections)
{
available.push(source.getPooledConnection());
}
initialized = true;
}
}
/**
* Gets a <b>non-pooled</b> connection, unless the user and password are the
* same as the default values for this connection pool.
*
* @return A pooled connection.
* @throws SQLException
* Occurs when no pooled connection is available, and a new physical
* connection cannot be created.
*/
public Connection getConnection(String user, String password) throws SQLException {
// If this is for the default user/password, use a pooled connection
if(user == null ||
(user.equals(getUser()) && ((password == null && getPassword() == null) || (password != null && password.equals(getPassword()))))) {
return getConnection();
}
// Otherwise, use a non-pooled connection
if (!initialized) {
initialize();
}
return super.getConnection(user, password);
}
/**
* Gets a <b>non-pooled</b> connection, unless the user and password are the
* same as the default values for this connection pool.
*
* @return A pooled connection.
* @throws SQLException
* Occurs when no pooled connection is available, and a new physical
* connection cannot be created.
*/
public Connection getConnection(String user, String password) throws SQLException
{
// If this is for the default user/password, use a pooled connection
if (user == null ||
(user.equals(getUser()) && ((password == null && getPassword() == null) || (password != null && password.equals(getPassword())))))
{
return getConnection();
}
// Otherwise, use a non-pooled connection
if (!initialized)
{
initialize();
}
return super.getConnection(user, password);
}
/**
* Gets a connection from the connection pool.
*
* @return A pooled connection.
* @throws SQLException
* Occurs when no pooled connection is available, and a new physical
* connection cannot be created.
*/
public Connection getConnection() throws SQLException {
if(!initialized) {
initialize();
}
return getPooledConnection();
}
/**
* Gets a connection from the connection pool.
*
* @return A pooled connection.
* @throws SQLException
* Occurs when no pooled connection is available, and a new physical
* connection cannot be created.
*/
public Connection getConnection() throws SQLException
{
if (!initialized)
{
initialize();
}
return getPooledConnection();
}
/**
* Closes this DataSource, and all the pooled connections, whether in use or not.
*/
public void close() {
synchronized(lock) {
while(available.size() > 0) {
PooledConnectionImpl pci = (PooledConnectionImpl)available.pop();
try {
pci.close();
} catch (SQLException e) {
}
}
available = null;
while (used.size() > 0) {
PooledConnectionImpl pci = (PooledConnectionImpl)used.pop();
pci.removeConnectionEventListener(connectionEventListener);
try {
pci.close();
} catch (SQLException e) {
}
}
used = null;
}
synchronized (dataSources) {
dataSources.remove(dataSourceName);
}
}
/**
* Closes this DataSource, and all the pooled connections, whether in use or not.
*/
public void close()
{
synchronized (lock)
{
while (available.size() > 0)
{
PooledConnectionImpl pci = (PooledConnectionImpl)available.pop();
try
{
pci.close();
}
catch (SQLException e)
{}
}
available = null;
while (used.size() > 0)
{
PooledConnectionImpl pci = (PooledConnectionImpl)used.pop();
pci.removeConnectionEventListener(connectionEventListener);
try
{
pci.close();
}
catch (SQLException e)
{}
}
used = null;
}
synchronized (dataSources)
{
dataSources.remove(dataSourceName);
}
}
/**
* Gets a connection from the pool. Will get an available one if
* present, or create a new one if under the max limit. Will
* block if all used and a new one would exceed the max.
*/
private Connection getPooledConnection() throws SQLException {
PooledConnection pc = null;
synchronized(lock) {
if (available == null) {
throw new SQLException("DataSource has been closed.");
}
while(true) {
if(available.size() > 0) {
pc = (PooledConnection)available.pop();
used.push(pc);
break;
}
if(maxConnections == 0 || used.size() < maxConnections) {
pc = source.getPooledConnection();
used.push(pc);
break;
} else {
try {
// Wake up every second at a minimum
lock.wait(1000L);
} catch(InterruptedException e) {
}
}
}
}
pc.addConnectionEventListener(connectionEventListener);
return pc.getConnection();
}
/**
* Gets a connection from the pool. Will get an available one if
* present, or create a new one if under the max limit. Will
* block if all used and a new one would exceed the max.
*/
private Connection getPooledConnection() throws SQLException
{
PooledConnection pc = null;
synchronized (lock)
{
if (available == null)
{
throw new SQLException("DataSource has been closed.");
}
while (true)
{
if (available.size() > 0)
{
pc = (PooledConnection)available.pop();
used.push(pc);
break;
}
if (maxConnections == 0 || used.size() < maxConnections)
{
pc = source.getPooledConnection();
used.push(pc);
break;
}
else
{
try
{
// Wake up every second at a minimum
lock.wait(1000L);
}
catch (InterruptedException e)
{}
}
}
}
pc.addConnectionEventListener(connectionEventListener);
return pc.getConnection();
}
/**
* Notified when a pooled connection is closed, or a fatal error occurs
* on a pooled connection. This is the only way connections are marked
* as unused.
*/
private ConnectionEventListener connectionEventListener = new ConnectionEventListener() {
public void connectionClosed(ConnectionEvent event) {
((PooledConnection)event.getSource()).removeConnectionEventListener(this);
synchronized(lock) {
if(available == null) {
return; // DataSource has been closed
}
boolean removed = used.remove(event.getSource());
if(removed) {
available.push(event.getSource());
// There's now a new connection available
lock.notify();
} else {
// a connection error occured
}
}
}
/**
* Notified when a pooled connection is closed, or a fatal error occurs
* on a pooled connection. This is the only way connections are marked
* as unused.
*/
private ConnectionEventListener connectionEventListener = new ConnectionEventListener()
{
public void connectionClosed(ConnectionEvent event)
{
((PooledConnection)event.getSource()).removeConnectionEventListener(this);
synchronized (lock)
{
if (available == null)
{
return ; // DataSource has been closed
}
boolean removed = used.remove(event.getSource());
if (removed)
{
available.push(event.getSource());
// There's now a new connection available
lock.notify();
}
else
{
// a connection error occured
}
}
}
/**
* This is only called for fatal errors, where the physical connection is
* useless afterward and should be removed from the pool.
*/
public void connectionErrorOccurred(ConnectionEvent event) {
((PooledConnection) event.getSource()).removeConnectionEventListener(this);
synchronized(lock) {
if (available == null) {
return; // DataSource has been closed
}
used.remove(event.getSource());
// We're now at least 1 connection under the max
lock.notify();
}
}
};
/**
* This is only called for fatal errors, where the physical connection is
* useless afterward and should be removed from the pool.
*/
public void connectionErrorOccurred(ConnectionEvent event)
{
((PooledConnection) event.getSource()).removeConnectionEventListener(this);
synchronized (lock)
{
if (available == null)
{
return ; // DataSource has been closed
}
used.remove(event.getSource());
// We're now at least 1 connection under the max
lock.notify();
}
}
};
/**
* Adds custom properties for this DataSource to the properties defined in
* the superclass.
*/
public Reference getReference() throws NamingException {
Reference ref = super.getReference();
ref.add(new StringRefAddr("dataSourceName", dataSourceName));
if (initialConnections > 0) {
ref.add(new StringRefAddr("initialConnections", Integer.toString(initialConnections)));
}
if (maxConnections > 0) {
ref.add(new StringRefAddr("maxConnections", Integer.toString(maxConnections)));
}
return ref;
}
/**
* Adds custom properties for this DataSource to the properties defined in
* the superclass.
*/
public Reference getReference() throws NamingException
{
Reference ref = super.getReference();
ref.add(new StringRefAddr("dataSourceName", dataSourceName));
if (initialConnections > 0)
{
ref.add(new StringRefAddr("initialConnections", Integer.toString(initialConnections)));
}
if (maxConnections > 0)
{
ref.add(new StringRefAddr("maxConnections", Integer.toString(maxConnections)));
}
return ref;
}
}
......@@ -5,18 +5,20 @@ import java.io.Serializable;
/**
* Simple DataSource which does not perform connection pooling. In order to use
* the DataSource, you must set the property databaseName. The settings for
* the DataSource, you must set the property databaseName. The settings for
* serverName, portNumber, user, and password are optional. Note: these properties
* are declared in the superclass.
*
* @author Aaron Mulder (ammulder@chariotsolutions.com)
* @version $Revision: 1.1 $
* @version $Revision: 1.2 $
*/
public class SimpleDataSource extends BaseDataSource implements Serializable, DataSource {
/**
* Gets a description of this DataSource.
*/
public String getDescription() {
return "Non-Pooling DataSource from "+org.postgresql.Driver.getVersion();
}
public class SimpleDataSource extends BaseDataSource implements Serializable, DataSource
{
/**
* Gets a description of this DataSource.
*/
public String getDescription()
{
return "Non-Pooling DataSource from " + org.postgresql.Driver.getVersion();
}
}
......@@ -11,80 +11,84 @@ public abstract class AbstractJdbc3Blob extends org.postgresql.jdbc2.AbstractJdb
super(conn, oid);
}
/**
* Writes the given array of bytes to the <code>BLOB</code> value that
* this <code>Blob</code> object represents, starting at position
* <code>pos</code>, and returns the number of bytes written.
*
* @param pos the position in the <code>BLOB</code> object at which
* to start writing
* @param bytes the array of bytes to be written to the <code>BLOB</code>
* value that this <code>Blob</code> object represents
* @return the number of bytes written
* @exception SQLException if there is an error accessing the
* <code>BLOB</code> value
* @see #getBytes
* @since 1.4
*/
public int setBytes(long pos, byte[] bytes) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Writes the given array of bytes to the <code>BLOB</code> value that
* this <code>Blob</code> object represents, starting at position
* <code>pos</code>, and returns the number of bytes written.
*
* @param pos the position in the <code>BLOB</code> object at which
* to start writing
* @param bytes the array of bytes to be written to the <code>BLOB</code>
* value that this <code>Blob</code> object represents
* @return the number of bytes written
* @exception SQLException if there is an error accessing the
* <code>BLOB</code> value
* @see #getBytes
* @since 1.4
*/
public int setBytes(long pos, byte[] bytes) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Writes all or part of the given <code>byte</code> array to the
* <code>BLOB</code> value that this <code>Blob</code> object represents
* and returns the number of bytes written.
* Writing starts at position <code>pos</code> in the <code>BLOB</code>
* value; <code>len</code> bytes from the given byte array are written.
*
* @param pos the position in the <code>BLOB</code> object at which
* to start writing
* @param bytes the array of bytes to be written to this <code>BLOB</code>
* object
* @param offset the offset into the array <code>bytes</code> at which
* to start reading the bytes to be set
* @param len the number of bytes to be written to the <code>BLOB</code>
* value from the array of bytes <code>bytes</code>
* @return the number of bytes written
* @exception SQLException if there is an error accessing the
* <code>BLOB</code> value
* @see #getBytes
* @since 1.4
*/
public int setBytes(long pos, byte[] bytes, int offset, int len) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Writes all or part of the given <code>byte</code> array to the
* <code>BLOB</code> value that this <code>Blob</code> object represents
* and returns the number of bytes written.
* Writing starts at position <code>pos</code> in the <code>BLOB</code>
* value; <code>len</code> bytes from the given byte array are written.
*
* @param pos the position in the <code>BLOB</code> object at which
* to start writing
* @param bytes the array of bytes to be written to this <code>BLOB</code>
* object
* @param offset the offset into the array <code>bytes</code> at which
* to start reading the bytes to be set
* @param len the number of bytes to be written to the <code>BLOB</code>
* value from the array of bytes <code>bytes</code>
* @return the number of bytes written
* @exception SQLException if there is an error accessing the
* <code>BLOB</code> value
* @see #getBytes
* @since 1.4
*/
public int setBytes(long pos, byte[] bytes, int offset, int len) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves a stream that can be used to write to the <code>BLOB</code>
* value that this <code>Blob</code> object represents. The stream begins
* at position <code>pos</code>.
*
* @param pos the position in the <code>BLOB</code> value at which
* to start writing
* @return a <code>java.io.OutputStream</code> object to which data can
* be written
* @exception SQLException if there is an error accessing the
* <code>BLOB</code> value
* @see #getBinaryStream
* @since 1.4
*/
public java.io.OutputStream setBinaryStream(long pos) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves a stream that can be used to write to the <code>BLOB</code>
* value that this <code>Blob</code> object represents. The stream begins
* at position <code>pos</code>.
*
* @param pos the position in the <code>BLOB</code> value at which
* to start writing
* @return a <code>java.io.OutputStream</code> object to which data can
* be written
* @exception SQLException if there is an error accessing the
* <code>BLOB</code> value
* @see #getBinaryStream
* @since 1.4
*/
public java.io.OutputStream setBinaryStream(long pos) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Truncates the <code>BLOB</code> value that this <code>Blob</code>
* object represents to be <code>len</code> bytes in length.
*
* @param len the length, in bytes, to which the <code>BLOB</code> value
* that this <code>Blob</code> object represents should be truncated
* @exception SQLException if there is an error accessing the
* <code>BLOB</code> value
* @since 1.4
*/
public void truncate(long len) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Truncates the <code>BLOB</code> value that this <code>Blob</code>
* object represents to be <code>len</code> bytes in length.
*
* @param len the length, in bytes, to which the <code>BLOB</code> value
* that this <code>Blob</code> object represents should be truncated
* @exception SQLException if there is an error accessing the
* <code>BLOB</code> value
* @since 1.4
*/
public void truncate(long len) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
}
......@@ -11,97 +11,102 @@ public abstract class AbstractJdbc3Clob extends org.postgresql.jdbc2.AbstractJdb
super(conn, oid);
}
/**
* Writes the given Java <code>String</code> to the <code>CLOB</code>
* value that this <code>Clob</code> object designates at the position
* <code>pos</code>.
*
* @param pos the position at which to start writing to the <code>CLOB</code>
* value that this <code>Clob</code> object represents
* @param str the string to be written to the <code>CLOB</code>
* value that this <code>Clob</code> designates
* @return the number of characters written
* @exception SQLException if there is an error accessing the
* <code>CLOB</code> value
*
* @since 1.4
*/
public int setString(long pos, String str) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Writes the given Java <code>String</code> to the <code>CLOB</code>
* value that this <code>Clob</code> object designates at the position
* <code>pos</code>.
*
* @param pos the position at which to start writing to the <code>CLOB</code>
* value that this <code>Clob</code> object represents
* @param str the string to be written to the <code>CLOB</code>
* value that this <code>Clob</code> designates
* @return the number of characters written
* @exception SQLException if there is an error accessing the
* <code>CLOB</code> value
*
* @since 1.4
*/
public int setString(long pos, String str) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Writes <code>len</code> characters of <code>str</code>, starting
* at character <code>offset</code>, to the <code>CLOB</code> value
* that this <code>Clob</code> represents.
*
* @param pos the position at which to start writing to this
* <code>CLOB</code> object
* @param str the string to be written to the <code>CLOB</code>
* value that this <code>Clob</code> object represents
* @param offset the offset into <code>str</code> to start reading
* the characters to be written
* @param len the number of characters to be written
* @return the number of characters written
* @exception SQLException if there is an error accessing the
* <code>CLOB</code> value
*
* @since 1.4
*/
public int setString(long pos, String str, int offset, int len) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Writes <code>len</code> characters of <code>str</code>, starting
* at character <code>offset</code>, to the <code>CLOB</code> value
* that this <code>Clob</code> represents.
*
* @param pos the position at which to start writing to this
* <code>CLOB</code> object
* @param str the string to be written to the <code>CLOB</code>
* value that this <code>Clob</code> object represents
* @param offset the offset into <code>str</code> to start reading
* the characters to be written
* @param len the number of characters to be written
* @return the number of characters written
* @exception SQLException if there is an error accessing the
* <code>CLOB</code> value
*
* @since 1.4
*/
public int setString(long pos, String str, int offset, int len) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves a stream to be used to write Ascii characters to the
* <code>CLOB</code> value that this <code>Clob</code> object represents,
* starting at position <code>pos</code>.
*
* @param pos the position at which to start writing to this
* <code>CLOB</code> object
* @return the stream to which ASCII encoded characters can be written
* @exception SQLException if there is an error accessing the
* <code>CLOB</code> value
* @see #getAsciiStream
*
* @since 1.4
*/
public java.io.OutputStream setAsciiStream(long pos) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves a stream to be used to write Ascii characters to the
* <code>CLOB</code> value that this <code>Clob</code> object represents,
* starting at position <code>pos</code>.
*
* @param pos the position at which to start writing to this
* <code>CLOB</code> object
* @return the stream to which ASCII encoded characters can be written
* @exception SQLException if there is an error accessing the
* <code>CLOB</code> value
* @see #getAsciiStream
*
* @since 1.4
*/
public java.io.OutputStream setAsciiStream(long pos) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves a stream to be used to write a stream of Unicode characters
* to the <code>CLOB</code> value that this <code>Clob</code> object
* represents, at position <code>pos</code>.
*
* @param pos the position at which to start writing to the
* <code>CLOB</code> value
*
* @return a stream to which Unicode encoded characters can be written
* @exception SQLException if there is an error accessing the
* <code>CLOB</code> value
* @see #getCharacterStream
*
* @since 1.4
*/
public java.io.Writer setCharacterStream(long pos) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves a stream to be used to write a stream of Unicode characters
* to the <code>CLOB</code> value that this <code>Clob</code> object
* represents, at position <code>pos</code>.
*
* @param pos the position at which to start writing to the
* <code>CLOB</code> value
*
* @return a stream to which Unicode encoded characters can be written
* @exception SQLException if there is an error accessing the
* <code>CLOB</code> value
* @see #getCharacterStream
*
* @since 1.4
*/
public java.io.Writer setCharacterStream(long pos) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Truncates the <code>CLOB</code> value that this <code>Clob</code>
* designates to have a length of <code>len</code>
* characters.
* @param len the length, in bytes, to which the <code>CLOB</code> value
* should be truncated
* @exception SQLException if there is an error accessing the
* <code>CLOB</code> value
*
* @since 1.4
*/
public void truncate(long len) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Truncates the <code>CLOB</code> value that this <code>Clob</code>
* designates to have a length of <code>len</code>
* characters.
* @param len the length, in bytes, to which the <code>CLOB</code> value
* should be truncated
* @exception SQLException if there is an error accessing the
* <code>CLOB</code> value
*
* @since 1.4
*/
public void truncate(long len) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
}
......@@ -2,7 +2,7 @@ package org.postgresql.jdbc3;
import java.sql.*;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc3/Attic/AbstractJdbc3Connection.java,v 1.1 2002/08/14 20:35:39 barry Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc3/Attic/AbstractJdbc3Connection.java,v 1.2 2002/09/06 21:23:06 momjian Exp $
* This class defines methods of the jdbc3 specification. This class extends
* org.postgresql.jdbc2.AbstractJdbc2Connection which provides the jdbc2
* methods. The real Connection class (for jdbc3) is org.postgresql.jdbc3.Jdbc3Connection
......@@ -10,359 +10,371 @@ import java.sql.*;
public abstract class AbstractJdbc3Connection extends org.postgresql.jdbc2.AbstractJdbc2Connection
{
/**
* Changes the holdability of <code>ResultSet</code> objects
* created using this <code>Connection</code> object to the given
* holdability.
*
* @param holdability a <code>ResultSet</code> holdability constant; one of
* <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
* <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
* @throws SQLException if a database access occurs, the given parameter
* is not a <code>ResultSet</code> constant indicating holdability,
* or the given holdability is not supported
* @see #getHoldability
* @see ResultSet
* @since 1.4
*/
public void setHoldability(int holdability) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Changes the holdability of <code>ResultSet</code> objects
* created using this <code>Connection</code> object to the given
* holdability.
*
* @param holdability a <code>ResultSet</code> holdability constant; one of
* <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
* <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
* @throws SQLException if a database access occurs, the given parameter
* is not a <code>ResultSet</code> constant indicating holdability,
* or the given holdability is not supported
* @see #getHoldability
* @see ResultSet
* @since 1.4
*/
public void setHoldability(int holdability) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves the current holdability of <code>ResultSet</code> objects
* created using this <code>Connection</code> object.
*
* @return the holdability, one of
* <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
* <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
* @throws SQLException if a database access occurs
* @see #setHoldability
* @see ResultSet
* @since 1.4
*/
public int getHoldability() throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Creates an unnamed savepoint in the current transaction and
* returns the new <code>Savepoint</code> object that represents it.
*
* @return the new <code>Savepoint</code> object
* @exception SQLException if a database access error occurs
* or this <code>Connection</code> object is currently in
* auto-commit mode
* @see Savepoint
* @since 1.4
*/
public Savepoint setSavepoint() throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Creates a savepoint with the given name in the current transaction
* and returns the new <code>Savepoint</code> object that represents it.
*
* @param name a <code>String</code> containing the name of the savepoint
* @return the new <code>Savepoint</code> object
* @exception SQLException if a database access error occurs
* or this <code>Connection</code> object is currently in
* auto-commit mode
* @see Savepoint
* @since 1.4
*/
public Savepoint setSavepoint(String name) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Undoes all changes made after the given <code>Savepoint</code> object
* was set.
* <P>
* This method should be used only when auto-commit has been disabled.
*
* @param savepoint the <code>Savepoint</code> object to roll back to
* @exception SQLException if a database access error occurs,
* the <code>Savepoint</code> object is no longer valid,
* or this <code>Connection</code> object is currently in
* auto-commit mode
* @see Savepoint
* @see #rollback
* @since 1.4
*/
public void rollback(Savepoint savepoint) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves the current holdability of <code>ResultSet</code> objects
* created using this <code>Connection</code> object.
*
* @return the holdability, one of
* <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
* <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
* @throws SQLException if a database access occurs
* @see #setHoldability
* @see ResultSet
* @since 1.4
*/
public int getHoldability() throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Removes the given <code>Savepoint</code> object from the current
* transaction. Any reference to the savepoint after it have been removed
* will cause an <code>SQLException</code> to be thrown.
*
* @param savepoint the <code>Savepoint</code> object to be removed
* @exception SQLException if a database access error occurs or
* the given <code>Savepoint</code> object is not a valid
* savepoint in the current transaction
* @since 1.4
*/
public void releaseSavepoint(Savepoint savepoint) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Creates an unnamed savepoint in the current transaction and
* returns the new <code>Savepoint</code> object that represents it.
*
* @return the new <code>Savepoint</code> object
* @exception SQLException if a database access error occurs
* or this <code>Connection</code> object is currently in
* auto-commit mode
* @see Savepoint
* @since 1.4
*/
public Savepoint setSavepoint() throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Creates a <code>Statement</code> object that will generate
* <code>ResultSet</code> objects with the given type, concurrency,
* and holdability.
* This method is the same as the <code>createStatement</code> method
* above, but it allows the default result set
* type, concurrency, and holdability to be overridden.
*
* @param resultSetType one of the following <code>ResultSet</code>
* constants:
* <code>ResultSet.TYPE_FORWARD_ONLY</code>,
* <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
* <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
* @param resultSetConcurrency one of the following <code>ResultSet</code>
* constants:
* <code>ResultSet.CONCUR_READ_ONLY</code> or
* <code>ResultSet.CONCUR_UPDATABLE</code>
* @param resultSetHoldability one of the following <code>ResultSet</code>
* constants:
* <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
* <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
* @return a new <code>Statement</code> object that will generate
* <code>ResultSet</code> objects with the given type,
* concurrency, and holdability
* @exception SQLException if a database access error occurs
* or the given parameters are not <code>ResultSet</code>
* constants indicating type, concurrency, and holdability
* @see ResultSet
* @since 1.4
*/
public Statement createStatement(int resultSetType, int resultSetConcurrency,
int resultSetHoldability) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Creates a savepoint with the given name in the current transaction
* and returns the new <code>Savepoint</code> object that represents it.
*
* @param name a <code>String</code> containing the name of the savepoint
* @return the new <code>Savepoint</code> object
* @exception SQLException if a database access error occurs
* or this <code>Connection</code> object is currently in
* auto-commit mode
* @see Savepoint
* @since 1.4
*/
public Savepoint setSavepoint(String name) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Creates a <code>PreparedStatement</code> object that will generate
* <code>ResultSet</code> objects with the given type, concurrency,
* and holdability.
* <P>
* This method is the same as the <code>prepareStatement</code> method
* above, but it allows the default result set
* type, concurrency, and holdability to be overridden.
*
* @param sql a <code>String</code> object that is the SQL statement to
* be sent to the database; may contain one or more ? IN
* parameters
* @param resultSetType one of the following <code>ResultSet</code>
* constants:
* <code>ResultSet.TYPE_FORWARD_ONLY</code>,
* <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
* <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
* @param resultSetConcurrency one of the following <code>ResultSet</code>
* constants:
* <code>ResultSet.CONCUR_READ_ONLY</code> or
* <code>ResultSet.CONCUR_UPDATABLE</code>
* @param resultSetHoldability one of the following <code>ResultSet</code>
* constants:
* <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
* <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
* @return a new <code>PreparedStatement</code> object, containing the
* pre-compiled SQL statement, that will generate
* <code>ResultSet</code> objects with the given type,
* concurrency, and holdability
* @exception SQLException if a database access error occurs
* or the given parameters are not <code>ResultSet</code>
* constants indicating type, concurrency, and holdability
* @see ResultSet
* @since 1.4
*/
public PreparedStatement prepareStatement(String sql, int resultSetType,
int resultSetConcurrency, int resultSetHoldability)
throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Undoes all changes made after the given <code>Savepoint</code> object
* was set.
* <P>
* This method should be used only when auto-commit has been disabled.
*
* @param savepoint the <code>Savepoint</code> object to roll back to
* @exception SQLException if a database access error occurs,
* the <code>Savepoint</code> object is no longer valid,
* or this <code>Connection</code> object is currently in
* auto-commit mode
* @see Savepoint
* @see #rollback
* @since 1.4
*/
public void rollback(Savepoint savepoint) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Creates a <code>CallableStatement</code> object that will generate
* <code>ResultSet</code> objects with the given type and concurrency.
* This method is the same as the <code>prepareCall</code> method
* above, but it allows the default result set
* type, result set concurrency type and holdability to be overridden.
*
* @param sql a <code>String</code> object that is the SQL statement to
* be sent to the database; may contain on or more ? parameters
* @param resultSetType one of the following <code>ResultSet</code>
* constants:
* <code>ResultSet.TYPE_FORWARD_ONLY</code>,
* <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
* <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
* @param resultSetConcurrency one of the following <code>ResultSet</code>
* constants:
* <code>ResultSet.CONCUR_READ_ONLY</code> or
* <code>ResultSet.CONCUR_UPDATABLE</code>
* @param resultSetHoldability one of the following <code>ResultSet</code>
* constants:
* <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
* <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
* @return a new <code>CallableStatement</code> object, containing the
* pre-compiled SQL statement, that will generate
* <code>ResultSet</code> objects with the given type,
* concurrency, and holdability
* @exception SQLException if a database access error occurs
* or the given parameters are not <code>ResultSet</code>
* constants indicating type, concurrency, and holdability
* @see ResultSet
* @since 1.4
*/
public CallableStatement prepareCall(String sql, int resultSetType,
int resultSetConcurrency,
int resultSetHoldability) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Removes the given <code>Savepoint</code> object from the current
* transaction. Any reference to the savepoint after it have been removed
* will cause an <code>SQLException</code> to be thrown.
*
* @param savepoint the <code>Savepoint</code> object to be removed
* @exception SQLException if a database access error occurs or
* the given <code>Savepoint</code> object is not a valid
* savepoint in the current transaction
* @since 1.4
*/
public void releaseSavepoint(Savepoint savepoint) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Creates a default <code>PreparedStatement</code> object that has
* the capability to retrieve auto-generated keys. The given constant
* tells the driver whether it should make auto-generated keys
* available for retrieval. This parameter is ignored if the SQL
* statement is not an <code>INSERT</code> statement.
* <P>
* <B>Note:</B> This method is optimized for handling
* parametric SQL statements that benefit from precompilation. If
* the driver supports precompilation,
* the method <code>prepareStatement</code> will send
* the statement to the database for precompilation. Some drivers
* may not support precompilation. In this case, the statement may
* not be sent to the database until the <code>PreparedStatement</code>
* object is executed. This has no direct effect on users; however, it does
* affect which methods throw certain SQLExceptions.
* <P>
* Result sets created using the returned <code>PreparedStatement</code>
* object will by default be type <code>TYPE_FORWARD_ONLY</code>
* and have a concurrency level of <code>CONCUR_READ_ONLY</code>.
*
* @param sql an SQL statement that may contain one or more '?' IN
* parameter placeholders
* @param autoGeneratedKeys a flag indicating whether auto-generated keys
* should be returned; one of the following <code>Statement</code>
* constants:
* @param autoGeneratedKeys a flag indicating that auto-generated keys should be returned, one of
* <code>Statement.RETURN_GENERATED_KEYS</code> or
* <code>Statement.NO_GENERATED_KEYS</code>.
* @return a new <code>PreparedStatement</code> object, containing the
* pre-compiled SQL statement, that will have the capability of
* returning auto-generated keys
* @exception SQLException if a database access error occurs
* or the given parameter is not a <code>Statement</code>
* constant indicating whether auto-generated keys should be
* returned
* @since 1.4
*/
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Creates a default <code>PreparedStatement</code> object capable
* of returning the auto-generated keys designated by the given array.
* This array contains the indexes of the columns in the target
* table that contain the auto-generated keys that should be made
* available. This array is ignored if the SQL
* statement is not an <code>INSERT</code> statement.
* <P>
* An SQL statement with or without IN parameters can be
* pre-compiled and stored in a <code>PreparedStatement</code> object. This
* object can then be used to efficiently execute this statement
* multiple times.
* <P>
* <B>Note:</B> This method is optimized for handling
* parametric SQL statements that benefit from precompilation. If
* the driver supports precompilation,
* the method <code>prepareStatement</code> will send
* the statement to the database for precompilation. Some drivers
* may not support precompilation. In this case, the statement may
* not be sent to the database until the <code>PreparedStatement</code>
* object is executed. This has no direct effect on users; however, it does
* affect which methods throw certain SQLExceptions.
* <P>
* Result sets created using the returned <code>PreparedStatement</code>
* object will by default be type <code>TYPE_FORWARD_ONLY</code>
* and have a concurrency level of <code>CONCUR_READ_ONLY</code>.
*
* @param sql an SQL statement that may contain one or more '?' IN
* parameter placeholders
* @param columnIndexes an array of column indexes indicating the columns
* that should be returned from the inserted row or rows
* @return a new <code>PreparedStatement</code> object, containing the
* pre-compiled statement, that is capable of returning the
* auto-generated keys designated by the given array of column
* indexes
* @exception SQLException if a database access error occurs
*
* @since 1.4
*/
public PreparedStatement prepareStatement(String sql, int columnIndexes[])
throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Creates a <code>Statement</code> object that will generate
* <code>ResultSet</code> objects with the given type, concurrency,
* and holdability.
* This method is the same as the <code>createStatement</code> method
* above, but it allows the default result set
* type, concurrency, and holdability to be overridden.
*
* @param resultSetType one of the following <code>ResultSet</code>
* constants:
* <code>ResultSet.TYPE_FORWARD_ONLY</code>,
* <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
* <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
* @param resultSetConcurrency one of the following <code>ResultSet</code>
* constants:
* <code>ResultSet.CONCUR_READ_ONLY</code> or
* <code>ResultSet.CONCUR_UPDATABLE</code>
* @param resultSetHoldability one of the following <code>ResultSet</code>
* constants:
* <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
* <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
* @return a new <code>Statement</code> object that will generate
* <code>ResultSet</code> objects with the given type,
* concurrency, and holdability
* @exception SQLException if a database access error occurs
* or the given parameters are not <code>ResultSet</code>
* constants indicating type, concurrency, and holdability
* @see ResultSet
* @since 1.4
*/
public Statement createStatement(int resultSetType, int resultSetConcurrency,
int resultSetHoldability) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Creates a <code>PreparedStatement</code> object that will generate
* <code>ResultSet</code> objects with the given type, concurrency,
* and holdability.
* <P>
* This method is the same as the <code>prepareStatement</code> method
* above, but it allows the default result set
* type, concurrency, and holdability to be overridden.
*
* @param sql a <code>String</code> object that is the SQL statement to
* be sent to the database; may contain one or more ? IN
* parameters
* @param resultSetType one of the following <code>ResultSet</code>
* constants:
* <code>ResultSet.TYPE_FORWARD_ONLY</code>,
* <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
* <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
* @param resultSetConcurrency one of the following <code>ResultSet</code>
* constants:
* <code>ResultSet.CONCUR_READ_ONLY</code> or
* <code>ResultSet.CONCUR_UPDATABLE</code>
* @param resultSetHoldability one of the following <code>ResultSet</code>
* constants:
* <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
* <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
* @return a new <code>PreparedStatement</code> object, containing the
* pre-compiled SQL statement, that will generate
* <code>ResultSet</code> objects with the given type,
* concurrency, and holdability
* @exception SQLException if a database access error occurs
* or the given parameters are not <code>ResultSet</code>
* constants indicating type, concurrency, and holdability
* @see ResultSet
* @since 1.4
*/
public PreparedStatement prepareStatement(String sql, int resultSetType,
int resultSetConcurrency, int resultSetHoldability)
throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Creates a <code>CallableStatement</code> object that will generate
* <code>ResultSet</code> objects with the given type and concurrency.
* This method is the same as the <code>prepareCall</code> method
* above, but it allows the default result set
* type, result set concurrency type and holdability to be overridden.
*
* @param sql a <code>String</code> object that is the SQL statement to
* be sent to the database; may contain on or more ? parameters
* @param resultSetType one of the following <code>ResultSet</code>
* constants:
* <code>ResultSet.TYPE_FORWARD_ONLY</code>,
* <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
* <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
* @param resultSetConcurrency one of the following <code>ResultSet</code>
* constants:
* <code>ResultSet.CONCUR_READ_ONLY</code> or
* <code>ResultSet.CONCUR_UPDATABLE</code>
* @param resultSetHoldability one of the following <code>ResultSet</code>
* constants:
* <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
* <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
* @return a new <code>CallableStatement</code> object, containing the
* pre-compiled SQL statement, that will generate
* <code>ResultSet</code> objects with the given type,
* concurrency, and holdability
* @exception SQLException if a database access error occurs
* or the given parameters are not <code>ResultSet</code>
* constants indicating type, concurrency, and holdability
* @see ResultSet
* @since 1.4
*/
public CallableStatement prepareCall(String sql, int resultSetType,
int resultSetConcurrency,
int resultSetHoldability) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Creates a default <code>PreparedStatement</code> object that has
* the capability to retrieve auto-generated keys. The given constant
* tells the driver whether it should make auto-generated keys
* available for retrieval. This parameter is ignored if the SQL
* statement is not an <code>INSERT</code> statement.
* <P>
* <B>Note:</B> This method is optimized for handling
* parametric SQL statements that benefit from precompilation. If
* the driver supports precompilation,
* the method <code>prepareStatement</code> will send
* the statement to the database for precompilation. Some drivers
* may not support precompilation. In this case, the statement may
* not be sent to the database until the <code>PreparedStatement</code>
* object is executed. This has no direct effect on users; however, it does
* affect which methods throw certain SQLExceptions.
* <P>
* Result sets created using the returned <code>PreparedStatement</code>
* object will by default be type <code>TYPE_FORWARD_ONLY</code>
* and have a concurrency level of <code>CONCUR_READ_ONLY</code>.
*
* @param sql an SQL statement that may contain one or more '?' IN
* parameter placeholders
* @param autoGeneratedKeys a flag indicating whether auto-generated keys
* should be returned; one of the following <code>Statement</code>
* constants:
* @param autoGeneratedKeys a flag indicating that auto-generated keys should be returned, one of
* <code>Statement.RETURN_GENERATED_KEYS</code> or
* <code>Statement.NO_GENERATED_KEYS</code>.
* @return a new <code>PreparedStatement</code> object, containing the
* pre-compiled SQL statement, that will have the capability of
* returning auto-generated keys
* @exception SQLException if a database access error occurs
* or the given parameter is not a <code>Statement</code>
* constant indicating whether auto-generated keys should be
* returned
* @since 1.4
*/
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Creates a default <code>PreparedStatement</code> object capable
* of returning the auto-generated keys designated by the given array.
* This array contains the indexes of the columns in the target
* table that contain the auto-generated keys that should be made
* available. This array is ignored if the SQL
* statement is not an <code>INSERT</code> statement.
* <P>
* An SQL statement with or without IN parameters can be
* pre-compiled and stored in a <code>PreparedStatement</code> object. This
* object can then be used to efficiently execute this statement
* multiple times.
* <P>
* <B>Note:</B> This method is optimized for handling
* parametric SQL statements that benefit from precompilation. If
* the driver supports precompilation,
* the method <code>prepareStatement</code> will send
* the statement to the database for precompilation. Some drivers
* may not support precompilation. In this case, the statement may
* not be sent to the database until the <code>PreparedStatement</code>
* object is executed. This has no direct effect on users; however, it does
* affect which methods throw certain SQLExceptions.
* <P>
* Result sets created using the returned <code>PreparedStatement</code>
* object will by default be type <code>TYPE_FORWARD_ONLY</code>
* and have a concurrency level of <code>CONCUR_READ_ONLY</code>.
*
* @param sql an SQL statement that may contain one or more '?' IN
* parameter placeholders
* @param columnIndexes an array of column indexes indicating the columns
* that should be returned from the inserted row or rows
* @return a new <code>PreparedStatement</code> object, containing the
* pre-compiled statement, that is capable of returning the
* auto-generated keys designated by the given array of column
* indexes
* @exception SQLException if a database access error occurs
*
* @since 1.4
*/
public PreparedStatement prepareStatement(String sql, int columnIndexes[])
throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Creates a default <code>PreparedStatement</code> object capable
* of returning the auto-generated keys designated by the given array.
* This array contains the names of the columns in the target
* table that contain the auto-generated keys that should be returned.
* This array is ignored if the SQL
* statement is not an <code>INSERT</code> statement.
* <P>
* An SQL statement with or without IN parameters can be
* pre-compiled and stored in a <code>PreparedStatement</code> object. This
* object can then be used to efficiently execute this statement
* multiple times.
* <P>
* <B>Note:</B> This method is optimized for handling
* parametric SQL statements that benefit from precompilation. If
* the driver supports precompilation,
* the method <code>prepareStatement</code> will send
* the statement to the database for precompilation. Some drivers
* may not support precompilation. In this case, the statement may
* not be sent to the database until the <code>PreparedStatement</code>
* object is executed. This has no direct effect on users; however, it does
* affect which methods throw certain SQLExceptions.
* <P>
* Result sets created using the returned <code>PreparedStatement</code>
* object will by default be type <code>TYPE_FORWARD_ONLY</code>
* and have a concurrency level of <code>CONCUR_READ_ONLY</code>.
*
* @param sql an SQL statement that may contain one or more '?' IN
* parameter placeholders
* @param columnNames an array of column names indicating the columns
* that should be returned from the inserted row or rows
* @return a new <code>PreparedStatement</code> object, containing the
* pre-compiled statement, that is capable of returning the
* auto-generated keys designated by the given array of column
* names
* @exception SQLException if a database access error occurs
*
* @since 1.4
*/
public PreparedStatement prepareStatement(String sql, String columnNames[])
throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Creates a default <code>PreparedStatement</code> object capable
* of returning the auto-generated keys designated by the given array.
* This array contains the names of the columns in the target
* table that contain the auto-generated keys that should be returned.
* This array is ignored if the SQL
* statement is not an <code>INSERT</code> statement.
* <P>
* An SQL statement with or without IN parameters can be
* pre-compiled and stored in a <code>PreparedStatement</code> object. This
* object can then be used to efficiently execute this statement
* multiple times.
* <P>
* <B>Note:</B> This method is optimized for handling
* parametric SQL statements that benefit from precompilation. If
* the driver supports precompilation,
* the method <code>prepareStatement</code> will send
* the statement to the database for precompilation. Some drivers
* may not support precompilation. In this case, the statement may
* not be sent to the database until the <code>PreparedStatement</code>
* object is executed. This has no direct effect on users; however, it does
* affect which methods throw certain SQLExceptions.
* <P>
* Result sets created using the returned <code>PreparedStatement</code>
* object will by default be type <code>TYPE_FORWARD_ONLY</code>
* and have a concurrency level of <code>CONCUR_READ_ONLY</code>.
*
* @param sql an SQL statement that may contain one or more '?' IN
* parameter placeholders
* @param columnNames an array of column names indicating the columns
* that should be returned from the inserted row or rows
* @return a new <code>PreparedStatement</code> object, containing the
* pre-compiled statement, that is capable of returning the
* auto-generated keys designated by the given array of column
* names
* @exception SQLException if a database access error occurs
*
* @since 1.4
*/
public PreparedStatement prepareStatement(String sql, String columnNames[])
throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
}
......
......@@ -8,332 +8,348 @@ public abstract class AbstractJdbc3DatabaseMetaData extends org.postgresql.jdbc2
public AbstractJdbc3DatabaseMetaData(AbstractJdbc3Connection conn)
{
super(conn);
super(conn);
}
/**
* Retrieves whether this database supports savepoints.
*
* @return <code>true</code> if savepoints are supported;
* <code>false</code> otherwise
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public boolean supportsSavepoints() throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves whether this database supports savepoints.
*
* @return <code>true</code> if savepoints are supported;
* <code>false</code> otherwise
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public boolean supportsSavepoints() throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves whether this database supports named parameters to callable
* statements.
*
* @return <code>true</code> if named parameters are supported;
* <code>false</code> otherwise
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public boolean supportsNamedParameters() throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves whether this database supports named parameters to callable
* statements.
*
* @return <code>true</code> if named parameters are supported;
* <code>false</code> otherwise
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public boolean supportsNamedParameters() throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves whether it is possible to have multiple <code>ResultSet</code> objects
* returned from a <code>CallableStatement</code> object
* simultaneously.
*
* @return <code>true</code> if a <code>CallableStatement</code> object
* can return multiple <code>ResultSet</code> objects
* simultaneously; <code>false</code> otherwise
* @exception SQLException if a datanase access error occurs
* @since 1.4
*/
public boolean supportsMultipleOpenResults() throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves whether it is possible to have multiple <code>ResultSet</code> objects
* returned from a <code>CallableStatement</code> object
* simultaneously.
*
* @return <code>true</code> if a <code>CallableStatement</code> object
* can return multiple <code>ResultSet</code> objects
* simultaneously; <code>false</code> otherwise
* @exception SQLException if a datanase access error occurs
* @since 1.4
*/
public boolean supportsMultipleOpenResults() throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves whether auto-generated keys can be retrieved after
* a statement has been executed.
*
* @return <code>true</code> if auto-generated keys can be retrieved
* after a statement has executed; <code>false</code> otherwise
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public boolean supportsGetGeneratedKeys() throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves whether auto-generated keys can be retrieved after
* a statement has been executed.
*
* @return <code>true</code> if auto-generated keys can be retrieved
* after a statement has executed; <code>false</code> otherwise
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public boolean supportsGetGeneratedKeys() throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves a description of the user-defined type (UDT) hierarchies defined in a
* particular schema in this database. Only the immediate super type/
* sub type relationship is modeled.
* <P>
* Only supertype information for UDTs matching the catalog,
* schema, and type name is returned. The type name parameter
* may be a fully-qualified name. When the UDT name supplied is a
* fully-qualified name, the catalog and schemaPattern parameters are
* ignored.
* <P>
* If a UDT does not have a direct super type, it is not listed here.
* A row of the <code>ResultSet</code> object returned by this method
* describes the designated UDT and a direct supertype. A row has the following
* columns:
* <OL>
* <LI><B>TYPE_CAT</B> String => the UDT's catalog (may be <code>null</code>)
* <LI><B>TYPE_SCHEM</B> String => UDT's schema (may be <code>null</code>)
* <LI><B>TYPE_NAME</B> String => type name of the UDT
* <LI><B>SUPERTYPE_CAT</B> String => the direct super type's catalog
* (may be <code>null</code>)
* <LI><B>SUPERTYPE_SCHEM</B> String => the direct super type's schema
* (may be <code>null</code>)
* <LI><B>SUPERTYPE_NAME</B> String => the direct super type's name
* </OL>
*
* <P><B>Note:</B> If the driver does not support type hierarchies, an
* empty result set is returned.
*
* @param catalog a catalog name; "" retrieves those without a catalog;
* <code>null</code> means drop catalog name from the selection criteria
* @param schemaPattern a schema name pattern; "" retrieves those
* without a schema
* @param typeNamePattern a UDT name pattern; may be a fully-qualified
* name
* @return a <code>ResultSet</code> object in which a row gives information
* about the designated UDT
* @throws SQLException if a database access error occurs
* @since 1.4
*/
public ResultSet getSuperTypes(String catalog, String schemaPattern,
String typeNamePattern) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves a description of the table hierarchies defined in a particular
* schema in this database.
*
* <P>Only supertable information for tables matching the catalog, schema
* and table name are returned. The table name parameter may be a fully-
* qualified name, in which case, the catalog and schemaPattern parameters
* are ignored. If a table does not have a super table, it is not listed here.
* Supertables have to be defined in the same catalog and schema as the
* sub tables. Therefore, the type description does not need to include
* this information for the supertable.
*
* <P>Each type description has the following columns:
* <OL>
* <LI><B>TABLE_CAT</B> String => the type's catalog (may be <code>null</code>)
* <LI><B>TABLE_SCHEM</B> String => type's schema (may be <code>null</code>)
* <LI><B>TABLE_NAME</B> String => type name
* <LI><B>SUPERTABLE_NAME</B> String => the direct super type's name
* </OL>
*
* <P><B>Note:</B> If the driver does not support type hierarchies, an
* empty result set is returned.
*
* @param catalog a catalog name; "" retrieves those without a catalog;
* <code>null</code> means drop catalog name from the selection criteria
* @param schemaPattern a schema name pattern; "" retrieves those
* without a schema
* @param tableNamePattern a table name pattern; may be a fully-qualified
* name
* @return a <code>ResultSet</code> object in which each row is a type description
* @throws SQLException if a database access error occurs
* @since 1.4
*/
public ResultSet getSuperTables(String catalog, String schemaPattern,
String tableNamePattern) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves a description of the user-defined type (UDT) hierarchies defined in a
* particular schema in this database. Only the immediate super type/
* sub type relationship is modeled.
* <P>
* Only supertype information for UDTs matching the catalog,
* schema, and type name is returned. The type name parameter
* may be a fully-qualified name. When the UDT name supplied is a
* fully-qualified name, the catalog and schemaPattern parameters are
* ignored.
* <P>
* If a UDT does not have a direct super type, it is not listed here.
* A row of the <code>ResultSet</code> object returned by this method
* describes the designated UDT and a direct supertype. A row has the following
* columns:
* <OL>
* <LI><B>TYPE_CAT</B> String => the UDT's catalog (may be <code>null</code>)
* <LI><B>TYPE_SCHEM</B> String => UDT's schema (may be <code>null</code>)
* <LI><B>TYPE_NAME</B> String => type name of the UDT
* <LI><B>SUPERTYPE_CAT</B> String => the direct super type's catalog
* (may be <code>null</code>)
* <LI><B>SUPERTYPE_SCHEM</B> String => the direct super type's schema
* (may be <code>null</code>)
* <LI><B>SUPERTYPE_NAME</B> String => the direct super type's name
* </OL>
*
* <P><B>Note:</B> If the driver does not support type hierarchies, an
* empty result set is returned.
*
* @param catalog a catalog name; "" retrieves those without a catalog;
* <code>null</code> means drop catalog name from the selection criteria
* @param schemaPattern a schema name pattern; "" retrieves those
* without a schema
* @param typeNamePattern a UDT name pattern; may be a fully-qualified
* name
* @return a <code>ResultSet</code> object in which a row gives information
* about the designated UDT
* @throws SQLException if a database access error occurs
* @since 1.4
*/
public ResultSet getSuperTypes(String catalog, String schemaPattern,
String typeNamePattern) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves a description of the given attribute of the given type
* for a user-defined type (UDT) that is available in the given schema
* and catalog.
* <P>
* Descriptions are returned only for attributes of UDTs matching the
* catalog, schema, type, and attribute name criteria. They are ordered by
* TYPE_SCHEM, TYPE_NAME and ORDINAL_POSITION. This description
* does not contain inherited attributes.
* <P>
* The <code>ResultSet</code> object that is returned has the following
* columns:
* <OL>
* <LI><B>TYPE_CAT</B> String => type catalog (may be <code>null</code>)
* <LI><B>TYPE_SCHEM</B> String => type schema (may be <code>null</code>)
* <LI><B>TYPE_NAME</B> String => type name
* <LI><B>ATTR_NAME</B> String => attribute name
* <LI><B>DATA_TYPE</B> short => attribute type SQL type from java.sql.Types
* <LI><B>ATTR_TYPE_NAME</B> String => Data source dependent type name.
* For a UDT, the type name is fully qualified. For a REF, the type name is
* fully qualified and represents the target type of the reference type.
* <LI><B>ATTR_SIZE</B> int => column size. For char or date
* types this is the maximum number of characters; for numeric or
* decimal types this is precision.
* <LI><B>DECIMAL_DIGITS</B> int => the number of fractional digits
* <LI><B>NUM_PREC_RADIX</B> int => Radix (typically either 10 or 2)
* <LI><B>NULLABLE</B> int => whether NULL is allowed
* <UL>
* <LI> attributeNoNulls - might not allow NULL values
* <LI> attributeNullable - definitely allows NULL values
* <LI> attributeNullableUnknown - nullability unknown
* </UL>
* <LI><B>REMARKS</B> String => comment describing column (may be <code>null</code>)
* <LI><B>ATTR_DEF</B> String => default value (may be <code>null</code>)
* <LI><B>SQL_DATA_TYPE</B> int => unused
* <LI><B>SQL_DATETIME_SUB</B> int => unused
* <LI><B>CHAR_OCTET_LENGTH</B> int => for char types the
* maximum number of bytes in the column
* <LI><B>ORDINAL_POSITION</B> int => index of column in table
* (starting at 1)
* <LI><B>IS_NULLABLE</B> String => "NO" means column definitely
* does not allow NULL values; "YES" means the column might
* allow NULL values. An empty string means unknown.
* <LI><B>SCOPE_CATALOG</B> String => catalog of table that is the
* scope of a reference attribute (<code>null</code> if DATA_TYPE isn't REF)
* <LI><B>SCOPE_SCHEMA</B> String => schema of table that is the
* scope of a reference attribute (<code>null</code> if DATA_TYPE isn't REF)
* <LI><B>SCOPE_TABLE</B> String => table name that is the scope of a
* reference attribute (<code>null</code> if the DATA_TYPE isn't REF)
* <LI><B>SOURCE_DATA_TYPE</B> short => source type of a distinct type or user-generated
* Ref type,SQL type from java.sql.Types (<code>null</code> if DATA_TYPE
* isn't DISTINCT or user-generated REF)
* </OL>
* @param catalog a catalog name; must match the catalog name as it
* is stored in the database; "" retrieves those without a catalog;
* <code>null</code> means that the catalog name should not be used to narrow
* the search
* @param schemaPattern a schema name pattern; must match the schema name
* as it is stored in the database; "" retrieves those without a schema;
* <code>null</code> means that the schema name should not be used to narrow
* the search
* @param typeNamePattern a type name pattern; must match the
* type name as it is stored in the database
* @param attributeNamePattern an attribute name pattern; must match the attribute
* name as it is declared in the database
* @return a <code>ResultSet</code> object in which each row is an
* attribute description
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public ResultSet getAttributes(String catalog, String schemaPattern,
String typeNamePattern, String attributeNamePattern)
throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves a description of the table hierarchies defined in a particular
* schema in this database.
*
* <P>Only supertable information for tables matching the catalog, schema
* and table name are returned. The table name parameter may be a fully-
* qualified name, in which case, the catalog and schemaPattern parameters
* are ignored. If a table does not have a super table, it is not listed here.
* Supertables have to be defined in the same catalog and schema as the
* sub tables. Therefore, the type description does not need to include
* this information for the supertable.
*
* <P>Each type description has the following columns:
* <OL>
* <LI><B>TABLE_CAT</B> String => the type's catalog (may be <code>null</code>)
* <LI><B>TABLE_SCHEM</B> String => type's schema (may be <code>null</code>)
* <LI><B>TABLE_NAME</B> String => type name
* <LI><B>SUPERTABLE_NAME</B> String => the direct super type's name
* </OL>
*
* <P><B>Note:</B> If the driver does not support type hierarchies, an
* empty result set is returned.
*
* @param catalog a catalog name; "" retrieves those without a catalog;
* <code>null</code> means drop catalog name from the selection criteria
* @param schemaPattern a schema name pattern; "" retrieves those
* without a schema
* @param tableNamePattern a table name pattern; may be a fully-qualified
* name
* @return a <code>ResultSet</code> object in which each row is a type description
* @throws SQLException if a database access error occurs
* @since 1.4
*/
public ResultSet getSuperTables(String catalog, String schemaPattern,
String tableNamePattern) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves whether this database supports the given result set holdability.
*
* @param holdability one of the following constants:
* <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
* <code>ResultSet.CLOSE_CURSORS_AT_COMMIT<code>
* @return <code>true</code> if so; <code>false</code> otherwise
* @exception SQLException if a database access error occurs
* @see Connection
* @since 1.4
*/
public boolean supportsResultSetHoldability(int holdability) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves a description of the given attribute of the given type
* for a user-defined type (UDT) that is available in the given schema
* and catalog.
* <P>
* Descriptions are returned only for attributes of UDTs matching the
* catalog, schema, type, and attribute name criteria. They are ordered by
* TYPE_SCHEM, TYPE_NAME and ORDINAL_POSITION. This description
* does not contain inherited attributes.
* <P>
* The <code>ResultSet</code> object that is returned has the following
* columns:
* <OL>
* <LI><B>TYPE_CAT</B> String => type catalog (may be <code>null</code>)
* <LI><B>TYPE_SCHEM</B> String => type schema (may be <code>null</code>)
* <LI><B>TYPE_NAME</B> String => type name
* <LI><B>ATTR_NAME</B> String => attribute name
* <LI><B>DATA_TYPE</B> short => attribute type SQL type from java.sql.Types
* <LI><B>ATTR_TYPE_NAME</B> String => Data source dependent type name.
* For a UDT, the type name is fully qualified. For a REF, the type name is
* fully qualified and represents the target type of the reference type.
* <LI><B>ATTR_SIZE</B> int => column size. For char or date
* types this is the maximum number of characters; for numeric or
* decimal types this is precision.
* <LI><B>DECIMAL_DIGITS</B> int => the number of fractional digits
* <LI><B>NUM_PREC_RADIX</B> int => Radix (typically either 10 or 2)
* <LI><B>NULLABLE</B> int => whether NULL is allowed
* <UL>
* <LI> attributeNoNulls - might not allow NULL values
* <LI> attributeNullable - definitely allows NULL values
* <LI> attributeNullableUnknown - nullability unknown
* </UL>
* <LI><B>REMARKS</B> String => comment describing column (may be <code>null</code>)
* <LI><B>ATTR_DEF</B> String => default value (may be <code>null</code>)
* <LI><B>SQL_DATA_TYPE</B> int => unused
* <LI><B>SQL_DATETIME_SUB</B> int => unused
* <LI><B>CHAR_OCTET_LENGTH</B> int => for char types the
* maximum number of bytes in the column
* <LI><B>ORDINAL_POSITION</B> int => index of column in table
* (starting at 1)
* <LI><B>IS_NULLABLE</B> String => "NO" means column definitely
* does not allow NULL values; "YES" means the column might
* allow NULL values. An empty string means unknown.
* <LI><B>SCOPE_CATALOG</B> String => catalog of table that is the
* scope of a reference attribute (<code>null</code> if DATA_TYPE isn't REF)
* <LI><B>SCOPE_SCHEMA</B> String => schema of table that is the
* scope of a reference attribute (<code>null</code> if DATA_TYPE isn't REF)
* <LI><B>SCOPE_TABLE</B> String => table name that is the scope of a
* reference attribute (<code>null</code> if the DATA_TYPE isn't REF)
* <LI><B>SOURCE_DATA_TYPE</B> short => source type of a distinct type or user-generated
* Ref type,SQL type from java.sql.Types (<code>null</code> if DATA_TYPE
* isn't DISTINCT or user-generated REF)
* </OL>
* @param catalog a catalog name; must match the catalog name as it
* is stored in the database; "" retrieves those without a catalog;
* <code>null</code> means that the catalog name should not be used to narrow
* the search
* @param schemaPattern a schema name pattern; must match the schema name
* as it is stored in the database; "" retrieves those without a schema;
* <code>null</code> means that the schema name should not be used to narrow
* the search
* @param typeNamePattern a type name pattern; must match the
* type name as it is stored in the database
* @param attributeNamePattern an attribute name pattern; must match the attribute
* name as it is declared in the database
* @return a <code>ResultSet</code> object in which each row is an
* attribute description
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public ResultSet getAttributes(String catalog, String schemaPattern,
String typeNamePattern, String attributeNamePattern)
throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves the default holdability of this <code>ResultSet</code>
* object.
*
* @return the default holdability; either
* <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
* <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public int getResultSetHoldability() throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves whether this database supports the given result set holdability.
*
* @param holdability one of the following constants:
* <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
* <code>ResultSet.CLOSE_CURSORS_AT_COMMIT<code>
* @return <code>true</code> if so; <code>false</code> otherwise
* @exception SQLException if a database access error occurs
* @see Connection
* @since 1.4
*/
public boolean supportsResultSetHoldability(int holdability) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves the major version number of the underlying database.
*
* @return the underlying database's major version
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public int getDatabaseMajorVersion() throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves the default holdability of this <code>ResultSet</code>
* object.
*
* @return the default holdability; either
* <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
* <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public int getResultSetHoldability() throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves the major version number of the underlying database.
*
* @return the underlying database's major version
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public int getDatabaseMajorVersion() throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves the minor version number of the underlying database.
*
* @return underlying database's minor version
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public int getDatabaseMinorVersion() throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves the minor version number of the underlying database.
*
* @return underlying database's minor version
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public int getDatabaseMinorVersion() throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves the major JDBC version number for this
* driver.
*
* @return JDBC version major number
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public int getJDBCMajorVersion() throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves the major JDBC version number for this
* driver.
*
* @return JDBC version major number
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public int getJDBCMajorVersion() throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves the minor JDBC version number for this
* driver.
*
* @return JDBC version minor number
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public int getJDBCMinorVersion() throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves the minor JDBC version number for this
* driver.
*
* @return JDBC version minor number
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public int getJDBCMinorVersion() throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Indicates whether the SQLSTATEs returned by <code>SQLException.getSQLState</code>
* is X/Open (now known as Open Group) SQL CLI or SQL99.
* @return the type of SQLSTATEs, one of:
* sqlStateXOpen or
* sqlStateSQL99
* @throws SQLException if a database access error occurs
* @since 1.4
*/
public int getSQLStateType() throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Indicates whether the SQLSTATEs returned by <code>SQLException.getSQLState</code>
* is X/Open (now known as Open Group) SQL CLI or SQL99.
* @return the type of SQLSTATEs, one of:
* sqlStateXOpen or
* sqlStateSQL99
* @throws SQLException if a database access error occurs
* @since 1.4
*/
public int getSQLStateType() throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Indicates whether updates made to a LOB are made on a copy or directly
* to the LOB.
* @return <code>true</code> if updates are made to a copy of the LOB;
* <code>false</code> if updates are made directly to the LOB
* @throws SQLException if a database access error occurs
* @since 1.4
*/
public boolean locatorsUpdateCopy() throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Indicates whether updates made to a LOB are made on a copy or directly
* to the LOB.
* @return <code>true</code> if updates are made to a copy of the LOB;
* <code>false</code> if updates are made directly to the LOB
* @throws SQLException if a database access error occurs
* @since 1.4
*/
public boolean locatorsUpdateCopy() throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves weather this database supports statement pooling.
*
* @return <code>true</code> is so;
<code>false</code> otherwise
* @throws SQLExcpetion if a database access error occurs
* @since 1.4
*/
public boolean supportsStatementPooling() throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves weather this database supports statement pooling.
*
* @return <code>true</code> is so;
<code>false</code> otherwise
* @throws SQLExcpetion if a database access error occurs
* @since 1.4
*/
public boolean supportsStatementPooling() throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
}
......@@ -4,178 +4,190 @@ package org.postgresql.jdbc3;
import java.sql.*;
import java.util.Vector;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc3/Attic/AbstractJdbc3ResultSet.java,v 1.1 2002/08/14 20:35:39 barry Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc3/Attic/AbstractJdbc3ResultSet.java,v 1.2 2002/09/06 21:23:06 momjian Exp $
* This class defines methods of the jdbc3 specification. This class extends
* org.postgresql.jdbc2.AbstractJdbc2ResultSet which provides the jdbc2
* methods. The real Statement class (for jdbc3) is org.postgresql.jdbc3.Jdbc3ResultSet
*/
public abstract class AbstractJdbc3ResultSet extends org.postgresql.jdbc2.AbstractJdbc2ResultSet {
public AbstractJdbc3ResultSet(org.postgresql.PGConnection conn, Statement statement, org.postgresql.Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) {
super (conn, statement, fields, tuples, status, updateCount, insertOID, binaryCursor);
}
/**
* Retrieves the value of the designated column in the current row
* of this <code>ResultSet</code> object as a <code>java.net.URL</code>
* object in the Java programming language.
*
* @param columnIndex the index of the column 1 is the first, 2 is the second,...
* @return the column value as a <code>java.net.URL</code> object;
* if the value is SQL <code>NULL</code>,
* the value returned is <code>null</code> in the Java programming language
* @exception SQLException if a database access error occurs,
* or if a URL is malformed
* @since 1.4
*/
public java.net.URL getURL(int columnIndex) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves the value of the designated column in the current row
* of this <code>ResultSet</code> object as a <code>java.net.URL</code>
* object in the Java programming language.
*
* @param columnName the SQL name of the column
* @return the column value as a <code>java.net.URL</code> object;
* if the value is SQL <code>NULL</code>,
* the value returned is <code>null</code> in the Java programming language
* @exception SQLException if a database access error occurs
* or if a URL is malformed
* @since 1.4
*/
public java.net.URL getURL(String columnName) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Updates the designated column with a <code>java.sql.Ref</code> value.
* The updater methods are used to update column values in the
* current row or the insert row. The updater methods do not
* update the underlying database; instead the <code>updateRow</code> or
* <code>insertRow</code> methods are called to update the database.
*
* @param columnIndex the first column is 1, the second is 2, ...
* @param x the new column value
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public void updateRef(int columnIndex, java.sql.Ref x) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Updates the designated column with a <code>java.sql.Ref</code> value.
* The updater methods are used to update column values in the
* current row or the insert row. The updater methods do not
* update the underlying database; instead the <code>updateRow</code> or
* <code>insertRow</code> methods are called to update the database.
*
* @param columnName the name of the column
* @param x the new column value
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public void updateRef(String columnName, java.sql.Ref x) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Updates the designated column with a <code>java.sql.Blob</code> value.
* The updater methods are used to update column values in the
* current row or the insert row. The updater methods do not
* update the underlying database; instead the <code>updateRow</code> or
* <code>insertRow</code> methods are called to update the database.
*
* @param columnIndex the first column is 1, the second is 2, ...
* @param x the new column value
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public void updateBlob(int columnIndex, java.sql.Blob x) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Updates the designated column with a <code>java.sql.Blob</code> value.
* The updater methods are used to update column values in the
* current row or the insert row. The updater methods do not
* update the underlying database; instead the <code>updateRow</code> or
* <code>insertRow</code> methods are called to update the database.
*
* @param columnName the name of the column
* @param x the new column value
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public void updateBlob(String columnName, java.sql.Blob x) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Updates the designated column with a <code>java.sql.Clob</code> value.
* The updater methods are used to update column values in the
* current row or the insert row. The updater methods do not
* update the underlying database; instead the <code>updateRow</code> or
* <code>insertRow</code> methods are called to update the database.
*
* @param columnIndex the first column is 1, the second is 2, ...
* @param x the new column value
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public void updateClob(int columnIndex, java.sql.Clob x) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Updates the designated column with a <code>java.sql.Clob</code> value.
* The updater methods are used to update column values in the
* current row or the insert row. The updater methods do not
* update the underlying database; instead the <code>updateRow</code> or
* <code>insertRow</code> methods are called to update the database.
*
* @param columnName the name of the column
* @param x the new column value
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public void updateClob(String columnName, java.sql.Clob x) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Updates the designated column with a <code>java.sql.Array</code> value.
* The updater methods are used to update column values in the
* current row or the insert row. The updater methods do not
* update the underlying database; instead the <code>updateRow</code> or
* <code>insertRow</code> methods are called to update the database.
*
* @param columnIndex the first column is 1, the second is 2, ...
* @param x the new column value
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public void updateArray(int columnIndex, java.sql.Array x) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/**
* Updates the designated column with a <code>java.sql.Array</code> value.
* The updater methods are used to update column values in the
* current row or the insert row. The updater methods do not
* update the underlying database; instead the <code>updateRow</code> or
* <code>insertRow</code> methods are called to update the database.
*
* @param columnName the name of the column
* @param x the new column value
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public void updateArray(String columnName, java.sql.Array x) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
public abstract class AbstractJdbc3ResultSet extends org.postgresql.jdbc2.AbstractJdbc2ResultSet
{
public AbstractJdbc3ResultSet(org.postgresql.PGConnection conn, Statement statement, org.postgresql.Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor)
{
super (conn, statement, fields, tuples, status, updateCount, insertOID, binaryCursor);
}
/**
* Retrieves the value of the designated column in the current row
* of this <code>ResultSet</code> object as a <code>java.net.URL</code>
* object in the Java programming language.
*
* @param columnIndex the index of the column 1 is the first, 2 is the second,...
* @return the column value as a <code>java.net.URL</code> object;
* if the value is SQL <code>NULL</code>,
* the value returned is <code>null</code> in the Java programming language
* @exception SQLException if a database access error occurs,
* or if a URL is malformed
* @since 1.4
*/
public java.net.URL getURL(int columnIndex) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Retrieves the value of the designated column in the current row
* of this <code>ResultSet</code> object as a <code>java.net.URL</code>
* object in the Java programming language.
*
* @param columnName the SQL name of the column
* @return the column value as a <code>java.net.URL</code> object;
* if the value is SQL <code>NULL</code>,
* the value returned is <code>null</code> in the Java programming language
* @exception SQLException if a database access error occurs
* or if a URL is malformed
* @since 1.4
*/
public java.net.URL getURL(String columnName) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Updates the designated column with a <code>java.sql.Ref</code> value.
* The updater methods are used to update column values in the
* current row or the insert row. The updater methods do not
* update the underlying database; instead the <code>updateRow</code> or
* <code>insertRow</code> methods are called to update the database.
*
* @param columnIndex the first column is 1, the second is 2, ...
* @param x the new column value
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public void updateRef(int columnIndex, java.sql.Ref x) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Updates the designated column with a <code>java.sql.Ref</code> value.
* The updater methods are used to update column values in the
* current row or the insert row. The updater methods do not
* update the underlying database; instead the <code>updateRow</code> or
* <code>insertRow</code> methods are called to update the database.
*
* @param columnName the name of the column
* @param x the new column value
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public void updateRef(String columnName, java.sql.Ref x) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Updates the designated column with a <code>java.sql.Blob</code> value.
* The updater methods are used to update column values in the
* current row or the insert row. The updater methods do not
* update the underlying database; instead the <code>updateRow</code> or
* <code>insertRow</code> methods are called to update the database.
*
* @param columnIndex the first column is 1, the second is 2, ...
* @param x the new column value
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public void updateBlob(int columnIndex, java.sql.Blob x) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Updates the designated column with a <code>java.sql.Blob</code> value.
* The updater methods are used to update column values in the
* current row or the insert row. The updater methods do not
* update the underlying database; instead the <code>updateRow</code> or
* <code>insertRow</code> methods are called to update the database.
*
* @param columnName the name of the column
* @param x the new column value
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public void updateBlob(String columnName, java.sql.Blob x) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Updates the designated column with a <code>java.sql.Clob</code> value.
* The updater methods are used to update column values in the
* current row or the insert row. The updater methods do not
* update the underlying database; instead the <code>updateRow</code> or
* <code>insertRow</code> methods are called to update the database.
*
* @param columnIndex the first column is 1, the second is 2, ...
* @param x the new column value
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public void updateClob(int columnIndex, java.sql.Clob x) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Updates the designated column with a <code>java.sql.Clob</code> value.
* The updater methods are used to update column values in the
* current row or the insert row. The updater methods do not
* update the underlying database; instead the <code>updateRow</code> or
* <code>insertRow</code> methods are called to update the database.
*
* @param columnName the name of the column
* @param x the new column value
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public void updateClob(String columnName, java.sql.Clob x) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Updates the designated column with a <code>java.sql.Array</code> value.
* The updater methods are used to update column values in the
* current row or the insert row. The updater methods do not
* update the underlying database; instead the <code>updateRow</code> or
* <code>insertRow</code> methods are called to update the database.
*
* @param columnIndex the first column is 1, the second is 2, ...
* @param x the new column value
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public void updateArray(int columnIndex, java.sql.Array x) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* Updates the designated column with a <code>java.sql.Array</code> value.
* The updater methods are used to update column values in the
* current row or the insert row. The updater methods do not
* update the underlying database; instead the <code>updateRow</code> or
* <code>insertRow</code> methods are called to update the database.
*
* @param columnName the name of the column
* @param x the new column value
* @exception SQLException if a database access error occurs
* @since 1.4
*/
public void updateArray(String columnName, java.sql.Array x) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -5,11 +5,11 @@ import java.sql.*;
public class Jdbc3CallableStatement extends org.postgresql.jdbc3.AbstractJdbc3Statement implements java.sql.CallableStatement
{
public Jdbc3CallableStatement(Jdbc3Connection connection, String sql) throws SQLException
{
super(connection, sql);
}
}
......@@ -6,56 +6,56 @@ import java.util.Vector;
import java.util.Hashtable;
import org.postgresql.Field;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc3/Attic/Jdbc3Connection.java,v 1.1 2002/08/14 20:35:40 barry Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc3/Attic/Jdbc3Connection.java,v 1.2 2002/09/06 21:23:06 momjian Exp $
* This class implements the java.sql.Connection interface for JDBC3.
* However most of the implementation is really done in
* However most of the implementation is really done in
* org.postgresql.jdbc3.AbstractJdbc3Connection or one of it's parents
*/
public class Jdbc3Connection extends org.postgresql.jdbc3.AbstractJdbc3Connection implements java.sql.Connection
{
public java.sql.Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException
{
Jdbc3Statement s = new Jdbc3Statement(this);
s.setResultSetType(resultSetType);
s.setResultSetConcurrency(resultSetConcurrency);
return s;
}
public java.sql.PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{
Jdbc3PreparedStatement s = new Jdbc3PreparedStatement(this, sql);
s.setResultSetType(resultSetType);
s.setResultSetConcurrency(resultSetConcurrency);
return s;
}
public java.sql.CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{
Jdbc3CallableStatement s = new Jdbc3CallableStatement(this,sql);
public java.sql.Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException
{
Jdbc3Statement s = new Jdbc3Statement(this);
s.setResultSetType(resultSetType);
s.setResultSetConcurrency(resultSetConcurrency);
return s;
}
public java.sql.PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{
Jdbc3PreparedStatement s = new Jdbc3PreparedStatement(this, sql);
s.setResultSetType(resultSetType);
s.setResultSetConcurrency(resultSetConcurrency);
return s;
}
public java.sql.DatabaseMetaData getMetaData() throws SQLException
{
if (metadata == null)
metadata = new Jdbc3DatabaseMetaData(this);
return metadata;
}
public java.sql.ResultSet getResultSet(Statement statement, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException
{
return new Jdbc3ResultSet(this, statement, fields, tuples, status, updateCount, insertOID, binaryCursor);
}
public java.sql.ResultSet getResultSet(Statement statement, Field[] fields, Vector tuples, String status, int updateCount) throws SQLException
{
return new Jdbc3ResultSet(this, statement, fields, tuples, status, updateCount, 0, false);
}
s.setResultSetConcurrency(resultSetConcurrency);
return s;
}
public java.sql.CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{
Jdbc3CallableStatement s = new Jdbc3CallableStatement(this, sql);
s.setResultSetType(resultSetType);
s.setResultSetConcurrency(resultSetConcurrency);
return s;
}
public java.sql.DatabaseMetaData getMetaData() throws SQLException
{
if (metadata == null)
metadata = new Jdbc3DatabaseMetaData(this);
return metadata;
}
public java.sql.ResultSet getResultSet(Statement statement, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException
{
return new Jdbc3ResultSet(this, statement, fields, tuples, status, updateCount, insertOID, binaryCursor);
}
public java.sql.ResultSet getResultSet(Statement statement, Field[] fields, Vector tuples, String status, int updateCount) throws SQLException
{
return new Jdbc3ResultSet(this, statement, fields, tuples, status, updateCount, 0, false);
}
}
......@@ -3,10 +3,10 @@ package org.postgresql.jdbc3;
public class Jdbc3DatabaseMetaData extends org.postgresql.jdbc3.AbstractJdbc3DatabaseMetaData implements java.sql.DatabaseMetaData
{
public Jdbc3DatabaseMetaData(Jdbc3Connection conn)
{
super(conn);
}
}
......@@ -5,11 +5,11 @@ import java.sql.*;
public class Jdbc3PreparedStatement extends org.postgresql.jdbc3.AbstractJdbc3Statement implements java.sql.PreparedStatement
{
public Jdbc3PreparedStatement(Jdbc3Connection connection, String sql) throws SQLException
{
super(connection, sql);
}
}
......@@ -5,31 +5,33 @@ import java.sql.*;
import java.util.Vector;
import org.postgresql.Field;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc3/Attic/Jdbc3ResultSet.java,v 1.1 2002/08/14 20:35:40 barry Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc3/Attic/Jdbc3ResultSet.java,v 1.2 2002/09/06 21:23:06 momjian Exp $
* This class implements the java.sql.ResultSet interface for JDBC3.
* However most of the implementation is really done in
* However most of the implementation is really done in
* org.postgresql.jdbc3.AbstractJdbc3ResultSet or one of it's parents
*/
public class Jdbc3ResultSet extends org.postgresql.jdbc3.AbstractJdbc3ResultSet implements java.sql.ResultSet
{
public Jdbc3ResultSet(Jdbc3Connection conn, Statement statement, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor)
{
super(conn, statement, fields, tuples, status, updateCount, insertOID, binaryCursor);
}
public java.sql.ResultSetMetaData getMetaData() throws SQLException
{
return new Jdbc3ResultSetMetaData(rows, fields);
}
public java.sql.Clob getClob(int i) throws SQLException {
return new Jdbc3Clob(connection, getInt(i));
}
public java.sql.Blob getBlob(int i) throws SQLException {
return new Jdbc3Blob(connection, getInt(i));
}
public java.sql.Clob getClob(int i) throws SQLException
{
return new Jdbc3Clob(connection, getInt(i));
}
public java.sql.Blob getBlob(int i) throws SQLException
{
return new Jdbc3Blob(connection, getInt(i));
}
}
......@@ -2,11 +2,11 @@ package org.postgresql.jdbc3;
public class Jdbc3ResultSetMetaData extends org.postgresql.jdbc2.AbstractJdbc2ResultSetMetaData implements java.sql.ResultSetMetaData
{
public Jdbc3ResultSetMetaData(java.util.Vector rows, org.postgresql.Field[] fields)
{
super(rows, fields);
super(rows, fields);
}
}
......@@ -3,17 +3,17 @@ package org.postgresql.jdbc3;
import java.sql.*;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc3/Attic/Jdbc3Statement.java,v 1.1 2002/08/14 20:35:40 barry Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc3/Attic/Jdbc3Statement.java,v 1.2 2002/09/06 21:23:06 momjian Exp $
* This class implements the java.sql.Statement interface for JDBC3.
* However most of the implementation is really done in
* However most of the implementation is really done in
* org.postgresql.jdbc3.AbstractJdbc3Statement or one of it's parents
*/
public class Jdbc3Statement extends org.postgresql.jdbc3.AbstractJdbc3Statement implements java.sql.Statement
{
public Jdbc3Statement (Jdbc3Connection c)
{
super(c);
}
}
......@@ -92,12 +92,12 @@ public class LargeObject
/* Release large object resources during garbage cleanup */
protected void finalize() throws SQLException
{
//This code used to call close() however that was problematic
//because the scope of the fd is a transaction, thus if commit
//or rollback was called before garbage collection ran then
//the call to close would error out with an invalid large object
//handle. So this method now does nothing and lets the server
//handle cleanup when it ends the transaction.
//This code used to call close() however that was problematic
//because the scope of the fd is a transaction, thus if commit
//or rollback was called before garbage collection ran then
//the call to close would error out with an invalid large object
//handle. So this method now does nothing and lets the server
//handle cleanup when it ends the transaction.
}
/*
......
......@@ -104,21 +104,22 @@ public class LargeObjectManager
// This is an example of Fastpath.addFunctions();
//
ResultSet res = conn.createStatement().executeQuery("select proname, oid from pg_proc" +
" where proname = 'lo_open'" +
" or proname = 'lo_close'" +
" or proname = 'lo_creat'" +
" or proname = 'lo_unlink'" +
" or proname = 'lo_lseek'" +
" or proname = 'lo_tell'" +
" or proname = 'loread'" +
" or proname = 'lowrite'");
" where proname = 'lo_open'" +
" or proname = 'lo_close'" +
" or proname = 'lo_creat'" +
" or proname = 'lo_unlink'" +
" or proname = 'lo_lseek'" +
" or proname = 'lo_tell'" +
" or proname = 'loread'" +
" or proname = 'lowrite'");
if (res == null)
throw new PSQLException("postgresql.lo.init");
fp.addFunctions(res);
res.close();
if (Driver.logDebug) Driver.debug("Large Object initialised");
if (Driver.logDebug)
Driver.debug("Large Object initialised");
}
/*
......
......@@ -22,17 +22,17 @@ public class CallableStmtTest extends TestCase
{
con = TestUtil.openDB();
Statement stmt = con.createStatement ();
stmt.execute ("CREATE OR REPLACE FUNCTION testspg__getString (varchar) " +
"RETURNS varchar AS ' DECLARE inString alias for $1; begin "+
stmt.execute ("CREATE OR REPLACE FUNCTION testspg__getString (varchar) " +
"RETURNS varchar AS ' DECLARE inString alias for $1; begin " +
"return ''bob''; end; ' LANGUAGE 'plpgsql';");
stmt.execute ("CREATE OR REPLACE FUNCTION testspg__getDouble (float) " +
stmt.execute ("CREATE OR REPLACE FUNCTION testspg__getDouble (float) " +
"RETURNS float AS ' DECLARE inString alias for $1; begin " +
"return 42.42; end; ' LANGUAGE 'plpgsql';");
stmt.execute ("CREATE OR REPLACE FUNCTION testspg__getInt (int) RETURNS int " +
" AS 'DECLARE inString alias for $1; begin " +
"return 42; end;' LANGUAGE 'plpgsql';");
stmt.execute ("CREATE OR REPLACE FUNCTION testspg__getNumeric (numeric) " +
"RETURNS numeric AS ' DECLARE inString alias for $1; " +
" AS 'DECLARE inString alias for $1; begin " +
"return 42; end;' LANGUAGE 'plpgsql';");
stmt.execute ("CREATE OR REPLACE FUNCTION testspg__getNumeric (numeric) " +
"RETURNS numeric AS ' DECLARE inString alias for $1; " +
"begin return 42; end; ' LANGUAGE 'plpgsql';");
stmt.close ();
}
......@@ -54,7 +54,8 @@ public class CallableStmtTest extends TestCase
//testGetString ();
//}
public void testGetDouble () throws Throwable {
public void testGetDouble () throws Throwable
{
// System.out.println ("Testing CallableStmt Types.DOUBLE");
CallableStatement call = con.prepareCall (func + pkgName + "getDouble (?) }");
call.setDouble (2, (double)3.04);
......@@ -64,7 +65,8 @@ public class CallableStmtTest extends TestCase
assertTrue ("correct return from getString ()", result == 42.42);
}
public void testGetInt () throws Throwable {
public void testGetInt () throws Throwable
{
// System.out.println ("Testing CallableStmt Types.INTEGER");
CallableStatement call = con.prepareCall (func + pkgName + "getInt (?) }");
call.setInt (2, 4);
......@@ -74,18 +76,20 @@ public class CallableStmtTest extends TestCase
assertTrue ("correct return from getString ()", result == 42);
}
public void testGetNumeric () throws Throwable {
public void testGetNumeric () throws Throwable
{
// System.out.println ("Testing CallableStmt Types.NUMERIC");
CallableStatement call = con.prepareCall (func + pkgName + "getNumeric (?) }");
call.setBigDecimal (2, new java.math.BigDecimal(4));
call.registerOutParameter (1, Types.NUMERIC);
call.execute ();
java.math.BigDecimal result = call.getBigDecimal (1);
assertTrue ("correct return from getString ()",
assertTrue ("correct return from getString ()",
result.equals (new java.math.BigDecimal(42)));
}
public void testGetString () throws Throwable {
public void testGetString () throws Throwable
{
// System.out.println ("Testing CallableStmt Types.VARCHAR");
CallableStatement call = con.prepareCall (func + pkgName + "getString (?) }");
call.setString (2, "foo");
......@@ -96,20 +100,25 @@ public class CallableStmtTest extends TestCase
}
public void testBadStmt () throws Throwable {
public void testBadStmt () throws Throwable
{
tryOneBadStmt ("{ ?= " + pkgName + "getString (?) }");
tryOneBadStmt ("{ ?= call getString (?) ");
tryOneBadStmt ("{ = ? call getString (?); }");
}
protected void tryOneBadStmt (String sql) throws Throwable {
protected void tryOneBadStmt (String sql) throws Throwable
{
boolean wasCaught = false;
try {
try
{
CallableStatement call = con.prepareCall (sql);
} catch (SQLException e) {
}
catch (SQLException e)
{
wasCaught = true; // good -> this statement was missing something
}
assertTrue ("bad statment ('"+sql+"')was not caught", wasCaught);
assertTrue ("bad statment ('" + sql + "')was not caught", wasCaught);
}
}
......@@ -9,7 +9,7 @@ import java.sql.*;
*
* PS: Do you know how difficult it is to type on a train? ;-)
*
* $Id: DatabaseMetaDataTest.java,v 1.12 2002/08/23 20:45:49 barry Exp $
* $Id: DatabaseMetaDataTest.java,v 1.13 2002/09/06 21:23:06 momjian Exp $
*/
public class DatabaseMetaDataTest extends TestCase
......@@ -48,7 +48,7 @@ public class DatabaseMetaDataTest extends TestCase
ResultSet rs = dbmd.getTables( null, null, "test%", new String[] {"TABLE"});
assertTrue( rs.next() );
String tableName = rs.getString("TABLE_NAME");
String tableName = rs.getString("TABLE_NAME");
assertTrue( tableName.equals("testmetadata") );
rs.close();
......@@ -102,10 +102,10 @@ public class DatabaseMetaDataTest extends TestCase
assertTrue(dbmd.supportsMinimumSQLGrammar());
assertTrue(!dbmd.supportsCoreSQLGrammar());
assertTrue(!dbmd.supportsExtendedSQLGrammar());
if (((org.postgresql.jdbc1.AbstractJdbc1Connection)con).haveMinimumServerVersion("7.3"))
assertTrue(dbmd.supportsANSI92EntryLevelSQL());
else
assertTrue(!dbmd.supportsANSI92EntryLevelSQL());
if (((org.postgresql.jdbc1.AbstractJdbc1Connection)con).haveMinimumServerVersion("7.3"))
assertTrue(dbmd.supportsANSI92EntryLevelSQL());
else
assertTrue(!dbmd.supportsANSI92EntryLevelSQL());
assertTrue(!dbmd.supportsANSI92IntermediateSQL());
assertTrue(!dbmd.supportsANSI92FullSQL());
......@@ -232,124 +232,124 @@ public class DatabaseMetaDataTest extends TestCase
}
}
public void testCrossReference()
{
public void testCrossReference()
{
try
{
Connection con1 = TestUtil.openDB();
Connection con1 = TestUtil.openDB();
TestUtil.createTable( con1, "vv", "a int not null, b int not null, primary key ( a, b )" );
TestUtil.createTable( con1, "vv", "a int not null, b int not null, primary key ( a, b )" );
TestUtil.createTable( con1, "ww", "m int not null, n int not null, primary key ( m, n ), foreign key ( m, n ) references vv ( a, b )" );
TestUtil.createTable( con1, "ww", "m int not null, n int not null, primary key ( m, n ), foreign key ( m, n ) references vv ( a, b )" );
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
ResultSet rs = dbmd.getCrossReference(null, "", "vv", null, "", "ww" );
ResultSet rs = dbmd.getCrossReference(null, "", "vv", null, "", "ww" );
for (int j=1; rs.next(); j++ )
{
for (int j = 1; rs.next(); j++ )
{
String pkTableName = rs.getString( "PKTABLE_NAME" );
assertTrue ( pkTableName.equals("vv") );
String pkTableName = rs.getString( "PKTABLE_NAME" );
assertTrue ( pkTableName.equals("vv") );
String pkColumnName = rs.getString( "PKCOLUMN_NAME" );
assertTrue( pkColumnName.equals("a") || pkColumnName.equals("b"));
String pkColumnName = rs.getString( "PKCOLUMN_NAME" );
assertTrue( pkColumnName.equals("a") || pkColumnName.equals("b"));
String fkTableName = rs.getString( "FKTABLE_NAME" );
assertTrue( fkTableName.equals( "ww" ) );
String fkTableName = rs.getString( "FKTABLE_NAME" );
assertTrue( fkTableName.equals( "ww" ) );
String fkColumnName = rs.getString( "FKCOLUMN_NAME" );
assertTrue( fkColumnName.equals( "m" ) || fkColumnName.equals( "n" ) ) ;
String fkColumnName = rs.getString( "FKCOLUMN_NAME" );
assertTrue( fkColumnName.equals( "m" ) || fkColumnName.equals( "n" ) ) ;
String fkName = rs.getString( "FK_NAME" );
assertTrue( fkName.equals( "<unnamed>") );
String fkName = rs.getString( "FK_NAME" );
assertTrue( fkName.equals( "<unnamed>") );
String pkName = rs.getString( "PK_NAME" );
assertTrue( pkName.equals("vv_pkey") );
String pkName = rs.getString( "PK_NAME" );
assertTrue( pkName.equals("vv_pkey") );
int keySeq = rs.getInt( "KEY_SEQ" );
assertTrue( keySeq == j );
}
int keySeq = rs.getInt( "KEY_SEQ" );
assertTrue( keySeq == j );
}
TestUtil.dropTable( con1, "vv" );
TestUtil.dropTable( con1, "ww" );
TestUtil.dropTable( con1, "vv" );
TestUtil.dropTable( con1, "ww" );
}
catch (SQLException ex)
{
fail(ex.getMessage());
}
}
public void testForeignKeys()
{
}
public void testForeignKeys()
{
try
{
Connection con1 = TestUtil.openDB();
TestUtil.createTable( con1, "people", "id int4 primary key, name text" );
TestUtil.createTable( con1, "policy", "id int4 primary key, name text" );
Connection con1 = TestUtil.openDB();
TestUtil.createTable( con1, "people", "id int4 primary key, name text" );
TestUtil.createTable( con1, "policy", "id int4 primary key, name text" );
TestUtil.createTable( con1, "users", "id int4 primary key, people_id int4, policy_id int4,"+
"CONSTRAINT people FOREIGN KEY (people_id) references people(id),"+
"constraint policy FOREIGN KEY (policy_id) references policy(id)" );
TestUtil.createTable( con1, "users", "id int4 primary key, people_id int4, policy_id int4," +
"CONSTRAINT people FOREIGN KEY (people_id) references people(id)," +
"constraint policy FOREIGN KEY (policy_id) references policy(id)" );
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
ResultSet rs = dbmd.getImportedKeys(null, "", "users" );
int j = 0;
for (; rs.next(); j++ )
{
ResultSet rs = dbmd.getImportedKeys(null, "", "users" );
int j = 0;
for (; rs.next(); j++ )
{
String pkTableName = rs.getString( "PKTABLE_NAME" );
assertTrue ( pkTableName.equals("people") || pkTableName.equals("policy") );
String pkTableName = rs.getString( "PKTABLE_NAME" );
assertTrue ( pkTableName.equals("people") || pkTableName.equals("policy") );
String pkColumnName = rs.getString( "PKCOLUMN_NAME" );
assertTrue( pkColumnName.equals("id") );
String pkColumnName = rs.getString( "PKCOLUMN_NAME" );
assertTrue( pkColumnName.equals("id") );
String fkTableName = rs.getString( "FKTABLE_NAME" );
assertTrue( fkTableName.equals( "users" ) );
String fkTableName = rs.getString( "FKTABLE_NAME" );
assertTrue( fkTableName.equals( "users" ) );
String fkColumnName = rs.getString( "FKCOLUMN_NAME" );
assertTrue( fkColumnName.equals( "people_id" ) || fkColumnName.equals( "policy_id" ) ) ;
String fkColumnName = rs.getString( "FKCOLUMN_NAME" );
assertTrue( fkColumnName.equals( "people_id" ) || fkColumnName.equals( "policy_id" ) ) ;
String fkName = rs.getString( "FK_NAME" );
assertTrue( fkName.equals( "people") || fkName.equals( "policy" ) );
String fkName = rs.getString( "FK_NAME" );
assertTrue( fkName.equals( "people") || fkName.equals( "policy" ) );
String pkName = rs.getString( "PK_NAME" );
assertTrue( pkName.equals( "people_pkey") || pkName.equals( "policy_pkey" ) );
String pkName = rs.getString( "PK_NAME" );
assertTrue( pkName.equals( "people_pkey") || pkName.equals( "policy_pkey" ) );
}
}
assertTrue ( j== 2 );
assertTrue ( j == 2 );
rs = dbmd.getExportedKeys( null, "", "people" );
rs = dbmd.getExportedKeys( null, "", "people" );
// this is hacky, but it will serve the purpose
assertTrue ( rs.next() );
// this is hacky, but it will serve the purpose
assertTrue ( rs.next() );
assertTrue( rs.getString( "PKTABLE_NAME" ).equals( "people" ) );
assertTrue( rs.getString( "PKCOLUMN_NAME" ).equals( "id" ) );
assertTrue( rs.getString( "PKTABLE_NAME" ).equals( "people" ) );
assertTrue( rs.getString( "PKCOLUMN_NAME" ).equals( "id" ) );
assertTrue( rs.getString( "FKTABLE_NAME" ).equals( "users" ) );
assertTrue( rs.getString( "FKCOLUMN_NAME" ).equals( "people_id" ) );
assertTrue( rs.getString( "FKTABLE_NAME" ).equals( "users" ) );
assertTrue( rs.getString( "FKCOLUMN_NAME" ).equals( "people_id" ) );
assertTrue( rs.getString( "FK_NAME" ).equals( "people" ) );
assertTrue( rs.getString( "FK_NAME" ).equals( "people" ) );
TestUtil.dropTable( con1, "users" );
TestUtil.dropTable( con1, "people" );
TestUtil.dropTable( con1, "policy" );
TestUtil.dropTable( con1, "users" );
TestUtil.dropTable( con1, "people" );
TestUtil.dropTable( con1, "policy" );
}
catch (SQLException ex)
{
fail(ex.getMessage());
}
}
}
public void testTables()
{
try
......@@ -422,20 +422,20 @@ public class DatabaseMetaDataTest extends TestCase
{
try
{
assertTrue(con instanceof org.postgresql.PGConnection);
assertTrue(con instanceof org.postgresql.PGConnection);
org.postgresql.jdbc2.AbstractJdbc2Connection pc = (org.postgresql.jdbc2.AbstractJdbc2Connection) con;
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
assertTrue(dbmd.getDatabaseProductName().equals("PostgreSQL"));
//The test below doesn't make sense to me, it tests that
//the version of the driver = the version of the database it is connected to
//since the driver should be backwardly compatible this test is commented out
//The test below doesn't make sense to me, it tests that
//the version of the driver = the version of the database it is connected to
//since the driver should be backwardly compatible this test is commented out
//assertTrue(dbmd.getDatabaseProductVersion().startsWith(
// Integer.toString(pc.getDriver().getMajorVersion())
// + "."
// + Integer.toString(pc.getDriver().getMinorVersion())));
// Integer.toString(pc.getDriver().getMajorVersion())
// + "."
// + Integer.toString(pc.getDriver().getMinorVersion())));
assertTrue(dbmd.getDriverName().equals("PostgreSQL Native Driver"));
}
......
......@@ -6,7 +6,7 @@ import java.sql.*;
import java.math.BigDecimal;
/*
* $Id: JBuilderTest.java,v 1.6 2002/08/14 20:35:40 barry Exp $
* $Id: JBuilderTest.java,v 1.7 2002/09/06 21:23:06 momjian Exp $
*
* Some simple tests to check that the required components needed for JBuilder
* stay working
......@@ -26,7 +26,7 @@ public class JBuilderTest extends TestCase
Connection con = TestUtil.openDB();
TestUtil.createTable( con, "test_c",
"source text,cost money,imageid int4" );
"source text,cost money,imageid int4" );
TestUtil.closeDB(con);
}
......
......@@ -63,7 +63,7 @@ public class Jdbc2TestSuite extends TestSuite
suite.addTestSuite( UpdateableResultTest.class );
suite.addTestSuite( CallableStmtTest.class );
// That's all folks
return suite;
}
......
......@@ -5,7 +5,7 @@ import junit.framework.TestCase;
import java.sql.*;
/*
* $Id: MiscTest.java,v 1.7 2002/08/14 20:35:40 barry Exp $
* $Id: MiscTest.java,v 1.8 2002/09/06 21:23:06 momjian Exp $
*
* Some simple tests based on problems reported by users. Hopefully these will
* help prevent previous problems from re-occuring ;-)
......@@ -52,28 +52,29 @@ public class MiscTest extends TestCase
}
}
public void testError()
{
Connection con = TestUtil.openDB();
public void testError()
{
Connection con = TestUtil.openDB();
try
{
// transaction mode
con.setAutoCommit(false);
Statement stmt = con.createStatement();
stmt.execute("select 1/0");
// transaction mode
con.setAutoCommit(false);
Statement stmt = con.createStatement();
stmt.execute("select 1/0");
fail( "Should not execute this, as a SQLException s/b thrown" );
con.commit();
con.commit();
}
catch ( Exception ex )
{}
try
{
con.commit();
con.close();
}
try
{
con.commit();
con.close();
}catch ( Exception ex) {}
}
catch ( Exception ex)
{}
}
public void xtestLocking()
{
......@@ -90,7 +91,7 @@ public class MiscTest extends TestCase
con.setAutoCommit(false);
st.execute("lock table test_lock");
st2.executeUpdate( "insert into test_lock ( name ) values ('hello')" );
con.commit();
con.commit();
TestUtil.dropTable(con, "test_lock");
con.close();
}
......
......@@ -63,24 +63,24 @@ public class ResultSetTest extends TestCase
stmt.close();
}
public void testEmptyResult()
{
try
{
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM testrs where id=100");
rs.beforeFirst();
rs.afterLast();
assertTrue(!rs.first());
assertTrue(!rs.last());
assertTrue(!rs.next());
}
catch ( Exception ex )
{
fail( ex.getMessage() );
}
}
public void testEmptyResult()
{
try
{
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM testrs where id=100");
rs.beforeFirst();
rs.afterLast();
assertTrue(!rs.first());
assertTrue(!rs.last());
assertTrue(!rs.next());
}
catch ( Exception ex )
{
fail( ex.getMessage() );
}
}
}
......@@ -5,9 +5,9 @@ import junit.framework.TestCase;
import java.sql.*;
/*
* $Id: TimestampTest.java,v 1.8 2002/08/14 20:35:40 barry Exp $
* $Id: TimestampTest.java,v 1.9 2002/09/06 21:23:06 momjian Exp $
*
* Test get/setTimestamp for both timestamp with time zone and
* Test get/setTimestamp for both timestamp with time zone and
* timestamp without time zone datatypes
*
*/
......@@ -39,8 +39,8 @@ public class TimestampTest extends TestCase
/*
* Tests the timestamp methods in ResultSet on timestamp with time zone
* we insert a known string value (don't use setTimestamp) then see that
* we get back the same value from getTimestamp
* we insert a known string value (don't use setTimestamp) then see that
* we get back the same value from getTimestamp
*/
public void testGetTimestampWTZ()
{
......@@ -48,15 +48,15 @@ public class TimestampTest extends TestCase
{
Statement stmt = con.createStatement();
//Insert the three timestamp values in raw pg format
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWTZ_TABLE,"'" + TS1WTZ_PGFORMAT + "'")));
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWTZ_TABLE,"'" + TS2WTZ_PGFORMAT + "'")));
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWTZ_TABLE,"'" + TS3WTZ_PGFORMAT + "'")));
//Insert the three timestamp values in raw pg format
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWTZ_TABLE, "'" + TS1WTZ_PGFORMAT + "'")));
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWTZ_TABLE, "'" + TS2WTZ_PGFORMAT + "'")));
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWTZ_TABLE, "'" + TS3WTZ_PGFORMAT + "'")));
// Fall through helper
timestampTestWTZ();
timestampTestWTZ();
assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWTZ_TABLE));
assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWTZ_TABLE));
stmt.close();
}
......@@ -68,9 +68,9 @@ public class TimestampTest extends TestCase
/*
* Tests the timestamp methods in PreparedStatement on timestamp with time zone
* we insert a value using setTimestamp then see that
* we get back the same value from getTimestamp (which we know works as it was tested
* independently of setTimestamp
* we insert a value using setTimestamp then see that
* we get back the same value from getTimestamp (which we know works as it was tested
* independently of setTimestamp
*/
public void testSetTimestampWTZ()
{
......@@ -80,18 +80,18 @@ public class TimestampTest extends TestCase
PreparedStatement pstmt = con.prepareStatement(TestUtil.insertSQL(TSWTZ_TABLE, "?"));
pstmt.setTimestamp(1, TS1WTZ);
assertEquals(1, pstmt.executeUpdate());
assertEquals(1, pstmt.executeUpdate());
pstmt.setTimestamp(1, TS2WTZ);
assertEquals(1, pstmt.executeUpdate());
assertEquals(1, pstmt.executeUpdate());
pstmt.setTimestamp(1, TS3WTZ);
assertEquals(1, pstmt.executeUpdate());
assertEquals(1, pstmt.executeUpdate());
// Fall through helper
timestampTestWTZ();
assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWTZ_TABLE));
assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWTZ_TABLE));
pstmt.close();
stmt.close();
......@@ -104,8 +104,8 @@ public class TimestampTest extends TestCase
/*
* Tests the timestamp methods in ResultSet on timestamp without time zone
* we insert a known string value (don't use setTimestamp) then see that
* we get back the same value from getTimestamp
* we insert a known string value (don't use setTimestamp) then see that
* we get back the same value from getTimestamp
*/
public void testGetTimestampWOTZ()
{
......@@ -113,15 +113,15 @@ public class TimestampTest extends TestCase
{
Statement stmt = con.createStatement();
//Insert the three timestamp values in raw pg format
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWOTZ_TABLE,"'" + TS1WOTZ_PGFORMAT + "'")));
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWOTZ_TABLE,"'" + TS2WOTZ_PGFORMAT + "'")));
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWOTZ_TABLE,"'" + TS3WOTZ_PGFORMAT + "'")));
//Insert the three timestamp values in raw pg format
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWOTZ_TABLE, "'" + TS1WOTZ_PGFORMAT + "'")));
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWOTZ_TABLE, "'" + TS2WOTZ_PGFORMAT + "'")));
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWOTZ_TABLE, "'" + TS3WOTZ_PGFORMAT + "'")));
// Fall through helper
timestampTestWOTZ();
assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWOTZ_TABLE));
assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWOTZ_TABLE));
stmt.close();
}
......@@ -134,9 +134,9 @@ public class TimestampTest extends TestCase
/*
* Tests the timestamp methods in PreparedStatement on timestamp without time zone
* we insert a value using setTimestamp then see that
* we get back the same value from getTimestamp (which we know works as it was tested
* independently of setTimestamp
* we insert a value using setTimestamp then see that
* we get back the same value from getTimestamp (which we know works as it was tested
* independently of setTimestamp
*/
public void testSetTimestampWOTZ()
{
......@@ -146,18 +146,18 @@ public class TimestampTest extends TestCase
PreparedStatement pstmt = con.prepareStatement(TestUtil.insertSQL(TSWOTZ_TABLE, "?"));
pstmt.setTimestamp(1, TS1WOTZ);
assertEquals(1, pstmt.executeUpdate());
assertEquals(1, pstmt.executeUpdate());
pstmt.setTimestamp(1, TS2WOTZ);
assertEquals(1, pstmt.executeUpdate());
assertEquals(1, pstmt.executeUpdate());
pstmt.setTimestamp(1, TS3WOTZ);
assertEquals(1, pstmt.executeUpdate());
assertEquals(1, pstmt.executeUpdate());
// Fall through helper
timestampTestWOTZ();
assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWOTZ_TABLE));
assertEquals(3, stmt.executeUpdate("DELETE FROM " + TSWOTZ_TABLE));
pstmt.close();
stmt.close();
......@@ -178,22 +178,22 @@ public class TimestampTest extends TestCase
java.sql.Timestamp t;
rs = stmt.executeQuery("select ts from " + TSWTZ_TABLE + " order by ts");
assertNotNull(rs);
assertNotNull(rs);
assertTrue(rs.next());
t = rs.getTimestamp(1);
assertNotNull(t);
assertNotNull(t);
assertTrue(t.equals(TS1WTZ));
assertTrue(rs.next());
t = rs.getTimestamp(1);
assertNotNull(t);
assertNotNull(t);
assertTrue(t.equals(TS2WTZ));
assertTrue(rs.next());
t = rs.getTimestamp(1);
assertNotNull(t);
assertTrue(t.equals(TS3WTZ));
assertNotNull(t);
assertTrue(t.equals(TS3WTZ));
assertTrue(! rs.next()); // end of table. Fail if more entries exist.
......@@ -211,21 +211,21 @@ public class TimestampTest extends TestCase
java.sql.Timestamp t;
rs = stmt.executeQuery("select ts from " + TSWOTZ_TABLE + " order by ts");
assertNotNull(rs);
assertNotNull(rs);
assertTrue(rs.next());
t = rs.getTimestamp(1);
assertNotNull(t);
assertNotNull(t);
assertTrue(t.toString().equals(TS1WOTZ_JAVAFORMAT));
assertTrue(rs.next());
t = rs.getTimestamp(1);
assertNotNull(t);
assertNotNull(t);
assertTrue(t.toString().equals(TS2WOTZ_JAVAFORMAT));
assertTrue(rs.next());
t = rs.getTimestamp(1);
assertNotNull(t);
assertNotNull(t);
assertTrue(t.toString().equals(TS3WOTZ_JAVAFORMAT));
assertTrue(! rs.next()); // end of table. Fail if more entries exist.
......@@ -236,57 +236,63 @@ public class TimestampTest extends TestCase
private static java.sql.Timestamp getTimestamp(int y, int m, int d, int h, int mn, int se, int f, String tz)
{
java.sql.Timestamp l_return = null;
java.text.DateFormat l_df;
try {
String l_ts;
l_ts = TestUtil.fix(y, 4) + "-" +
TestUtil.fix(m, 2) + "-" +
TestUtil.fix(d, 2) + " " +
TestUtil.fix(h, 2) + ":" +
TestUtil.fix(mn, 2) + ":" +
TestUtil.fix(se, 2) + " ";
if (tz == null) {
l_df = new java.text.SimpleDateFormat("y-M-d H:m:s");
} else {
l_ts = l_ts + tz;
l_df = new java.text.SimpleDateFormat("y-M-d H:m:s z");
java.sql.Timestamp l_return = null;
java.text.DateFormat l_df;
try
{
String l_ts;
l_ts = TestUtil.fix(y, 4) + "-" +
TestUtil.fix(m, 2) + "-" +
TestUtil.fix(d, 2) + " " +
TestUtil.fix(h, 2) + ":" +
TestUtil.fix(mn, 2) + ":" +
TestUtil.fix(se, 2) + " ";
if (tz == null)
{
l_df = new java.text.SimpleDateFormat("y-M-d H:m:s");
}
else
{
l_ts = l_ts + tz;
l_df = new java.text.SimpleDateFormat("y-M-d H:m:s z");
}
java.util.Date l_date = l_df.parse(l_ts);
l_return = new java.sql.Timestamp(l_date.getTime());
l_return.setNanos(f);
}
java.util.Date l_date = l_df.parse(l_ts);
l_return = new java.sql.Timestamp(l_date.getTime());
l_return.setNanos(f);
} catch (Exception ex) {
fail(ex.getMessage());
}
return l_return;
catch (Exception ex)
{
fail(ex.getMessage());
}
return l_return;
}
private static final java.sql.Timestamp TS1WTZ = getTimestamp(1950, 2, 7, 15, 0, 0, 100000000, "PST");
private static final String TS1WTZ_PGFORMAT = "1950-02-07 15:00:00.1-08";
private static final java.sql.Timestamp TS2WTZ = getTimestamp(2000, 2, 7, 15, 0, 0, 120000000, "GMT");
private static final String TS2WTZ_PGFORMAT = "2000-02-07 15:00:00.12+00";
private static final java.sql.Timestamp TS1WTZ = getTimestamp(1950, 2, 7, 15, 0, 0, 100000000, "PST");
private static final String TS1WTZ_PGFORMAT = "1950-02-07 15:00:00.1-08";
private static final java.sql.Timestamp TS2WTZ = getTimestamp(2000, 2, 7, 15, 0, 0, 120000000, "GMT");
private static final String TS2WTZ_PGFORMAT = "2000-02-07 15:00:00.12+00";
private static final java.sql.Timestamp TS3WTZ = getTimestamp(2000, 7, 7, 15, 0, 0, 123000000, "GMT");
private static final String TS3WTZ_PGFORMAT = "2000-07-07 15:00:00.123+00";
private static final java.sql.Timestamp TS3WTZ = getTimestamp(2000, 7, 7, 15, 0, 0, 123000000, "GMT");
private static final String TS3WTZ_PGFORMAT = "2000-07-07 15:00:00.123+00";
private static final java.sql.Timestamp TS1WOTZ = getTimestamp(1950, 2, 7, 15, 0, 0, 100000000, null);
private static final String TS1WOTZ_PGFORMAT = "1950-02-07 15:00:00.1";
private static final String TS1WOTZ_JAVAFORMAT = "1950-02-07 15:00:00.1";
private static final java.sql.Timestamp TS1WOTZ = getTimestamp(1950, 2, 7, 15, 0, 0, 100000000, null);
private static final String TS1WOTZ_PGFORMAT = "1950-02-07 15:00:00.1";
private static final String TS1WOTZ_JAVAFORMAT = "1950-02-07 15:00:00.1";
private static final java.sql.Timestamp TS2WOTZ = getTimestamp(2000, 2, 7, 15, 0, 0, 120000000, null);
private static final String TS2WOTZ_PGFORMAT = "2000-02-07 15:00:00.12";
//there is probably a bug here in that this needs to be .1 instead of .12, but I couldn't find it now
private static final String TS2WOTZ_JAVAFORMAT = "2000-02-07 15:00:00.1";
private static final java.sql.Timestamp TS2WOTZ = getTimestamp(2000, 2, 7, 15, 0, 0, 120000000, null);
private static final String TS2WOTZ_PGFORMAT = "2000-02-07 15:00:00.12";
//there is probably a bug here in that this needs to be .1 instead of .12, but I couldn't find it now
private static final String TS2WOTZ_JAVAFORMAT = "2000-02-07 15:00:00.1";
private static final java.sql.Timestamp TS3WOTZ = getTimestamp(2000, 7, 7, 15, 0, 0, 123000000, null);
private static final String TS3WOTZ_PGFORMAT = "2000-07-07 15:00:00.123";
//there is probably a bug here in that this needs to be .12 instead of .123, but I couldn't find it now
private static final String TS3WOTZ_JAVAFORMAT = "2000-07-07 15:00:00.12";
private static final java.sql.Timestamp TS3WOTZ = getTimestamp(2000, 7, 7, 15, 0, 0, 123000000, null);
private static final String TS3WOTZ_PGFORMAT = "2000-07-07 15:00:00.123";
//there is probably a bug here in that this needs to be .12 instead of .123, but I couldn't find it now
private static final String TS3WOTZ_JAVAFORMAT = "2000-07-07 15:00:00.12";
private static final String TSWTZ_TABLE = "testtimestampwtz";
private static final String TSWOTZ_TABLE = "testtimestampwotz";
private static final String TSWTZ_TABLE = "testtimestampwtz";
private static final String TSWOTZ_TABLE = "testtimestampwotz";
}
......@@ -16,120 +16,121 @@ import org.postgresql.test.TestUtil;
public class UpdateableResultTest extends TestCase
{
public UpdateableResultTest( String name )
{
super( name );
}
public void testUpdateable()
{
try
{
Connection con = TestUtil.openDB();
TestUtil.createTable(con, "updateable","id int primary key, name text, notselected text");
TestUtil.createTable(con, "second","id1 int primary key, name1 text");
// put some dummy data into second
Statement st2 = con.createStatement();
st2.execute( "insert into second values (1,'anyvalue' )");
st2.close();
Statement st = con.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE );
ResultSet rs = st.executeQuery( "select * from updateable");
assertNotNull( rs );
rs.moveToInsertRow();
rs.updateInt( 1, 1 );
rs.updateString( 2, "jake" );
rs.updateString( 3, "avalue" );
rs.insertRow();
rs.first();
rs.updateInt( "id",2 );
rs.updateString( "name","dave" );
rs.updateRow();
assertTrue( rs.getInt("id") == 2 );
assertTrue( rs.getString("name").equals("dave"));
assertTrue( rs.getString("notselected").equals("avalue") );
rs.deleteRow();
rs.moveToInsertRow();
rs.updateInt("id",3);
rs.updateString("name", "paul");
rs.insertRow();
rs.refreshRow();
assertTrue( rs.getInt("id") == 3 );
assertTrue( rs.getString("name").equals("paul"));
assertTrue( rs.getString("notselected") == null );
rs.close();
rs = st.executeQuery("select id1, id, name, name1 from updateable, second" );
try
{
while( rs.next() )
{
rs.updateInt( "id",2 );
rs.updateString( "name","dave" );
rs.updateRow();
}
assertTrue( "should not get here, update should fail", false );
}
catch (SQLException ex){}
try
{
rs = st.executeQuery("select oid,* from updateable");
if ( rs.first() )
{
rs.updateInt( "id", 3 );
rs.updateString( "name", "dave3");
rs.updateRow();
assertTrue(rs.getInt("id") == 3 );
assertTrue(rs.getString("name").equals("dave3"));
rs.moveToInsertRow();
rs.updateInt( "id", 4 );
rs.updateString( "name", "dave4" );
rs.insertRow();
rs.updateInt("id", 5 );
rs.updateString( "name", "dave5" );
rs.insertRow();
rs.moveToCurrentRow();
assertTrue(rs.getInt("id") == 3 );
assertTrue(rs.getString("name").equals("dave3"));
assertTrue( rs.next() );
assertTrue(rs.getInt("id") == 4 );
assertTrue(rs.getString("name").equals("dave4"));
assertTrue( rs.next() );
assertTrue(rs.getInt("id") == 5 );
assertTrue(rs.getString("name").equals("dave5"));
}
}
catch(SQLException ex)
{
fail(ex.getMessage());
}
st.close();
TestUtil.dropTable( con,"updateable" );
TestUtil.closeDB( con );
}
catch (Exception ex)
{
fail(ex.getMessage());
}
}
public UpdateableResultTest( String name )
{
super( name );
}
public void testUpdateable()
{
try
{
Connection con = TestUtil.openDB();
TestUtil.createTable(con, "updateable", "id int primary key, name text, notselected text");
TestUtil.createTable(con, "second", "id1 int primary key, name1 text");
// put some dummy data into second
Statement st2 = con.createStatement();
st2.execute( "insert into second values (1,'anyvalue' )");
st2.close();
Statement st = con.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE );
ResultSet rs = st.executeQuery( "select * from updateable");
assertNotNull( rs );
rs.moveToInsertRow();
rs.updateInt( 1, 1 );
rs.updateString( 2, "jake" );
rs.updateString( 3, "avalue" );
rs.insertRow();
rs.first();
rs.updateInt( "id", 2 );
rs.updateString( "name", "dave" );
rs.updateRow();
assertTrue( rs.getInt("id") == 2 );
assertTrue( rs.getString("name").equals("dave"));
assertTrue( rs.getString("notselected").equals("avalue") );
rs.deleteRow();
rs.moveToInsertRow();
rs.updateInt("id", 3);
rs.updateString("name", "paul");
rs.insertRow();
rs.refreshRow();
assertTrue( rs.getInt("id") == 3 );
assertTrue( rs.getString("name").equals("paul"));
assertTrue( rs.getString("notselected") == null );
rs.close();
rs = st.executeQuery("select id1, id, name, name1 from updateable, second" );
try
{
while ( rs.next() )
{
rs.updateInt( "id", 2 );
rs.updateString( "name", "dave" );
rs.updateRow();
}
assertTrue( "should not get here, update should fail", false );
}
catch (SQLException ex)
{}
try
{
rs = st.executeQuery("select oid,* from updateable");
if ( rs.first() )
{
rs.updateInt( "id", 3 );
rs.updateString( "name", "dave3");
rs.updateRow();
assertTrue(rs.getInt("id") == 3 );
assertTrue(rs.getString("name").equals("dave3"));
rs.moveToInsertRow();
rs.updateInt( "id", 4 );
rs.updateString( "name", "dave4" );
rs.insertRow();
rs.updateInt("id", 5 );
rs.updateString( "name", "dave5" );
rs.insertRow();
rs.moveToCurrentRow();
assertTrue(rs.getInt("id") == 3 );
assertTrue(rs.getString("name").equals("dave3"));
assertTrue( rs.next() );
assertTrue(rs.getInt("id") == 4 );
assertTrue(rs.getString("name").equals("dave4"));
assertTrue( rs.next() );
assertTrue(rs.getInt("id") == 5 );
assertTrue(rs.getString("name").equals("dave5"));
}
}
catch (SQLException ex)
{
fail(ex.getMessage());
}
st.close();
TestUtil.dropTable( con, "updateable" );
TestUtil.closeDB( con );
}
catch (Exception ex)
{
fail(ex.getMessage());
}
}
}
......@@ -10,151 +10,179 @@ import java.sql.*;
/**
* Common tests for all the BaseDataSource implementations. This is
* a small variety to make sure that a connection can be opened and
* some basic queries run. The different BaseDataSource subclasses
* some basic queries run. The different BaseDataSource subclasses
* have different subclasses of this which add additional custom
* tests.
*
* @author Aaron Mulder (ammulder@chariotsolutions.com)
* @version $Revision: 1.1 $
* @version $Revision: 1.2 $
*/
public abstract class BaseDataSourceTest extends TestCase {
protected Connection con;
protected BaseDataSource bds;
public abstract class BaseDataSourceTest extends TestCase
{
protected Connection con;
protected BaseDataSource bds;
/**
* Constructor required by JUnit
*/
public BaseDataSourceTest(String name) {
super(name);
}
/**
* Constructor required by JUnit
*/
public BaseDataSourceTest(String name)
{
super(name);
}
/**
* Creates a test table using a standard connection (not from a
* DataSource).
*/
protected void setUp() throws Exception {
con = JDBC2Tests.openDB();
JDBC2Tests.createTable(con, "poolingtest", "id int4 not null primary key, name varchar(50)");
Statement stmt = con.createStatement();
stmt.executeUpdate("INSERT INTO poolingtest VALUES (1, 'Test Row 1')");
stmt.executeUpdate("INSERT INTO poolingtest VALUES (2, 'Test Row 2')");
JDBC2Tests.closeDB(con);
}
/**
* Creates a test table using a standard connection (not from a
* DataSource).
*/
protected void setUp() throws Exception
{
con = JDBC2Tests.openDB();
JDBC2Tests.createTable(con, "poolingtest", "id int4 not null primary key, name varchar(50)");
Statement stmt = con.createStatement();
stmt.executeUpdate("INSERT INTO poolingtest VALUES (1, 'Test Row 1')");
stmt.executeUpdate("INSERT INTO poolingtest VALUES (2, 'Test Row 2')");
JDBC2Tests.closeDB(con);
}
/**
* Removes the test table using a standard connection (not from
* a DataSource)
*/
protected void tearDown() throws Exception {
con = JDBC2Tests.openDB();
JDBC2Tests.dropTable(con, "poolingtest");
JDBC2Tests.closeDB(con);
}
/**
* Removes the test table using a standard connection (not from
* a DataSource)
*/
protected void tearDown() throws Exception
{
con = JDBC2Tests.openDB();
JDBC2Tests.dropTable(con, "poolingtest");
JDBC2Tests.closeDB(con);
}
/**
* Gets a connection from the current BaseDataSource
*/
protected Connection getDataSourceConnection() throws SQLException {
initializeDataSource();
return bds.getConnection();
}
/**
* Gets a connection from the current BaseDataSource
*/
protected Connection getDataSourceConnection() throws SQLException
{
initializeDataSource();
return bds.getConnection();
}
/**
* Creates an instance of the current BaseDataSource for
* testing. Must be customized by each subclass.
*/
protected abstract void initializeDataSource();
/**
* Creates an instance of the current BaseDataSource for
* testing. Must be customized by each subclass.
*/
protected abstract void initializeDataSource();
/**
* Test to make sure you can instantiate and configure the
* appropriate DataSource
*/
public void testCreateDataSource() {
initializeDataSource();
}
/**
* Test to make sure you can instantiate and configure the
* appropriate DataSource
*/
public void testCreateDataSource()
{
initializeDataSource();
}
/**
* Test to make sure you can get a connection from the DataSource,
* which in turn means the DataSource was able to open it.
*/
public void testGetConnection() {
try {
con = getDataSourceConnection();
con.close();
} catch (SQLException e) {
fail(e.getMessage());
}
}
/**
* Test to make sure you can get a connection from the DataSource,
* which in turn means the DataSource was able to open it.
*/
public void testGetConnection()
{
try
{
con = getDataSourceConnection();
con.close();
}
catch (SQLException e)
{
fail(e.getMessage());
}
}
/**
* A simple test to make sure you can execute SQL using the
* Connection from the DataSource
*/
public void testUseConnection() {
try {
con = getDataSourceConnection();
Statement st = con.createStatement();
ResultSet rs = st.executeQuery("SELECT COUNT(*) FROM poolingtest");
if(rs.next()) {
int count = rs.getInt(1);
if(rs.next()) {
fail("Should only have one row in SELECT COUNT result set");
}
if(count != 2) {
fail("Count returned "+count+" expecting 2");
}
} else {
fail("Should have one row in SELECT COUNT result set");
}
rs.close();
st.close();
con.close();
} catch (SQLException e) {
fail(e.getMessage());
}
}
/**
* A simple test to make sure you can execute SQL using the
* Connection from the DataSource
*/
public void testUseConnection()
{
try
{
con = getDataSourceConnection();
Statement st = con.createStatement();
ResultSet rs = st.executeQuery("SELECT COUNT(*) FROM poolingtest");
if (rs.next())
{
int count = rs.getInt(1);
if (rs.next())
{
fail("Should only have one row in SELECT COUNT result set");
}
if (count != 2)
{
fail("Count returned " + count + " expecting 2");
}
}
else
{
fail("Should have one row in SELECT COUNT result set");
}
rs.close();
st.close();
con.close();
}
catch (SQLException e)
{
fail(e.getMessage());
}
}
/**
* A test to make sure you can execute DDL SQL using the
* Connection from the DataSource.
*/
public void testDdlOverConnection() {
try {
con = getDataSourceConnection();
JDBC2Tests.dropTable(con, "poolingtest");
JDBC2Tests.createTable(con, "poolingtest", "id int4 not null primary key, name varchar(50)");
con.close();
} catch (SQLException e) {
fail(e.getMessage());
}
}
/**
* A test to make sure you can execute DDL SQL using the
* Connection from the DataSource.
*/
public void testDdlOverConnection()
{
try
{
con = getDataSourceConnection();
JDBC2Tests.dropTable(con, "poolingtest");
JDBC2Tests.createTable(con, "poolingtest", "id int4 not null primary key, name varchar(50)");
con.close();
}
catch (SQLException e)
{
fail(e.getMessage());
}
}
/**
* A test to make sure the connections are not being pooled by the
* current DataSource. Obviously need to be overridden in the case
* of a pooling Datasource.
*/
public void testNotPooledConnection() {
try {
con = getDataSourceConnection();
String name = con.toString();
con.close();
con = getDataSourceConnection();
String name2 = con.toString();
con.close();
assertTrue(!name.equals(name2));
} catch (SQLException e) {
fail(e.getMessage());
}
}
/**
* A test to make sure the connections are not being pooled by the
* current DataSource. Obviously need to be overridden in the case
* of a pooling Datasource.
*/
public void testNotPooledConnection()
{
try
{
con = getDataSourceConnection();
String name = con.toString();
con.close();
con = getDataSourceConnection();
String name2 = con.toString();
con.close();
assertTrue(!name.equals(name2));
}
catch (SQLException e)
{
fail(e.getMessage());
}
}
/**
* Eventually, we must test stuffing the DataSource in JNDI and
* then getting it back out and make sure it's still usable. This
* should ideally test both Serializable and Referenceable
* mechanisms. Will probably be multiple tests when implemented.
*/
public void testJndi() {
// TODO: Put the DS in JNDI, retrieve it, and try some of this stuff again
}
/**
* Eventually, we must test stuffing the DataSource in JNDI and
* then getting it back out and make sure it's still usable. This
* should ideally test both Serializable and Referenceable
* mechanisms. Will probably be multiple tests when implemented.
*/
public void testJndi()
{
// TODO: Put the DS in JNDI, retrieve it, and try some of this stuff again
}
}
......@@ -11,317 +11,382 @@ import java.sql.*;
* interface to the PooledConnection is through the CPDS.
*
* @author Aaron Mulder (ammulder@chariotsolutions.com)
* @version $Revision: 1.1 $
* @version $Revision: 1.2 $
*/
public class ConnectionPoolTest extends BaseDataSourceTest {
/**
* Constructor required by JUnit
*/
public ConnectionPoolTest(String name) {
super(name);
}
public class ConnectionPoolTest extends BaseDataSourceTest
{
/**
* Constructor required by JUnit
*/
public ConnectionPoolTest(String name)
{
super(name);
}
/**
* Creates and configures a ConnectionPool
*/
protected void initializeDataSource() {
if(bds == null) {
bds = new ConnectionPool();
String db = JDBC2Tests.getURL();
if(db.indexOf('/') > -1) {
db = db.substring(db.lastIndexOf('/')+1);
} else if(db.indexOf(':') > -1) {
db = db.substring(db.lastIndexOf(':')+1);
}
bds.setDatabaseName(db);
bds.setUser(JDBC2Tests.getUser());
bds.setPassword(JDBC2Tests.getPassword());
}
}
/**
* Creates and configures a ConnectionPool
*/
protected void initializeDataSource()
{
if (bds == null)
{
bds = new ConnectionPool();
String db = JDBC2Tests.getURL();
if (db.indexOf('/') > -1)
{
db = db.substring(db.lastIndexOf('/') + 1);
}
else if (db.indexOf(':') > -1)
{
db = db.substring(db.lastIndexOf(':') + 1);
}
bds.setDatabaseName(db);
bds.setUser(JDBC2Tests.getUser());
bds.setPassword(JDBC2Tests.getPassword());
}
}
/**
* Though the normal client interface is to grab a Connection, in
* order to test the middleware/server interface, we need to deal
* with PooledConnections. Some tests use each.
*/
protected PooledConnection getPooledConnection() throws SQLException {
initializeDataSource();
return ((ConnectionPool)bds).getPooledConnection();
}
/**
* Though the normal client interface is to grab a Connection, in
* order to test the middleware/server interface, we need to deal
* with PooledConnections. Some tests use each.
*/
protected PooledConnection getPooledConnection() throws SQLException
{
initializeDataSource();
return ((ConnectionPool)bds).getPooledConnection();
}
/**
* Instead of just fetching a Connection from the ConnectionPool,
* get a PooledConnection, add a listener to close it when the
* Connection is closed, and then get the Connection. Without
* the listener the PooledConnection (and thus the physical connection)
* would never by closed. Probably not a disaster during testing, but
* you never know.
*/
protected Connection getDataSourceConnection() throws SQLException {
initializeDataSource();
final PooledConnection pc = getPooledConnection();
// Since the pooled connection won't be reused in these basic tests, close it when the connection is closed
pc.addConnectionEventListener(new ConnectionEventListener() {
public void connectionClosed(ConnectionEvent event) {
try {
pc.close();
} catch (SQLException e) {
fail("Unable to close PooledConnection: "+e);
}
}
/**
* Instead of just fetching a Connection from the ConnectionPool,
* get a PooledConnection, add a listener to close it when the
* Connection is closed, and then get the Connection. Without
* the listener the PooledConnection (and thus the physical connection)
* would never by closed. Probably not a disaster during testing, but
* you never know.
*/
protected Connection getDataSourceConnection() throws SQLException
{
initializeDataSource();
final PooledConnection pc = getPooledConnection();
// Since the pooled connection won't be reused in these basic tests, close it when the connection is closed
pc.addConnectionEventListener(new ConnectionEventListener()
{
public void connectionClosed(ConnectionEvent event)
{
try
{
pc.close();
}
catch (SQLException e)
{
fail("Unable to close PooledConnection: " + e);
}
}
public void connectionErrorOccurred(ConnectionEvent event) {
}
});
return pc.getConnection();
}
public void connectionErrorOccurred(ConnectionEvent event)
{}
}
);
return pc.getConnection();
}
/**
* Makes sure that if you get a connection from a PooledConnection,
* close it, and then get another one, you're really using the same
* physical connection. Depends on the implementation of toString
* for the connection handle.
*/
public void testPoolReuse() {
try {
PooledConnection pc = getPooledConnection();
con = pc.getConnection();
String name = con.toString();
con.close();
con = pc.getConnection();
String name2 = con.toString();
con.close();
pc.close();
assertTrue("Physical connection doesn't appear to be reused across PooledConnection wrappers", name.equals(name2));
} catch (SQLException e) {
fail(e.getMessage());
}
}
/**
* Makes sure that if you get a connection from a PooledConnection,
* close it, and then get another one, you're really using the same
* physical connection. Depends on the implementation of toString
* for the connection handle.
*/
public void testPoolReuse()
{
try
{
PooledConnection pc = getPooledConnection();
con = pc.getConnection();
String name = con.toString();
con.close();
con = pc.getConnection();
String name2 = con.toString();
con.close();
pc.close();
assertTrue("Physical connection doesn't appear to be reused across PooledConnection wrappers", name.equals(name2));
}
catch (SQLException e)
{
fail(e.getMessage());
}
}
/**
* Makes sure that when you request a connection from the
* PooledConnection, and previous connection it might have given
* out is closed. See JDBC 2.0 Optional Package spec section
* 6.2.3
*/
public void testPoolCloseOldWrapper() {
try {
PooledConnection pc = getPooledConnection();
con = pc.getConnection();
Connection con2 = pc.getConnection();
try {
con.createStatement();
fail("Original connection wrapper should be closed when new connection wrapper is generated");
} catch(SQLException e) {}
try {
con.close();
fail("Original connection wrapper should be closed when new connection wrapper is generated");
} catch(SQLException e) {}
con2.close();
pc.close();
} catch (SQLException e) {
fail(e.getMessage());
}
}
/**
* Makes sure that when you request a connection from the
* PooledConnection, and previous connection it might have given
* out is closed. See JDBC 2.0 Optional Package spec section
* 6.2.3
*/
public void testPoolCloseOldWrapper()
{
try
{
PooledConnection pc = getPooledConnection();
con = pc.getConnection();
Connection con2 = pc.getConnection();
try
{
con.createStatement();
fail("Original connection wrapper should be closed when new connection wrapper is generated");
}
catch (SQLException e)
{}
try
{
con.close();
fail("Original connection wrapper should be closed when new connection wrapper is generated");
}
catch (SQLException e)
{}
con2.close();
pc.close();
}
catch (SQLException e)
{
fail(e.getMessage());
}
}
/**
* Makes sure that if you get two connection wrappers from the same
* PooledConnection, they are different, even though the represent
* the same physical connection. See JDBC 2.0 Optional Pacakge spec
* section 6.2.2
*/
public void testPoolNewWrapper() {
try {
PooledConnection pc = getPooledConnection();
con = pc.getConnection();
Connection con2 = pc.getConnection();
con2.close();
pc.close();
assertTrue("Two calls to PooledConnection.getConnection should not return the same connection wrapper", con != con2);
} catch (SQLException e) {
fail(e.getMessage());
}
}
/**
* Makes sure that if you get two connection wrappers from the same
* PooledConnection, they are different, even though the represent
* the same physical connection. See JDBC 2.0 Optional Pacakge spec
* section 6.2.2
*/
public void testPoolNewWrapper()
{
try
{
PooledConnection pc = getPooledConnection();
con = pc.getConnection();
Connection con2 = pc.getConnection();
con2.close();
pc.close();
assertTrue("Two calls to PooledConnection.getConnection should not return the same connection wrapper", con != con2);
}
catch (SQLException e)
{
fail(e.getMessage());
}
}
/**
* Makes sure that exactly one close event is fired for each time a
* connection handle is closed. Also checks that events are not
* fired after a given handle has been closed once.
*/
public void testCloseEvent() {
try {
PooledConnection pc = getPooledConnection();
CountClose cc = new CountClose();
pc.addConnectionEventListener(cc);
con = pc.getConnection();
assertTrue(cc.getCount() == 0);
assertTrue(cc.getErrorCount() == 0);
con.close();
assertTrue(cc.getCount() == 1);
assertTrue(cc.getErrorCount() == 0);
con = pc.getConnection();
assertTrue(cc.getCount() == 1);
assertTrue(cc.getErrorCount() == 0);
con.close();
assertTrue(cc.getCount() == 2);
assertTrue(cc.getErrorCount() == 0);
try {
con.close();
fail("Should not be able to close a connection wrapper twice");
} catch (SQLException e) {}
assertTrue(cc.getCount() == 2);
assertTrue(cc.getErrorCount() == 0);
pc.close();
} catch (SQLException e) {
fail(e.getMessage());
}
}
/**
* Makes sure that exactly one close event is fired for each time a
* connection handle is closed. Also checks that events are not
* fired after a given handle has been closed once.
*/
public void testCloseEvent()
{
try
{
PooledConnection pc = getPooledConnection();
CountClose cc = new CountClose();
pc.addConnectionEventListener(cc);
con = pc.getConnection();
assertTrue(cc.getCount() == 0);
assertTrue(cc.getErrorCount() == 0);
con.close();
assertTrue(cc.getCount() == 1);
assertTrue(cc.getErrorCount() == 0);
con = pc.getConnection();
assertTrue(cc.getCount() == 1);
assertTrue(cc.getErrorCount() == 0);
con.close();
assertTrue(cc.getCount() == 2);
assertTrue(cc.getErrorCount() == 0);
try
{
con.close();
fail("Should not be able to close a connection wrapper twice");
}
catch (SQLException e)
{}
assertTrue(cc.getCount() == 2);
assertTrue(cc.getErrorCount() == 0);
pc.close();
}
catch (SQLException e)
{
fail(e.getMessage());
}
}
/**
* Makes sure that close events are not fired after a listener has
* been removed.
*/
public void testNoCloseEvent() {
try {
PooledConnection pc = getPooledConnection();
CountClose cc = new CountClose();
pc.addConnectionEventListener(cc);
con = pc.getConnection();
assertTrue(cc.getCount() == 0);
assertTrue(cc.getErrorCount() == 0);
con.close();
assertTrue(cc.getCount() == 1);
assertTrue(cc.getErrorCount() == 0);
pc.removeConnectionEventListener(cc);
con = pc.getConnection();
assertTrue(cc.getCount() == 1);
assertTrue(cc.getErrorCount() == 0);
con.close();
assertTrue(cc.getCount() == 1);
assertTrue(cc.getErrorCount() == 0);
} catch (SQLException e) {
fail(e.getMessage());
}
}
/**
* Makes sure that close events are not fired after a listener has
* been removed.
*/
public void testNoCloseEvent()
{
try
{
PooledConnection pc = getPooledConnection();
CountClose cc = new CountClose();
pc.addConnectionEventListener(cc);
con = pc.getConnection();
assertTrue(cc.getCount() == 0);
assertTrue(cc.getErrorCount() == 0);
con.close();
assertTrue(cc.getCount() == 1);
assertTrue(cc.getErrorCount() == 0);
pc.removeConnectionEventListener(cc);
con = pc.getConnection();
assertTrue(cc.getCount() == 1);
assertTrue(cc.getErrorCount() == 0);
con.close();
assertTrue(cc.getCount() == 1);
assertTrue(cc.getErrorCount() == 0);
}
catch (SQLException e)
{
fail(e.getMessage());
}
}
/**
* Makes sure that a listener can be removed while dispatching
* events. Sometimes this causes a ConcurrentModificationException
* or something.
*/
public void testInlineCloseEvent() {
try {
PooledConnection pc = getPooledConnection();
RemoveClose rc1 = new RemoveClose();
RemoveClose rc2 = new RemoveClose();
RemoveClose rc3 = new RemoveClose();
pc.addConnectionEventListener(rc1);
pc.addConnectionEventListener(rc2);
pc.addConnectionEventListener(rc3);
con = pc.getConnection();
con.close();
con = pc.getConnection();
con.close();
} catch (Exception e) {
fail(e.getMessage());
}
}
/**
* Makes sure that a listener can be removed while dispatching
* events. Sometimes this causes a ConcurrentModificationException
* or something.
*/
public void testInlineCloseEvent()
{
try
{
PooledConnection pc = getPooledConnection();
RemoveClose rc1 = new RemoveClose();
RemoveClose rc2 = new RemoveClose();
RemoveClose rc3 = new RemoveClose();
pc.addConnectionEventListener(rc1);
pc.addConnectionEventListener(rc2);
pc.addConnectionEventListener(rc3);
con = pc.getConnection();
con.close();
con = pc.getConnection();
con.close();
}
catch (Exception e)
{
fail(e.getMessage());
}
}
/**
* Tests that a close event is not generated when a connection
* handle is closed automatically due to a new connection handle
* being opened for the same PooledConnection. See JDBC 2.0
* Optional Package spec section 6.3
*/
public void testAutomaticCloseEvent() {
try {
PooledConnection pc = getPooledConnection();
CountClose cc = new CountClose();
pc.addConnectionEventListener(cc);
con = pc.getConnection();
assertTrue(cc.getCount() == 0);
assertTrue(cc.getErrorCount() == 0);
con.close();
assertTrue(cc.getCount() == 1);
assertTrue(cc.getErrorCount() == 0);
con = pc.getConnection();
assertTrue(cc.getCount() == 1);
assertTrue(cc.getErrorCount() == 0);
// Open a 2nd connection, causing the first to be closed. No even should be generated.
Connection con2 = pc.getConnection();
assertTrue("Connection handle was not closed when new handle was opened", con.isClosed());
assertTrue(cc.getCount() == 1);
assertTrue(cc.getErrorCount() == 0);
con2.close();
assertTrue(cc.getCount() == 2);
assertTrue(cc.getErrorCount() == 0);
pc.close();
} catch (SQLException e) {
fail(e.getMessage());
}
}
/**
* Tests that a close event is not generated when a connection
* handle is closed automatically due to a new connection handle
* being opened for the same PooledConnection. See JDBC 2.0
* Optional Package spec section 6.3
*/
public void testAutomaticCloseEvent()
{
try
{
PooledConnection pc = getPooledConnection();
CountClose cc = new CountClose();
pc.addConnectionEventListener(cc);
con = pc.getConnection();
assertTrue(cc.getCount() == 0);
assertTrue(cc.getErrorCount() == 0);
con.close();
assertTrue(cc.getCount() == 1);
assertTrue(cc.getErrorCount() == 0);
con = pc.getConnection();
assertTrue(cc.getCount() == 1);
assertTrue(cc.getErrorCount() == 0);
// Open a 2nd connection, causing the first to be closed. No even should be generated.
Connection con2 = pc.getConnection();
assertTrue("Connection handle was not closed when new handle was opened", con.isClosed());
assertTrue(cc.getCount() == 1);
assertTrue(cc.getErrorCount() == 0);
con2.close();
assertTrue(cc.getCount() == 2);
assertTrue(cc.getErrorCount() == 0);
pc.close();
}
catch (SQLException e)
{
fail(e.getMessage());
}
}
/**
* Makes sure the isClosed method on a connection wrapper does what
* you'd expect. Checks the usual case, as well as automatic
* closure when a new handle is opened on the same physical connection.
*/
public void testIsClosed() {
try {
PooledConnection pc = getPooledConnection();
Connection con = pc.getConnection();
assertTrue(!con.isClosed());
con.close();
assertTrue(con.isClosed());
con = pc.getConnection();
Connection con2 = pc.getConnection();
assertTrue(con.isClosed());
assertTrue(!con2.isClosed());
con2.close();
assertTrue(con.isClosed());
pc.close();
} catch (SQLException e) {
fail(e.getMessage());
}
}
/**
* Makes sure the isClosed method on a connection wrapper does what
* you'd expect. Checks the usual case, as well as automatic
* closure when a new handle is opened on the same physical connection.
*/
public void testIsClosed()
{
try
{
PooledConnection pc = getPooledConnection();
Connection con = pc.getConnection();
assertTrue(!con.isClosed());
con.close();
assertTrue(con.isClosed());
con = pc.getConnection();
Connection con2 = pc.getConnection();
assertTrue(con.isClosed());
assertTrue(!con2.isClosed());
con2.close();
assertTrue(con.isClosed());
pc.close();
}
catch (SQLException e)
{
fail(e.getMessage());
}
}
/**
* Helper class to remove a listener during event dispatching.
*/
private class RemoveClose implements ConnectionEventListener {
public void connectionClosed(ConnectionEvent event) {
((PooledConnection)event.getSource()).removeConnectionEventListener(this);
}
/**
* Helper class to remove a listener during event dispatching.
*/
private class RemoveClose implements ConnectionEventListener
{
public void connectionClosed(ConnectionEvent event)
{
((PooledConnection)event.getSource()).removeConnectionEventListener(this);
}
public void connectionErrorOccurred(ConnectionEvent event) {
((PooledConnection)event.getSource()).removeConnectionEventListener(this);
}
}
public void connectionErrorOccurred(ConnectionEvent event)
{
((PooledConnection)event.getSource()).removeConnectionEventListener(this);
}
}
/**
* Helper class that implements the event listener interface, and
* counts the number of events it sees.
*/
private class CountClose implements ConnectionEventListener {
private int count = 0, errorCount = 0;
public void connectionClosed(ConnectionEvent event) {
count++;
}
/**
* Helper class that implements the event listener interface, and
* counts the number of events it sees.
*/
private class CountClose implements ConnectionEventListener
{
private int count = 0, errorCount = 0;
public void connectionClosed(ConnectionEvent event)
{
count++;
}
public void connectionErrorOccurred(ConnectionEvent event) {
errorCount++;
}
public void connectionErrorOccurred(ConnectionEvent event)
{
errorCount++;
}
public int getCount() {
return count;
}
public int getCount()
{
return count;
}
public int getErrorCount() {
return errorCount;
}
public int getErrorCount()
{
return errorCount;
}
public void clear() {
count = errorCount = 0;
}
}
public void clear()
{
count = errorCount = 0;
}
}
}
......@@ -8,17 +8,19 @@ import junit.framework.TestSuite;
* PooledConnection implementations.
*
* @author Aaron Mulder (ammulder@chariotsolutions.com)
* @version $Revision: 1.1 $
* @version $Revision: 1.2 $
*/
public class OptionalTestSuite extends TestSuite {
/**
* Gets the test suite for the entire JDBC 2.0 Optional Package
* implementation.
*/
public static TestSuite suite() {
TestSuite suite = new TestSuite();
suite.addTestSuite(SimpleDataSourceTest.class);
suite.addTestSuite(ConnectionPoolTest.class);
return suite;
}
public class OptionalTestSuite extends TestSuite
{
/**
* Gets the test suite for the entire JDBC 2.0 Optional Package
* implementation.
*/
public static TestSuite suite()
{
TestSuite suite = new TestSuite();
suite.addTestSuite(SimpleDataSourceTest.class);
suite.addTestSuite(ConnectionPoolTest.class);
return suite;
}
}
......@@ -4,35 +4,42 @@ import org.postgresql.test.JDBC2Tests;
import org.postgresql.jdbc2.optional.SimpleDataSource;
/**
* Performs the basic tests defined in the superclass. Just adds the
* Performs the basic tests defined in the superclass. Just adds the
* configuration logic.
*
* @author Aaron Mulder (ammulder@chariotsolutions.com)
* @version $Revision: 1.1 $
* @version $Revision: 1.2 $
*/
public class SimpleDataSourceTest extends BaseDataSourceTest {
/**
* Constructor required by JUnit
*/
public SimpleDataSourceTest(String name) {
super(name);
}
public class SimpleDataSourceTest extends BaseDataSourceTest
{
/**
* Constructor required by JUnit
*/
public SimpleDataSourceTest(String name)
{
super(name);
}
/**
* Creates and configures a new SimpleDataSource.
*/
protected void initializeDataSource() {
if(bds == null) {
bds = new SimpleDataSource();
String db = JDBC2Tests.getURL();
if(db.indexOf('/') > -1) {
db = db.substring(db.lastIndexOf('/')+1);
} else if(db.indexOf(':') > -1) {
db = db.substring(db.lastIndexOf(':')+1);
}
bds.setDatabaseName(db);
bds.setUser(JDBC2Tests.getUser());
bds.setPassword(JDBC2Tests.getPassword());
}
}
/**
* Creates and configures a new SimpleDataSource.
*/
protected void initializeDataSource()
{
if (bds == null)
{
bds = new SimpleDataSource();
String db = JDBC2Tests.getURL();
if (db.indexOf('/') > -1)
{
db = db.substring(db.lastIndexOf('/') + 1);
}
else if (db.indexOf(':') > -1)
{
db = db.substring(db.lastIndexOf(':') + 1);
}
bds.setDatabaseName(db);
bds.setUser(JDBC2Tests.getUser());
bds.setPassword(JDBC2Tests.getPassword());
}
}
}
......@@ -7,7 +7,7 @@ import junit.framework.Test;
import java.sql.*;
/*
* Executes all known tests for JDBC3
* Executes all known tests for JDBC3
*/
public class Jdbc3TestSuite extends TestSuite
{
......@@ -17,7 +17,7 @@ public class Jdbc3TestSuite extends TestSuite
*/
public static TestSuite suite()
{
//Currently there are no specific jdbc3 tests so just run the jdbc2 tests
return org.postgresql.test.jdbc2.Jdbc2TestSuite.suite();
//Currently there are no specific jdbc3 tests so just run the jdbc2 tests
return org.postgresql.test.jdbc2.Jdbc2TestSuite.suite();
}
}
......@@ -5,7 +5,7 @@ import java.sql.*;
/*
* Converts to and from the postgresql bytea datatype used by the backend.
*
* $Id: PGbytea.java,v 1.5 2002/08/16 17:51:38 barry Exp $
* $Id: PGbytea.java,v 1.6 2002/09/06 21:23:06 momjian Exp $
*/
public class PGbytea
......@@ -19,7 +19,7 @@ public class PGbytea
{
if (s == null)
return null;
int slength = s.length;
int slength = s.length;
byte[] buf = new byte[slength];
int bufpos = 0;
int thebyte;
......
......@@ -78,6 +78,7 @@ public class PGtokenizer
// Don't forget the last token ;-)
if (s < string.length())
tokens.addElement(string.substring(s));
......
......@@ -129,14 +129,16 @@ public class Serialize
try
{
conn = c;
if (Driver.logDebug) Driver.debug("Serialize: initializing instance for type: " + type);
if (Driver.logDebug)
Driver.debug("Serialize: initializing instance for type: " + type);
tableName = toPostgreSQL(type);
className = type;
ourClass = Class.forName(className);
}
catch (ClassNotFoundException cnfe)
{
if (Driver.logDebug) Driver.debug("Serialize: " + className + " java class not found");
if (Driver.logDebug)
Driver.debug("Serialize: " + className + " java class not found");
throw new PSQLException("postgresql.serial.noclass", type);
}
......@@ -148,14 +150,16 @@ public class Serialize
if (rs.next())
{
status = true;
if (Driver.logDebug) Driver.debug("Serialize: " + tableName + " table found");
if (Driver.logDebug)
Driver.debug("Serialize: " + tableName + " table found");
}
rs.close();
}
// This should never occur, as org.postgresql has it's own internal checks
if (!status)
{
if (Driver.logDebug) Driver.debug("Serialize: " + tableName + " table not found");
if (Driver.logDebug)
Driver.debug("Serialize: " + tableName + " table not found");
throw new PSQLException("postgresql.serial.table", type);
}
// Finally cache the fields within the table
......@@ -187,9 +191,11 @@ public class Serialize
{
try
{
if (Driver.logDebug) Driver.debug("Serialize.fetch: " + "attempting to instantiate object of type: " + ourClass.getName() );
if (Driver.logDebug)
Driver.debug("Serialize.fetch: " + "attempting to instantiate object of type: " + ourClass.getName() );
Object obj = ourClass.newInstance();
if (Driver.logDebug) Driver.debug("Serialize.fetch: " + "instantiated object of type: " + ourClass.getName() );
if (Driver.logDebug)
Driver.debug("Serialize.fetch: " + "instantiated object of type: " + ourClass.getName() );
// NB: we use java.lang.reflect here to prevent confusion with
// the org.postgresql.Field
......@@ -220,7 +226,8 @@ public class Serialize
sb.append(" where oid=");
sb.append(oid);
if (Driver.logDebug) Driver.debug("Serialize.fetch: " + sb.toString());
if (Driver.logDebug)
Driver.debug("Serialize.fetch: " + sb.toString());
ResultSet rs = ((org.postgresql.jdbc1.AbstractJdbc1Connection)conn).ExecSQL(sb.toString());
if (rs != null)
......@@ -270,13 +277,13 @@ public class Serialize
/*
* This stores an object into a table, returning it's OID.<p>
* This method was deprecated in 7.2 because the value of an OID
* can be larger than a java signed int.
* This method was deprecated in 7.2 because the value of an OID
* can be larger than a java signed int.
* @deprecated Replaced by storeObject() in 7.2
*/
public int store(Object o) throws SQLException
{
return (int) storeObject(o);
return (int) storeObject(o);
}
/*
......@@ -296,7 +303,7 @@ public class Serialize
* @param o Object to store (must implement Serializable)
* @return oid of stored object
* @exception SQLException on error
* @since 7.2
* @since 7.2
*/
public long storeObject(Object o) throws SQLException
{
......@@ -389,7 +396,8 @@ public class Serialize
sb.append(')');
}
if (Driver.logDebug) Driver.debug("Serialize.store: " + sb.toString() );
if (Driver.logDebug)
Driver.debug("Serialize.store: " + sb.toString() );
ResultSet rs = ((org.postgresql.jdbc1.AbstractJdbc1Connection)conn).ExecSQL(sb.toString());
// fetch the OID for returning
......@@ -496,13 +504,15 @@ public class Serialize
ResultSet rs = ((org.postgresql.jdbc1.AbstractJdbc1Connection)con).ExecSQL("select relname from pg_class where relname = '" + tableName + "'");
if ( rs.next() )
{
if (Driver.logDebug) Driver.debug("Serialize.create: table " + tableName + " exists, skipping");
if (Driver.logDebug)
Driver.debug("Serialize.create: table " + tableName + " exists, skipping");
rs.close();
return;
return ;
}
// else table not found, so create it
if (Driver.logDebug) Driver.debug("Serialize.create: table " + tableName + " not found, creating" );
if (Driver.logDebug)
Driver.debug("Serialize.create: table " + tableName + " not found, creating" );
// No entries returned, so the table doesn't exist
StringBuffer sb = new StringBuffer("create table ");
......@@ -548,7 +558,8 @@ public class Serialize
sb.append(")");
// Now create the table
if (Driver.logDebug) Driver.debug("Serialize.create: " + sb );
if (Driver.logDebug)
Driver.debug("Serialize.create: " + sb );
((org.postgresql.jdbc1.AbstractJdbc1Connection)con).ExecSQL(sb.toString());
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment