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;
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
* extended by org.postgresql.jdbc2.AbstractJdbc2Connection which adds the jdbc2
* methods. The real Connection class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Connection
......@@ -359,8 +359,7 @@ public abstract class AbstractJdbc1Connection implements org.postgresql.PGConnec
// are common to all implementations (JDBC1 or 2), they are placed here.
// 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(java.sql.Statement stat, org.postgresql.Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException;
public abstract java.sql.ResultSet getResultSet(Statement statement, org.postgresql.Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException;
/*
* This adds a warning to the warning chain.
......
......@@ -13,15 +13,15 @@ import org.postgresql.largeobject.*;
import org.postgresql.util.PGbytea;
import org.postgresql.util.PSQLException;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1ResultSet.java,v 1.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
* extended by org.postgresql.jdbc2.AbstractJdbc2ResultSet which adds the jdbc2
* methods. The real ResultSet class (for jdbc1) is org.postgresql.jdbc1.Jdbc1ResultSet
*/
public abstract class AbstractJdbc1ResultSet
{
protected Vector rows; // The results
protected Statement statement;
protected Field fields[]; // The field descriptions
protected String status; // Status of the result
protected boolean binaryCursor = false; // is the data binary or Strings
......@@ -41,9 +41,10 @@ public abstract class AbstractJdbc1ResultSet
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.statement = statement;
this.fields = fields;
this.rows = tuples;
this.status = status;
......
......@@ -8,7 +8,7 @@ import java.util.Vector;
import org.postgresql.largeobject.*;
import org.postgresql.util.*;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.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
* extended by org.postgresql.jdbc2.AbstractJdbc2Statement which adds the jdbc2
* methods. The real Statement class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Statement
......@@ -47,6 +47,20 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
protected String[] templateStrings;
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)
......@@ -62,6 +76,10 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
}
protected void parseSqlStmt () throws SQLException {
if (this instanceof CallableStatement) {
modifyJdbcCall();
}
Vector v = new Vector();
boolean inQuotes = false;
int lastParmEnd = 0, i;
......@@ -179,8 +197,24 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
// New in 7.1, pass Statement so that ExecSQL can customise to it
result = ((AbstractJdbc1Connection)connection).ExecSQL(sql, (java.sql.Statement)this);
//If we are executing a callable statement function set the return data
if (isFunction) {
if (!((AbstractJdbc1ResultSet)result).reallyResultSet())
throw new PSQLException("postgresql.call.noreturnval");
if (!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());
}
}
/*
* Some prepared statements return multiple results; the execute method
......@@ -233,6 +267,8 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
{
if (result == null)
return -1;
if (isFunction)
return 1;
if (((AbstractJdbc1ResultSet)result).reallyResultSet())
return -1;
return ((AbstractJdbc1ResultSet)result).getResultCount();
......@@ -253,14 +289,6 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
/*
* Returns the status message from the current Result.<p>
* This is used internally by the driver.
......@@ -1214,6 +1242,291 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
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
* substituted.
......@@ -1253,6 +1566,8 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
{
if (paramIndex < 1 || paramIndex > inStrings.length)
throw new PSQLException("postgresql.prep.range");
if (paramIndex == 1 && isFunction) // need to registerOut instead
throw new PSQLException ("postgresql.call.funcover");
inStrings[paramIndex - 1] = s;
}
......@@ -1267,6 +1582,13 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
sbuf.setLength(0);
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)
{
if (inStrings[i] == null)
......@@ -1299,5 +1621,67 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
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;
/*
* 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
* can use the normal ResultSet methods such as getString and getInt to
......@@ -1549,7 +1549,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
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
// 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
v.addElement(tuple);
}
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
......@@ -1809,7 +1809,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
f[0] = new Field(connection, "TABLE_SCHEM", iVarcharOid, 32);
tuple[0] = "".getBytes();
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
tuple[0] = getTableTypes[i][0].getBytes();
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
}
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
//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
f[6] = new Field(connection, "DECIMAL_DIGITS", 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
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
v.addElement(tuple);
}
rs.close();
return new Jdbc1ResultSet(connection, f, v, "OK", 1);
return connection.getResultSet(null, f, v, "OK", 1);
}
throw new PSQLException("postgresql.metadata.unavailable");
......@@ -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.*;
import org.postgresql.Field;
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.
* However most of the implementation is really done in
* org.postgresql.jdbc1.AbstractJdbc1Connection
......@@ -24,10 +24,9 @@ public class Jdbc1Connection extends org.postgresql.jdbc1.AbstractJdbc1Connectio
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
{
throw new PSQLException("postgresql.con.call");
return new org.postgresql.jdbc1.Jdbc1CallableStatement(this, sql);
}
public java.sql.DatabaseMetaData getMetaData() throws SQLException
......@@ -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
{
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.*;
import java.util.Vector;
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.
* However most of the implementation is really done in
* org.postgresql.jdbc1.AbstractJdbc1ResultSet
......@@ -13,14 +13,9 @@ import org.postgresql.Field;
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);
}
public Jdbc1ResultSet(Jdbc1Connection conn, Field[] fields, Vector tuples, String status, int updateCount)
{
super(conn, fields, tuples, status, updateCount, 0, false);
super(conn, statement, fields, tuples, status, updateCount, insertOID, binaryCursor);
}
public java.sql.ResultSetMetaData getMetaData() throws SQLException
......
......@@ -6,39 +6,54 @@ import java.io.*;
import java.sql.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Vector;
import java.util.*;
import org.postgresql.Driver;
import org.postgresql.Field;
import org.postgresql.core.Encoding;
import org.postgresql.largeobject.*;
import org.postgresql.util.PGbytea;
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
* org.postgresql.jdbc1.AbstractJdbc1ResultSet which provides the jdbc1
* methods. The real Statement class (for jdbc2) is org.postgresql.jdbc2.Jdbc2ResultSet
*/
public class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.AbstractJdbc1ResultSet
{
protected Statement statement;
public class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.AbstractJdbc1ResultSet {
protected String sqlQuery = null;
//needed for updateable result set support
protected boolean updateable = false;
protected boolean doingUpdates = false;
protected boolean onInsertRow = false;
protected Hashtable updateValues = new Hashtable();
private boolean usingOID = false; // are we using the OID for the primary key?
private Vector primaryKeys; // list of primary keys
private int numKeys = 0;
private boolean singleTable = false;
protected String tableName = null;
protected PreparedStatement updateStatement = null;
protected PreparedStatement insertStatement = null;
protected PreparedStatement deleteStatement = null;
private PreparedStatement selectStatement = null;
protected String sqlQuery=null;
public AbstractJdbc2ResultSet(org.postgresql.PGConnection conn, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor)
{
super(conn, fields, tuples, status, updateCount, insertOID, binaryCursor);
public AbstractJdbc2ResultSet(org.postgresql.PGConnection conn, Statement statement, Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) {
super (conn, statement, fields, tuples, status, updateCount, insertOID, binaryCursor);
}
public java.net.URL getURL(int columnIndex) throws SQLException
{
public java.net.URL getURL(int columnIndex) throws SQLException {
return null;
}
public java.net.URL getURL(String columnName) throws SQLException
{
public java.net.URL getURL(String columnName) throws SQLException {
return null;
}
/*
* Get the value of a column in the current row as a Java object
*
......@@ -54,8 +69,7 @@ public class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.AbstractJdbc1Re
* @return a Object holding the column value
* @exception SQLException if a database access error occurs
*/
public Object getObject(int columnIndex) throws SQLException
{
public Object getObject(int columnIndex) throws SQLException {
Field field;
checkResultSet( columnIndex );
......@@ -67,59 +81,68 @@ public class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.AbstractJdbc1Re
field = fields[columnIndex - 1];
// some fields can be null, mainly from those returned by MetaData methods
if (field == null)
{
if (field == null) {
wasNullFlag = true;
return null;
}
switch (field.getSQLType())
{
switch (field.getSQLType()) {
case Types.BIT:
return getBoolean(columnIndex) ? Boolean.TRUE : Boolean.FALSE;
case Types.SMALLINT:
return new Short(getShort(columnIndex));
case Types.INTEGER:
return new Integer(getInt(columnIndex));
case Types.BIGINT:
return new Long(getLong(columnIndex));
case Types.NUMERIC:
return getBigDecimal
(columnIndex, (field.getMod() == -1) ? -1 : ((field.getMod() - 4) & 0xffff));
case Types.REAL:
return new Float(getFloat(columnIndex));
case Types.DOUBLE:
return new Double(getDouble(columnIndex));
case Types.CHAR:
case Types.VARCHAR:
return getString(columnIndex);
case Types.DATE:
return getDate(columnIndex);
case Types.TIME:
return getTime(columnIndex);
case Types.TIMESTAMP:
return getTimestamp(columnIndex);
case Types.BINARY:
case Types.VARBINARY:
return getBytes(columnIndex);
case Types.ARRAY:
return getArray(columnIndex);
default:
String type = field.getPGType();
// if the backend doesn't know the type then coerce to String
if (type.equals("unknown"))
{
if (type.equals("unknown")) {
return getString(columnIndex);
}
else
{
else {
return connection.getObject(field.getPGType(), getString(columnIndex));
}
}
}
public boolean absolute(int index) throws SQLException
{
public boolean absolute(int index) throws SQLException {
// index is 1-based, but internally we use 0-based indices
int internalIndex;
......@@ -130,124 +153,107 @@ public class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.AbstractJdbc1Re
//if index<0, count from the end of the result set, but check
//to be sure that it is not beyond the first index
if (index < 0)
{
if (index < 0) {
if (index >= -rows_size)
internalIndex = rows_size + index;
else
{
else {
beforeFirst();
return false;
}
}
else
{
else {
//must be the case that index>0,
//find the correct place, assuming that
//the index is not too large
if (index <= rows_size)
internalIndex = index - 1;
else
{
else {
afterLast();
return false;
}
}
current_row = internalIndex;
this_row = (byte [][])rows.elementAt(internalIndex);
this_row = (byte[][]) rows.elementAt(internalIndex);
return true;
}
public void afterLast() throws SQLException
{
public void afterLast() throws SQLException {
final int rows_size = rows.size();
if (rows_size > 0)
current_row = rows_size;
}
public void beforeFirst() throws SQLException
{
public void beforeFirst() throws SQLException {
if (rows.size() > 0)
current_row = -1;
}
public void cancelRowUpdates() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
}
public void deleteRow() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
}
public boolean first() throws SQLException
{
public boolean first() throws SQLException {
if (rows.size() <= 0)
return false;
current_row = 0;
this_row = (byte [][])rows.elementAt(current_row);
this_row = (byte[][]) rows.elementAt(current_row);
rowBuffer=new byte[this_row.length][];
System.arraycopy(this_row,0,rowBuffer,0,this_row.length);
rowBuffer = new byte[this_row.length][];
System.arraycopy(this_row, 0, rowBuffer, 0, this_row.length);
return true;
}
public java.sql.Array getArray(String colName) throws SQLException
{
public java.sql.Array getArray(String colName) throws SQLException {
return getArray(findColumn(colName));
}
public java.sql.Array getArray(int i) throws SQLException
{
public java.sql.Array getArray(int i) throws SQLException {
wasNullFlag = (this_row[i - 1] == null);
if (wasNullFlag)
return null;
if (i < 1 || i > fields.length)
throw new PSQLException("postgresql.res.colrange");
return (java.sql.Array) new org.postgresql.jdbc2.Array( connection, i, fields[i - 1], (java.sql.ResultSet)this );
return (java.sql.Array) new org.postgresql.jdbc2.Array( connection, i, fields[i - 1], (java.sql.ResultSet) this );
}
public java.math.BigDecimal getBigDecimal(int columnIndex) throws SQLException
{
public java.math.BigDecimal getBigDecimal(int columnIndex) throws SQLException {
return getBigDecimal(columnIndex, -1);
}
public java.math.BigDecimal getBigDecimal(String columnName) throws SQLException
{
public java.math.BigDecimal getBigDecimal(String columnName) throws SQLException {
return getBigDecimal(findColumn(columnName));
}
public Blob getBlob(String columnName) throws SQLException
{
public Blob getBlob(String columnName) throws SQLException {
return getBlob(findColumn(columnName));
}
public Blob getBlob(int i) throws SQLException
{
public Blob getBlob(int i) throws SQLException {
return new org.postgresql.largeobject.PGblob(connection, getInt(i));
}
public java.io.Reader getCharacterStream(String columnName) throws SQLException
{
public java.io.Reader getCharacterStream(String columnName) throws SQLException {
return getCharacterStream(findColumn(columnName));
}
public java.io.Reader getCharacterStream(int i) throws SQLException
{
public java.io.Reader getCharacterStream(int i) throws SQLException {
checkResultSet( i );
wasNullFlag = (this_row[i - 1] == null);
if (wasNullFlag)
return null;
if (((AbstractJdbc2Connection)connection).haveMinimumCompatibleVersion("7.2"))
{
if (((AbstractJdbc2Connection) connection).haveMinimumCompatibleVersion("7.2")) {
//Version 7.2 supports AsciiStream for all the PG text types
//As the spec/javadoc for this method indicate this is to be used for
//large text values (i.e. LONGVARCHAR) PG doesn't have a separate
......@@ -256,8 +262,7 @@ public class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.AbstractJdbc1Re
//getString() since there is no current way to stream the value from the server
return new CharArrayReader(getString(i).toCharArray());
}
else
{
else {
// In 7.1 Handle as BLOBS so return the LargeObject input stream
Encoding encoding = connection.getEncoding();
InputStream input = getBinaryStream(i);
......@@ -265,105 +270,104 @@ public class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.AbstractJdbc1Re
}
}
public Clob getClob(String columnName) throws SQLException
{
public Clob getClob(String columnName) throws SQLException {
return getClob(findColumn(columnName));
}
public Clob getClob(int i) throws SQLException
{
public Clob getClob(int i) throws SQLException {
return new org.postgresql.largeobject.PGclob(connection, getInt(i));
}
public int getConcurrency() throws SQLException
{
// 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 {
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
{
public java.sql.Date getDate(int i, java.util.Calendar cal) throws SQLException {
// If I read the specs, this should use cal only if we don't
// store the timezone, and if we do, then act just like getDate()?
// for now...
return getDate(i);
}
public Time getTime(int i, java.util.Calendar cal) throws SQLException
{
public Time getTime(int i, java.util.Calendar cal) throws SQLException {
// If I read the specs, this should use cal only if we don't
// store the timezone, and if we do, then act just like getTime()?
// for now...
return getTime(i);
}
public Timestamp getTimestamp(int i, java.util.Calendar cal) throws SQLException
{
public Timestamp getTimestamp(int i, java.util.Calendar cal) throws SQLException {
// If I read the specs, this should use cal only if we don't
// store the timezone, and if we do, then act just like getDate()?
// for now...
return getTimestamp(i);
}
public java.sql.Date getDate(String c, java.util.Calendar cal) throws SQLException
{
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
{
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
{
public Timestamp getTimestamp(String c, java.util.Calendar cal) throws SQLException {
return getTimestamp(findColumn(c), cal);
}
public int getFetchDirection() throws SQLException
{
public int getFetchDirection() throws SQLException {
//PostgreSQL normally sends rows first->last
return java.sql.ResultSet.FETCH_FORWARD;
}
public int getFetchSize() throws SQLException
{
public int getFetchSize() throws SQLException {
// In this implementation we return the entire result set, so
// here return the number of rows we have. Sub-classes can return a proper
// value
return rows.size();
}
public Object getObject(String columnName, java.util.Map map) throws SQLException
{
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.
*/
public Object getObject(int i, java.util.Map map) throws SQLException
{
public Object getObject(int i, java.util.Map map) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
public Ref getRef(String columnName) throws SQLException
{
public Ref getRef(String columnName) throws SQLException {
return getRef(findColumn(columnName));
}
public Ref getRef(int i) throws SQLException
{
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
{
public int getRow() throws SQLException {
final int rows_size = rows.size();
if (current_row < 0 || current_row >= rows_size)
......@@ -372,381 +376,978 @@ public class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.AbstractJdbc1Re
return current_row + 1;
}
// This one needs some thought, as not all ResultSets come from a statement
public Statement getStatement() throws SQLException
{
public Statement getStatement() throws SQLException {
return statement;
}
public int getType() throws SQLException
{
public int getType() throws SQLException {
// This implementation allows scrolling but is not able to
// see any changes. Sub-classes may overide this to return a more
// meaningful result.
return java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE;
}
public void insertRow() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
}
public boolean isAfterLast() throws SQLException
{
public boolean isAfterLast() throws SQLException {
final int rows_size = rows.size();
return (current_row >= rows_size && rows_size > 0);
}
public boolean isBeforeFirst() throws SQLException
{
public boolean isBeforeFirst() throws SQLException {
return (current_row < 0 && rows.size() > 0);
}
public boolean isFirst() throws SQLException
{
public boolean isFirst() throws SQLException {
return (current_row == 0 && rows.size() >= 0);
}
public boolean isLast() throws SQLException
{
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
{
public boolean last() throws SQLException {
final int rows_size = rows.size();
if (rows_size <= 0)
return false;
current_row = rows_size - 1;
this_row = (byte [][])rows.elementAt(current_row);
this_row = (byte[][]) rows.elementAt(current_row);
rowBuffer=new byte[this_row.length][];
System.arraycopy(this_row,0,rowBuffer,0,this_row.length);
rowBuffer = new byte[this_row.length][];
System.arraycopy(this_row, 0, rowBuffer, 0, this_row.length);
return true;
}
public void moveToCurrentRow() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
}
public void moveToInsertRow() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
}
public boolean previous() throws SQLException
{
public boolean previous() throws SQLException {
if (--current_row < 0)
return false;
this_row = (byte [][])rows.elementAt(current_row);
System.arraycopy(this_row,0,rowBuffer,0,this_row.length);
this_row = (byte[][]) rows.elementAt(current_row);
System.arraycopy(this_row, 0, rowBuffer, 0, this_row.length);
return true;
}
public void refreshRow() throws SQLException
{
throw new PSQLException("postgresql.notsensitive");
}
public boolean relative(int rows) throws SQLException
{
public boolean relative(int rows) throws SQLException {
//have to add 1 since absolute expects a 1-based index
return absolute(current_row + 1 + rows);
}
public boolean rowDeleted() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
return false; // javac complains about not returning a value!
public void setFetchDirection(int direction) throws SQLException {
throw new PSQLException("postgresql.psqlnotimp");
}
public boolean rowInserted() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
return false; // javac complains about not returning a value!
public void setFetchSize(int rows) throws SQLException {
// Sub-classes should implement this as part of their cursor support
throw org.postgresql.Driver.notImplemented();
}
public boolean rowUpdated() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
return false; // javac complains about not returning a value!
public synchronized void cancelRowUpdates() throws SQLException {
if (doingUpdates) {
doingUpdates = false;
clearRowBuffer();
}
}
public void setFetchDirection(int direction) throws SQLException
{
throw new PSQLException("postgresql.psqlnotimp");
public synchronized void deleteRow() throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
public void setFetchSize(int rows) throws SQLException
{
// Sub-classes should implement this as part of their cursor support
throw org.postgresql.Driver.notImplemented();
if (onInsertRow) {
throw new PSQLException( "postgresql.updateable.oninsertrow" );
}
public void updateAsciiStream(int columnIndex,
java.io.InputStream x,
int length
) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
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" );
}
public void updateAsciiStream(String columnName,
java.io.InputStream x,
int length
) throws SQLException
{
updateAsciiStream(findColumn(columnName), x, length);
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 " );
}
}
public void updateBigDecimal(int columnIndex,
java.math.BigDecimal x
) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
deleteStatement = ((java.sql.Connection) connection).prepareStatement(deleteSQL.toString());
}
deleteStatement.clearParameters();
public void updateBigDecimal(String columnName,
java.math.BigDecimal x
) throws SQLException
{
updateBigDecimal(findColumn(columnName), x);
for ( int i = 0; i < numKeys; i++ ) {
deleteStatement.setObject(i + 1, ((PrimaryKey) primaryKeys.get(i)).getValue());
}
deleteStatement.executeUpdate();
rows.removeElementAt(current_row);
}
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();
}
}
public synchronized void moveToCurrentRow() throws SQLException {
if (!updateable) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
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;
}
public synchronized void moveToInsertRow() throws SQLException {
if (!updateable) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
if (insertStatement != null) {
insertStatement = null;
}
public void updateBinaryStream(int columnIndex,
// make sure the underlying data is null
clearRowBuffer();
onInsertRow = true;
doingUpdates = false;
}
private synchronized void clearRowBuffer() throws SQLException {
// rowBuffer is the temporary storage for the row
rowBuffer = new byte[fields.length][];
// clear the updateValues hashTable for the next set of updates
updateValues.clear();
}
public boolean rowDeleted() throws SQLException {
// only sub-classes implement CONCURuPDATEABLE
throw Driver.notImplemented();
}
public boolean rowInserted() throws SQLException {
// only sub-classes implement CONCURuPDATEABLE
throw Driver.notImplemented();
}
public boolean rowUpdated() throws SQLException {
// only sub-classes implement CONCURuPDATEABLE
throw Driver.notImplemented();
}
public synchronized void updateAsciiStream(int columnIndex,
java.io.InputStream x,
int length
) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
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 );
}
public void updateBinaryStream(String columnName,
public synchronized void updateBigDecimal(int columnIndex,
java.math.BigDecimal x )
throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), x );
}
public synchronized void updateBinaryStream(int columnIndex,
java.io.InputStream x,
int length
) throws SQLException
{
updateBinaryStream(findColumn(columnName), x, length);
) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
public void updateBoolean(int columnIndex, boolean x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
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);
}
public void updateBoolean(String columnName, boolean x) throws SQLException
{
updateBoolean(findColumn(columnName), x);
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), theData );
}
public void updateByte(int columnIndex, byte x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
public synchronized void updateBoolean(int columnIndex, boolean x) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
public void updateByte(String columnName, byte x) throws SQLException
{
updateByte(findColumn(columnName), x);
if ( Driver.logDebug ) Driver.debug("updating boolean " + fields[columnIndex - 1].getName() + "=" + x);
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), new Boolean(x) );
}
public void updateBytes(String columnName, byte[] x) throws SQLException
{
updateBytes(findColumn(columnName), x);
public synchronized void updateByte(int columnIndex, byte x) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
public void updateBytes(int columnIndex, byte[] x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
doingUpdates = true;
updateValues.put( fields[columnIndex - 1].getName(), String.valueOf(x) );
}
public void updateCharacterStream(int columnIndex,
java.io.Reader x,
int length
) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
public synchronized void updateBytes(int columnIndex, byte[] x) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
public void updateCharacterStream(String columnName,
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), x );
}
public synchronized void updateCharacterStream(int columnIndex,
java.io.Reader x,
int length
) throws SQLException
{
updateCharacterStream(findColumn(columnName), x, length);
) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
public void updateDate(int columnIndex, java.sql.Date x) throws SQLException
{
// only sub-classes implement CONCUR_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);
}
public void updateDate(String columnName, java.sql.Date x) throws SQLException
{
updateDate(findColumn(columnName), x);
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), theData);
}
public void updateDouble(int columnIndex, double x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
public synchronized void updateDate(int columnIndex, java.sql.Date x) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
public void updateDouble(String columnName, double x) throws SQLException
{
updateDouble(findColumn(columnName), x);
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" );
}
public void updateFloat(int columnIndex, float x) throws SQLException
{
// only sub-classes implement CONCUR_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 void updateFloat(String columnName, float x) throws SQLException
{
updateFloat(findColumn(columnName), x);
public synchronized void updateFloat(int columnIndex, float x) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
public void updateInt(int columnIndex, int x) throws SQLException
{
// only sub-classes implement CONCUR_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 void updateInt(String columnName, int x) throws SQLException
{
updateInt(findColumn(columnName), x);
public synchronized void updateInt(int columnIndex, int x) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
public void updateLong(int columnIndex, long x) throws SQLException
{
// only sub-classes implement CONCUR_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 void updateLong(String columnName, long x) throws SQLException
{
updateLong(findColumn(columnName), x);
public synchronized void updateLong(int columnIndex, long x) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
public void updateNull(int columnIndex) throws SQLException
{
// only sub-classes implement CONCUR_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 void updateNull(String columnName) throws SQLException
{
updateNull(findColumn(columnName));
public synchronized void updateNull(int columnIndex) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
public void updateObject(int columnIndex, Object x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), null);
}
public void updateObject(String columnName, Object x) throws SQLException
{
updateObject(findColumn(columnName), x);
public synchronized void updateObject(int columnIndex, Object x) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
public void updateObject(int columnIndex, Object x, int scale) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
if ( Driver.logDebug ) Driver.debug("updating object " + fields[columnIndex - 1].getName() + " = " + x);
doingUpdates = !onInsertRow;
updateValues.put( fields[columnIndex - 1].getName(), x );
}
public void updateObject(String columnName, Object x, int scale) throws SQLException
{
updateObject(findColumn(columnName), x, scale);
public synchronized void updateObject(int columnIndex, Object x, int scale) throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
public void updateRow() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
this.updateObject(columnIndex, x);
}
public void updateShort(int columnIndex, short x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
public void refreshRow() throws SQLException {
if ( !isUpdateable() ) {
throw new PSQLException( "postgresql.updateable.notupdateable" );
}
public void updateShort(String columnName, short x) throws SQLException
{
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 void updateString(int columnIndex, String x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
public synchronized void updateInt(String columnName, int x) throws SQLException {
updateInt(findColumn(columnName), x);
}
public void updateString(String columnName, String x) throws SQLException
{
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 void updateTime(int columnIndex, Time x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
public synchronized void updateBytes(String columnName, byte x[]) throws SQLException {
updateBytes(findColumn(columnName), x);
}
public void updateTime(String columnName, Time x) throws SQLException
{
updateTime(findColumn(columnName), x);
public synchronized void updateDate(String columnName, java.sql.Date x)
throws SQLException {
updateDate(findColumn(columnName), x);
}
public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
notUpdateable();
public synchronized void updateTime(String columnName, java.sql.Time x)
throws SQLException {
updateTime(findColumn(columnName), x);
}
public void updateTimestamp(String columnName, Timestamp x) throws SQLException
{
public synchronized void updateTimestamp(String columnName, java.sql.Timestamp x)
throws SQLException {
updateTimestamp(findColumn(columnName), x);
}
// helper method. Throws an SQLException when an update is not possible
public void notUpdateable() throws SQLException
{
throw new PSQLException("postgresql.noupdate");
public synchronized void updateAsciiStream(
String columnName,
java.io.InputStream x,
int length)
throws SQLException {
updateAsciiStream(findColumn(columnName), x, length);
}
/*
* It's used currently by getStatement() but may also with the new core
* package.
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?
*/
public void setStatement(Statement statement)
{
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;
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;
import java.io.*;
import java.math.*;
import java.sql.*;
import java.util.Vector;
import org.postgresql.largeobject.*;
import org.postgresql.util.PSQLException;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2Statement.java,v 1.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
* org.postgresql.jdbc1.AbstractJdbc1Statement which provides the jdbc1
* 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
{
boolean l_return = super.execute(sql);
//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);
// 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
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
default:
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()
......
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;
/*
* 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
* can use the normal ResultSet methods such as getString and getInt to
......@@ -1653,7 +1653,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
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
// 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
v.addElement(tuple);
}
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
......@@ -1913,7 +1913,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
f[0] = new Field(connection, "TABLE_SCHEM", iVarcharOid, 32);
tuple[0] = "".getBytes();
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
tuple[0] = getTableTypes[i][0].getBytes();
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
}
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
//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
//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
f[6] = new Field(connection, "DECIMAL_DIGITS", 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
tuples.addElement(tuple);
}
return new Jdbc2ResultSet(connection, f, tuples, "OK", 1);
return connection.getResultSet(null, f, tuples, "OK", 1);
}
/*
......@@ -2959,7 +2959,7 @@ WHERE
v.addElement(tuple);
}
rs.close();
return new Jdbc2ResultSet(connection, f, v, "OK", 1);
return connection.getResultSet(null, f, v, "OK", 1);
}
throw new PSQLException("postgresql.metadata.unavailable");
......@@ -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;
import java.sql.*;
import java.util.Vector;
import java.util.Hashtable;
import org.postgresql.Field;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/Jdbc2Connection.java,v 1.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.
* However most of the implementation is really done in
* org.postgresql.jdbc2.AbstractJdbc2Connection or one of it's parents
......@@ -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
{
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.setResultSetConcurrency(resultSetConcurrency);
return s;
......@@ -45,15 +46,14 @@ public class Jdbc2Connection extends org.postgresql.jdbc2.AbstractJdbc2Connectio
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)
{
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, statement, 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.*;
import java.util.Vector;
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.
* However most of the implementation is really done in
* org.postgresql.jdbc2.AbstractJdbc2ResultSet or one of it's parents
......@@ -13,14 +13,9 @@ import org.postgresql.Field;
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);
}
public Jdbc2ResultSet(Jdbc2Connection conn, Field[] fields, Vector tuples, String status, int updateCount)
{
super(conn, fields, tuples, status, updateCount, 0, false);
super(conn, statement, fields, tuples, status, updateCount, insertOID, binaryCursor);
}
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