Commit 68c6eff9 authored by Barry Lind's avatar Barry Lind

Third phase of restructuring to add jdbc3 support.

 Modified Files:
 	jdbc/org/postgresql/jdbc1/AbstractJdbc1Connection.java
 	jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java
 	jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java
 	jdbc/org/postgresql/jdbc1/DatabaseMetaData.java
 	jdbc/org/postgresql/jdbc1/Jdbc1Connection.java
 	jdbc/org/postgresql/jdbc1/Jdbc1ResultSet.java
 	jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java
 	jdbc/org/postgresql/jdbc2/AbstractJdbc2Statement.java
 	jdbc/org/postgresql/jdbc2/Array.java
 	jdbc/org/postgresql/jdbc2/DatabaseMetaData.java
 	jdbc/org/postgresql/jdbc2/Jdbc2Connection.java
 	jdbc/org/postgresql/jdbc2/Jdbc2ResultSet.java
 Added Files:
 	jdbc/org/postgresql/jdbc1/Jdbc1CallableStatement.java
 	jdbc/org/postgresql/jdbc2/Jdbc2CallableStatement.java
 Removed Files:
 	jdbc/org/postgresql/jdbc1/CallableStatement.java
 	jdbc/org/postgresql/jdbc2/CallableStatement.java
 	jdbc/org/postgresql/jdbc2/UpdateableResultSet.java
parent 73eb2dfe
...@@ -13,7 +13,7 @@ import org.postgresql.largeobject.LargeObjectManager; ...@@ -13,7 +13,7 @@ import org.postgresql.largeobject.LargeObjectManager;
import org.postgresql.util.*; import org.postgresql.util.*;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Connection.java,v 1.1 2002/07/23 03:59:55 barry Exp $ /* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Connection.java,v 1.2 2002/07/25 22:45:27 barry Exp $
* This class defines methods of the jdbc1 specification. This class is * This class defines methods of the jdbc1 specification. This class is
* extended by org.postgresql.jdbc2.AbstractJdbc2Connection which adds the jdbc2 * extended by org.postgresql.jdbc2.AbstractJdbc2Connection which adds the jdbc2
* methods. The real Connection class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Connection * methods. The real Connection class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Connection
...@@ -359,8 +359,7 @@ public abstract class AbstractJdbc1Connection implements org.postgresql.PGConnec ...@@ -359,8 +359,7 @@ public abstract class AbstractJdbc1Connection implements org.postgresql.PGConnec
// are common to all implementations (JDBC1 or 2), they are placed here. // are common to all implementations (JDBC1 or 2), they are placed here.
// This should make it easy to maintain the two specifications. // This should make it easy to maintain the two specifications.
//BJL TODO this method shouldn't need to take a Connection since this can be used. 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(java.sql.Statement stat, org.postgresql.Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException;
/* /*
* This adds a warning to the warning chain. * This adds a warning to the warning chain.
......
...@@ -13,15 +13,15 @@ import org.postgresql.largeobject.*; ...@@ -13,15 +13,15 @@ import org.postgresql.largeobject.*;
import org.postgresql.util.PGbytea; import org.postgresql.util.PGbytea;
import org.postgresql.util.PSQLException; import org.postgresql.util.PSQLException;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1ResultSet.java,v 1.1 2002/07/23 03:59:55 barry Exp $ /* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1ResultSet.java,v 1.2 2002/07/25 22:45:27 barry Exp $
* This class defines methods of the jdbc1 specification. This class is * This class defines methods of the jdbc1 specification. This class is
* extended by org.postgresql.jdbc2.AbstractJdbc2ResultSet which adds the jdbc2 * extended by org.postgresql.jdbc2.AbstractJdbc2ResultSet which adds the jdbc2
* methods. The real ResultSet class (for jdbc1) is org.postgresql.jdbc1.Jdbc1ResultSet * methods. The real ResultSet class (for jdbc1) is org.postgresql.jdbc1.Jdbc1ResultSet
*/ */
public abstract class AbstractJdbc1ResultSet public abstract class AbstractJdbc1ResultSet
{ {
protected Vector rows; // The results protected Vector rows; // The results
protected Statement statement;
protected Field fields[]; // The field descriptions protected Field fields[]; // The field descriptions
protected String status; // Status of the result protected String status; // Status of the result
protected boolean binaryCursor = false; // is the data binary or Strings protected boolean binaryCursor = false; // is the data binary or Strings
...@@ -33,7 +33,7 @@ public abstract class AbstractJdbc1ResultSet ...@@ -33,7 +33,7 @@ public abstract class AbstractJdbc1ResultSet
protected SQLWarning warnings = null; // The warning chain protected SQLWarning warnings = null; // The warning chain
protected boolean wasNullFlag = false; // the flag for wasNull() protected boolean wasNullFlag = false; // the flag for wasNull()
// We can chain multiple resultSets together - this points to // We can chain multiple resultSets together - this points to
// next resultSet in the chain. // next resultSet in the chain.
protected ResultSet next = null; protected ResultSet next = null;
...@@ -41,9 +41,10 @@ public abstract class AbstractJdbc1ResultSet ...@@ -41,9 +41,10 @@ public abstract class AbstractJdbc1ResultSet
public byte[][] rowBuffer=null; public byte[][] rowBuffer=null;
public AbstractJdbc1ResultSet(org.postgresql.PGConnection conn, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) public AbstractJdbc1ResultSet(org.postgresql.PGConnection conn, Statement statement, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor)
{ {
this.connection = conn; this.connection = conn;
this.statement = statement;
this.fields = fields; this.fields = fields;
this.rows = tuples; this.rows = tuples;
this.status = status; this.status = status;
...@@ -116,7 +117,7 @@ public abstract class AbstractJdbc1ResultSet ...@@ -116,7 +117,7 @@ public abstract class AbstractJdbc1ResultSet
throw new PSQLException("postgresql.res.badbyte", s); throw new PSQLException("postgresql.res.badbyte", s);
} }
} }
return 0; // SQL NULL return 0; // SQL NULL
} }
public short getShort(int columnIndex) throws SQLException public short getShort(int columnIndex) throws SQLException
...@@ -134,7 +135,7 @@ public abstract class AbstractJdbc1ResultSet ...@@ -134,7 +135,7 @@ public abstract class AbstractJdbc1ResultSet
throw new PSQLException("postgresql.res.badshort", s); throw new PSQLException("postgresql.res.badshort", s);
} }
} }
return 0; // SQL NULL return 0; // SQL NULL
} }
public int getInt(int columnIndex) throws SQLException public int getInt(int columnIndex) throws SQLException
......
...@@ -8,7 +8,7 @@ import java.util.Vector; ...@@ -8,7 +8,7 @@ import java.util.Vector;
import org.postgresql.largeobject.*; import org.postgresql.largeobject.*;
import org.postgresql.util.*; import org.postgresql.util.*;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.2 2002/07/24 22:08:39 barry Exp $ /* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.3 2002/07/25 22:45:27 barry Exp $
* This class defines methods of the jdbc1 specification. This class is * This class defines methods of the jdbc1 specification. This class is
* extended by org.postgresql.jdbc2.AbstractJdbc2Statement which adds the jdbc2 * extended by org.postgresql.jdbc2.AbstractJdbc2Statement which adds the jdbc2
* methods. The real Statement class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Statement * methods. The real Statement class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Statement
...@@ -47,6 +47,20 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme ...@@ -47,6 +47,20 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
protected String[] templateStrings; protected String[] templateStrings;
protected String[] inStrings; protected String[] inStrings;
//Used by the callablestatement style methods
private static final String JDBC_SYNTAX = "{[? =] call <some_function> ([? [,?]*]) }";
private static final String RESULT_COLUMN = "result";
private String originalSql = "";
private boolean isFunction;
// functionReturnType contains the user supplied value to check
// testReturn contains a modified version to make it easier to
// check the getXXX methods..
private int functionReturnType;
private int testReturn;
// returnTypeSet is true when a proper call to registerOutParameter has been made
private boolean returnTypeSet;
protected Object callResult;
public AbstractJdbc1Statement (AbstractJdbc1Connection connection) public AbstractJdbc1Statement (AbstractJdbc1Connection connection)
...@@ -62,6 +76,10 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme ...@@ -62,6 +76,10 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
} }
protected void parseSqlStmt () throws SQLException { protected void parseSqlStmt () throws SQLException {
if (this instanceof CallableStatement) {
modifyJdbcCall();
}
Vector v = new Vector(); Vector v = new Vector();
boolean inQuotes = false; boolean inQuotes = false;
int lastParmEnd = 0, i; int lastParmEnd = 0, i;
...@@ -179,7 +197,23 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme ...@@ -179,7 +197,23 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
// New in 7.1, pass Statement so that ExecSQL can customise to it // New in 7.1, pass Statement so that ExecSQL can customise to it
result = ((AbstractJdbc1Connection)connection).ExecSQL(sql, (java.sql.Statement)this); result = ((AbstractJdbc1Connection)connection).ExecSQL(sql, (java.sql.Statement)this);
return (result != null && ((AbstractJdbc1ResultSet)result).reallyResultSet()); //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)
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());
}
} }
/* /*
...@@ -233,6 +267,8 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme ...@@ -233,6 +267,8 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
{ {
if (result == null) if (result == null)
return -1; return -1;
if (isFunction)
return 1;
if (((AbstractJdbc1ResultSet)result).reallyResultSet()) if (((AbstractJdbc1ResultSet)result).reallyResultSet())
return -1; return -1;
return ((AbstractJdbc1ResultSet)result).getResultCount(); return ((AbstractJdbc1ResultSet)result).getResultCount();
...@@ -253,14 +289,6 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme ...@@ -253,14 +289,6 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
/* /*
* Returns the status message from the current Result.<p> * Returns the status message from the current Result.<p>
* This is used internally by the driver. * This is used internally by the driver.
...@@ -1214,6 +1242,291 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme ...@@ -1214,6 +1242,291 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
setSerialize(parameterIndex, connection.storeObject(x), x.getClass().getName() ); setSerialize(parameterIndex, connection.storeObject(x), x.getClass().getName() );
} }
/*
* Before executing a stored procedure call you must explicitly
* call registerOutParameter to register the java.sql.Type of each
* out parameter.
*
* <p>Note: When reading the value of an out parameter, you must use
* the getXXX method whose Java type XXX corresponds to the
* parameter's registered SQL type.
*
* ONLY 1 RETURN PARAMETER if {?= call ..} syntax is used
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param sqlType SQL type code defined by java.sql.Types; for
* parameters of type Numeric or Decimal use the version of
* registerOutParameter that accepts a scale value
* @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 ||
functionReturnType == Types.LONGVARCHAR)
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:
*
* <p>Note: When reading the value of an out parameter, you must use
* the getXXX method whose Java type XXX corresponds to the
* parameter's registered SQL type.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param sqlType use either java.sql.Type.NUMERIC or java.sql.Type.DECIMAL
* @param scale a value greater than or equal to zero representing the
* desired number of digits to the right of the decimal point
* @exception SQLException if a database-access error occurs.
*/
public void registerOutParameter(int parameterIndex, int sqlType,
int scale) throws SQLException
{
registerOutParameter (parameterIndex, sqlType); // ignore for now..
}
/*
* An OUT parameter may have the value of SQL NULL; wasNull
* reports whether the last value read has this special value.
*
* <p>Note: You must first call getXXX on a parameter to read its
* value and then call wasNull() to see if the value was SQL NULL.
* @return true if the last parameter read was SQL NULL
* @exception SQLException if a database-access error occurs.
*/
public boolean wasNull() throws SQLException
{
// check to see if the last access threw an exception
return (callResult == null);
}
/*
* Get the value of a CHAR, VARCHAR, or LONGVARCHAR parameter as a
* Java String.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public String getString(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.VARCHAR, "String");
return (String)callResult;
}
/*
* Get the value of a BIT parameter as a Java boolean.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is false
* @exception SQLException if a database-access error occurs.
*/
public boolean getBoolean(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.BIT, "Boolean");
if (callResult == null) return false;
return ((Boolean)callResult).booleanValue ();
}
/*
* Get the value of a TINYINT parameter as a Java byte.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public byte getByte(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.TINYINT, "Byte");
if (callResult == null) return 0;
return (byte)((Integer)callResult).intValue ();
}
/*
* Get the value of a SMALLINT parameter as a Java short.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public short getShort(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.SMALLINT, "Short");
if (callResult == null) return 0;
return (short)((Integer)callResult).intValue ();
}
/*
* Get the value of an INTEGER parameter as a Java int.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public int getInt(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.INTEGER, "Int");
if (callResult == null) return 0;
return ((Integer)callResult).intValue ();
}
/*
* Get the value of a BIGINT parameter as a Java long.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public long getLong(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.BIGINT, "Long");
if (callResult == null) return 0;
return ((Long)callResult).longValue ();
}
/*
* Get the value of a FLOAT parameter as a Java float.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public float getFloat(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.REAL, "Float");
if (callResult == null) return 0;
return ((Float)callResult).floatValue ();
}
/*
* Get the value of a DOUBLE parameter as a Java double.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public double getDouble(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.DOUBLE, "Double");
if (callResult == null) return 0;
return ((Double)callResult).doubleValue ();
}
/*
* Get the value of a NUMERIC parameter as a java.math.BigDecimal
* object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param scale a value greater than or equal to zero representing the
* desired number of digits to the right of the decimal point
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
* @deprecated in Java2.0
*/
public BigDecimal getBigDecimal(int parameterIndex, int scale)
throws SQLException
{
checkIndex (parameterIndex, Types.NUMERIC, "BigDecimal");
return ((BigDecimal)callResult);
}
/*
* Get the value of a SQL BINARY or VARBINARY parameter as a Java
* byte[]
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public byte[] getBytes(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.VARBINARY, "Bytes");
return ((byte [])callResult);
}
/*
* Get the value of a SQL DATE parameter as a java.sql.Date object
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public java.sql.Date getDate(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.DATE, "Date");
return (java.sql.Date)callResult;
}
/*
* Get the value of a SQL TIME parameter as a java.sql.Time object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public java.sql.Time getTime(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.TIME, "Time");
return (java.sql.Time)callResult;
}
/*
* Get the value of a SQL TIMESTAMP parameter as a java.sql.Timestamp object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public java.sql.Timestamp getTimestamp(int parameterIndex)
throws SQLException
{
checkIndex (parameterIndex, Types.TIMESTAMP, "Timestamp");
return (java.sql.Timestamp)callResult;
}
// getObject returns a Java object for the parameter.
// See the JDBC spec's "Dynamic Programming" chapter for details.
/*
* Get the value of a parameter as a Java object.
*
* <p>This method returns a Java object whose type coresponds to the
* SQL type that was registered for this parameter using
* registerOutParameter.
*
* <P>Note that this method may be used to read datatabase-specific,
* abstract data types. This is done by specifying a targetSqlType
* of java.sql.types.OTHER, which allows the driver to return a
* database-specific Java type.
*
* <p>See the JDBC spec's "Dynamic Programming" chapter for details.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return A java.lang.Object holding the OUT parameter value.
* @exception SQLException if a database-access error occurs.
*/
public Object getObject(int parameterIndex)
throws SQLException
{
checkIndex (parameterIndex);
return callResult;
}
/* /*
* Returns the SQL statement with the current template values * Returns the SQL statement with the current template values
* substituted. * substituted.
...@@ -1253,6 +1566,8 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme ...@@ -1253,6 +1566,8 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
{ {
if (paramIndex < 1 || paramIndex > inStrings.length) if (paramIndex < 1 || paramIndex > inStrings.length)
throw new PSQLException("postgresql.prep.range"); throw new PSQLException("postgresql.prep.range");
if (paramIndex == 1 && isFunction) // need to registerOut instead
throw new PSQLException ("postgresql.call.funcover");
inStrings[paramIndex - 1] = s; inStrings[paramIndex - 1] = s;
} }
...@@ -1267,6 +1582,13 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme ...@@ -1267,6 +1582,13 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
sbuf.setLength(0); sbuf.setLength(0);
int i; int i;
if (isFunction && !returnTypeSet)
throw new PSQLException("postgresql.call.noreturntype");
if (isFunction) { // set entry 1 to dummy entry..
inStrings[0] = ""; // dummy entry which ensured that no one overrode
// and calls to setXXX (2,..) really went to first arg in a function call..
}
for (i = 0 ; i < inStrings.length ; ++i) for (i = 0 ; i < inStrings.length ; ++i)
{ {
if (inStrings[i] == null) if (inStrings[i] == null)
...@@ -1299,5 +1621,67 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme ...@@ -1299,5 +1621,67 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
set(parameterIndex, Long.toString(x) + "::" + tablename ); set(parameterIndex, Long.toString(x) + "::" + tablename );
} }
/**
* this method will turn a string of the form
* {? = call <some_function> (?, [?,..]) }
* into the PostgreSQL format which is
* select <some_function> (?, [?, ...]) as result
*
*/
private void modifyJdbcCall() throws SQLException {
// syntax checking is not complete only a few basics :(
originalSql = sql; // save for error msgs..
int index = sql.indexOf ("="); // is implied func or proc?
boolean isValid = true;
if (index != -1) {
isFunction = true;
isValid = sql.indexOf ("?") < index; // ? before =
}
sql = sql.trim ();
if (sql.startsWith ("{") && sql.endsWith ("}")) {
sql = sql.substring (1, sql.length() -1);
} else isValid = false;
index = sql.indexOf ("call");
if (index == -1 || !isValid)
throw new PSQLException ("postgresql.call.malformed",
new Object[]{sql, JDBC_SYNTAX});
sql = sql.replace ('{', ' '); // replace these characters
sql = sql.replace ('}', ' ');
sql = 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
sql = (isFunction ? "?" : "") + sql.substring (index + 4);
sql = "select " + sql + " as " + RESULT_COLUMN + ";";
}
/** helperfunction for the getXXX calls to check isFunction and index == 1
*/
protected void checkIndex (int parameterIndex, int type, String getName)
throws SQLException {
checkIndex (parameterIndex);
if (type != this.testReturn)
throw new PSQLException("postgresql.call.wrongget",
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 {
if (!isFunction)
throw new PSQLException("postgresql.call.noreturntype");
if (parameterIndex != 1)
throw new PSQLException("postgresql.call.noinout");
}
} }
package org.postgresql.jdbc1;
// IMPORTANT NOTE: This file implements the JDBC 1 version of the driver.
// If you make any modifications to this file, you must make sure that the
// changes are also made (if relevent) to the related JDBC 2 class in the
// org.postgresql.jdbc2 package.
import java.sql.*;
import java.math.*;
/*
* CallableStatement is used to execute SQL stored procedures.
*
* <p>JDBC provides a stored procedure SQL escape that allows stored
* procedures to be called in a standard way for all RDBMS's. This escape
* syntax has one form that includes a result parameter and one that does
* not. If used, the result parameter must be registered as an OUT
* parameter. The other parameters may be used for input, output or both.
* Parameters are refered to sequentially, by number. The first parameter
* is 1.
*
* {?= call <procedure-name>[<arg1>,<arg2>, ...]}
* {call <procedure-name>[<arg1>,<arg2>, ...]}
*
*
* <p>IN parameter values are set using the set methods inherited from
* PreparedStatement. The type of all OUT parameters must be registered
* prior to executing the stored procedure; their values are retrieved
* after execution via the get methods provided here.
*
* <p>A Callable statement may return a ResultSet or multiple ResultSets.
* Multiple ResultSets are handled using operations inherited from
* Statement.
*
* <p>For maximum portability, a call's ResultSets and update counts should
* be processed prior to getting the values of output parameters.
*
* @see Connection#prepareCall
* @see ResultSet
*/
public class CallableStatement extends Jdbc1PreparedStatement implements java.sql.CallableStatement
{
/*
* @exception SQLException on failure
*/
CallableStatement(Jdbc1Connection c, String q) throws SQLException
{
super(c, q);
}
/*
* Before executing a stored procedure call you must explicitly
* call registerOutParameter to register the java.sql.Type of each
* out parameter.
*
* <p>Note: When reading the value of an out parameter, you must use
* the getXXX method whose Java type XXX corresponds to the
* parameter's registered SQL type.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param sqlType SQL type code defined by java.sql.Types; for
* parameters of type Numeric or Decimal use the version of
* registerOutParameter that accepts a scale value
* @exception SQLException if a database-access error occurs.
*/
public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException
{}
/*
* You must also specify the scale for numeric/decimal types:
*
* <p>Note: When reading the value of an out parameter, you must use
* the getXXX method whose Java type XXX corresponds to the
* parameter's registered SQL type.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param sqlType use either java.sql.Type.NUMERIC or java.sql.Type.DECIMAL
* @param scale a value greater than or equal to zero representing the
* desired number of digits to the right of the decimal point
* @exception SQLException if a database-access error occurs.
*/
public void registerOutParameter(int parameterIndex, int sqlType,
int scale) throws SQLException
{}
// Old api?
//public boolean isNull(int parameterIndex) throws SQLException {
//return true;
//}
/*
* An OUT parameter may have the value of SQL NULL; wasNull
* reports whether the last value read has this special value.
*
* <p>Note: You must first call getXXX on a parameter to read its
* value and then call wasNull() to see if the value was SQL NULL.
* @return true if the last parameter read was SQL NULL
* @exception SQLException if a database-access error occurs.
*/
public boolean wasNull() throws SQLException
{
// check to see if the last access threw an exception
return false; // fake it for now
}
// Old api?
//public String getChar(int parameterIndex) throws SQLException {
//return null;
//}
/*
* Get the value of a CHAR, VARCHAR, or LONGVARCHAR parameter as a
* Java String.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public String getString(int parameterIndex) throws SQLException
{
return null;
}
//public String getVarChar(int parameterIndex) throws SQLException {
// return null;
//}
//public String getLongVarChar(int parameterIndex) throws SQLException {
//return null;
//}
/*
* Get the value of a BIT parameter as a Java boolean.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is false
* @exception SQLException if a database-access error occurs.
*/
public boolean getBoolean(int parameterIndex) throws SQLException
{
return false;
}
/*
* Get the value of a TINYINT parameter as a Java byte.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public byte getByte(int parameterIndex) throws SQLException
{
return 0;
}
/*
* Get the value of a SMALLINT parameter as a Java short.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public short getShort(int parameterIndex) throws SQLException
{
return 0;
}
/*
* Get the value of an INTEGER parameter as a Java int.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public int getInt(int parameterIndex) throws SQLException
{
return 0;
}
/*
* Get the value of a BIGINT parameter as a Java long.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public long getLong(int parameterIndex) throws SQLException
{
return 0;
}
/*
* Get the value of a FLOAT parameter as a Java float.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public float getFloat(int parameterIndex) throws SQLException
{
return (float) 0.0;
}
/*
* Get the value of a DOUBLE parameter as a Java double.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public double getDouble(int parameterIndex) throws SQLException
{
return 0.0;
}
/*
* Get the value of a NUMERIC parameter as a java.math.BigDecimal
* object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param scale a value greater than or equal to zero representing the
* desired number of digits to the right of the decimal point
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public BigDecimal getBigDecimal(int parameterIndex, int scale)
throws SQLException
{
return null;
}
/*
* Get the value of a SQL BINARY or VARBINARY parameter as a Java
* byte[]
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public byte[] getBytes(int parameterIndex) throws SQLException
{
return null;
}
// New API (JPM) (getLongVarBinary)
//public byte[] getBinaryStream(int parameterIndex) throws SQLException {
//return null;
//}
/*
* Get the value of a SQL DATE parameter as a java.sql.Date object
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public java.sql.Date getDate(int parameterIndex) throws SQLException
{
return null;
}
/*
* Get the value of a SQL TIME parameter as a java.sql.Time object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public java.sql.Time getTime(int parameterIndex) throws SQLException
{
return null;
}
/*
* Get the value of a SQL TIMESTAMP parameter as a java.sql.Timestamp object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public java.sql.Timestamp getTimestamp(int parameterIndex)
throws SQLException
{
return null;
}
//----------------------------------------------------------------------
// Advanced features:
// You can obtain a ParameterMetaData object to get information
// about the parameters to this CallableStatement.
//public DatabaseMetaData getMetaData() {
//return null;
//}
// getObject returns a Java object for the parameter.
// See the JDBC spec's "Dynamic Programming" chapter for details.
/*
* Get the value of a parameter as a Java object.
*
* <p>This method returns a Java object whose type coresponds to the
* SQL type that was registered for this parameter using
* registerOutParameter.
*
* <P>Note that this method may be used to read datatabase-specific,
* abstract data types. This is done by specifying a targetSqlType
* of java.sql.types.OTHER, which allows the driver to return a
* database-specific Java type.
*
* <p>See the JDBC spec's "Dynamic Programming" chapter for details.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return A java.lang.Object holding the OUT parameter value.
* @exception SQLException if a database-access error occurs.
*/
public Object getObject(int parameterIndex)
throws SQLException
{
return null;
}
}
...@@ -13,7 +13,7 @@ import org.postgresql.util.PSQLException; ...@@ -13,7 +13,7 @@ import org.postgresql.util.PSQLException;
/* /*
* This class provides information about the database as a whole. * This class provides information about the database as a whole.
* *
* $Id: DatabaseMetaData.java,v 1.48 2002/07/23 03:59:55 barry Exp $ * $Id: DatabaseMetaData.java,v 1.49 2002/07/25 22:45:28 barry Exp $
* *
* <p>Many of the methods here return lists of information in ResultSets. You * <p>Many of the methods here return lists of information in ResultSets. You
* can use the normal ResultSet methods such as getString and getInt to * can use the normal ResultSet methods such as getString and getInt to
...@@ -1549,7 +1549,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData ...@@ -1549,7 +1549,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
v.addElement(tuple); v.addElement(tuple);
} }
return new Jdbc1ResultSet(connection, f, v, "OK", 1); return connection.getResultSet(null, f, v, "OK", 1);
} }
/* /*
...@@ -1627,7 +1627,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData ...@@ -1627,7 +1627,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
// add query loop here // add query loop here
return new Jdbc1ResultSet(connection, f, v, "OK", 1); return connection.getResultSet(null, f, v, "OK", 1);
} }
/* /*
...@@ -1762,7 +1762,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData ...@@ -1762,7 +1762,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
v.addElement(tuple); v.addElement(tuple);
} }
r.close(); r.close();
return new Jdbc1ResultSet(connection, f, v, "OK", 1); return connection.getResultSet(null, f, v, "OK", 1);
} }
// This array contains the valid values for the types argument // This array contains the valid values for the types argument
...@@ -1809,7 +1809,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData ...@@ -1809,7 +1809,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
f[0] = new Field(connection, "TABLE_SCHEM", iVarcharOid, 32); f[0] = new Field(connection, "TABLE_SCHEM", iVarcharOid, 32);
tuple[0] = "".getBytes(); tuple[0] = "".getBytes();
v.addElement(tuple); v.addElement(tuple);
return new Jdbc1ResultSet(connection, f, v, "OK", 1); return connection.getResultSet(null, f, v, "OK", 1);
} }
/* /*
...@@ -1854,7 +1854,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData ...@@ -1854,7 +1854,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
tuple[0] = getTableTypes[i][0].getBytes(); tuple[0] = getTableTypes[i][0].getBytes();
v.addElement(tuple); v.addElement(tuple);
} }
return new Jdbc1ResultSet(connection, f, v, "OK", 1); return connection.getResultSet(null, f, v, "OK", 1);
} }
/* /*
...@@ -2050,7 +2050,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData ...@@ -2050,7 +2050,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
} }
r.close(); r.close();
return new Jdbc1ResultSet(connection, f, v, "OK", 1); return connection.getResultSet(null, f, v, "OK", 1);
} }
/* /*
...@@ -2113,7 +2113,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData ...@@ -2113,7 +2113,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
//v.addElement(tuple); //v.addElement(tuple);
} }
return new Jdbc1ResultSet(connection, f, v, "OK", 1); return connection.getResultSet(null, f, v, "OK", 1);
} }
/* /*
...@@ -2203,7 +2203,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData ...@@ -2203,7 +2203,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
f[6] = new Field(connection, "DECIMAL_DIGITS", iInt2Oid, 2); f[6] = new Field(connection, "DECIMAL_DIGITS", iInt2Oid, 2);
f[7] = new Field(connection, "PSEUDO_COLUMN", iInt2Oid, 2); f[7] = new Field(connection, "PSEUDO_COLUMN", iInt2Oid, 2);
return new Jdbc1ResultSet(connection, f, v, "OK", 1); return connection.getResultSet(null, f, v, "OK", 1);
} }
/* /*
...@@ -2413,7 +2413,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData ...@@ -2413,7 +2413,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
while (hasMore); while (hasMore);
} }
return new Jdbc1ResultSet(connection, f, tuples, "OK", 1); return connection.getResultSet(null, f, tuples, "OK", 1);
} }
/* /*
...@@ -2692,7 +2692,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData ...@@ -2692,7 +2692,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
v.addElement(tuple); v.addElement(tuple);
} }
rs.close(); rs.close();
return new Jdbc1ResultSet(connection, f, v, "OK", 1); return connection.getResultSet(null, f, v, "OK", 1);
} }
throw new PSQLException("postgresql.metadata.unavailable"); throw new PSQLException("postgresql.metadata.unavailable");
...@@ -2832,7 +2832,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData ...@@ -2832,7 +2832,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
} }
} }
return new Jdbc1ResultSet(connection, f, v, "OK", 1); return connection.getResultSet(null, f, v, "OK", 1);
} }
} }
package org.postgresql.jdbc1;
import java.sql.*;
public class Jdbc1CallableStatement extends AbstractJdbc1Statement implements java.sql.CallableStatement
{
public Jdbc1CallableStatement(Jdbc1Connection connection, String sql) throws SQLException
{
super(connection, sql);
}
}
...@@ -6,7 +6,7 @@ import java.sql.*; ...@@ -6,7 +6,7 @@ import java.sql.*;
import org.postgresql.Field; import org.postgresql.Field;
import org.postgresql.util.PSQLException; import org.postgresql.util.PSQLException;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/Jdbc1Connection.java,v 1.2 2002/07/24 22:08:40 barry Exp $ /* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/Jdbc1Connection.java,v 1.3 2002/07/25 22:45:28 barry Exp $
* This class implements the java.sql.Connection interface for JDBC1. * 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 * org.postgresql.jdbc1.AbstractJdbc1Connection
...@@ -24,10 +24,9 @@ public class Jdbc1Connection extends org.postgresql.jdbc1.AbstractJdbc1Connectio ...@@ -24,10 +24,9 @@ public class Jdbc1Connection extends org.postgresql.jdbc1.AbstractJdbc1Connectio
return new org.postgresql.jdbc1.Jdbc1PreparedStatement(this, sql); return new org.postgresql.jdbc1.Jdbc1PreparedStatement(this, sql);
} }
//BJL TODO - merge callable statement logic from jdbc2 to jdbc1
public java.sql.CallableStatement prepareCall(String sql) throws SQLException public java.sql.CallableStatement prepareCall(String sql) throws SQLException
{ {
throw new PSQLException("postgresql.con.call"); return new org.postgresql.jdbc1.Jdbc1CallableStatement(this, sql);
} }
public java.sql.DatabaseMetaData getMetaData() throws SQLException public java.sql.DatabaseMetaData getMetaData() throws SQLException
...@@ -39,7 +38,12 @@ public class Jdbc1Connection extends org.postgresql.jdbc1.AbstractJdbc1Connectio ...@@ -39,7 +38,12 @@ public class Jdbc1Connection extends org.postgresql.jdbc1.AbstractJdbc1Connectio
public java.sql.ResultSet getResultSet(java.sql.Statement stat, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException public java.sql.ResultSet getResultSet(java.sql.Statement stat, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException
{ {
return new Jdbc1ResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor); return new Jdbc1ResultSet(this, stat, fields, tuples, status, updateCount, insertOID, binaryCursor);
}
public java.sql.ResultSet getResultSet(java.sql.Statement stat, Field[] fields, Vector tuples, String status, int updateCount) throws SQLException
{
return new Jdbc1ResultSet(this, stat, fields, tuples, status, updateCount, 0, false);
} }
} }
......
...@@ -5,7 +5,7 @@ import java.sql.*; ...@@ -5,7 +5,7 @@ import java.sql.*;
import java.util.Vector; import java.util.Vector;
import org.postgresql.Field; import org.postgresql.Field;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/Jdbc1ResultSet.java,v 1.1 2002/07/23 03:59:55 barry Exp $ /* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/Jdbc1ResultSet.java,v 1.2 2002/07/25 22:45:28 barry Exp $
* This class implements the java.sql.ResultSet interface for JDBC1. * 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 * org.postgresql.jdbc1.AbstractJdbc1ResultSet
...@@ -13,14 +13,9 @@ import org.postgresql.Field; ...@@ -13,14 +13,9 @@ import org.postgresql.Field;
public class Jdbc1ResultSet extends org.postgresql.jdbc1.AbstractJdbc1ResultSet implements java.sql.ResultSet public class Jdbc1ResultSet extends org.postgresql.jdbc1.AbstractJdbc1ResultSet implements java.sql.ResultSet
{ {
public Jdbc1ResultSet(Jdbc1Connection conn, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) public Jdbc1ResultSet(Jdbc1Connection conn, Statement statement, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor)
{ {
super(conn, fields, tuples, status, updateCount, insertOID, binaryCursor); super(conn, statement, fields, tuples, status, updateCount, insertOID, binaryCursor);
}
public Jdbc1ResultSet(Jdbc1Connection conn, Field[] fields, Vector tuples, String status, int updateCount)
{
super(conn, fields, tuples, status, updateCount, 0, false);
} }
public java.sql.ResultSetMetaData getMetaData() throws SQLException public java.sql.ResultSetMetaData getMetaData() throws SQLException
......
...@@ -6,747 +6,1348 @@ import java.io.*; ...@@ -6,747 +6,1348 @@ import java.io.*;
import java.sql.*; import java.sql.*;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Vector; import java.util.*;
import org.postgresql.Driver;
import org.postgresql.Field; import org.postgresql.Field;
import org.postgresql.core.Encoding; import org.postgresql.core.Encoding;
import org.postgresql.largeobject.*; import org.postgresql.largeobject.*;
import org.postgresql.util.PGbytea; import org.postgresql.util.PGbytea;
import org.postgresql.util.PSQLException; import org.postgresql.util.PSQLException;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2ResultSet.java,v 1.2 2002/07/24 22:08:42 barry Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2ResultSet.java,v 1.3 2002/07/25 22:45:28 barry Exp $
* This class defines methods of the jdbc2 specification. This class extends * This class defines methods of the jdbc2 specification. This class extends
* org.postgresql.jdbc1.AbstractJdbc1ResultSet which provides the jdbc1 * org.postgresql.jdbc1.AbstractJdbc1ResultSet which provides the jdbc1
* methods. The real Statement class (for jdbc2) is org.postgresql.jdbc2.Jdbc2ResultSet * methods. The real Statement class (for jdbc2) is org.postgresql.jdbc2.Jdbc2ResultSet
*/ */
public class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.AbstractJdbc1ResultSet public class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.AbstractJdbc1ResultSet {
{ protected String sqlQuery = null;
protected Statement statement;
//needed for updateable result set support
protected String sqlQuery=null; protected boolean updateable = false;
protected boolean doingUpdates = false;
public AbstractJdbc2ResultSet(org.postgresql.PGConnection conn, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) protected boolean onInsertRow = false;
{ protected Hashtable updateValues = new Hashtable();
super(conn, fields, tuples, status, updateCount, insertOID, binaryCursor); private boolean usingOID = false; // are we using the OID for the primary key?
} private Vector primaryKeys; // list of primary keys
private int numKeys = 0;
public java.net.URL getURL(int columnIndex) throws SQLException private boolean singleTable = false;
{ protected String tableName = null;
return null; protected PreparedStatement updateStatement = null;
} protected PreparedStatement insertStatement = null;
protected PreparedStatement deleteStatement = null;
public java.net.URL getURL(String columnName) throws SQLException private PreparedStatement selectStatement = null;
{
return 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);
* 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 public java.net.URL getURL(int columnIndex) throws SQLException {
* Java object. The type of the Java object will be the default return null;
* 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 public java.net.URL getURL(String columnName) throws SQLException {
* data types. return null;
* }
* @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 /*
*/ * Get the value of a column in the current row as a Java object
public Object getObject(int columnIndex) throws SQLException *
{ * <p>This method will return the value of the given column as a
Field field; * Java object. The type of the Java object will be the default
* Java Object type corresponding to the column's SQL type, following
checkResultSet( columnIndex ); * the mapping specified in the JDBC specification.
*
wasNullFlag = (this_row[columnIndex - 1] == null); * <p>This method may also be used to read database specific abstract
if (wasNullFlag) * data types.
return null; *
* @param columnIndex the first column is 1, the second is 2...
field = fields[columnIndex - 1]; * @return a Object holding the column value
* @exception SQLException if a database access error occurs
// some fields can be null, mainly from those returned by MetaData methods */
if (field == null) public Object getObject(int columnIndex) throws SQLException {
{ Field field;
wasNullFlag = true;
return null; checkResultSet( columnIndex );
}
wasNullFlag = (this_row[columnIndex - 1] == null);
switch (field.getSQLType()) if (wasNullFlag)
{ return null;
case Types.BIT:
return getBoolean(columnIndex) ? Boolean.TRUE : Boolean.FALSE; field = fields[columnIndex - 1];
case Types.SMALLINT:
return new Short(getShort(columnIndex)); // some fields can be null, mainly from those returned by MetaData methods
case Types.INTEGER: if (field == null) {
return new Integer(getInt(columnIndex)); wasNullFlag = true;
case Types.BIGINT: return null;
return new Long(getLong(columnIndex)); }
case Types.NUMERIC:
return getBigDecimal switch (field.getSQLType()) {
(columnIndex, (field.getMod() == -1) ? -1 : ((field.getMod() - 4) & 0xffff)); case Types.BIT:
case Types.REAL: return getBoolean(columnIndex) ? Boolean.TRUE : Boolean.FALSE;
return new Float(getFloat(columnIndex));
case Types.DOUBLE: case Types.SMALLINT:
return new Double(getDouble(columnIndex)); return new Short(getShort(columnIndex));
case Types.CHAR:
case Types.VARCHAR: case Types.INTEGER:
return getString(columnIndex); return new Integer(getInt(columnIndex));
case Types.DATE:
return getDate(columnIndex); case Types.BIGINT:
case Types.TIME: return new Long(getLong(columnIndex));
return getTime(columnIndex);
case Types.TIMESTAMP: case Types.NUMERIC:
return getTimestamp(columnIndex); return getBigDecimal
case Types.BINARY: (columnIndex, (field.getMod() == -1) ? -1 : ((field.getMod() - 4) & 0xffff));
case Types.VARBINARY:
return getBytes(columnIndex); case Types.REAL:
case Types.ARRAY: return new Float(getFloat(columnIndex));
return getArray(columnIndex);
default: case Types.DOUBLE:
String type = field.getPGType(); return new Double(getDouble(columnIndex));
// if the backend doesn't know the type then coerce to String
if (type.equals("unknown")) case Types.CHAR:
{ case Types.VARCHAR:
return getString(columnIndex); return getString(columnIndex);
}
else case Types.DATE:
{ return getDate(columnIndex);
return connection.getObject(field.getPGType(), getString(columnIndex));
} case Types.TIME:
} return getTime(columnIndex);
}
case Types.TIMESTAMP:
public boolean absolute(int index) throws SQLException return getTimestamp(columnIndex);
{
// index is 1-based, but internally we use 0-based indices case Types.BINARY:
int internalIndex; case Types.VARBINARY:
return getBytes(columnIndex);
if (index == 0)
throw new SQLException("Cannot move to index of 0"); case Types.ARRAY:
return getArray(columnIndex);
final int rows_size = rows.size();
default:
//if index<0, count from the end of the result set, but check String type = field.getPGType();
//to be sure that it is not beyond the first index // if the backend doesn't know the type then coerce to String
if (index < 0) if (type.equals("unknown")) {
{ return getString(columnIndex);
if (index >= -rows_size) }
internalIndex = rows_size + index; else {
else return connection.getObject(field.getPGType(), getString(columnIndex));
{ }
beforeFirst(); }
return false; }
}
}
else public boolean absolute(int index) throws SQLException {
{ // index is 1-based, but internally we use 0-based indices
//must be the case that index>0, int internalIndex;
//find the correct place, assuming that
//the index is not too large if (index == 0)
if (index <= rows_size) throw new SQLException("Cannot move to index of 0");
internalIndex = index - 1;
else final int rows_size = rows.size();
{
afterLast(); //if index<0, count from the end of the result set, but check
return false; //to be sure that it is not beyond the first index
} if (index < 0) {
} if (index >= -rows_size)
internalIndex = rows_size + index;
current_row = internalIndex; else {
this_row = (byte [][])rows.elementAt(internalIndex); beforeFirst();
return true; return false;
} }
}
public void afterLast() throws SQLException else {
{ //must be the case that index>0,
final int rows_size = rows.size(); //find the correct place, assuming that
if (rows_size > 0) //the index is not too large
current_row = rows_size; if (index <= rows_size)
} internalIndex = index - 1;
else {
public void beforeFirst() throws SQLException afterLast();
{ return false;
if (rows.size() > 0) }
current_row = -1; }
}
current_row = internalIndex;
public void cancelRowUpdates() throws SQLException this_row = (byte[][]) rows.elementAt(internalIndex);
{ return true;
// only sub-classes implement CONCUR_UPDATEABLE }
notUpdateable();
}
public void afterLast() throws SQLException {
public void deleteRow() throws SQLException final int rows_size = rows.size();
{ if (rows_size > 0)
// only sub-classes implement CONCUR_UPDATEABLE current_row = rows_size;
notUpdateable(); }
}
public boolean first() throws SQLException public void beforeFirst() throws SQLException {
{ if (rows.size() > 0)
if (rows.size() <= 0) current_row = -1;
return false; }
current_row = 0;
this_row = (byte [][])rows.elementAt(current_row); public boolean first() throws SQLException {
if (rows.size() <= 0)
rowBuffer=new byte[this_row.length][]; return false;
System.arraycopy(this_row,0,rowBuffer,0,this_row.length);
current_row = 0;
return true; this_row = (byte[][]) rows.elementAt(current_row);
}
rowBuffer = new byte[this_row.length][];
public java.sql.Array getArray(String colName) throws SQLException System.arraycopy(this_row, 0, rowBuffer, 0, this_row.length);
{
return getArray(findColumn(colName)); return true;
} }
public java.sql.Array getArray(int i) throws SQLException
{ public java.sql.Array getArray(String colName) throws SQLException {
wasNullFlag = (this_row[i - 1] == null); return getArray(findColumn(colName));
if (wasNullFlag) }
return null;
if (i < 1 || i > fields.length) public java.sql.Array getArray(int i) throws SQLException {
throw new PSQLException("postgresql.res.colrange"); wasNullFlag = (this_row[i - 1] == null);
return (java.sql.Array) new org.postgresql.jdbc2.Array( connection, i, fields[i - 1], (java.sql.ResultSet)this ); if (wasNullFlag)
} return null;
public java.math.BigDecimal getBigDecimal(int columnIndex) throws SQLException if (i < 1 || i > fields.length)
{ throw new PSQLException("postgresql.res.colrange");
return getBigDecimal(columnIndex, -1); return (java.sql.Array) new org.postgresql.jdbc2.Array( connection, i, fields[i - 1], (java.sql.ResultSet) this );
} }
public java.math.BigDecimal getBigDecimal(String columnName) throws SQLException
{ public java.math.BigDecimal getBigDecimal(int columnIndex) throws SQLException {
return getBigDecimal(findColumn(columnName)); return getBigDecimal(columnIndex, -1);
} }
public Blob getBlob(String columnName) throws SQLException
{ public java.math.BigDecimal getBigDecimal(String columnName) throws SQLException {
return getBlob(findColumn(columnName)); return getBigDecimal(findColumn(columnName));
} }
public Blob getBlob(int i) throws SQLException
{ public Blob getBlob(String columnName) throws SQLException {
return new org.postgresql.largeobject.PGblob(connection, getInt(i)); return getBlob(findColumn(columnName));
} }
public java.io.Reader getCharacterStream(String columnName) throws SQLException
{ public Blob getBlob(int i) throws SQLException {
return getCharacterStream(findColumn(columnName)); return new org.postgresql.largeobject.PGblob(connection, getInt(i));
} }
public java.io.Reader getCharacterStream(int i) throws SQLException
{ public java.io.Reader getCharacterStream(String columnName) throws SQLException {
checkResultSet( i ); return getCharacterStream(findColumn(columnName));
wasNullFlag = (this_row[i - 1] == null); }
if (wasNullFlag)
return null;
public java.io.Reader getCharacterStream(int i) throws SQLException {
if (((AbstractJdbc2Connection)connection).haveMinimumCompatibleVersion("7.2")) checkResultSet( i );
{ wasNullFlag = (this_row[i - 1] == null);
//Version 7.2 supports AsciiStream for all the PG text types if (wasNullFlag)
//As the spec/javadoc for this method indicate this is to be used for return null;
//large text values (i.e. LONGVARCHAR) PG doesn't have a separate
//long string datatype, but with toast the text datatype is capable of if (((AbstractJdbc2Connection) connection).haveMinimumCompatibleVersion("7.2")) {
//handling very large values. Thus the implementation ends up calling //Version 7.2 supports AsciiStream for all the PG text types
//getString() since there is no current way to stream the value from the server //As the spec/javadoc for this method indicate this is to be used for
return new CharArrayReader(getString(i).toCharArray()); //large text values (i.e. LONGVARCHAR) PG doesn't have a separate
} //long string datatype, but with toast the text datatype is capable of
else //handling very large values. Thus the implementation ends up calling
{ //getString() since there is no current way to stream the value from the server
// In 7.1 Handle as BLOBS so return the LargeObject input stream return new CharArrayReader(getString(i).toCharArray());
Encoding encoding = connection.getEncoding(); }
InputStream input = getBinaryStream(i); else {
return encoding.getDecodingReader(input); // 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 Clob getClob(String columnName) throws SQLException }
{ }
return getClob(findColumn(columnName));
}
public Clob getClob(String columnName) throws SQLException {
public Clob getClob(int i) throws SQLException return getClob(findColumn(columnName));
{ }
return new org.postgresql.largeobject.PGclob(connection, getInt(i));
}
public Clob getClob(int i) throws SQLException {
public int getConcurrency() throws SQLException return new org.postgresql.largeobject.PGclob(connection, getInt(i));
{ }
// The standard ResultSet class will now return
// CONCUR_READ_ONLY. A sub-class will overide this if the query was
// updateable. public int getConcurrency() throws SQLException {
return java.sql.ResultSet.CONCUR_READ_ONLY; if (statement == null)
} return java.sql.ResultSet.CONCUR_READ_ONLY;
return statement.getResultSetConcurrency();
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()? public java.sql.Date getDate(int i, java.util.Calendar cal) throws SQLException {
// for now... // If I read the specs, this should use cal only if we don't
return getDate(i); // store the timezone, and if we do, then act just like getDate()?
} // for now...
return getDate(i);
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()? public Time getTime(int i, java.util.Calendar cal) throws SQLException {
// for now... // If I read the specs, this should use cal only if we don't
return getTime(i); // store the timezone, and if we do, then act just like getTime()?
} // for now...
return getTime(i);
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()? public Timestamp getTimestamp(int i, java.util.Calendar cal) throws SQLException {
// for now... // If I read the specs, this should use cal only if we don't
return getTimestamp(i); // store the timezone, and if we do, then act just like getDate()?
} // for now...
return getTimestamp(i);
public java.sql.Date getDate(String c, java.util.Calendar cal) throws SQLException }
{
return getDate(findColumn(c), cal);
} public java.sql.Date getDate(String c, java.util.Calendar cal) throws SQLException {
return getDate(findColumn(c), cal);
public Time getTime(String c, java.util.Calendar cal) throws SQLException }
{
return getTime(findColumn(c), cal);
} public Time getTime(String c, java.util.Calendar cal) throws SQLException {
return getTime(findColumn(c), cal);
public Timestamp getTimestamp(String c, java.util.Calendar cal) throws SQLException }
{
return getTimestamp(findColumn(c), cal);
} public Timestamp getTimestamp(String c, java.util.Calendar cal) throws SQLException {
return getTimestamp(findColumn(c), cal);
public int getFetchDirection() throws SQLException }
{
//PostgreSQL normally sends rows first->last
return java.sql.ResultSet.FETCH_FORWARD; public int getFetchDirection() throws SQLException {
} //PostgreSQL normally sends rows first->last
return java.sql.ResultSet.FETCH_FORWARD;
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 public int getFetchSize() throws SQLException {
// value // In this implementation we return the entire result set, so
return rows.size(); // here return the number of rows we have. Sub-classes can return a proper
} // value
return rows.size();
public Object getObject(String columnName, java.util.Map map) throws SQLException }
{
return getObject(findColumn(columnName), map);
} public Object getObject(String columnName, java.util.Map map) throws SQLException {
return getObject(findColumn(columnName), map);
/* }
* 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. /*
*/ * This checks against map for the type of column i, and if found returns
public Object getObject(int i, java.util.Map map) throws SQLException * an object based on that mapping. The class must implement the SQLData
{ * interface.
throw org.postgresql.Driver.notImplemented(); */
} public Object getObject(int i, java.util.Map map) throws SQLException {
throw org.postgresql.Driver.notImplemented();
public Ref getRef(String columnName) throws SQLException }
{
return getRef(findColumn(columnName));
} public Ref getRef(String columnName) throws SQLException {
return getRef(findColumn(columnName));
public Ref getRef(int i) throws SQLException }
{
//The backend doesn't yet have SQL3 REF types
throw new PSQLException("postgresql.psqlnotimp"); public Ref getRef(int i) throws SQLException {
} //The backend doesn't yet have SQL3 REF types
throw new PSQLException("postgresql.psqlnotimp");
public int getRow() throws SQLException }
{
final int rows_size = rows.size();
public int getRow() throws SQLException {
if (current_row < 0 || current_row >= rows_size) final int rows_size = rows.size();
return 0;
if (current_row < 0 || current_row >= rows_size)
return current_row + 1; return 0;
}
return current_row + 1;
// This one needs some thought, as not all ResultSets come from a statement }
public Statement getStatement() throws SQLException
{
return statement; // This one needs some thought, as not all ResultSets come from a statement
} public Statement getStatement() throws SQLException {
return statement;
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 public int getType() throws SQLException {
// meaningful result. // This implementation allows scrolling but is not able to
return java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE; // see any changes. Sub-classes may overide this to return a more
} // meaningful result.
return java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE;
public void insertRow() throws SQLException }
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable(); public boolean isAfterLast() throws SQLException {
} final int rows_size = rows.size();
return (current_row >= rows_size && rows_size > 0);
public boolean isAfterLast() throws SQLException }
{
final int rows_size = rows.size();
return (current_row >= rows_size && rows_size > 0); public boolean isBeforeFirst() throws SQLException {
} return (current_row < 0 && rows.size() > 0);
}
public boolean isBeforeFirst() throws SQLException
{
return (current_row < 0 && rows.size() > 0); public boolean isFirst() throws SQLException {
} return (current_row == 0 && rows.size() >= 0);
}
public boolean isFirst() throws SQLException
{
return (current_row == 0 && rows.size() >= 0); public boolean isLast() throws SQLException {
} final int rows_size = rows.size();
return (current_row == rows_size - 1 && rows_size > 0);
public boolean isLast() throws SQLException }
{
final int rows_size = rows.size();
return (current_row == rows_size - 1 && rows_size > 0); public boolean last() throws SQLException {
} final int rows_size = rows.size();
if (rows_size <= 0)
public boolean last() throws SQLException return false;
{
final int rows_size = rows.size(); current_row = rows_size - 1;
if (rows_size <= 0) this_row = (byte[][]) rows.elementAt(current_row);
return false;
rowBuffer = new byte[this_row.length][];
current_row = rows_size - 1; System.arraycopy(this_row, 0, rowBuffer, 0, this_row.length);
this_row = (byte [][])rows.elementAt(current_row);
return true;
rowBuffer=new byte[this_row.length][]; }
System.arraycopy(this_row,0,rowBuffer,0,this_row.length);
return true; public boolean previous() throws SQLException {
} if (--current_row < 0)
return false;
public void moveToCurrentRow() throws SQLException this_row = (byte[][]) rows.elementAt(current_row);
{ System.arraycopy(this_row, 0, rowBuffer, 0, this_row.length);
// only sub-classes implement CONCUR_UPDATEABLE return true;
notUpdateable(); }
}
public void moveToInsertRow() throws SQLException public boolean relative(int rows) throws SQLException {
{ //have to add 1 since absolute expects a 1-based index
// only sub-classes implement CONCUR_UPDATEABLE return absolute(current_row + 1 + rows);
notUpdateable(); }
}
public boolean previous() throws SQLException public void setFetchDirection(int direction) throws SQLException {
{ throw new PSQLException("postgresql.psqlnotimp");
if (--current_row < 0) }
return false;
this_row = (byte [][])rows.elementAt(current_row);
System.arraycopy(this_row,0,rowBuffer,0,this_row.length); public void setFetchSize(int rows) throws SQLException {
return true; // Sub-classes should implement this as part of their cursor support
} throw org.postgresql.Driver.notImplemented();
}
public void refreshRow() throws SQLException
{
throw new PSQLException("postgresql.notsensitive"); public synchronized void cancelRowUpdates() throws SQLException {
} if (doingUpdates) {
doingUpdates = false;
public boolean relative(int rows) throws SQLException
{ clearRowBuffer();
//have to add 1 since absolute expects a 1-based index }
return absolute(current_row + 1 + rows); }
}
public boolean rowDeleted() throws SQLException public synchronized void deleteRow() throws SQLException {
{ if ( !isUpdateable() ) {
// only sub-classes implement CONCUR_UPDATEABLE throw new PSQLException( "postgresql.updateable.notupdateable" );
notUpdateable(); }
return false; // javac complains about not returning a value!
} if (onInsertRow) {
throw new PSQLException( "postgresql.updateable.oninsertrow" );
public boolean rowInserted() throws SQLException }
{
// only sub-classes implement CONCUR_UPDATEABLE if (rows.size() == 0) {
notUpdateable(); throw new PSQLException( "postgresql.updateable.emptydelete" );
return false; // javac complains about not returning a value! }
} if (isBeforeFirst()) {
throw new PSQLException( "postgresql.updateable.beforestartdelete" );
public boolean rowUpdated() throws SQLException }
{ if (isAfterLast()) {
// only sub-classes implement CONCUR_UPDATEABLE throw new PSQLException( "postgresql.updateable.afterlastdelete" );
notUpdateable(); }
return false; // javac complains about not returning a value!
}
int numKeys = primaryKeys.size();
public void setFetchDirection(int direction) throws SQLException if ( deleteStatement == null ) {
{
throw new PSQLException("postgresql.psqlnotimp");
} StringBuffer deleteSQL = new StringBuffer("DELETE FROM " ).append(tableName).append(" where " );
public void setFetchSize(int rows) throws SQLException for ( int i = 0; i < numKeys; i++ ) {
{ deleteSQL.append( ((PrimaryKey) primaryKeys.get(i)).name ).append( " = ? " );
// Sub-classes should implement this as part of their cursor support if ( i < numKeys - 1 ) {
throw org.postgresql.Driver.notImplemented(); deleteSQL.append( " and " );
} }
}
public void updateAsciiStream(int columnIndex,
java.io.InputStream x, deleteStatement = ((java.sql.Connection) connection).prepareStatement(deleteSQL.toString());
int length }
) throws SQLException deleteStatement.clearParameters();
{
// only sub-classes implement CONCUR_UPDATEABLE for ( int i = 0; i < numKeys; i++ ) {
notUpdateable(); deleteStatement.setObject(i + 1, ((PrimaryKey) primaryKeys.get(i)).getValue());
} }
public void updateAsciiStream(String columnName,
java.io.InputStream x, deleteStatement.executeUpdate();
int length
) throws SQLException rows.removeElementAt(current_row);
{ }
updateAsciiStream(findColumn(columnName), x, length);
}
public synchronized void insertRow() throws SQLException {
public void updateBigDecimal(int columnIndex, if ( !isUpdateable() ) {
java.math.BigDecimal x throw new PSQLException( "postgresql.updateable.notupdateable" );
) throws SQLException }
{
// only sub-classes implement CONCUR_UPDATEABLE if (!onInsertRow) {
notUpdateable(); throw new PSQLException( "postgresql.updateable.notoninsertrow" );
} }
else {
public void updateBigDecimal(String columnName,
java.math.BigDecimal x // loop through the keys in the insertTable and create the sql statement
) throws SQLException // we have to create the sql every time since the user could insert different
{ // columns each time
updateBigDecimal(findColumn(columnName), x);
} StringBuffer insertSQL = new StringBuffer("INSERT INTO ").append(tableName).append(" (");
StringBuffer paramSQL = new StringBuffer(") values (" );
public void updateBinaryStream(int columnIndex,
java.io.InputStream x, Enumeration columnNames = updateValues.keys();
int length int numColumns = updateValues.size();
) throws SQLException
{ for ( int i = 0; columnNames.hasMoreElements(); i++ ) {
// only sub-classes implement CONCUR_UPDATEABLE String columnName = (String) columnNames.nextElement();
notUpdateable();
} insertSQL.append( columnName );
if ( i < numColumns - 1 ) {
public void updateBinaryStream(String columnName, insertSQL.append(", ");
java.io.InputStream x, paramSQL.append("?,");
int length }
) throws SQLException else {
{ paramSQL.append("?)");
updateBinaryStream(findColumn(columnName), x, length); }
}
}
public void updateBoolean(int columnIndex, boolean x) throws SQLException
{ insertSQL.append(paramSQL.toString());
// only sub-classes implement CONCUR_UPDATEABLE insertStatement = ((java.sql.Connection) connection).prepareStatement(insertSQL.toString());
notUpdateable();
} Enumeration keys = updateValues.keys();
public void updateBoolean(String columnName, boolean x) throws SQLException for ( int i = 1; keys.hasMoreElements(); i++) {
{ String key = (String) keys.nextElement();
updateBoolean(findColumn(columnName), x); insertStatement.setObject(i, updateValues.get( key ) );
} }
public void updateByte(int columnIndex, byte x) throws SQLException insertStatement.executeUpdate();
{
// only sub-classes implement CONCUR_UPDATEABLE if ( usingOID ) {
notUpdateable(); // we have to get the last inserted OID and put it in the resultset
}
long insertedOID = ((AbstractJdbc2Statement) insertStatement).getLastOID();
public void updateByte(String columnName, byte x) throws SQLException
{ updateValues.put("oid", new Long(insertedOID) );
updateByte(findColumn(columnName), x);
} }
public void updateBytes(String columnName, byte[] x) throws SQLException // update the underlying row to the new inserted data
{ updateRowBuffer();
updateBytes(findColumn(columnName), x);
} rows.addElement(rowBuffer);
public void updateBytes(int columnIndex, byte[] x) throws SQLException // we should now reflect the current data in this_row
{ // that way getXXX will get the newly inserted data
// only sub-classes implement CONCUR_UPDATEABLE this_row = rowBuffer;
notUpdateable();
} // need to clear this in case of another insert
clearRowBuffer();
public void updateCharacterStream(int columnIndex,
java.io.Reader x,
int length }
) throws SQLException }
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable(); public synchronized void moveToCurrentRow() throws SQLException {
} if (!updateable) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
public void updateCharacterStream(String columnName, }
java.io.Reader x,
int length this_row = (byte[][]) rows.elementAt(current_row);
) throws SQLException
{ rowBuffer = new byte[this_row.length][];
updateCharacterStream(findColumn(columnName), x, length); System.arraycopy(this_row, 0, rowBuffer, 0, this_row.length);
}
onInsertRow = false;
public void updateDate(int columnIndex, java.sql.Date x) throws SQLException doingUpdates = false;
{ }
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
} public synchronized void moveToInsertRow() throws SQLException {
if (!updateable) {
public void updateDate(String columnName, java.sql.Date x) throws SQLException throw new PSQLException( "postgresql.updateable.notupdateable" );
{ }
updateDate(findColumn(columnName), x);
} if (insertStatement != null) {
insertStatement = null;
public void updateDouble(int columnIndex, double x) throws SQLException }
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable(); // make sure the underlying data is null
} clearRowBuffer();
public void updateDouble(String columnName, double x) throws SQLException onInsertRow = true;
{ doingUpdates = false;
updateDouble(findColumn(columnName), x);
} }
public void updateFloat(int columnIndex, float x) throws SQLException
{ private synchronized void clearRowBuffer() throws SQLException {
// only sub-classes implement CONCUR_UPDATEABLE // rowBuffer is the temporary storage for the row
notUpdateable(); rowBuffer = new byte[fields.length][];
}
// clear the updateValues hashTable for the next set of updates
public void updateFloat(String columnName, float x) throws SQLException updateValues.clear();
{
updateFloat(findColumn(columnName), x); }
}
public void updateInt(int columnIndex, int x) throws SQLException public boolean rowDeleted() throws SQLException {
{ // only sub-classes implement CONCURuPDATEABLE
// only sub-classes implement CONCUR_UPDATEABLE throw Driver.notImplemented();
notUpdateable(); }
}
public void updateInt(String columnName, int x) throws SQLException public boolean rowInserted() throws SQLException {
{ // only sub-classes implement CONCURuPDATEABLE
updateInt(findColumn(columnName), x); throw Driver.notImplemented();
} }
public void updateLong(int columnIndex, long x) throws SQLException
{ public boolean rowUpdated() throws SQLException {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCURuPDATEABLE
notUpdateable(); throw Driver.notImplemented();
} }
public void updateLong(String columnName, long x) throws SQLException
{ public synchronized void updateAsciiStream(int columnIndex,
updateLong(findColumn(columnName), x); java.io.InputStream x,
} int length
) throws SQLException {
public void updateNull(int columnIndex) throws SQLException
{ if ( !isUpdateable() ) {
// only sub-classes implement CONCUR_UPDATEABLE throw new PSQLException( "postgresql.updateable.notupdateable" );
notUpdateable(); }
}
byte[] theData = null;
public void updateNull(String columnName) throws SQLException
{ try {
updateNull(findColumn(columnName)); x.read(theData, 0, length);
} }
catch (NullPointerException ex ) {
public void updateObject(int columnIndex, Object x) throws SQLException throw new PSQLException("postgresql.updateable.inputstream");
{ }
// only sub-classes implement CONCUR_UPDATEABLE catch (IOException ie) {
notUpdateable(); throw new PSQLException("postgresql.updateable.ioerror" + ie);
} }
public void updateObject(String columnName, Object x) throws SQLException doingUpdates = !onInsertRow;
{
updateObject(findColumn(columnName), x); updateValues.put( fields[columnIndex - 1].getName(), theData );
}
}
public void updateObject(int columnIndex, Object x, int scale) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE public synchronized void updateBigDecimal(int columnIndex,
notUpdateable(); java.math.BigDecimal x )
} throws SQLException {
public void updateObject(String columnName, Object x, int scale) throws SQLException if ( !isUpdateable() ) {
{ throw new PSQLException( "postgresql.updateable.notupdateable" );
updateObject(findColumn(columnName), x, scale); }
}
doingUpdates = !onInsertRow;
public void updateRow() throws SQLException updateValues.put( fields[columnIndex - 1].getName(), x );
{
// only sub-classes implement CONCUR_UPDATEABLE }
notUpdateable();
}
public synchronized void updateBinaryStream(int columnIndex,
public void updateShort(int columnIndex, short x) throws SQLException java.io.InputStream x,
{ int length
// only sub-classes implement CONCUR_UPDATEABLE ) throws SQLException {
notUpdateable();
} if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
public void updateShort(String columnName, short x) throws SQLException }
{
updateShort(findColumn(columnName), x); byte[] theData = null;
}
try {
public void updateString(int columnIndex, String x) throws SQLException x.read(theData, 0, length);
{
// only sub-classes implement CONCUR_UPDATEABLE }
notUpdateable(); catch ( NullPointerException ex ) {
} throw new PSQLException("postgresql.updateable.inputstream");
}
public void updateString(String columnName, String x) throws SQLException catch (IOException ie) {
{ throw new PSQLException("postgresql.updateable.ioerror" + ie);
updateString(findColumn(columnName), x); }
}
doingUpdates = !onInsertRow;
public void updateTime(int columnIndex, Time x) throws SQLException
{ updateValues.put( fields[columnIndex - 1].getName(), theData );
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable(); }
}
public void updateTime(String columnName, Time x) throws SQLException public synchronized void updateBoolean(int columnIndex, boolean x) throws SQLException {
{
updateTime(findColumn(columnName), x); if ( !isUpdateable() ) {
} throw new PSQLException( "postgresql.updateable.notupdateable" );
}
public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException
{ if ( Driver.logDebug ) Driver.debug("updating boolean " + fields[columnIndex - 1].getName() + "=" + x);
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable(); doingUpdates = !onInsertRow;
} updateValues.put( fields[columnIndex - 1].getName(), new Boolean(x) );
public void updateTimestamp(String columnName, Timestamp x) throws SQLException }
{
updateTimestamp(findColumn(columnName), x);
} public synchronized void updateByte(int columnIndex, byte x) throws SQLException {
if ( !isUpdateable() ) {
// helper method. Throws an SQLException when an update is not possible throw new PSQLException( "postgresql.updateable.notupdateable" );
public void notUpdateable() throws SQLException }
{
throw new PSQLException("postgresql.noupdate"); doingUpdates = true;
} updateValues.put( fields[columnIndex - 1].getName(), String.valueOf(x) );
}
/*
* It's used currently by getStatement() but may also with the new core
* package. public synchronized void updateBytes(int columnIndex, byte[] x) throws SQLException {
*/
public void setStatement(Statement statement) if ( !isUpdateable() ) {
{ throw new PSQLException( "postgresql.updateable.notupdateable" );
this.statement = statement; }
}
doingUpdates = !onInsertRow;
public void setSQLQuery(String sqlQuery) { updateValues.put( fields[columnIndex - 1].getName(), x );
this.sqlQuery=sqlQuery;
} }
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;
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 updateDate(int columnIndex, java.sql.Date x) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), x );
}
public synchronized void updateDouble(int columnIndex, double x) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
if ( Driver.logDebug ) Driver.debug("updating double " + fields[columnIndex - 1].getName() + "=" + x);
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), new Double(x) );
}
public synchronized void updateFloat(int columnIndex, float x) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
if ( Driver.logDebug ) Driver.debug("updating float " + fields[columnIndex - 1].getName() + "=" + x);
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), new Float(x) );
}
public synchronized void updateInt(int columnIndex, int x) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
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 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 updateNull(int columnIndex) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), null);
}
public synchronized void updateObject(int columnIndex, Object x) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
if ( Driver.logDebug ) Driver.debug("updating object " + 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" );
}
this.updateObject(columnIndex, x);
}
public void refreshRow() throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
try {
StringBuffer selectSQL = new StringBuffer( "select ");
final int numColumns = java.lang.reflect.Array.getLength(fields);
for (int i = 0; i < numColumns; i++ ) {
selectSQL.append( fields[i].getName() );
if ( i < numColumns - 1 ) {
selectSQL.append(", ");
}
}
selectSQL.append(" from " ).append(tableName).append(" where ");
int numKeys = primaryKeys.size();
for ( int i = 0; i < numKeys; i++ ) {
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());
for ( int j = 0, i = 1; j < numKeys; j++, i++) {
selectStatement.setObject( i, ((PrimaryKey) primaryKeys.get(j)).getValue() );
}
Jdbc2ResultSet rs = (Jdbc2ResultSet) selectStatement.executeQuery();
if ( rs.first() ) {
rowBuffer = rs.rowBuffer;
}
rows.setElementAt( rowBuffer, current_row );
if ( Driver.logDebug ) Driver.debug("done updates");
rs.close();
selectStatement.close();
selectStatement = null;
}
catch (Exception e) {
if ( Driver.logDebug ) Driver.debug(e.getClass().getName() + e);
throw new SQLException( e.getMessage() );
}
}
public synchronized void updateRow() throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
if (doingUpdates) {
try {
StringBuffer updateSQL = new StringBuffer("UPDATE " + tableName + " SET ");
int numColumns = updateValues.size();
Enumeration columns = updateValues.keys();
for (int i = 0; columns.hasMoreElements(); i++ ) {
String column = (String) columns.nextElement();
updateSQL.append( column + "= ?");
if ( i < numColumns - 1 ) {
updateSQL.append(", ");
}
}
updateSQL.append( " WHERE " );
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());
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() );
}
updateStatement.executeUpdate();
updateStatement.close();
updateStatement = null;
updateRowBuffer();
if ( Driver.logDebug ) Driver.debug("copying data");
System.arraycopy(rowBuffer, 0, this_row, 0, rowBuffer.length);
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 updateShort(int columnIndex, short x) throws SQLException {
if ( Driver.logDebug ) Driver.debug("in update Short " + fields[columnIndex - 1].getName() + " = " + x);
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), new Short(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 updateTime(int columnIndex, Time x) throws SQLException {
if ( Driver.logDebug ) Driver.debug("in update Time " + fields[columnIndex - 1].getName() + " = " + x);
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), x );
}
public synchronized void updateTimestamp(int columnIndex, Timestamp x) throws SQLException {
if ( Driver.logDebug ) Driver.debug("updating Timestamp " + fields[columnIndex - 1].getName() + " = " + x);
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), x );
}
public synchronized void updateNull(String columnName) throws SQLException {
updateNull(findColumn(columnName));
}
public synchronized void updateBoolean(String columnName, boolean x) throws SQLException {
updateBoolean(findColumn(columnName), x);
}
public synchronized void updateByte(String columnName, byte x) throws SQLException {
updateByte(findColumn(columnName), x);
}
public synchronized void updateShort(String columnName, short x) throws SQLException {
updateShort(findColumn(columnName), x);
}
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 updateFloat(String columnName, float x) throws SQLException {
updateFloat(findColumn(columnName), 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(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 updateDate(String columnName, java.sql.Date x)
throws SQLException {
updateDate(findColumn(columnName), x);
}
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() {
StringTokenizer st = new StringTokenizer(sqlQuery, " \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;
}
public void setSQLQuery(String sqlQuery) {
this.sqlQuery = sqlQuery;
}
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);
}
};
} }
...@@ -2,12 +2,13 @@ package org.postgresql.jdbc2; ...@@ -2,12 +2,13 @@ package org.postgresql.jdbc2;
import java.io.*; import java.io.*;
import java.math.*;
import java.sql.*; import java.sql.*;
import java.util.Vector; import java.util.Vector;
import org.postgresql.largeobject.*; import org.postgresql.largeobject.*;
import org.postgresql.util.PSQLException; import org.postgresql.util.PSQLException;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2Statement.java,v 1.2 2002/07/24 22:08:42 barry Exp $ /* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2Statement.java,v 1.3 2002/07/25 22:45:28 barry Exp $
* This class defines methods of the jdbc2 specification. This class extends * This class defines methods of the jdbc2 specification. This class extends
* org.postgresql.jdbc1.AbstractJdbc1Statement which provides the jdbc1 * org.postgresql.jdbc1.AbstractJdbc1Statement which provides the jdbc1
* methods. The real Statement class (for jdbc2) is org.postgresql.jdbc2.Jdbc2Statement * methods. The real Statement class (for jdbc2) is org.postgresql.jdbc2.Jdbc2Statement
...@@ -46,7 +47,7 @@ public abstract class AbstractJdbc2Statement extends org.postgresql.jdbc1.Abstra ...@@ -46,7 +47,7 @@ public abstract class AbstractJdbc2Statement extends org.postgresql.jdbc1.Abstra
{ {
boolean l_return = super.execute(sql); boolean l_return = super.execute(sql);
//Now do the jdbc2 specific stuff //Now do the jdbc2 specific stuff
//required for ResultSet.getStatement() to work //required for ResultSet.getStatement() to work and updateable resultsets
((AbstractJdbc2ResultSet)result).setStatement((Statement)this); ((AbstractJdbc2ResultSet)result).setStatement((Statement)this);
// Added this so that the Updateable resultset knows the query that gave this // Added this so that the Updateable resultset knows the query that gave this
...@@ -331,4 +332,60 @@ public abstract class AbstractJdbc2Statement extends org.postgresql.jdbc1.Abstra ...@@ -331,4 +332,60 @@ public abstract class AbstractJdbc2Statement extends org.postgresql.jdbc1.Abstra
setTimestamp(i, new java.sql.Timestamp(cal.getTime().getTime())); setTimestamp(i, new java.sql.Timestamp(cal.getTime().getTime()));
} }
} }
// ** JDBC 2 Extensions for CallableStatement**
public java.sql.Array getArray(int i) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public java.math.BigDecimal getBigDecimal(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.NUMERIC, "BigDecimal");
return ((BigDecimal)callResult);
}
public Blob getBlob(int i) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public Clob getClob(int i) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public Object getObject(int i, java.util.Map map) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public Ref getRef(int i) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public java.sql.Date getDate(int i, java.util.Calendar cal) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public Time getTime(int i, java.util.Calendar cal) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public Timestamp getTimestamp(int i, java.util.Calendar cal) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
// no custom types allowed yet..
public void registerOutParameter(int parameterIndex, int sqlType, String typeName) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
} }
...@@ -340,7 +340,7 @@ public class Array implements java.sql.Array ...@@ -340,7 +340,7 @@ public class Array implements java.sql.Array
default: default:
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
return new Jdbc2ResultSet((org.postgresql.jdbc2.Jdbc2Connection)conn, fields, rows, "OK", 1 ); return ((Jdbc2Connection)conn).getResultSet(null, fields, rows, "OK", 1 );
} }
public String toString() public String toString()
......
package org.postgresql.jdbc2;
// IMPORTANT NOTE: This file implements the JDBC 2 version of the driver.
// If you make any modifications to this file, you must make sure that the
// changes are also made (if relevent) to the related JDBC 1 class in the
// org.postgresql.jdbc1 package.
import java.sql.*;
import java.math.*;
import org.postgresql.util.*;
/*
* CallableStatement is used to execute SQL stored procedures.
*
* <p>JDBC provides a stored procedure SQL escape that allows stored
* procedures to be called in a standard way for all RDBMS's. This escape
* syntax has one form that includes a result parameter and one that does
* not. If used, the result parameter must be registered as an OUT
* parameter. The other parameters may be used for input, output or both.
* Parameters are refered to sequentially, by number. The first parameter
* is 1.
*
* {?= call <procedure-name>[<arg1>,<arg2>, ...]}
* {call <procedure-name>[<arg1>,<arg2>, ...]}
*
*
* <p>IN parameter values are set using the set methods inherited from
* PreparedStatement. The type of all OUT parameters must be registered
* prior to executing the stored procedure; their values are retrieved
* after execution via the get methods provided here.
*
* <p>A Callable statement may return a ResultSet or multiple ResultSets.
* Multiple ResultSets are handled using operations inherited from
* Statement.
*
* <p>For maximum portability, a call's ResultSets and update counts should
* be processed prior to getting the values of output parameters.
*
* @see Connection#prepareCall
* @see ResultSet
* @author Paul Bethe (implementer)
*/
public class CallableStatement extends org.postgresql.jdbc2.Jdbc2PreparedStatement implements java.sql.CallableStatement
{
/*
* @exception SQLException on failure
*/
public CallableStatement(Jdbc2Connection c, String q) throws SQLException
{
super(c, q); // don't parse yet..
}
/**
* allows this class to tweak the standard JDBC call !see Usage
* -> and replace with the pgsql function syntax
* ie. select <function ([params])> as RESULT;
*/
protected void parseSqlStmt () throws SQLException {
modifyJdbcCall ();
super.parseSqlStmt ();
}
/**
* this method will turn a string of the form
* {? = call <some_function> (?, [?,..]) }
* into the PostgreSQL format which is
* select <some_function> (?, [?, ...]) as result
*
*/
private void modifyJdbcCall () throws SQLException {
// syntax checking is not complete only a few basics :(
originalSql = sql; // save for error msgs..
int index = sql.indexOf ("="); // is implied func or proc?
boolean isValid = true;
if (index != -1) {
isFunction = true;
isValid = sql.indexOf ("?") < index; // ? before =
}
sql = sql.trim ();
if (sql.startsWith ("{") && sql.endsWith ("}")) {
sql = sql.substring (1, sql.length() -1);
} else isValid = false;
index = sql.indexOf ("call");
if (index == -1 || !isValid)
throw new PSQLException ("postgresql.call.malformed",
new Object[]{sql, JDBC_SYNTAX});
sql = sql.replace ('{', ' '); // replace these characters
sql = sql.replace ('}', ' ');
sql = 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
sql = (isFunction ? "?" : "") + sql.substring (index + 4);
sql = "select " + sql + " as " + RESULT_COLUMN + ";";
}
// internals
static final String JDBC_SYNTAX = "{[? =] call <some_function> ([? [,?]*]) }";
static final String RESULT_COLUMN = "result";
String originalSql = "";
boolean isFunction;
// functionReturnType contains the user supplied value to check
// testReturn contains a modified version to make it easier to
// check the getXXX methods..
int functionReturnType;
int testReturn;
// returnTypeSet is true when a proper call to registerOutParameter has been made
boolean returnTypeSet;
Object result;
/*
* Before executing a stored procedure call you must explicitly
* call registerOutParameter to register the java.sql.Type of each
* out parameter.
*
* <p>Note: When reading the value of an out parameter, you must use
* the getXXX method whose Java type XXX corresponds to the
* parameter's registered SQL type.
*
* ONLY 1 RETURN PARAMETER if {?= call ..} syntax is used
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param sqlType SQL type code defined by java.sql.Types; for
* parameters of type Numeric or Decimal use the version of
* registerOutParameter that accepts a scale value
* @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 ||
functionReturnType == Types.LONGVARCHAR)
testReturn = Types.VARCHAR;
else if (functionReturnType == Types.FLOAT)
testReturn = Types.REAL; // changes to streamline later error checking
returnTypeSet = true;
}
/**
* allow calls to execute update
* @return 1 if succesful call otherwise 0
*/
public int executeUpdate() throws SQLException
{
java.sql.ResultSet rs = super.executeQuery (compileQuery());
if (isFunction) {
if (!rs.next ())
throw new PSQLException ("postgresql.call.noreturnval");
result = rs.getObject(1);
int columnType = rs.getMetaData().getColumnType(1);
if (columnType != functionReturnType)
throw new PSQLException ("postgresql.call.wrongrtntype",
new Object[]{
getSqlTypeName (columnType), getSqlTypeName (functionReturnType) });
}
rs.close ();
return 1;
}
/**
* allow calls to execute update
* @return true if succesful
*/
public boolean execute() throws SQLException
{
return (executeUpdate() == 1);
}
/*
* You must also specify the scale for numeric/decimal types:
*
* <p>Note: When reading the value of an out parameter, you must use
* the getXXX method whose Java type XXX corresponds to the
* parameter's registered SQL type.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param sqlType use either java.sql.Type.NUMERIC or java.sql.Type.DECIMAL
* @param scale a value greater than or equal to zero representing the
* desired number of digits to the right of the decimal point
* @exception SQLException if a database-access error occurs.
*/
public void registerOutParameter(int parameterIndex, int sqlType,
int scale) throws SQLException
{
registerOutParameter (parameterIndex, sqlType); // ignore for now..
}
/*
* override this method to check for set @ 1 when declared function..
*
* @param paramIndex the index into the inString
* @param s a string to be stored
* @exception SQLException if something goes wrong
*/
protected void set(int paramIndex, String s) throws SQLException
{
if (paramIndex == 1 && isFunction) // need to registerOut instead
throw new PSQLException ("postgresql.call.funcover");
super.set (paramIndex, s); // else set as usual..
}
/*
* Helper - this compiles the SQL query from the various parameters
* This is identical to toString() except it throws an exception if a
* parameter is unused.
*/
protected synchronized String compileQuery()
throws SQLException
{
if (isFunction && !returnTypeSet)
throw new PSQLException("postgresql.call.noreturntype");
if (isFunction) { // set entry 1 to dummy entry..
inStrings[0] = ""; // dummy entry which ensured that no one overrode
// and calls to setXXX (2,..) really went to first arg in a function call..
}
return super.compileQuery ();
}
/*
* An OUT parameter may have the value of SQL NULL; wasNull
* reports whether the last value read has this special value.
*
* <p>Note: You must first call getXXX on a parameter to read its
* value and then call wasNull() to see if the value was SQL NULL.
* @return true if the last parameter read was SQL NULL
* @exception SQLException if a database-access error occurs.
*/
public boolean wasNull() throws SQLException
{
// check to see if the last access threw an exception
return (result == null);
}
/*
* Get the value of a CHAR, VARCHAR, or LONGVARCHAR parameter as a
* Java String.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public String getString(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.VARCHAR, "String");
return (String)result;
}
//public String getVarChar(int parameterIndex) throws SQLException {
// return null;
//}
//public String getLongVarChar(int parameterIndex) throws SQLException {
//return null;
//}
/*
* Get the value of a BIT parameter as a Java boolean.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is false
* @exception SQLException if a database-access error occurs.
*/
public boolean getBoolean(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.BIT, "Boolean");
if (result == null) return false;
return ((Boolean)result).booleanValue ();
}
/*
* Get the value of a TINYINT parameter as a Java byte.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public byte getByte(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.TINYINT, "Byte");
if (result == null) return 0;
return (byte)((Integer)result).intValue ();
}
/*
* Get the value of a SMALLINT parameter as a Java short.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public short getShort(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.SMALLINT, "Short");
if (result == null) return 0;
return (short)((Integer)result).intValue ();
}
/*
* Get the value of an INTEGER parameter as a Java int.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public int getInt(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.INTEGER, "Int");
if (result == null) return 0;
return ((Integer)result).intValue ();
}
/*
* Get the value of a BIGINT parameter as a Java long.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public long getLong(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.BIGINT, "Long");
if (result == null) return 0;
return ((Long)result).longValue ();
}
/*
* Get the value of a FLOAT parameter as a Java float.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public float getFloat(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.REAL, "Float");
if (result == null) return 0;
return ((Float)result).floatValue ();
}
/*
* Get the value of a DOUBLE parameter as a Java double.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public double getDouble(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.DOUBLE, "Double");
if (result == null) return 0;
return ((Double)result).doubleValue ();
}
/*
* Get the value of a NUMERIC parameter as a java.math.BigDecimal
* object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param scale a value greater than or equal to zero representing the
* desired number of digits to the right of the decimal point
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
* @deprecated in Java2.0
*/
public BigDecimal getBigDecimal(int parameterIndex, int scale)
throws SQLException
{
checkIndex (parameterIndex, Types.NUMERIC, "BigDecimal");
return ((BigDecimal)result);
}
/*
* Get the value of a SQL BINARY or VARBINARY parameter as a Java
* byte[]
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public byte[] getBytes(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.VARBINARY, "Bytes");
return ((byte [])result);
}
// New API (JPM) (getLongVarBinary)
//public byte[] getBinaryStream(int parameterIndex) throws SQLException {
//return null;
//}
/*
* Get the value of a SQL DATE parameter as a java.sql.Date object
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public java.sql.Date getDate(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.DATE, "Date");
return (java.sql.Date)result;
}
/*
* Get the value of a SQL TIME parameter as a java.sql.Time object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public java.sql.Time getTime(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.TIME, "Time");
return (java.sql.Time)result;
}
/*
* Get the value of a SQL TIMESTAMP parameter as a java.sql.Timestamp object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public java.sql.Timestamp getTimestamp(int parameterIndex)
throws SQLException
{
checkIndex (parameterIndex, Types.TIMESTAMP, "Timestamp");
return (java.sql.Timestamp)result;
}
//----------------------------------------------------------------------
// Advanced features:
// You can obtain a ParameterMetaData object to get information
// about the parameters to this CallableStatement.
//public DatabaseMetaData getMetaData() {
//return null;
//}
// getObject returns a Java object for the parameter.
// See the JDBC spec's "Dynamic Programming" chapter for details.
/*
* Get the value of a parameter as a Java object.
*
* <p>This method returns a Java object whose type coresponds to the
* SQL type that was registered for this parameter using
* registerOutParameter.
*
* <P>Note that this method may be used to read datatabase-specific,
* abstract data types. This is done by specifying a targetSqlType
* of java.sql.types.OTHER, which allows the driver to return a
* database-specific Java type.
*
* <p>See the JDBC spec's "Dynamic Programming" chapter for details.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return A java.lang.Object holding the OUT parameter value.
* @exception SQLException if a database-access error occurs.
*/
public Object getObject(int parameterIndex)
throws SQLException
{
checkIndex (parameterIndex);
return result;
}
// ** JDBC 2 Extensions **
public java.sql.Array getArray(int i) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public java.math.BigDecimal getBigDecimal(int parameterIndex) throws SQLException
{
checkIndex (parameterIndex, Types.NUMERIC, "BigDecimal");
return ((BigDecimal)result);
}
public Blob getBlob(int i) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public Clob getClob(int i) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public Object getObject(int i, java.util.Map map) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public Ref getRef(int i) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public java.sql.Date getDate(int i, java.util.Calendar cal) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public Time getTime(int i, java.util.Calendar cal) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public Timestamp getTimestamp(int i, java.util.Calendar cal) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
// no custom types allowed yet..
public void registerOutParameter(int parameterIndex, int sqlType, String typeName) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/** helperfunction for the getXXX calls to check isFunction and index == 1
*/
private void checkIndex (int parameterIndex, int type, String getName)
throws SQLException {
checkIndex (parameterIndex);
if (type != this.testReturn)
throw new PSQLException("postgresql.call.wrongget",
new Object[]{getSqlTypeName (testReturn),
getName,
getSqlTypeName (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 {
if (!isFunction)
throw new PSQLException("postgresql.call.noreturntype");
if (parameterIndex != 1)
throw new PSQLException("postgresql.call.noinout");
}
/** helper function for creating msg with type names
* @param sqlType a java.sql.Types.XX constant
* @return String which is the name of the constant..
*/
private static String getSqlTypeName (int sqlType) {
switch (sqlType)
{
case Types.BIT:
return "BIT";
case Types.SMALLINT:
return "SMALLINT";
case Types.INTEGER:
return "INTEGER";
case Types.BIGINT:
return "BIGINT";
case Types.NUMERIC:
return "NUMERIC";
case Types.REAL:
return "REAL";
case Types.DOUBLE:
return "DOUBLE";
case Types.FLOAT:
return "FLOAT";
case Types.CHAR:
return "CHAR";
case Types.VARCHAR:
return "VARCHAR";
case Types.DATE:
return "DATE";
case Types.TIME:
return "TIME";
case Types.TIMESTAMP:
return "TIMESTAMP";
case Types.BINARY:
return "BINARY";
case Types.VARBINARY:
return "VARBINARY";
default:
return "UNKNOWN";
}
}
}
...@@ -15,7 +15,7 @@ import org.postgresql.util.PSQLException; ...@@ -15,7 +15,7 @@ import org.postgresql.util.PSQLException;
/* /*
* This class provides information about the database as a whole. * This class provides information about the database as a whole.
* *
* $Id: DatabaseMetaData.java,v 1.59 2002/07/23 03:59:55 barry Exp $ * $Id: DatabaseMetaData.java,v 1.60 2002/07/25 22:45:28 barry Exp $
* *
* <p>Many of the methods here return lists of information in ResultSets. You * <p>Many of the methods here return lists of information in ResultSets. You
* can use the normal ResultSet methods such as getString and getInt to * can use the normal ResultSet methods such as getString and getInt to
...@@ -1653,7 +1653,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData ...@@ -1653,7 +1653,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
v.addElement(tuple); v.addElement(tuple);
} }
return new Jdbc2ResultSet(connection, f, v, "OK", 1); return connection.getResultSet(null, f, v, "OK", 1);
} }
/* /*
...@@ -1731,7 +1731,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData ...@@ -1731,7 +1731,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
// add query loop here // add query loop here
return new Jdbc2ResultSet(connection, f, v, "OK", 1); return connection.getResultSet(null, f, v, "OK", 1);
} }
/* /*
...@@ -1866,7 +1866,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData ...@@ -1866,7 +1866,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
v.addElement(tuple); v.addElement(tuple);
} }
r.close(); r.close();
return new Jdbc2ResultSet(connection, f, v, "OK", 1); return connection.getResultSet(null, f, v, "OK", 1);
} }
// This array contains the valid values for the types argument // This array contains the valid values for the types argument
...@@ -1913,7 +1913,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData ...@@ -1913,7 +1913,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
f[0] = new Field(connection, "TABLE_SCHEM", iVarcharOid, 32); f[0] = new Field(connection, "TABLE_SCHEM", iVarcharOid, 32);
tuple[0] = "".getBytes(); tuple[0] = "".getBytes();
v.addElement(tuple); v.addElement(tuple);
return new Jdbc2ResultSet(connection, f, v, "OK", 1); return connection.getResultSet(null, f, v, "OK", 1);
} }
/* /*
...@@ -1958,7 +1958,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData ...@@ -1958,7 +1958,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
tuple[0] = getTableTypes[i][0].getBytes(); tuple[0] = getTableTypes[i][0].getBytes();
v.addElement(tuple); v.addElement(tuple);
} }
return new Jdbc2ResultSet(connection, f, v, "OK", 1); return connection.getResultSet(null, f, v, "OK", 1);
} }
/* /*
...@@ -2154,7 +2154,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData ...@@ -2154,7 +2154,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
} }
r.close(); r.close();
return new Jdbc2ResultSet(connection, f, v, "OK", 1); return connection.getResultSet(null, f, v, "OK", 1);
} }
/* /*
...@@ -2218,7 +2218,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData ...@@ -2218,7 +2218,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
//v.addElement(tuple); //v.addElement(tuple);
} }
return new Jdbc2ResultSet(connection, f, v, "OK", 1); return connection.getResultSet(null, f, v, "OK", 1);
} }
/* /*
...@@ -2281,7 +2281,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData ...@@ -2281,7 +2281,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
//v.addElement(tuple); //v.addElement(tuple);
} }
return new Jdbc2ResultSet(connection, f, v, "OK", 1); return connection.getResultSet(null, f, v, "OK", 1);
} }
/* /*
...@@ -2337,7 +2337,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData ...@@ -2337,7 +2337,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
f[6] = new Field(connection, "DECIMAL_DIGITS", iInt2Oid, 2); f[6] = new Field(connection, "DECIMAL_DIGITS", iInt2Oid, 2);
f[7] = new Field(connection, "PSEUDO_COLUMN", iInt2Oid, 2); f[7] = new Field(connection, "PSEUDO_COLUMN", iInt2Oid, 2);
return new Jdbc2ResultSet(connection, f, v, "OK", 1); return connection.getResultSet(null, f, v, "OK", 1);
} }
/* /*
...@@ -2680,7 +2680,7 @@ WHERE ...@@ -2680,7 +2680,7 @@ WHERE
tuples.addElement(tuple); tuples.addElement(tuple);
} }
return new Jdbc2ResultSet(connection, f, tuples, "OK", 1); return connection.getResultSet(null, f, tuples, "OK", 1);
} }
/* /*
...@@ -2959,7 +2959,7 @@ WHERE ...@@ -2959,7 +2959,7 @@ WHERE
v.addElement(tuple); v.addElement(tuple);
} }
rs.close(); rs.close();
return new Jdbc2ResultSet(connection, f, v, "OK", 1); return connection.getResultSet(null, f, v, "OK", 1);
} }
throw new PSQLException("postgresql.metadata.unavailable"); throw new PSQLException("postgresql.metadata.unavailable");
...@@ -3097,7 +3097,7 @@ WHERE ...@@ -3097,7 +3097,7 @@ WHERE
} }
} }
return new Jdbc2ResultSet(connection, f, v, "OK", 1); return connection.getResultSet(null, f, v, "OK", 1);
} }
......
package org.postgresql.jdbc2;
import java.sql.*;
public class Jdbc2CallableStatement extends AbstractJdbc2Statement implements java.sql.CallableStatement
{
public Jdbc2CallableStatement(Jdbc2Connection connection, String sql) throws SQLException
{
super(connection, sql);
}
}
...@@ -3,9 +3,10 @@ package org.postgresql.jdbc2; ...@@ -3,9 +3,10 @@ package org.postgresql.jdbc2;
import java.sql.*; import java.sql.*;
import java.util.Vector; import java.util.Vector;
import java.util.Hashtable;
import org.postgresql.Field; import org.postgresql.Field;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/Jdbc2Connection.java,v 1.2 2002/07/24 22:08:42 barry Exp $ /* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/Jdbc2Connection.java,v 1.3 2002/07/25 22:45:28 barry Exp $
* This class implements the java.sql.Connection interface for JDBC2. * 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 * org.postgresql.jdbc2.AbstractJdbc2Connection or one of it's parents
...@@ -32,7 +33,7 @@ public class Jdbc2Connection extends org.postgresql.jdbc2.AbstractJdbc2Connectio ...@@ -32,7 +33,7 @@ public class Jdbc2Connection extends org.postgresql.jdbc2.AbstractJdbc2Connectio
public java.sql.CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException public java.sql.CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{ {
org.postgresql.jdbc2.CallableStatement s = new org.postgresql.jdbc2.CallableStatement(this,sql); Jdbc2CallableStatement s = new org.postgresql.jdbc2.Jdbc2CallableStatement(this,sql);
s.setResultSetType(resultSetType); s.setResultSetType(resultSetType);
s.setResultSetConcurrency(resultSetConcurrency); s.setResultSetConcurrency(resultSetConcurrency);
return s; return s;
...@@ -45,15 +46,14 @@ public class Jdbc2Connection extends org.postgresql.jdbc2.AbstractJdbc2Connectio ...@@ -45,15 +46,14 @@ public class Jdbc2Connection extends org.postgresql.jdbc2.AbstractJdbc2Connectio
return metadata; return metadata;
} }
public java.sql.ResultSet getResultSet(java.sql.Statement stat, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException public java.sql.ResultSet getResultSet(Statement statement, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException
{ {
if (stat != null) return new Jdbc2ResultSet(this, statement, fields, tuples, status, updateCount, insertOID, binaryCursor);
{ }
if (stat.getResultSetConcurrency() == java.sql.ResultSet.CONCUR_UPDATABLE)
return new org.postgresql.jdbc2.UpdateableResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor);
}
return new Jdbc2ResultSet(this, 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,7 +5,7 @@ import java.sql.*; ...@@ -5,7 +5,7 @@ import java.sql.*;
import java.util.Vector; import java.util.Vector;
import org.postgresql.Field; import org.postgresql.Field;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/Jdbc2ResultSet.java,v 1.1 2002/07/23 03:59:55 barry Exp $ /* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/Jdbc2ResultSet.java,v 1.2 2002/07/25 22:45:28 barry Exp $
* This class implements the java.sql.ResultSet interface for JDBC2. * 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 * org.postgresql.jdbc2.AbstractJdbc2ResultSet or one of it's parents
...@@ -13,14 +13,9 @@ import org.postgresql.Field; ...@@ -13,14 +13,9 @@ import org.postgresql.Field;
public class Jdbc2ResultSet extends org.postgresql.jdbc2.AbstractJdbc2ResultSet implements java.sql.ResultSet public class Jdbc2ResultSet extends org.postgresql.jdbc2.AbstractJdbc2ResultSet implements java.sql.ResultSet
{ {
public Jdbc2ResultSet(Jdbc2Connection conn, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) public Jdbc2ResultSet(Jdbc2Connection conn, Statement statement, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor)
{ {
super(conn, fields, tuples, status, updateCount, insertOID, binaryCursor); super(conn, statement, fields, tuples, status, updateCount, insertOID, binaryCursor);
}
public Jdbc2ResultSet(Jdbc2Connection conn, Field[] fields, Vector tuples, String status, int updateCount)
{
super(conn, fields, tuples, status, updateCount, 0, false);
} }
public java.sql.ResultSetMetaData getMetaData() throws SQLException public java.sql.ResultSetMetaData getMetaData() throws SQLException
......
package org.postgresql.jdbc2;
// IMPORTANT NOTE: This is the begining of supporting updateable ResultSets.
//
// This is because here we should be updateable, so any unimplemented methods
// must say so.
//
// Also you'll notice that the String columnName based calls are not present.
// They are not required as they are in the super class.
//
import java.lang.*;
import java.io.*;
import java.math.*;
import java.text.*;
import java.util.*;
import java.sql.*;
import org.postgresql.Field;
import org.postgresql.largeobject.*;
import org.postgresql.util.*;
import org.postgresql.Driver;
/*
* @see ResultSet
* @see ResultSetMetaData
* @see java.sql.ResultSet
*/
public class UpdateableResultSet extends org.postgresql.jdbc2.Jdbc2ResultSet
{
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);
}
};
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;
/**
* PreparedStatement used to delete data
*/
protected java.sql.PreparedStatement updateStatement = null;
/**
* PreparedStatement used to insert data
*/
protected java.sql.PreparedStatement insertStatement = null;
/**
* PreparedStatement used to delete data
*/
protected java.sql.PreparedStatement deleteStatement = null;
/**
* PreparedStatement used to refresh data
*/
private java.sql.PreparedStatement selectStatement = null;
/**
* Is this result set updateable?
*/
protected boolean updateable = false;
/**
* Are we in the middle of doing updates to the current row?
*/
protected boolean doingUpdates = false;
/**
* Are we on the insert row?
*/
protected boolean onInsertRow = false;
protected Hashtable updateValues = new Hashtable();
// The Row Buffer will be used to cache updated rows..then we shall sync this with the rows vector
/*
* Create a new ResultSet - Note that we create ResultSets to
* represent the results of everything.
*
* @param fields an array of Field objects (basically, the
* ResultSet MetaData)
* @param tuples Vector of the actual data
* @param status the status string returned from the back end
* @param updateCount the number of rows affected by the operation
* @param cursor the positioned update/delete cursor name
*/
public UpdateableResultSet(Jdbc2Connection conn, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor)
{
super(conn, fields, tuples, status, updateCount, insertOID, binaryCursor);
}
/**
*
* @throws SQLException
*/
public synchronized void cancelRowUpdates() throws SQLException
{
if (doingUpdates)
{
doingUpdates = false;
clearRowBuffer();
}
}
/**
*
* @throws SQLException
*/
public synchronized void deleteRow() throws SQLException
{
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
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" );
}
int numKeys = primaryKeys.size();
if ( deleteStatement == null )
{
StringBuffer deleteSQL= new StringBuffer("DELETE FROM " ).append(tableName).append(" where " );
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();
for ( int i =0; i < numKeys; i++ )
{
deleteStatement.setObject(i+1, ((PrimaryKey)primaryKeys.get(i)).getValue());
}
deleteStatement.executeUpdate();
rows.removeElementAt(current_row);
}
/**
*
* @return
* @throws SQLException
*/
public int getConcurrency() throws SQLException
{
// New in 7.1 - The updateable ResultSet class will now return
// CONCURuPDATEABLE.
return CONCUR_UPDATABLE;
}
/**
*
* @throws SQLException
*/
public synchronized void insertRow() throws SQLException
{
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
if (!onInsertRow)
{
throw new PSQLException( "postgresql.updateable.notoninsertrow" );
}
else
{
// 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();
for ( int i=0; columnNames.hasMoreElements() ; i++ )
{
String columnName = (String)columnNames.nextElement();
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());
Enumeration keys = updateValues.keys();
for( int i=1; keys.hasMoreElements() ; i++)
{
String key = (String)keys.nextElement();
insertStatement.setObject(i, updateValues.get( key ) );
}
insertStatement.executeUpdate();
if ( usingOID )
{
// we have to get the last inserted OID and put it in the resultset
long insertedOID = ((AbstractJdbc2Statement)insertStatement).getLastOID();
updateValues.put("oid", new Long(insertedOID) );
}
// update the underlying row to the new inserted data
updateRowBuffer();
rows.addElement(rowBuffer);
// we should now reflect the current data in this_row
// that way getXXX will get the newly inserted data
this_row = rowBuffer;
// need to clear this in case of another insert
clearRowBuffer();
}
}
/**
*
* @throws SQLException
*/
public synchronized void moveToCurrentRow() throws SQLException
{
this_row = (byte [][])rows.elementAt(current_row);
rowBuffer=new byte[this_row.length][];
System.arraycopy(this_row,0,rowBuffer,0,this_row.length);
onInsertRow = false;
doingUpdates = false;
}
/**
*
* @throws SQLException
*/
public synchronized void moveToInsertRow() throws SQLException
{
// only sub-classes implement CONCURuPDATEABLE
if (!updateable)
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
if (insertStatement != null)
{
insertStatement = null;
}
// make sure the underlying data is null
clearRowBuffer();
onInsertRow = true;
doingUpdates = false;
}
/**
*
* @throws SQLException
*/
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();
}
/**
*
* @return
* @throws SQLException
*/
public boolean rowDeleted() throws SQLException
{
// only sub-classes implement CONCURuPDATEABLE
throw Driver.notImplemented();
}
/**
*
* @return
* @throws SQLException
*/
public boolean rowInserted() throws SQLException
{
// only sub-classes implement CONCURuPDATEABLE
throw Driver.notImplemented();
}
/**
*
* @return
* @throws SQLException
*/
public boolean rowUpdated() throws SQLException
{
// only sub-classes implement CONCURuPDATEABLE
throw Driver.notImplemented();
}
/**
*
* @param columnIndex
* @param x
* @param length
* @throws SQLException
*/
public synchronized void updateAsciiStream(int columnIndex,
java.io.InputStream x,
int length
) throws SQLException
{
byte[] theData=null;
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 );
}
/**
*
* @param columnIndex
* @param x
* @throws SQLException
*/
public synchronized void updateBigDecimal(int columnIndex,
java.math.BigDecimal x )
throws SQLException
{
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex-1].getName(), x );
}
/**
*
* @param columnIndex
* @param x
* @param length
* @throws SQLException
*/
public synchronized void updateBinaryStream(int columnIndex,
java.io.InputStream x,
int length
) throws SQLException
{
byte[] theData=null;
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 );
}
/**
*
* @param columnIndex
* @param x
* @throws SQLException
*/
public synchronized void updateBoolean(int columnIndex, boolean x) throws SQLException
{
if ( Driver.logDebug ) Driver.debug("updating boolean "+fields[columnIndex-1].getName()+"="+x);
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex-1].getName(), new Boolean(x) );
}
/**
*
* @param columnIndex
* @param x
* @throws SQLException
*/
public synchronized void updateByte(int columnIndex, byte x) throws SQLException
{
doingUpdates = true;
updateValues.put( fields[columnIndex-1].getName(), String.valueOf(x) );
}
/**
*
* @param columnIndex
* @param x
* @throws SQLException
*/
public synchronized void updateBytes(int columnIndex, byte[] x) throws SQLException
{
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex-1].getName(), x );
}
/**
*
* @param columnIndex
* @param x
* @param length
* @throws SQLException
*/
public synchronized void updateCharacterStream(int columnIndex,
java.io.Reader x,
int length
) throws SQLException
{
char[] theData=null;
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 updateDate(int columnIndex, java.sql.Date x) throws SQLException
{
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex-1].getName(), x );
}
public synchronized void updateDouble(int columnIndex, double x) throws SQLException
{
if ( Driver.logDebug ) Driver.debug("updating double "+fields[columnIndex-1].getName()+"="+x);
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex-1].getName(), new Double(x) );
}
public synchronized void updateFloat(int columnIndex, float x) throws SQLException
{
if ( Driver.logDebug ) Driver.debug("updating float "+fields[columnIndex-1].getName()+"="+x);
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex-1].getName(), new Float(x) );
}
public synchronized void updateInt(int columnIndex, int x) throws SQLException
{
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 updateLong(int columnIndex, long x) throws SQLException
{
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 updateNull(int columnIndex) throws SQLException
{
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex-1].getName(), null);
}
public synchronized void updateObject(int columnIndex, Object x) throws SQLException
{
if ( Driver.logDebug ) Driver.debug("updating object " + 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
{
this.updateObject(columnIndex, x);
}
public void refreshRow() throws SQLException
{
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
try
{
StringBuffer selectSQL = new StringBuffer( "select ");
final int numColumns = java.lang.reflect.Array.getLength(fields);
for (int i=0; i < numColumns ; i++ )
{
selectSQL.append( fields[i].getName() );
if ( i < numColumns - 1 )
{
selectSQL.append(", ");
}
}
selectSQL.append(" from " ).append(tableName).append(" where ");
int numKeys = primaryKeys.size();
for ( int i = 0; i < numKeys; i++ )
{
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());
for( int j=0, i=1; j < numKeys; j++, i++)
{
selectStatement.setObject( i, ((PrimaryKey)primaryKeys.get(j)).getValue() );
}
Jdbc2ResultSet rs = (Jdbc2ResultSet) selectStatement.executeQuery();
if( rs.first() )
{
rowBuffer = rs.rowBuffer;
}
rows.setElementAt( rowBuffer, current_row );
if ( Driver.logDebug ) Driver.debug("done updates");
rs.close();
selectStatement.close();
selectStatement = null;
}
catch (Exception e)
{
if ( Driver.logDebug ) Driver.debug(e.getClass().getName()+e);
throw new SQLException( e.getMessage() );
}
}
/**
*
* @throws SQLException
*/
public synchronized void updateRow() throws SQLException
{
if ( !isUpdateable() )
{
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
if (doingUpdates)
{
try
{
StringBuffer updateSQL=new StringBuffer("UPDATE "+tableName+" SET ");
int numColumns = updateValues.size();
Enumeration columns = updateValues.keys();
for (int i=0; columns.hasMoreElements() ; i++ )
{
String column = (String)columns.nextElement();
updateSQL.append( column + "= ?");
if ( i < numColumns - 1 )
{
updateSQL.append(", ");
}
}
updateSQL.append( " WHERE " );
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());
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() );
}
updateStatement.executeUpdate();
updateStatement.close();
updateStatement = null;
updateRowBuffer();
if ( Driver.logDebug ) Driver.debug("copying data");
System.arraycopy(rowBuffer,0,this_row,0,rowBuffer.length);
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 updateShort(int columnIndex, short x) throws SQLException
{
if ( Driver.logDebug ) Driver.debug("in update Short "+fields[columnIndex-1].getName()+" = "+x);
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex-1].getName(), new Short(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 updateTime(int columnIndex, Time x) throws SQLException
{
if ( Driver.logDebug ) Driver.debug("in update Time "+fields[columnIndex-1].getName()+" = "+x);
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex-1].getName(), x );
}
public synchronized void updateTimestamp(int columnIndex, Timestamp x) throws SQLException
{
if ( Driver.logDebug ) Driver.debug("updating Timestamp "+fields[columnIndex-1].getName()+" = "+x);
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex-1].getName(), x );
}
public synchronized void updateNull(String columnName) throws SQLException
{
updateNull(findColumn(columnName));
}
/**
* JDBC 2.0
*
* Update a column with a boolean value.
*
* The updateXXX() methods are used to update column values in the
* current row, or the insert row. The updateXXX() methods do not
* update the underlying database, instead the updateRow() or insertRow()
* 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
*/
public synchronized void updateBoolean(String columnName, boolean x) throws SQLException
{
updateBoolean(findColumn(columnName), x);
}
/**
* JDBC 2.0
*
* Update a column with a byte value.
*
* The updateXXX() methods are used to update column values in the
* current row, or the insert row. The updateXXX() methods do not
* update the underlying database, instead the updateRow() or insertRow()
* 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
*/
public synchronized void updateByte(String columnName, byte x) throws SQLException
{
updateByte(findColumn(columnName), x);
}
/**
* JDBC 2.0
*
* Update a column with a short value.
*
* The updateXXX() methods are used to update column values in the
* current row, or the insert row. The updateXXX() methods do not
* update the underlying database, instead the updateRow() or insertRow()
* 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
*/
public synchronized void updateShort(String columnName, short x) throws SQLException
{
updateShort(findColumn(columnName), x);
}
/**
* JDBC 2.0
*
* Update a column with an integer value.
*
* The updateXXX() methods are used to update column values in the
* current row, or the insert row. The updateXXX() methods do not
* update the underlying database, instead the updateRow() or insertRow()
* 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
*/
public synchronized void updateInt(String columnName, int x) throws SQLException
{
updateInt(findColumn(columnName), x);
}
/**
* JDBC 2.0
*
* Update a column with a long value.
*
* The updateXXX() methods are used to update column values in the
* current row, or the insert row. The updateXXX() methods do not
* update the underlying database, instead the updateRow() or insertRow()
* 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
*/
public synchronized void updateLong(String columnName, long x) throws SQLException
{
updateLong(findColumn(columnName), x);
}
/**
* JDBC 2.0
*
* Update a column with a float value.
*
* The updateXXX() methods are used to update column values in the
* current row, or the insert row. The updateXXX() methods do not
* update the underlying database, instead the updateRow() or insertRow()
* 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
*/
public synchronized void updateFloat(String columnName, float x) throws SQLException
{
updateFloat(findColumn(columnName), x);
}
/**
* JDBC 2.0
*
* Update a column with a double value.
*
* The updateXXX() methods are used to update column values in the
* current row, or the insert row. The updateXXX() methods do not
* update the underlying database, instead the updateRow() or insertRow()
* 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
*/
public synchronized void updateDouble(String columnName, double x) throws SQLException
{
updateDouble(findColumn(columnName), x);
}
/**
* JDBC 2.0
*
* Update a column with a BigDecimal value.
*
* The updateXXX() methods are used to update column values in the
* current row, or the insert row. The updateXXX() methods do not
* update the underlying database, instead the updateRow() or insertRow()
* 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
*/
public synchronized void updateBigDecimal(String columnName, BigDecimal x)
throws SQLException
{
updateBigDecimal(findColumn(columnName), x);
}
/**
* JDBC 2.0
*
* Update a column with a String value.
*
* The updateXXX() methods are used to update column values in the
* current row, or the insert row. The updateXXX() methods do not
* update the underlying database, instead the updateRow() or insertRow()
* 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
*/
public synchronized void updateString(String columnName, String x) throws SQLException
{
updateString(findColumn(columnName), x);
}
/**
* JDBC 2.0
*
* Update a column with a byte array value.
*
* The updateXXX() methods are used to update column values in the
* current row, or the insert row. The updateXXX() methods do not
* update the underlying database, instead the updateRow() or insertRow()
* 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
*/
public synchronized void updateBytes(String columnName, byte x[]) throws SQLException
{
updateBytes(findColumn(columnName), x);
}
/**
* JDBC 2.0
*
* Update a column with a Date value.
*
* The updateXXX() methods are used to update column values in the
* current row, or the insert row. The updateXXX() methods do not
* update the underlying database, instead the updateRow() or insertRow()
* 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
*/
public synchronized void updateDate(String columnName, java.sql.Date x)
throws SQLException
{
updateDate(findColumn(columnName), x);
}
/**
* JDBC 2.0
*
* Update a column with a Time value.
*
* The updateXXX() methods are used to update column values in the
* current row, or the insert row. The updateXXX() methods do not
* update the underlying database, instead the updateRow() or insertRow()
* 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
*/
public synchronized void updateTime(String columnName, java.sql.Time x)
throws SQLException
{
updateTime(findColumn(columnName), x);
}
/**
* JDBC 2.0
*
* Update a column with a Timestamp value.
*
* The updateXXX() methods are used to update column values in the
* current row, or the insert row. The updateXXX() methods do not
* update the underlying database, instead the updateRow() or insertRow()
* 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
*/
public synchronized void updateTimestamp(String columnName, java.sql.Timestamp x)
throws SQLException
{
updateTimestamp(findColumn(columnName), x);
}
/**
* JDBC 2.0
*
* Update a column with an ascii stream value.
*
* The updateXXX() methods are used to update column values in the
* current row, or the insert row. The updateXXX() methods do not
* update the underlying database, instead the updateRow() or insertRow()
* methods are called to update the database.
*
* @param columnName the name of the column
* @param x the new column value
* @param length of the stream
* @exception SQLException if a database-access error occurs
*/
public synchronized void updateAsciiStream(
String columnName,
java.io.InputStream x,
int length)
throws SQLException
{
updateAsciiStream(findColumn(columnName), x, length);
}
/**
* JDBC 2.0
*
* Update a column with a binary stream value.
*
* The updateXXX() methods are used to update column values in the
* current row, or the insert row. The updateXXX() methods do not
* update the underlying database, instead the updateRow() or insertRow()
* methods are called to update the database.
*
* @param columnName the name of the column
* @param x the new column value
* @param length of the stream
* @exception SQLException if a database-access error occurs
*/
public synchronized void updateBinaryStream(
String columnName,
java.io.InputStream x,
int length)
throws SQLException
{
updateBinaryStream(findColumn(columnName), x, length);
}
/**
* JDBC 2.0
*
* Update a column with a character stream value.
*
* The updateXXX() methods are used to update column values in the
* current row, or the insert row. The updateXXX() methods do not
* update the underlying database, instead the updateRow() or insertRow()
* methods are called to update the database.
*
* @param columnName the name of the column
* @param x the new column value
* @param length of the stream
* @exception SQLException if a database-access error occurs
*/
public synchronized void updateCharacterStream(
String columnName,
java.io.Reader reader,
int length)
throws SQLException
{
updateCharacterStream(findColumn(columnName), reader,length);
}
/**
* JDBC 2.0
*
* Update a column with an Object value.
*
* The updateXXX() methods are used to update column values in the
* current row, or the insert row. The updateXXX() methods do not
* update the underlying database, instead the updateRow() or insertRow()
* methods are called to update the database.
*
* @param columnName the name of the column
* @param x the new column value
* @param scale For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types
* this is the number of digits after the decimal. For all other
* types this value will be ignored.
* @exception SQLException if a database-access error occurs
*/
public synchronized void updateObject(String columnName, Object x, int scale)
throws SQLException
{
updateObject(findColumn(columnName), x);
}
/**
* JDBC 2.0
*
* Update a column with an Object value.
*
* The updateXXX() methods are used to update column values in the
* current row, or the insert row. The updateXXX() methods do not
* update the underlying database, instead the updateRow() or insertRow()
* 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
*/
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()
{
StringTokenizer st=new StringTokenizer(sqlQuery," \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 );
}
}
}
}
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