org.firebirdsql.jdbc.AbstractCallableStatement Maven / Gradle / Ivy
Show all versions of jaybird-jdk17 Show documentation
/*
* Firebird Open Source JavaEE Connector - JDBC Driver
*
* Distributable under LGPL license.
* You may obtain a copy of the License at http://www.gnu.org/copyleft/lgpl.html
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* LGPL License for more details.
*
* This file was created by members of the firebird development team.
* All individual contributions remain the Copyright (C) of those
* individuals. Contributors to this file are either listed here or
* can be obtained from a source control history command.
*
* All rights reserved.
*/
package org.firebirdsql.jdbc;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.*;
import java.sql.Date;
import java.util.*;
import org.firebirdsql.gds.DatabaseParameterBuffer;
import org.firebirdsql.gds.GDSException;
import org.firebirdsql.gds.impl.DatabaseParameterBufferExtension;
import org.firebirdsql.gds.impl.GDSHelper;
import org.firebirdsql.jdbc.field.FBField;
import org.firebirdsql.jdbc.field.TypeConversionException;
/**
* The interface used to execute SQL
* stored procedures. JDBC provides a stored procedure
* SQL escape syntax that allows stored procedures to be called in a standard
* way for all RDBMSs. 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
* can be used for input, output or both. Parameters are referred to
* sequentially, by number, with the first parameter being 1.
*
*
* {?= call <procedure-name>[<arg1>,<arg2>, ...]}
* {call <procedure-name>[<arg1>,<arg2>, ...]}
*
*
* IN parameter values are set using the set methods inherited from
* {@link 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.
*
* A CallableStatement
can return one {@link ResultSet} or
* multiple ResultSet
objects. Multiple
* ResultSet
objects are handled using operations
* inherited from {@link Statement}.
*
* For maximum portability, a call's ResultSet
objects and
* update counts should be processed prior to getting the values of output
* parameters.
*
* Methods that are new in the JDBC 2.0 API are marked "Since 1.2."
*
* Note: Escape syntax currently is not supported. Please use native
* Firebird procedure call syntax:
*
* EXECUTE PROCEDURE (param1, ...);
*
*
* @see Connection#prepareCall
* @see ResultSet
*
* @author David Jencks
* @author Roman Rokytskyy
* @author Steven Jardine
* @author Mark Rotteveel
*/
public abstract class AbstractCallableStatement extends FBPreparedStatement implements CallableStatement, FirebirdCallableStatement {
static final String NATIVE_CALL_COMMAND = "EXECUTE PROCEDURE ";
static final String NATIVE_SELECT_COMMAND = "SELECT * FROM ";
private ResultSet currentRs;
private ResultSet singletonRs;
protected boolean selectableProcedure;
protected FBProcedureCall procedureCall;
protected AbstractCallableStatement(GDSHelper c, String sql, int rsType,
int rsConcurrency, int rsHoldability,
StoredProcedureMetaData storedProcMetaData,
FBObjectListener.StatementListener statementListener,
FBObjectListener.BlobListener blobListener)
throws SQLException {
super(c, rsType, rsConcurrency, rsHoldability, statementListener, blobListener);
DatabaseParameterBuffer dpb = c.getDatabaseParameterBuffer();
int mode = FBEscapedParser.USE_BUILT_IN;
if (dpb.hasArgument(DatabaseParameterBufferExtension.USE_STANDARD_UDF))
mode = FBEscapedParser.USE_STANDARD_UDF;
FBEscapedCallParser parser = new FBEscapedCallParser(mode);
// here statement is parsed twice, once in c.nativeSQL(...)
// and second time in parser.parseCall(...)... not nice, maybe
// in the future should be fixed by calling FBEscapedParser for
// each parameter in FBEscapedCallParser class
procedureCall = parser.parseCall(nativeSQL(sql));
if (storedProcMetaData.canGetSelectableInformation()) {
setSelectabilityAutomatically(storedProcMetaData);
}
}
public ParameterMetaData getParameterMetaData() throws SQLException {
statementListener.executionStarted(this);
synchronized (getSynchronizationObject()) {
try {
prepareFixedStatement(procedureCall.getSQL(isSelectableProcedure()), true);
} catch (GDSException ge) {
throw new FBSQLException(ge);
}
}
return new FBParameterMetaData(fixedStmt.getInSqlda().sqlvar, gdsHelper);
}
public void addBatch() throws SQLException {
procedureCall.checkParameters();
batchList.add(procedureCall.clone());
}
public int[] executeBatch() throws SQLException {
synchronized (getSynchronizationObject()) {
boolean success = false;
try {
notifyStatementStarted();
List results = new ArrayList(batchList.size());
Iterator iterator = batchList.iterator();
try {
while (iterator.hasNext()) {
procedureCall = (FBProcedureCall) iterator.next();
executeSingleForBatch(results);
}
success = true;
return toArray(results);
} finally {
clearBatch();
}
} finally {
notifyStatementCompleted(success);
}
}
}
private void executeSingleForBatch(List results) throws SQLException {
/*
* TODO: array given to BatchUpdateException might not be JDBC-compliant
* (should set Statement.EXECUTE_FAILED and throwing it right away
* instead of continuing may fail intention)
*/
try {
prepareFixedStatement(procedureCall.getSQL(isSelectableProcedure()), true);
if (internalExecute(!isSelectableProcedure()))
throw new BatchUpdateException(toArray(results));
results.add(getUpdateCount());
} catch (GDSException ex) {
throw new BatchUpdateException(ex.getMessage(), "", ex.getFbErrorCode(), toArray(results));
}
}
public void setSelectableProcedure(boolean selectableProcedure) {
this.selectableProcedure = selectableProcedure;
}
public boolean isSelectableProcedure() {
return selectableProcedure;
}
/**
* Set required types for output parameters.
*
* @throws SQLException if something went wrong.
*/
protected void setRequiredTypes() throws SQLException {
if (singletonRs != null) {
setRequiredTypesInternal((FBResultSet) singletonRs);
}
setRequiredTypesInternal((FBResultSet) getCurrentResultSet());
}
private void setRequiredTypesInternal(FBResultSet resultSet) throws SQLException {
for (FBProcedureParam param : procedureCall.getOutputParams()) {
if (param == null)
continue;
FBField field = resultSet.getField(
procedureCall.mapOutParamIndexToPosition(param.getIndex()),
false);
field.setRequiredType(param.getType());
}
}
/**
* We allow multiple calls to this method without re-preparing the statement.
* This is an workaround to the issue that the statement is actually prepared
* only after all OUT parameters are registered.
*/
protected void prepareFixedStatement(String sql, boolean describeBind) throws GDSException, SQLException {
if (fixedStmt != null) return;
super.prepareFixedStatement(sql, describeBind);
}
/**
* Since we deferred the statement preparation until all OUT params are
* registered, we ensure that the statement is prepared before the meta
* data for the callable statement is obtained.
*/
public ResultSetMetaData getMetaData() throws SQLException {
statementListener.executionStarted(this);
synchronized (getSynchronizationObject()) {
try {
prepareFixedStatement(procedureCall.getSQL(isSelectableProcedure()), true);
} catch (GDSException ge) {
throw new FBSQLException(ge);
}
}
return super.getMetaData();
}
/**
* Executes an execute stored procedure.
* Some prepared statements return multiple results; the execute
* method handles these complex statements as well as the simpler
* form of statements handled by the methods executeQuery
* and executeUpdate
.
*
* @exception SQLException if a database access error occurs
* @see Statement#execute
*/
public boolean execute() throws SQLException {
procedureCall.checkParameters();
boolean hasResultSet = false;
synchronized (getSynchronizationObject()) {
notifyStatementStarted();
try {
prepareFixedStatement(procedureCall.getSQL(isSelectableProcedure()), true);
hasResultSet = internalExecute(!isSelectableProcedure());
if (hasResultSet)
setRequiredTypes();
}catch (GDSException ge) {
throw new FBSQLException(ge);
} finally {
if (!hasResultSet) notifyStatementCompleted();
}
return hasResultSet;
}
}
/**
* Execute query. This method prepares statement before execution. Rest of
* the processing is done by superclass.
*/
public ResultSet executeQuery() throws SQLException {
procedureCall.checkParameters();
synchronized (getSynchronizationObject()) {
notifyStatementStarted();
try {
prepareFixedStatement(procedureCall.getSQL(isSelectableProcedure()), true);
if (!internalExecute(!isSelectableProcedure()))
throw new FBSQLException(
"No resultset for sql",
FBSQLException.SQL_STATE_NO_RESULT_SET);
getResultSet();
setRequiredTypes();
return getCurrentResultSet();
} catch (GDSException ex) {
throw new FBSQLException(ex);
}
}
}
/**
* Execute query. This method prepares statement before execution. Rest of
* the processing is done by superclass.
*/
public int executeUpdate() throws SQLException {
procedureCall.checkParameters();
synchronized (getSynchronizationObject()) {
try {
notifyStatementStarted();
prepareFixedStatement(procedureCall.getSQL(isSelectableProcedure()), true);
/*
* // R.Rokytskyy: JDBC CTS suite uses executeUpdate() //
* together with output parameters, therefore we cannot //
* throw exception if we want to pass the test suite
*
* if (internalExecute(true)) throw new FBSQLException(
* "Update statement returned results.");
*/
boolean hasResults = internalExecute(!isSelectableProcedure());
if (hasResults) {
setRequiredTypes();
}
return getUpdateCount();
} catch (GDSException ex) {
throw new FBSQLException(ex);
} finally {
notifyStatementCompleted();
}
}
}
/**
* Execute statement internally. This method sets cached parameters. Rest of
* the processing is done by superclass.
*/
protected boolean internalExecute(boolean sendOutParams) throws SQLException {
currentRs = null;
singletonRs = null;
int counter = 0;
for (FBProcedureParam param : procedureCall.getInputParams()) {
if (param != null && param.isParam()) {
counter++;
Object value = param.getValue();
FBField field = getField(counter);
if (value == null)
field.setNull();
else if (value instanceof WrapperWithCalendar) {
setField(field, (WrapperWithCalendar) value);
} else if (value instanceof WrapperWithInt) {
setField(field, (WrapperWithInt) value);
} else
field.setObject(value);
isParamSet[counter - 1] = true;
}
}
boolean hasResultSet = super.internalExecute(sendOutParams);
if (hasResultSet && !isSelectableProcedure()) {
// Safeguarding first row so it will work even if the result set from getResultSet is manipulated
final byte[][][] rows = fixedStmt.getRows();
if (rows.length > 0) {
ArrayList rowList = new ArrayList();
rowList.add(rows[0]);
singletonRs = new FBResultSet(fixedStmt.getOutSqlda().sqlvar, gdsHelper, rowList, true);
}
}
return hasResultSet;
}
private void setField(FBField field, WrapperWithInt value) throws SQLException {
Object obj = value.getValue();
if (obj == null) {
field.setNull();
} else {
int intValue = value.getIntValue();
if (obj instanceof InputStream)
field.setBinaryStream((InputStream) obj, intValue);
else if (obj instanceof Reader)
field.setCharacterStream((Reader) obj, intValue);
else
throw new TypeConversionException("Cannot convert type " + obj.getClass().getName());
}
}
private void setField(FBField field, WrapperWithCalendar value) throws SQLException {
Object obj = value.getValue();
if (obj == null) {
field.setNull();
} else {
Calendar cal = value.getCalendar();
if (obj instanceof Timestamp)
field.setTimestamp((Timestamp) obj, cal);
else if (obj instanceof java.sql.Date)
field.setDate((java.sql.Date) obj, cal);
else if (obj instanceof Time)
field.setTime((Time) obj, cal);
else
throw new TypeConversionException("Cannot convert type " + obj.getClass().getName());
}
}
/**
* Registers the OUT parameter in ordinal position
* parameterIndex
to the JDBC type
* sqlType
. All OUT parameters must be registered
* before a stored procedure is executed.
*
* The JDBC type specified by sqlType
for an OUT
* parameter determines the Java type that must be used
* in the get
method to read the value of that parameter.
*
* If the JDBC type expected to be returned to this output parameter
* is specific to this particular database, sqlType
* should be java.sql.Types.OTHER
. The method
* {@link #getObject} retrieves the value.
* @param parameterIndex the first parameter is 1, the second is 2,
* and so on
* @param sqlType the JDBC type code defined by java.sql.Types
.
* If the parameter is of JDBC type NUMERIC
* or DECIMAL
, the version of
* registerOutParameter
that accepts a scale value
* should be used.
* @exception SQLException if a database access error occurs
* @see Types
*/
public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException {
procedureCall.registerOutParam(parameterIndex, sqlType);
}
/**
* Registers the parameter in ordinal position
* parameterIndex
to be of JDBC type
* sqlType
. This method must be called
* before a stored procedure is executed.
*
* The JDBC type specified by sqlType
for an OUT
* parameter determines the Java type that must be used
* in the get
method to read the value of that parameter.
*
* This version of registerOutParameter
should be
* used when the parameter is of JDBC type NUMERIC
* or DECIMAL
.
* @param parameterIndex the first parameter is 1, the second is 2,
* and so on
* @param sqlType SQL type code defined by java.sql.Types
.
* @param scale the desired number of digits to the right of the
* decimal point. It must be greater than or equal to zero.
* @exception SQLException if a database access error occurs
* @see Types
*/
public void registerOutParameter(int parameterIndex, int sqlType, int scale) throws SQLException {
procedureCall.registerOutParam(parameterIndex, sqlType);
}
/**
* Indicates whether or not the last OUT parameter read had the value of
* SQL NULL
. Note that this method should be called only after
* calling a getXXX
method; otherwise, there is no value to use in
* determining whether it is null
or not.
* @return true
if the last parameter read was SQL
* NULL
; false
otherwise
* @exception SQLException if a database access error occurs
*/
public boolean wasNull() throws SQLException {
return getAndAssertSingletonResultSet().wasNull();
}
/**
* Retrieves the value of a JDBC CHAR
, VARCHAR
,
* or LONGVARCHAR
parameter as a String
in
* the Java programming language.
*
* For the fixed-length type JDBC CHAR
,
* the String
object
* returned has exactly the same value the JDBC
* CHAR
value had in the
* database, including any padding added by the database.
* @param parameterIndex the first parameter is 1, the second is 2,
* and so on
* @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 {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getString(parameterIndex);
}
/**
* Gets the value of a JDBC BIT
parameter as a boolean
* in the Java programming language.
* @param parameterIndex the first parameter is 1, the second is 2,
* and so on
* @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 {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getBoolean(parameterIndex);
}
/**
* Gets the value of a JDBC TINYINT
parameter as a byte
* in the Java programming language.
* @param parameterIndex the first parameter is 1, the second is 2,
* and so on
* @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 {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getByte(parameterIndex);
}
/**
* Gets the value of a JDBC SMALLINT
parameter as a short
* in the Java programming language.
* @param parameterIndex the first parameter is 1, the second is 2,
* and so on
* @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 {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getShort(parameterIndex);
}
/**
* Gets the value of a JDBC INTEGER
parameter as an int
* in the Java programming language.
* @param parameterIndex the first parameter is 1, the second is 2,
* and so on
* @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 {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getInt(parameterIndex);
}
/**
* Gets the value of a JDBC BIGINT
parameter as a long
* in the Java programming language.
* @param parameterIndex the first parameter is 1, the second is 2,
* and so on
* @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 {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getLong(parameterIndex);
}
/**
* Gets the value of a JDBC FLOAT
parameter as a float
* in the Java programming language.
* @param parameterIndex the first parameter is 1, the second is 2,
* and so on
* @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 {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getFloat(parameterIndex);
}
/**
* Gets the value of a JDBC DOUBLE
parameter as a double
* in the Java programming language.
* @param parameterIndex the first parameter is 1, the second is 2,
* and so on
* @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 {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getDouble(parameterIndex);
}
/**
* Gets the value of a JDBC NUMERIC
parameter as a
* java.math.BigDecimal
object with scale digits to
* the right of the decimal point.
* @param parameterIndex the first parameter is 1, the second is 2,
* and so on
* @param scale the 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
*/
@Deprecated
public BigDecimal getBigDecimal(int parameterIndex, int scale) throws SQLException {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getBigDecimal(parameterIndex, scale);
}
/**
* Gets the value of a JDBC BINARY
or VARBINARY
* parameter as an array of byte
values in the Java
* programming language.
* @param parameterIndex the first parameter is 1, the second is 2,
* and so on
* @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 {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getBytes(parameterIndex);
}
/**
* Gets the value of a JDBC DATE
parameter as a
* java.sql.Date
object.
* @param parameterIndex the first parameter is 1, the second is 2,
* and so on
* @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 {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getDate(parameterIndex);
}
/**
* Get the value of a JDBC TIME
parameter as a
* java.sql.Time
object.
* @param parameterIndex the first parameter is 1, the second is 2,
* and so on
* @return the parameter value. If the value is SQL NULL
, the result
* is null
.
* @exception SQLException if a database access error occurs
*/
public Time getTime(int parameterIndex) throws SQLException {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getTime(parameterIndex);
}
/**
* Gets the value of a JDBC TIMESTAMP
parameter as a
* java.sql.Timestamp
object.
* @param parameterIndex the first parameter is 1, the second is 2,
* and so on
* @return the parameter value. If the value is SQL NULL
, the result
* is null
.
* @exception SQLException if a database access error occurs
*/
public Timestamp getTimestamp(int parameterIndex) throws SQLException {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getTimestamp(parameterIndex);
}
/**
* Gets the value of a parameter as an Object
in the Java
* programming language.
*
* This method returns a Java object whose type corresponds to the JDBC
* type that was registered for this parameter using the method
* registerOutParameter
. By registering the target JDBC
* type as java.sql.Types.OTHER
, this method can be used
* to read database-specific abstract data types.
* @param parameterIndex the first parameter is 1, the second is 2,
* and so on
* @return A java.lang.Object
holding the OUT parameter value.
* @exception SQLException if a database access error occurs
* @see Types
*/
public Object getObject(int parameterIndex) throws SQLException {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getObject(parameterIndex);
}
public Object getObject(String colName) throws SQLException {
return getObject(findOutParameter(colName));
}
/**
* Returns an object representing the value of OUT parameter
* i
and uses map
for the custom
* mapping of the parameter value.
*
* This method returns a Java object whose type corresponds to the
* JDBC type that was registered for this parameter using the method
* registerOutParameter
. By registering the target
* JDBC type as java.sql.Types.OTHER
, this method can
* be used to read database-specific abstract data types.
* @param parameterIndex the first parameter is 1, the second is 2, and so on
* @param map the mapping from SQL type names to Java classes
* @return a java.lang.Object
holding the OUT parameter value
* @exception SQLException if a database access error occurs
* @since 1.2
* @see What Is in the JDBC 2.0 API
*/
public Object getObject(int parameterIndex, Map map) throws SQLException {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getObject(parameterIndex, map);
}
public Object getObject(String colName, Map map) throws SQLException {
return getObject(findOutParameter(colName), map);
}
public T getObject(int parameterIndex, Class type) throws SQLException {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return ((FBResultSet) getAndAssertSingletonResultSet()).getObject(parameterIndex, type);
}
public T getObject(String parameterName, Class type) throws SQLException {
return getObject(findOutParameter(parameterName), type);
}
/**
*
* Gets the value of a JDBC NUMERIC
parameter as a
* java.math.BigDecimal
object with as many digits to the
* right of the decimal point as the value contains.
* @param parameterIndex the first parameter is 1, the second is 2,
* and so on
* @return the parameter value in full precision. If the value is
* SQL NULL
, the result is null
.
* @exception SQLException if a database access error occurs
* @since 1.2
* @see What Is in the JDBC 2.0 API
*/
public BigDecimal getBigDecimal(int parameterIndex) throws SQLException {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getBigDecimal(parameterIndex);
}
/**
*
* Gets the value of a JDBC REF(<structured-type>)
* parameter as a {@link Ref} object in the Java programming language.
* @param parameterIndex the first parameter is 1, the second is 2,
* and so on
* @return the parameter value as a Ref
object in the
* Java programming language. If the value was SQL NULL
, the value
* null
is returned.
* @exception SQLException if a database access error occurs
* @since 1.2
* @see What Is in the JDBC 2.0 API
*/
public Ref getRef(int parameterIndex) throws SQLException {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getRef(parameterIndex);
}
/**
*
* Gets the value of a JDBC BLOB
parameter as a
* {@link Blob} object in the Java programming language.
* @param parameterIndex the first parameter is 1, the second is 2, and so on
* @return the parameter value as a Blob
object in the
* Java programming language. If the value was SQL NULL
, the value
* null
is returned.
* @exception SQLException if a database access error occurs
* @since 1.2
* @see What Is in the JDBC 2.0 API
*/
public Blob getBlob(int parameterIndex) throws SQLException {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getBlob(parameterIndex);
}
/**
*
* Gets the value of a JDBC CLOB
parameter as a
* Clob
object in the Java programming language.
* @param parameterIndex the first parameter is 1, the second is 2, and
* so on
* @return the parameter value as a Clob
object in the
* Java programming language. If the value was SQL NULL
, the
* value null
is returned.
* @exception SQLException if a database access error occurs
* @since 1.2
* @see What Is in the JDBC 2.0 API
*/
public Clob getClob(int parameterIndex) throws SQLException {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getClob(parameterIndex);
}
/**
*
* Gets the value of a JDBC ARRAY
parameter as an
* {@link Array} object in the Java programming language.
* @param parameterIndex the first parameter is 1, the second is 2, and
* so on
* @return the parameter value as an Array
object in
* the Java programming language. If the value was SQL NULL
, the
* value null
is returned.
* @exception SQLException if a database access error occurs
* @since 1.2
* @see What Is in the JDBC 2.0 API
*/
public Array getArray(int parameterIndex) throws SQLException {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getArray(parameterIndex);
}
/**
* Gets the value of a JDBC DATE
parameter as a
* java.sql.Date
object, using
* the given Calendar
object
* to construct the date.
* With a Calendar
object, the driver
* can calculate the date taking into account a custom timezone and locale.
* If no Calendar
object is specified, the driver uses the
* default timezone and locale.
*
* @param parameterIndex the first parameter is 1, the second is 2,
* and so on
* @param cal the Calendar
object the driver will use
* to construct the date
* @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, Calendar cal) throws SQLException {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getDate(parameterIndex, cal);
}
/**
* Gets the value of a JDBC TIME
parameter as a
* java.sql.Time
object, using
* the given Calendar
object
* to construct the time.
* With a Calendar
object, the driver
* can calculate the time taking into account a custom timezone and locale.
* If no Calendar
object is specified, the driver uses the
* default timezone and locale.
*
* @param parameterIndex the first parameter is 1, the second is 2,
* and so on
* @param cal the Calendar
object the driver will use
* to construct the time
* @return the parameter value; if the value is SQL NULL
, the result is
* null
.
* @exception SQLException if a database access error occurs
*/
public Time getTime(int parameterIndex, Calendar cal) throws SQLException {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getTime(parameterIndex, cal);
}
/**
* Gets the value of a JDBC TIMESTAMP
parameter as a
* java.sql.Timestamp
object, using
* the given Calendar
object to construct
* the Timestamp
object.
* With a Calendar
object, the driver
* can calculate the timestamp taking into account a custom timezone and locale.
* If no Calendar
object is specified, the driver uses the
* default timezone and locale.
*
*
* @param parameterIndex the first parameter is 1, the second is 2,
* and so on
* @param cal the Calendar
object the driver will use
* to construct the timestamp
* @return the parameter value. If the value is SQL NULL
, the result is
* null
.
* @exception SQLException if a database access error occurs
*/
public Timestamp getTimestamp(int parameterIndex, Calendar cal) throws SQLException {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getTimestamp(parameterIndex, cal);
}
public URL getURL(int colIndex) throws SQLException {
colIndex = procedureCall.mapOutParamIndexToPosition(colIndex);
return getAndAssertSingletonResultSet().getURL(colIndex);
}
public String getString(String colName) throws SQLException {
return getString(findOutParameter(colName));
}
public boolean getBoolean(String colName) throws SQLException {
return getBoolean(findOutParameter(colName));
}
public byte getByte(String colName) throws SQLException {
return getByte(findOutParameter(colName));
}
public short getShort(String colName) throws SQLException {
return getShort(findOutParameter(colName));
}
public int getInt(String colName) throws SQLException {
return getInt(findOutParameter(colName));
}
public long getLong(String colName) throws SQLException {
return getLong(findOutParameter(colName));
}
public float getFloat(String colName) throws SQLException {
return getFloat(findOutParameter(colName));
}
public double getDouble(String colName) throws SQLException {
return getDouble(findOutParameter(colName));
}
public byte[] getBytes(String colName) throws SQLException {
return getBytes(findOutParameter(colName));
}
public Date getDate(String colName) throws SQLException {
return getDate(findOutParameter(colName));
}
public Time getTime(String colName) throws SQLException {
return getTime(findOutParameter(colName));
}
public Timestamp getTimestamp(String colName) throws SQLException {
return getTimestamp(findOutParameter(colName));
}
public BigDecimal getBigDecimal(String colName) throws SQLException {
return getBigDecimal(findOutParameter(colName));
}
public Ref getRef(String colName) throws SQLException {
return getRef(findOutParameter(colName));
}
public Blob getBlob(String colName) throws SQLException {
return getBlob(findOutParameter(colName));
}
public Clob getClob(String colName) throws SQLException {
return getClob(findOutParameter(colName));
}
public Array getArray(String colName) throws SQLException {
return getArray(findOutParameter(colName));
}
public Date getDate(String colName, Calendar cal) throws SQLException {
return getDate(findOutParameter(colName), cal);
}
public Time getTime(String colName, Calendar cal) throws SQLException {
return getTime(findOutParameter(colName), cal);
}
public Timestamp getTimestamp(String colName, Calendar cal) throws SQLException {
return getTimestamp(findOutParameter(colName), cal);
}
public URL getURL(String colName) throws SQLException {
return getURL(findOutParameter(colName));
}
public Reader getCharacterStream(int parameterIndex) throws SQLException {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return getAndAssertSingletonResultSet().getCharacterStream(parameterIndex);
}
public Reader getCharacterStream(String parameterName) throws SQLException {
return getCharacterStream(findOutParameter(parameterName));
}
public Reader getNCharacterStream(int parameterIndex) throws SQLException {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return ((FBResultSet) getAndAssertSingletonResultSet()).getNCharacterStream(parameterIndex);
}
public Reader getNCharacterStream(String parameterName) throws SQLException {
return getNCharacterStream(findOutParameter(parameterName));
}
public String getNString(int parameterIndex) throws SQLException {
parameterIndex = procedureCall.mapOutParamIndexToPosition(parameterIndex);
return ((FBResultSet) getAndAssertSingletonResultSet()).getNString(parameterIndex);
}
public String getNString(String parameterName) throws SQLException {
return getNString(findOutParameter(parameterName));
}
public void setAsciiStream(String parameterName, InputStream x, long length) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setAsciiStream(String parameterName, InputStream x) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setBinaryStream(String parameterName, InputStream x, long length) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setBinaryStream(String parameterName, InputStream x) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setBlob(String parameterName, Blob x) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setBlob(String parameterName, InputStream inputStream, long length) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setBlob(String parameterName, InputStream inputStream) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setCharacterStream(String parameterName, Reader reader, long length) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setCharacterStream(String parameterName, Reader reader) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setClob(String parameterName, Clob x) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setClob(String parameterName, Reader reader, long length) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setClob(String parameterName, Reader reader) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setNCharacterStream(String parameterName, Reader value, long length) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setNCharacterStream(String parameterName, Reader value) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setNClob(String parameterName, Reader reader, long length) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setNClob(String parameterName, Reader reader) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setNString(String parameterName, String value) throws SQLException {
throw new FBDriverNotCapableException();
}
public void registerOutParameter(String param1, int param2) throws SQLException {
throw new FBDriverNotCapableException();
}
public void registerOutParameter(String param1, int param2, int param3) throws SQLException {
throw new FBDriverNotCapableException();
}
public void registerOutParameter(String param1, int param2, String param3) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setURL(String param1, URL param2) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setNull(String param1, int param2) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setBoolean(String param1, boolean param2) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setByte(String param1, byte param2) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setShort(String param1, short param2) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setInt(String param1, int param2) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setLong(String param1, long param2) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setFloat(String param1, float param2) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setDouble(String param1, double param2) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setBigDecimal(String param1, BigDecimal param2) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setString(String param1, String param2) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setBytes(String param1, byte[] param2) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setDate(String param1, Date param2) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setTime(String param1, Time param2) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setTimestamp(String param1, Timestamp param2) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setAsciiStream(String param1, InputStream param2, int param3) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setBinaryStream(String param1, InputStream param2, int param3) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setObject(String param1, Object param2, int param3, int param4) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setObject(String param1, Object param2, int param3) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setObject(String param1, Object param2) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setCharacterStream(String param1, Reader param2, int param3) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setDate(String param1, Date param2, Calendar param3) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setTime(String param1, Time param2, Calendar param3) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setTimestamp(String param1, Timestamp param2, Calendar param3) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setNull(String param1, int param2, String param3) throws SQLException {
throw new FBDriverNotCapableException();
}
public void setURL(int parameterIndex, URL x) throws SQLException {
throw new FBDriverNotCapableException();
}
public void registerOutParameter(int parameterIndex, int sqlType, String typeName) throws SQLException {
throw new FBDriverNotCapableException();
}
public ResultSet getGeneratedKeys() throws SQLException {
throw new FBDriverNotCapableException();
}
/**
* Asserts if the current statement has data to return. It checks if the
* result set has a row with data.
*
* @param rs result set to test
* @throws java.sql.SQLException when the result set has no data.
*/
private void assertHasData(ResultSet rs) throws SQLException {
if (rs == null) {
throw new SQLException("Current statement has no data to return.", FBSQLException.SQL_STATE_NO_RESULT_SET);
}
// check if we have a row, and try to move to the first position.
if (rs.getRow() == 0)
rs.next();
else
return;
// check if we still have no row and throw an exception in this case.
if (rs.getRow() == 0)
throw new FBSQLException(
"Current statement has no data to return.",
FBSQLException.SQL_STATE_NO_RESULT_SET);
}
// this method doesn't give an exception if it is called twice.
public ResultSet getCurrentResultSet() throws SQLException {
if (currentRs == null)
currentRs = super.getResultSet();
return currentRs;
}
/**
* Returns the result set for the singleton row of the callable statement and asserts it has data. If this is a
* selectable procedure, or there is no singleton row, it will return the normal result set.
*
* This should fix the problem described in JDBC-350
* in most circumstances.
*
*
* @return Either the singleton result set, or the current result set as described above
* @throws SQLException For database access errors
*/
protected ResultSet getAndAssertSingletonResultSet() throws SQLException {
final ResultSet rs;
if (!isSelectableProcedure() && singletonRs != null) {
rs = singletonRs;
} else {
rs = getCurrentResultSet();
}
assertHasData(rs);
return rs;
}
/**
* Returns the current result as a ResultSet
object.
* This method should be called only once per result.
* Calling this method twice with autocommit on and used will probably
* throw an inappropriate or uninformative exception.
*
* @return the current result as a ResultSet
object;
* null
if the result is an update count or there are no more results
* @exception SQLException if a database access error occurs
* @see #execute
*/
public ResultSet getResultSet() throws SQLException {
return getCurrentResultSet();
}
public void setArray(int i, Array x) throws SQLException {
procedureCall.getInputParam(i).setValue(x);
}
public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(x);
}
public void setBinaryStream(int parameterIndex, InputStream inputStream, int length)
throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(
new WrapperWithInt(inputStream, length));
}
public void setBlob(int parameterIndex, Blob blob) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(blob);
}
public void setBoolean(int parameterIndex, boolean x) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(x);
}
public void setByte(int parameterIndex, byte x) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(x);
}
public void setBytes(int parameterIndex, byte[] x) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(x);
}
public void setCharacterStream(int parameterIndex, Reader reader, int length)
throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(new WrapperWithInt(reader, length));
}
public void setClob(int parameterIndex, Clob x) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(x);
}
public void setDate(int parameterIndex, java.sql.Date x, Calendar cal) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(new WrapperWithCalendar(x, cal));
}
public void setDate(int parameterIndex, java.sql.Date x) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(x);
}
public void setDouble(int parameterIndex, double x) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(x);
}
public void setFloat(int parameterIndex, float x) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(x);
}
public void setInt(int parameterIndex, int x) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(x);
}
public void setLong(int parameterIndex, long x) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(x);
}
public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(null);
}
public void setNull(int parameterIndex, int sqlType) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(null);
}
public void setObject(int parameterIndex, Object x, int targetSqlType, int scale)
throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(x);
}
public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(x);
}
public void setObject(int parameterIndex, Object x) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(x);
}
public void setRef(int parameterIndex, Ref x) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(x);
}
public void setShort(int parameterIndex, short x) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(x);
}
public void setString(int parameterIndex, String x) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(x);
}
public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(new WrapperWithCalendar(x, cal));
}
public void setTime(int parameterIndex, Time x) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(x);
}
public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(new WrapperWithCalendar(x, cal));
}
public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(x);
}
@Deprecated
public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException {
procedureCall.getInputParam(parameterIndex).setValue(x);
}
/**
* Set the selectability of this stored procedure from RDB$PROCEDURE_TYPE
* @throws SQLException
*/
private void setSelectabilityAutomatically(StoredProcedureMetaData storedProcMetaData) throws SQLException {
selectableProcedure = storedProcMetaData.isSelectable(procedureCall.getName());
}
/**
* Helper method to identify the right resultset column for the give OUT
* parameter name.
*
* @param paramName
* Name of the OUT parameter
*/
protected int findOutParameter(String paramName) throws SQLException {
return getAndAssertSingletonResultSet().findColumn(paramName);
}
private static class WrapperWithCalendar {
private final Object value;
private final Calendar c;
private WrapperWithCalendar(Object value, Calendar c) {
this.value = value;
this.c = c;
}
private Object getValue() {
return value;
}
private Calendar getCalendar() {
return c;
}
}
private static class WrapperWithInt {
private final Object value;
private final int intValue;
private WrapperWithInt(Object value, int intValue) {
this.value = value;
this.intValue = intValue;
}
private Object getValue() {
return value;
}
private int getIntValue() {
return intValue;
}
}
}