/*
Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
There are special exceptions to the terms and conditions of the GPLv2 as it is applied to
this software, see the FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free Software Foundation; version 2
of the License.
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 GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this
program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth
Floor, Boston, MA 02110-1301 USA
*/
package com.mysql.jdbc;
import java.io.InputStream;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Constructor;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.Array;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.ParameterMetaData;
import java.sql.Ref;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Representation of stored procedures for JDBC
*
* @author Mark Matthews
* @version $Id: CallableStatement.java,v 1.1.2.1 2005/05/13 18:58:38 mmatthews
* Exp $
*/
public class CallableStatement extends PreparedStatement implements
java.sql.CallableStatement {
protected final static Constructor<?> JDBC_4_CSTMT_2_ARGS_CTOR;
protected final static Constructor<?> JDBC_4_CSTMT_4_ARGS_CTOR;
static {
if (Util.isJdbc4()) {
try {
JDBC_4_CSTMT_2_ARGS_CTOR = Class.forName(
"com.mysql.jdbc.JDBC4CallableStatement")
.getConstructor(
new Class[] { MySQLConnection.class,
CallableStatementParamInfo.class });
JDBC_4_CSTMT_4_ARGS_CTOR = Class.forName(
"com.mysql.jdbc.JDBC4CallableStatement")
.getConstructor(
new Class[] { MySQLConnection.class,
String.class, String.class,
Boolean.TYPE });
} catch (SecurityException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
} else {
JDBC_4_CSTMT_4_ARGS_CTOR = null;
JDBC_4_CSTMT_2_ARGS_CTOR = null;
}
}
protected static class CallableStatementParam {
int desiredJdbcType;
int index;
int inOutModifier;
boolean isIn;
boolean isOut;
int jdbcType;
short nullability;
String paramName;
int precision;
int scale;
String typeName;
CallableStatementParam(String name, int idx, boolean in, boolean out,
int jdbcType, String typeName, int precision, int scale,
short nullability, int inOutModifier) {
this.paramName = name;
this.isIn = in;
this.isOut = out;
this.index = idx;
this.jdbcType = jdbcType;
this.typeName = typeName;
this.precision = precision;
this.scale = scale;
this.nullability = nullability;
this.inOutModifier = inOutModifier;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#clone()
*/
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
protected class CallableStatementParamInfo {
String catalogInUse;
boolean isFunctionCall;
String nativeSql;
int numParameters;
List<CallableStatementParam> parameterList;
Map<String, CallableStatementParam> parameterMap;
/**
* synchronized externally in checkReadOnlyProcedure()
*/
boolean isReadOnlySafeProcedure = false;
/**
* synchronized externally in checkReadOnlyProcedure()
*/
boolean isReadOnlySafeChecked = false;
/**
* Constructor that converts a full list of parameter metadata into one
* that only represents the placeholders present in the {CALL ()}.
*
* @param fullParamInfo the metadata for all parameters for this stored
* procedure or function.
*/
CallableStatementParamInfo(CallableStatementParamInfo fullParamInfo) {
this.nativeSql = originalSql;
this.catalogInUse = currentCatalog;
isFunctionCall = fullParamInfo.isFunctionCall;
@SuppressWarnings("synthetic-access")
int[] localParameterMap = placeholderToParameterIndexMap;
int parameterMapLength = localParameterMap.length;
this.isReadOnlySafeProcedure = fullParamInfo.isReadOnlySafeProcedure;
this.isReadOnlySafeChecked = fullParamInfo.isReadOnlySafeChecked;
parameterList = new ArrayList<CallableStatementParam>(fullParamInfo.numParameters);
parameterMap = new HashMap<String, CallableStatementParam>(fullParamInfo.numParameters);
if (isFunctionCall) {
// Take the return value
parameterList.add(fullParamInfo.parameterList.get(0));
}
int offset = isFunctionCall ? 1 : 0;
for (int i = 0; i < parameterMapLength; i++) {
if (localParameterMap[i] != 0) {
CallableStatementParam param = fullParamInfo.parameterList.get(localParameterMap[i] + offset);
parameterList.add(param);
parameterMap.put(param.paramName, param);
}
}
this.numParameters = parameterList.size();
}
@SuppressWarnings("synthetic-access")
CallableStatementParamInfo(java.sql.ResultSet paramTypesRs)
throws SQLException {
boolean hadRows = paramTypesRs.last();
this.nativeSql = originalSql;
this.catalogInUse = currentCatalog;
isFunctionCall = callingStoredFunction;
if (hadRows) {
this.numParameters = paramTypesRs.getRow();
this.parameterList = new ArrayList<CallableStatementParam>(this.numParameters);
this.parameterMap = new HashMap<String, CallableStatementParam>(this.numParameters);
paramTypesRs.beforeFirst();
addParametersFromDBMD(paramTypesRs);
} else {
this.numParameters = 0;
}
if (isFunctionCall) {
this.numParameters += 1;
}
}
private void addParametersFromDBMD(java.sql.ResultSet paramTypesRs)
throws SQLException {
int i = 0;
while (paramTypesRs.next()) {
String paramName = paramTypesRs.getString(4);
int inOutModifier = paramTypesRs.getInt(5);
boolean isOutParameter = false;
boolean isInParameter = false;
if (i == 0 && isFunctionCall) {
isOutParameter = true;
isInParameter = false;
} else if (inOutModifier == DatabaseMetaData.procedureColumnInOut) {
isOutParameter = true;
isInParameter = true;
} else if (inOutModifier == DatabaseMetaData.procedureColumnIn) {
isOutParameter = false;
isInParameter = true;
} else if (inOutModifier == DatabaseMetaData.procedureColumnOut) {
isOutParameter = true;
isInParameter = false;
}
int jdbcType = paramTypesRs.getInt(6);
String typeName = paramTypesRs.getString(7);
int precision = paramTypesRs.getInt(8);
int scale = paramTypesRs.getInt(10);
short nullability = paramTypesRs.getShort(12);
CallableStatementParam paramInfoToAdd = new CallableStatementParam(
paramName, i++, isInParameter, isOutParameter,
jdbcType, typeName, precision, scale, nullability,
inOutModifier);
this.parameterList.add(paramInfoToAdd);
this.parameterMap.put(paramName, paramInfoToAdd);
}
}
protected void checkBounds(int paramIndex) throws SQLException {
int localParamIndex = paramIndex - 1;
if ((paramIndex < 0) || (localParamIndex >= this.numParameters)) {
throw SQLError.createSQLException(
Messages.getString("CallableStatement.11") + paramIndex //$NON-NLS-1$
+ Messages.getString("CallableStatement.12") + numParameters //$NON-NLS-1$
+ Messages.getString("CallableStatement.13"), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); //$NON-NLS-1$
}
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#clone()
*/
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
CallableStatementParam getParameter(int index) {
return this.parameterList.get(index);
}
CallableStatementParam getParameter(String name) {
return this.parameterMap.get(name);
}
public String getParameterClassName(int arg0) throws SQLException {
String mysqlTypeName = getParameterTypeName(arg0);
boolean isBinaryOrBlob = StringUtils.indexOfIgnoreCase(mysqlTypeName, "BLOB") != -1 ||
StringUtils.indexOfIgnoreCase(mysqlTypeName, "BINARY") != -1;
boolean isUnsigned = StringUtils.indexOfIgnoreCase(mysqlTypeName, "UNSIGNED") != -1;
int mysqlTypeIfKnown = 0;
if (StringUtils.startsWithIgnoreCase(mysqlTypeName, "MEDIUMINT")) {
mysqlTypeIfKnown = MysqlDefs.FIELD_TYPE_INT24;
}
return ResultSetMetaData.getClassNameForJavaType(getParameterType(arg0),
isUnsigned, mysqlTypeIfKnown, isBinaryOrBlob, false);
}
public int getParameterCount() throws SQLException {
if (this.parameterList == null) {
return 0;
}
return this.parameterList.size();
}
public int getParameterMode(int arg0) throws SQLException {
checkBounds(arg0);
return getParameter(arg0 - 1).inOutModifier;
}
public int getParameterType(int arg0) throws SQLException {
checkBounds(arg0);
return getParameter(arg0 - 1).jdbcType;
}
public String getParameterTypeName(int arg0) throws SQLException {
checkBounds(arg0);
return getParameter(arg0 - 1).typeName;
}
public int getPrecision(int arg0) throws SQLException {
checkBounds(arg0);
return getParameter(arg0 - 1).precision;
}
public int getScale(int arg0) throws SQLException {
checkBounds(arg0);
return getParameter(arg0 - 1).scale;
}
public int isNullable(int arg0) throws SQLException {
checkBounds(arg0);
return getParameter(arg0 - 1).nullability;
}
public boolean isSigned(int arg0) throws SQLException {
checkBounds(arg0);
return false;
}
Iterator<CallableStatementParam> iterator() {
return this.parameterList.iterator();
}
int numberOfParameters() {
return this.numParameters;
}
}
/**
* Can't implement this directly, as then you can't use callable statements
* on JDK-1.3.1, which unfortunately isn't EOL'd yet, and still present
* quite a bit out there in the wild (Websphere, FreeBSD, anyone?)
*/
protected class CallableStatementParamInfoJDBC3 extends CallableStatementParamInfo
implements ParameterMetaData {
CallableStatementParamInfoJDBC3(java.sql.ResultSet paramTypesRs)
throws SQLException {
super(paramTypesRs);
}
public CallableStatementParamInfoJDBC3(CallableStatementParamInfo paramInfo) {
super(paramInfo);
}
/**
* Returns true if this either implements the interface argument or is directly or indirectly a wrapper
* for an object that does. Returns false otherwise. If this implements the interface then return true,
* else if this is a wrapper then return the result of recursively calling <code>isWrapperFor</code> on the wrapped
* object. If this does not implement the interface and is not a wrapper, return false.
* This method should be implemented as a low-cost operation compared to <code>unwrap</code> so that
* callers can use this method to avoid expensive <code>unwrap</code> calls that may fail. If this method
* returns true then calling <code>unwrap</code> with the same argument should succeed.
*
* @param interfaces a Class defining an interface.
* @return true if this implements the interface or directly or indirectly wraps an object that does.
* @throws java.sql.SQLException if an error occurs while determining whether this is a wrapper
* for an object with the given interface.
* @since 1.6
*/
public boolean isWrapperFor(Class<?> iface) throws SQLException {
checkClosed();
// This works for classes that aren't actually wrapping
// anything
return iface.isInstance(this);
}
/**
* Returns an object that implements the given interface to allow access to non-standard methods,
* or standard methods not exposed by the proxy.
* The result may be either the object found to implement the interface or a proxy for that object.
* If the receiver implements the interface then that is the object. If the receiver is a wrapper
* and the wrapped object implements the interface then that is the object. Otherwise the object is
* the result of calling <code>unwrap</code> recursively on the wrapped object. If the receiver is not a
* wrapper and does not implement the interface, then an <code>SQLException</code> is thrown.
*
* @param iface A Class defining an interface that the result must implement.
* @return an object that implements the interface. May be a proxy for the actual implementing object.
* @throws java.sql.SQLException If no object found that implements the interface
* @since 1.6
*/
public Object unwrap(Class<?> iface) throws java.sql.SQLException {
try {
// This works for classes that aren't actually wrapping
// anything
return Util.cast(iface, this);
} catch (ClassCastException cce) {
throw SQLError.createSQLException("Unable to unwrap to " + iface.toString(),
SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
}
}
}
private final static int NOT_OUTPUT_PARAMETER_INDICATOR = Integer.MIN_VALUE;
private final static String PARAMETER_NAMESPACE_PREFIX = "@com_mysql_jdbc_outparam_"; //$NON-NLS-1$
private static String mangleParameterName(String origParameterName) {
//Fixed for 5.5+ in callers
if (origParameterName == null) {
return null;
}
int offset = 0;
if (origParameterName.length() > 0
&& origParameterName.charAt(0) == '@') {
offset = 1;
}
StringBuffer paramNameBuf = new StringBuffer(PARAMETER_NAMESPACE_PREFIX
.length()
+ origParameterName.length());
paramNameBuf.append(PARAMETER_NAMESPACE_PREFIX);
paramNameBuf.append(origParameterName.substring(offset));
return paramNameBuf.toString();
}
private boolean callingStoredFunction = false;
private ResultSetInternalMethods functionReturnValueResults;
private boolean hasOutputParams = false;
// private List parameterList;
// private Map parameterMap;
private ResultSetInternalMethods outputParameterResults;
protected boolean outputParamWasNull = false;
private int[] parameterIndexToRsIndex;
protected CallableStatementParamInfo paramInfo;
private CallableStatementParam returnValueParam;
/**
* Creates a new CallableStatement
*
* @param conn
* the connection creating this statement
* @param paramInfo
* the SQL to prepare
*
* @throws SQLException
* if an error occurs
*/
public CallableStatement(MySQLConnection conn,
CallableStatementParamInfo paramInfo) throws SQLException {
super(conn, paramInfo.nativeSql, paramInfo.catalogInUse);
this.paramInfo = paramInfo;
this.callingStoredFunction = this.paramInfo.isFunctionCall;
if (this.callingStoredFunction) {
this.parameterCount += 1;
}
this.retrieveGeneratedKeys = true; // not provided for in the JDBC spec
}
/**
* Creates a callable statement instance -- We need to provide factory-style methods
* so we can support both JDBC3 (and older) and JDBC4 runtimes, otherwise
* the class verifier complains when it tries to load JDBC4-only interface
* classes that are present in JDBC4 method signatures.
*/
protected static CallableStatement getInstance(MySQLConnection conn, String sql,
String catalog, boolean isFunctionCall) throws SQLException {
if (!Util.isJdbc4()) {
return new CallableStatement(conn, sql, catalog, isFunctionCall);
}
return (CallableStatement) Util.handleNewInstance(
JDBC_4_CSTMT_4_ARGS_CTOR, new Object[] { conn, sql, catalog,
Boolean.valueOf(isFunctionCall) }, conn.getExceptionInterceptor());
}
/**
* Creates a callable statement instance -- We need to provide factory-style methods
* so we can support both JDBC3 (and older) and JDBC4 runtimes, otherwise
* the class verifier complains when it tries to load JDBC4-only interface
* classes that are present in JDBC4 method signatures.
*/
protected static CallableStatement getInstance(MySQLConnection conn,
CallableStatementParamInfo paramInfo) throws SQLException {
if (!Util.isJdbc4()) {
return new CallableStatement(conn, paramInfo);
}
return (CallableStatement) Util.handleNewInstance(
JDBC_4_CSTMT_2_ARGS_CTOR, new Object[] { conn, paramInfo }, conn.getExceptionInterceptor());
}
private int[] placeholderToParameterIndexMap;
private void generateParameterMap() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
if (this.paramInfo == null) {
return;
}
// if the user specified some parameters as literals, we need to
// provide a map from the specified placeholders to the actual
// parameter numbers
int parameterCountFromMetaData = this.paramInfo.getParameterCount();
// Ignore the first ? if this is a stored function, it doesn't count
if (this.callingStoredFunction) {
parameterCountFromMetaData--;
}
if (this.paramInfo != null &&
this.parameterCount != parameterCountFromMetaData) {
this.placeholderToParameterIndexMap = new int[this.parameterCount];
int startPos = this.callingStoredFunction ? StringUtils.indexOfIgnoreCase(this.originalSql,
"SELECT") : StringUtils.indexOfIgnoreCase(this.originalSql, "CALL");
if (startPos != -1) {
int parenOpenPos = this.originalSql.indexOf('(', startPos + 4);
if (parenOpenPos != -1) {
int parenClosePos = StringUtils.indexOfIgnoreCaseRespectQuotes(parenOpenPos,
this.originalSql, ")", '\'', true);
if (parenClosePos != -1) {
List<?> parsedParameters = StringUtils.split(this.originalSql.substring(parenOpenPos + 1, parenClosePos), ",", "'\"", "'\"", true);
int numParsedParameters = parsedParameters.size();
// sanity check
if (numParsedParameters != this.parameterCount) {
// bail?
}
int placeholderCount = 0;
for (int i = 0; i < numParsedParameters; i++) {
if (((String)parsedParameters.get(i)).equals("?")) {
this.placeholderToParameterIndexMap[placeholderCount++] = i;
}
}
}
}
}
}
}
}
/**
* Creates a new CallableStatement
*
* @param conn
* the connection creating this statement
* @param sql
* the SQL to prepare
* @param catalog
* the current catalog
*
* @throws SQLException
* if an error occurs
*/
public CallableStatement(MySQLConnection conn, String sql, String catalog,
boolean isFunctionCall) throws SQLException {
super(conn, sql, catalog);
this.callingStoredFunction = isFunctionCall;
if (!this.callingStoredFunction) {
if (!StringUtils.startsWithIgnoreCaseAndWs(sql, "CALL")) {
// not really a stored procedure call
fakeParameterTypes(false);
} else {
determineParameterTypes();
}
generateParameterMap();
} else {
determineParameterTypes();
generateParameterMap();
this.parameterCount += 1;
}
this.retrieveGeneratedKeys = true; // not provided for in the JDBC spec
}
/*
* (non-Javadoc)
*
* @see java.sql.PreparedStatement#addBatch()
*/
public void addBatch() throws SQLException {
setOutParams();
super.addBatch();
}
private CallableStatementParam checkIsOutputParam(int paramIndex)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
if (this.callingStoredFunction) {
if (paramIndex == 1) {
if (this.returnValueParam == null) {
this.returnValueParam = new CallableStatementParam("", 0,
false, true, Types.VARCHAR, "VARCHAR", 0, 0,
DatabaseMetaData.attributeNullableUnknown,
DatabaseMetaData.procedureColumnReturn);
}
return this.returnValueParam;
}
// Move to position in output result set
paramIndex--;
}
checkParameterIndexBounds(paramIndex);
int localParamIndex = paramIndex - 1;
if (this.placeholderToParameterIndexMap != null) {
localParamIndex = this.placeholderToParameterIndexMap[localParamIndex];
}
CallableStatementParam paramDescriptor = this.paramInfo
.getParameter(localParamIndex);
// We don't have reliable metadata in this case, trust
// the caller
if (this.connection.getNoAccessToProcedureBodies()) {
paramDescriptor.isOut = true;
paramDescriptor.isIn = true;
paramDescriptor.inOutModifier = DatabaseMetaData.procedureColumnInOut;
} else if (!paramDescriptor.isOut) {
throw SQLError.createSQLException(
Messages.getString("CallableStatement.9") + paramIndex //$NON-NLS-1$
+ Messages.getString("CallableStatement.10"), //$NON-NLS-1$
SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
}
this.hasOutputParams = true;
return paramDescriptor;
}
}
/**
* DOCUMENT ME!
*
* @param paramIndex
*
* @throws SQLException
*/
private void checkParameterIndexBounds(int paramIndex) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
this.paramInfo.checkBounds(paramIndex);
}
}
/**
* Checks whether or not this statement is supposed to be providing
* streamable result sets...If output parameters are registered, the driver
* can not stream the results.
*
* @throws SQLException
* DOCUMENT ME!
*/
private void checkStreamability() throws SQLException {
if (this.hasOutputParams && createStreamingResultSet()) {
throw SQLError.createSQLException(Messages.getString("CallableStatement.14"), //$NON-NLS-1$
SQLError.SQL_STATE_DRIVER_NOT_CAPABLE, getExceptionInterceptor());
}
}
public void clearParameters() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
super.clearParameters();
try {
if (this.outputParameterResults != null) {
this.outputParameterResults.close();
}
} finally {
this.outputParameterResults = null;
}
}
}
/**
* Used to fake up some metadata when we don't have access to
* SHOW CREATE PROCEDURE or mysql.proc.
*
* @throws SQLException if we can't build the metadata.
*/
private void fakeParameterTypes(boolean isReallyProcedure) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
Field[] fields = new Field[13];
fields[0] = new Field("", "PROCEDURE_CAT", Types.CHAR, 0);
fields[1] = new Field("", "PROCEDURE_SCHEM", Types.CHAR, 0);
fields[2] = new Field("", "PROCEDURE_NAME", Types.CHAR, 0);
fields[3] = new Field("", "COLUMN_NAME", Types.CHAR, 0);
fields[4] = new Field("", "COLUMN_TYPE", Types.CHAR, 0);
fields[5] = new Field("", "DATA_TYPE", Types.SMALLINT, 0);
fields[6] = new Field("", "TYPE_NAME", Types.CHAR, 0);
fields[7] = new Field("", "PRECISION", Types.INTEGER, 0);
fields[8] = new Field("", "LENGTH", Types.INTEGER, 0);
fields[9] = new Field("", "SCALE", Types.SMALLINT, 0);
fields[10] = new Field("", "RADIX", Types.SMALLINT, 0);
fields[11] = new Field("", "NULLABLE", Types.SMALLINT, 0);
fields[12] = new Field("", "REMARKS", Types.CHAR, 0);
String procName = isReallyProcedure ? extractProcedureName() : null;
byte[] procNameAsBytes = null;
try {
procNameAsBytes = procName == null ? null : StringUtils.getBytes(procName, "UTF-8");
} catch (UnsupportedEncodingException ueEx) {
procNameAsBytes = StringUtils.s2b(procName, this.connection);
}
ArrayList<ResultSetRow> resultRows = new ArrayList<ResultSetRow>();
for (int i = 0; i < this.parameterCount; i++) {
byte[][] row = new byte[13][];
row[0] = null; // PROCEDURE_CAT
row[1] = null; // PROCEDURE_SCHEM
row[2] = procNameAsBytes; // PROCEDURE/NAME
row[3] = StringUtils.s2b(String.valueOf(i), this.connection); // COLUMN_NAME
row[4] = StringUtils.s2b(String
.valueOf(DatabaseMetaData.procedureColumnIn),
this.connection);
row[5] = StringUtils.s2b(String.valueOf(Types.VARCHAR),
this.connection); // DATA_TYPE
row[6] = StringUtils.s2b("VARCHAR", this.connection); // TYPE_NAME
row[7] = StringUtils.s2b(Integer.toString(65535), this.connection); // PRECISION
row[8] = StringUtils.s2b(Integer.toString(65535), this.connection); // LENGTH
row[9] = StringUtils.s2b(Integer.toString(0), this.connection); // SCALE
row[10] = StringUtils.s2b(Integer.toString(10), this.connection); // RADIX
row[11] = StringUtils.s2b(Integer
.toString(DatabaseMetaData.procedureNullableUnknown),
this.connection); // nullable
row[12] = null;
resultRows.add(new ByteArrayRow(row, getExceptionInterceptor()));
}
java.sql.ResultSet paramTypesRs = DatabaseMetaData.buildResultSet(
fields, resultRows, this.connection);
convertGetProcedureColumnsToInternalDescriptors(paramTypesRs);
}
}
private void determineParameterTypes() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
java.sql.ResultSet paramTypesRs = null;
try {
//Bug#57022, we need to check for db.SPname notation first
// and pass on only SPname
String procName = extractProcedureName();
String quotedId = "";
try {
quotedId = this.connection.supportsQuotedIdentifiers() ?
this.connection.getMetaData().getIdentifierQuoteString() : "";
} catch (SQLException sqlEx) {
// Forced by API, never thrown from getIdentifierQuoteString() in
// this implementation.
AssertionFailedException.shouldNotHappen(sqlEx);
}
List<?> parseList = StringUtils.splitDBdotName(procName, "",
quotedId , this.connection.isNoBackslashEscapesSet());
String tmpCatalog = "";
//There *should* be 2 rows, if any.
if (parseList.size() == 2) {
tmpCatalog = (String) parseList.get(0);
procName = (String) parseList.get(1);
} else {
//keep values as they are
}
java.sql.DatabaseMetaData dbmd = this.connection.getMetaData();
boolean useCatalog = false;
if (tmpCatalog.length() <= 0) {
useCatalog = true;
}
paramTypesRs = dbmd.getProcedureColumns(this.connection
.versionMeetsMinimum(5, 0, 2)
&& useCatalog ? this.currentCatalog : tmpCatalog/*null*/, null, procName,
"%"); //$NON-NLS-1$
boolean hasResults = false;
try {
if (paramTypesRs.next()) {
paramTypesRs.previous();
hasResults = true;
}
} catch (Exception e) {
// paramTypesRs is empty, proceed with fake params. swallow, was expected
}
if (hasResults){
convertGetProcedureColumnsToInternalDescriptors(paramTypesRs);
} else {
fakeParameterTypes(true);
}
} finally {
SQLException sqlExRethrow = null;
if (paramTypesRs != null) {
try {
paramTypesRs.close();
} catch (SQLException sqlEx) {
sqlExRethrow = sqlEx;
}
paramTypesRs = null;
}
if (sqlExRethrow != null) {
throw sqlExRethrow;
}
}
}
}
private void convertGetProcedureColumnsToInternalDescriptors(java.sql.ResultSet paramTypesRs) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
if (!this.connection.isRunningOnJDK13()) {
this.paramInfo = new CallableStatementParamInfoJDBC3(
paramTypesRs);
} else {
this.paramInfo = new CallableStatementParamInfo(paramTypesRs);
}
}
}
/*
* (non-Javadoc)
*
* @see java.sql.PreparedStatement#execute()
*/
public boolean execute() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
boolean returnVal = false;
checkStreamability();
setInOutParamsOnServer();
setOutParams();
returnVal = super.execute();
if (this.callingStoredFunction) {
this.functionReturnValueResults = this.results;
this.functionReturnValueResults.next();
this.results = null;
}
retrieveOutParams();
if (!this.callingStoredFunction) {
return returnVal;
}
// Functions can't return results
return false;
}
}
/*
* (non-Javadoc)
*
* @see java.sql.PreparedStatement#executeQuery()
*/
public java.sql.ResultSet executeQuery() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
checkStreamability();
java.sql.ResultSet execResults = null;
setInOutParamsOnServer();
setOutParams();
execResults = super.executeQuery();
retrieveOutParams();
return execResults;
}
}
/*
* (non-Javadoc)
*
* @see java.sql.PreparedStatement#executeUpdate()
*/
public int executeUpdate() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
int returnVal = -1;
checkStreamability();
if (this.callingStoredFunction) {
execute();
return -1;
}
setInOutParamsOnServer();
setOutParams();
returnVal = super.executeUpdate();
retrieveOutParams();
return returnVal;
}
}
private String extractProcedureName() throws SQLException {
String sanitizedSql = StringUtils.stripComments(this.originalSql,
"`\"'", "`\"'", true, false, true, true);
// TODO: Do this with less memory allocation
int endCallIndex = StringUtils.indexOfIgnoreCase(sanitizedSql,
"CALL "); //$NON-NLS-1$
int offset = 5;
if (endCallIndex == -1) {
endCallIndex = StringUtils.indexOfIgnoreCase(sanitizedSql,
"SELECT ");
offset = 7;
}
if (endCallIndex != -1) {
StringBuffer nameBuf = new StringBuffer();
String trimmedStatement = sanitizedSql.substring(
endCallIndex + offset).trim();
int statementLength = trimmedStatement.length();
for (int i = 0; i < statementLength; i++) {
char c = trimmedStatement.charAt(i);
if (Character.isWhitespace(c) || (c == '(') || (c == '?')) {
break;
}
nameBuf.append(c);
}
return nameBuf.toString();
}
throw SQLError.createSQLException(Messages.getString("CallableStatement.1"), //$NON-NLS-1$
SQLError.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
}
/**
* Adds 'at' symbol to beginning of parameter names if needed.
*
* @param paramNameIn
* the parameter name to 'fix'
*
* @return the parameter name with an 'a' prepended, if needed
*
* @throws SQLException
* if the parameter name is null or empty.
*/
protected String fixParameterName(String paramNameIn) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
//Fixed for 5.5+
if (((paramNameIn == null) || (paramNameIn.length() == 0)) && (!hasParametersView())) {
throw SQLError.createSQLException(
((Messages.getString("CallableStatement.0") + paramNameIn) == null) //$NON-NLS-1$
? Messages.getString("CallableStatement.15") : Messages.getString("CallableStatement.16"), SQLError.SQL_STATE_ILLEGAL_ARGUMENT,
getExceptionInterceptor()); //$NON-NLS-1$ //$NON-NLS-2$
}
if ((paramNameIn == null) && (hasParametersView())) {
paramNameIn = "nullpn";
};
if (this.connection.getNoAccessToProcedureBodies()) {
throw SQLError.createSQLException("No access to parameters by name when connection has been configured not to access procedure bodies",
SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
}
return mangleParameterName(paramNameIn);
}
}
/**
* @see java.sql.CallableStatement#getArray(int)
*/
public Array getArray(int i) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(i);
Array retValue = rs.getArray(mapOutputParameterIndexToRsIndex(i));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getArray(java.lang.String)
*/
public Array getArray(String parameterName)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
Array retValue = rs.getArray(fixParameterName(parameterName));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getBigDecimal(int)
*/
public BigDecimal getBigDecimal(int parameterIndex)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
BigDecimal retValue = rs
.getBigDecimal(mapOutputParameterIndexToRsIndex(parameterIndex));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* DOCUMENT ME!
*
* @param parameterIndex
* DOCUMENT ME!
* @param scale
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws SQLException
* DOCUMENT ME!
*
* @see java.sql.CallableStatement#getBigDecimal(int, int)
* @deprecated
*/
public BigDecimal getBigDecimal(int parameterIndex, int scale)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
BigDecimal retValue = rs.getBigDecimal(
mapOutputParameterIndexToRsIndex(parameterIndex), scale);
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getBigDecimal(java.lang.String)
*/
public BigDecimal getBigDecimal(String parameterName)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
BigDecimal retValue = rs.getBigDecimal(fixParameterName(parameterName));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getBlob(int)
*/
public Blob getBlob(int parameterIndex) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
Blob retValue = rs
.getBlob(mapOutputParameterIndexToRsIndex(parameterIndex));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getBlob(java.lang.String)
*/
public Blob getBlob(String parameterName) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
Blob retValue = rs.getBlob(fixParameterName(parameterName));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getBoolean(int)
*/
public boolean getBoolean(int parameterIndex)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
boolean retValue = rs
.getBoolean(mapOutputParameterIndexToRsIndex(parameterIndex));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getBoolean(java.lang.String)
*/
public boolean getBoolean(String parameterName)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
boolean retValue = rs.getBoolean(fixParameterName(parameterName));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getByte(int)
*/
public byte getByte(int parameterIndex) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
byte retValue = rs
.getByte(mapOutputParameterIndexToRsIndex(parameterIndex));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getByte(java.lang.String)
*/
public byte getByte(String parameterName) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
byte retValue = rs.getByte(fixParameterName(parameterName));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getBytes(int)
*/
public byte[] getBytes(int parameterIndex) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
byte[] retValue = rs
.getBytes(mapOutputParameterIndexToRsIndex(parameterIndex));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getBytes(java.lang.String)
*/
public byte[] getBytes(String parameterName)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
byte[] retValue = rs.getBytes(fixParameterName(parameterName));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getClob(int)
*/
public Clob getClob(int parameterIndex) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
Clob retValue = rs
.getClob(mapOutputParameterIndexToRsIndex(parameterIndex));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getClob(java.lang.String)
*/
public Clob getClob(String parameterName) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
Clob retValue = rs.getClob(fixParameterName(parameterName));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getDate(int)
*/
public Date getDate(int parameterIndex) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
Date retValue = rs
.getDate(mapOutputParameterIndexToRsIndex(parameterIndex));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getDate(int, java.util.Calendar)
*/
public Date getDate(int parameterIndex, Calendar cal)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
Date retValue = rs.getDate(
mapOutputParameterIndexToRsIndex(parameterIndex), cal);
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getDate(java.lang.String)
*/
public Date getDate(String parameterName) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
Date retValue = rs.getDate(fixParameterName(parameterName));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getDate(java.lang.String,
* java.util.Calendar)
*/
public Date getDate(String parameterName, Calendar cal)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
Date retValue = rs.getDate(fixParameterName(parameterName), cal);
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getDouble(int)
*/
public double getDouble(int parameterIndex)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
double retValue = rs
.getDouble(mapOutputParameterIndexToRsIndex(parameterIndex));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getDouble(java.lang.String)
*/
public double getDouble(String parameterName)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
double retValue = rs.getDouble(fixParameterName(parameterName));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getFloat(int)
*/
public float getFloat(int parameterIndex) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
float retValue = rs
.getFloat(mapOutputParameterIndexToRsIndex(parameterIndex));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getFloat(java.lang.String)
*/
public float getFloat(String parameterName)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
float retValue = rs.getFloat(fixParameterName(parameterName));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getInt(int)
*/
public int getInt(int parameterIndex) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
int retValue = rs
.getInt(mapOutputParameterIndexToRsIndex(parameterIndex));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getInt(java.lang.String)
*/
public int getInt(String parameterName) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
int retValue = rs.getInt(fixParameterName(parameterName));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getLong(int)
*/
public long getLong(int parameterIndex) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
long retValue = rs
.getLong(mapOutputParameterIndexToRsIndex(parameterIndex));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getLong(java.lang.String)
*/
public long getLong(String parameterName) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
long retValue = rs.getLong(fixParameterName(parameterName));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
protected int getNamedParamIndex(String paramName, boolean forOut)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
if (this.connection.getNoAccessToProcedureBodies()) {
throw SQLError.createSQLException("No access to parameters by name when connection has been configured not to access procedure bodies",
SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
}
//Fixed for 5.5+ in callers
if ((paramName == null) || (paramName.length() == 0)) {
throw SQLError.createSQLException(Messages.getString("CallableStatement.2"), //$NON-NLS-1$
SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
}
if (this.paramInfo == null) {
throw SQLError.createSQLException(
Messages.getString("CallableStatement.3") + paramName + Messages.getString("CallableStatement.4"), //$NON-NLS-1$ //$NON-NLS-2$
SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
}
CallableStatementParam namedParamInfo = this.paramInfo
.getParameter(paramName);
if (forOut && !namedParamInfo.isOut) {
throw SQLError.createSQLException(
Messages.getString("CallableStatement.5") + paramName //$NON-NLS-1$
+ Messages.getString("CallableStatement.6"), //$NON-NLS-1$
SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
}
if (this.placeholderToParameterIndexMap == null) {
return namedParamInfo.index + 1; // JDBC indices are 1-based
}
for (int i = 0; i < this.placeholderToParameterIndexMap.length; i++) {
if (this.placeholderToParameterIndexMap[i] == namedParamInfo.index) {
return i + 1;
}
}
throw SQLError.createSQLException("Can't find local placeholder mapping for parameter named \"" +
paramName + "\".", SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
}
}
/**
* @see java.sql.CallableStatement#getObject(int)
*/
public Object getObject(int parameterIndex)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
CallableStatementParam paramDescriptor = checkIsOutputParam(parameterIndex);
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
Object retVal = rs.getObjectStoredProc(
mapOutputParameterIndexToRsIndex(parameterIndex),
paramDescriptor.desiredJdbcType);
this.outputParamWasNull = rs.wasNull();
return retVal;
}
}
/**
* @see java.sql.CallableStatement#getObject(int, java.util.Map)
*/
public Object getObject(int parameterIndex, Map<String, Class<?>> map)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
Object retVal = rs.getObject(
mapOutputParameterIndexToRsIndex(parameterIndex), map);
this.outputParamWasNull = rs.wasNull();
return retVal;
}
}
/**
* @see java.sql.CallableStatement#getObject(java.lang.String)
*/
public Object getObject(String parameterName)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
Object retValue = rs.getObject(fixParameterName(parameterName));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getObject(java.lang.String,
* java.util.Map)
*/
public Object getObject(String parameterName, Map<String, Class<?>> map)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
Object retValue = rs.getObject(fixParameterName(parameterName), map);
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
// JDBC-4.1
public <T> T getObject(int parameterIndex, Class<T> type) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
// remove cast once 1.5, 1.6 EOL'd
T retVal = ((ResultSetImpl)rs).getObject(
mapOutputParameterIndexToRsIndex(parameterIndex), type);
this.outputParamWasNull = rs.wasNull();
return retVal;
}
}
public <T> T getObject(String parameterName, Class<T> type) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
T retValue = ((ResultSetImpl)rs).getObject(fixParameterName(parameterName), type);
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* Returns the ResultSet that holds the output parameters, or throws an
* appropriate exception if none exist, or they weren't returned.
*
* @return the ResultSet that holds the output parameters
*
* @throws SQLException
* if no output parameters were defined, or if no output
* parameters were returned.
*/
protected ResultSetInternalMethods getOutputParameters(int paramIndex) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
this.outputParamWasNull = false;
if (paramIndex == 1 && this.callingStoredFunction
&& this.returnValueParam != null) {
return this.functionReturnValueResults;
}
if (this.outputParameterResults == null) {
if (this.paramInfo.numberOfParameters() == 0) {
throw SQLError.createSQLException(Messages
.getString("CallableStatement.7"), //$NON-NLS-1$
SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
}
throw SQLError.createSQLException(Messages.getString("CallableStatement.8"), //$NON-NLS-1$
SQLError.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
}
return this.outputParameterResults;
}
}
public ParameterMetaData getParameterMetaData()
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
if (this.placeholderToParameterIndexMap == null) {
return (CallableStatementParamInfoJDBC3) this.paramInfo;
}
return new CallableStatementParamInfoJDBC3(this.paramInfo);
}
}
/**
* @see java.sql.CallableStatement#getRef(int)
*/
public Ref getRef(int parameterIndex) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
Ref retValue = rs
.getRef(mapOutputParameterIndexToRsIndex(parameterIndex));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getRef(java.lang.String)
*/
public Ref getRef(String parameterName) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
Ref retValue = rs.getRef(fixParameterName(parameterName));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getShort(int)
*/
public short getShort(int parameterIndex) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
short retValue = rs
.getShort(mapOutputParameterIndexToRsIndex(parameterIndex));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getShort(java.lang.String)
*/
public short getShort(String parameterName)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
short retValue = rs.getShort(fixParameterName(parameterName));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getString(int)
*/
public String getString(int parameterIndex)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
String retValue = rs
.getString(mapOutputParameterIndexToRsIndex(parameterIndex));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getString(java.lang.String)
*/
public String getString(String parameterName)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
String retValue = rs.getString(fixParameterName(parameterName));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getTime(int)
*/
public Time getTime(int parameterIndex) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
Time retValue = rs
.getTime(mapOutputParameterIndexToRsIndex(parameterIndex));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getTime(int, java.util.Calendar)
*/
public Time getTime(int parameterIndex, Calendar cal)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
Time retValue = rs.getTime(
mapOutputParameterIndexToRsIndex(parameterIndex), cal);
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getTime(java.lang.String)
*/
public Time getTime(String parameterName) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
Time retValue = rs.getTime(fixParameterName(parameterName));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getTime(java.lang.String,
* java.util.Calendar)
*/
public Time getTime(String parameterName, Calendar cal)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
Time retValue = rs.getTime(fixParameterName(parameterName), cal);
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getTimestamp(int)
*/
public Timestamp getTimestamp(int parameterIndex)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
Timestamp retValue = rs
.getTimestamp(mapOutputParameterIndexToRsIndex(parameterIndex));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getTimestamp(int, java.util.Calendar)
*/
public Timestamp getTimestamp(int parameterIndex, Calendar cal)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
Timestamp retValue = rs.getTimestamp(
mapOutputParameterIndexToRsIndex(parameterIndex), cal);
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getTimestamp(java.lang.String)
*/
public Timestamp getTimestamp(String parameterName)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
Timestamp retValue = rs.getTimestamp(fixParameterName(parameterName));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getTimestamp(java.lang.String,
* java.util.Calendar)
*/
public Timestamp getTimestamp(String parameterName,
Calendar cal) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
Timestamp retValue = rs.getTimestamp(fixParameterName(parameterName),
cal);
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getURL(int)
*/
public URL getURL(int parameterIndex) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
URL retValue = rs
.getURL(mapOutputParameterIndexToRsIndex(parameterIndex));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
/**
* @see java.sql.CallableStatement#getURL(java.lang.String)
*/
public URL getURL(String parameterName) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
// from ?=
URL retValue = rs.getURL(fixParameterName(parameterName));
this.outputParamWasNull = rs.wasNull();
return retValue;
}
}
protected int mapOutputParameterIndexToRsIndex(int paramIndex)
throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
if (this.returnValueParam != null && paramIndex == 1) {
return 1;
}
checkParameterIndexBounds(paramIndex);
int localParamIndex = paramIndex - 1;
if (this.placeholderToParameterIndexMap != null) {
localParamIndex = this.placeholderToParameterIndexMap[localParamIndex];
}
int rsIndex = this.parameterIndexToRsIndex[localParamIndex];
if (rsIndex == NOT_OUTPUT_PARAMETER_INDICATOR) {
throw SQLError.createSQLException(
Messages.getString("CallableStatement.21") + paramIndex //$NON-NLS-1$
+ Messages.getString("CallableStatement.22"), //$NON-NLS-1$
SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
}
return rsIndex + 1;
}
}
/**
* @see java.sql.CallableStatement#registerOutParameter(int, int)
*/
public void registerOutParameter(int parameterIndex, int sqlType)
throws SQLException {
CallableStatementParam paramDescriptor = checkIsOutputParam(parameterIndex);
paramDescriptor.desiredJdbcType = sqlType;
}
/**
* @see java.sql.CallableStatement#registerOutParameter(int, int, int)
*/
public void registerOutParameter(int parameterIndex, int sqlType, int scale)
throws SQLException {
registerOutParameter(parameterIndex, sqlType);
}
/**
* @see java.sql.CallableStatement#registerOutParameter(int, int,
* java.lang.String)
*/
public void registerOutParameter(int parameterIndex, int sqlType,
String typeName) throws SQLException {
checkIsOutputParam(parameterIndex);
}
/**
* @see java.sql.CallableStatement#registerOutParameter(java.lang.String,
* int)
*/
public void registerOutParameter(String parameterName,
int sqlType) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
registerOutParameter(getNamedParamIndex(parameterName, true), sqlType);
}
}
/**
* @see java.sql.CallableStatement#registerOutParameter(java.lang.String,
* int, int)
*/
public void registerOutParameter(String parameterName, int sqlType,
int scale) throws SQLException {
registerOutParameter(getNamedParamIndex(parameterName, true), sqlType);
}
/**
* @see java.sql.CallableStatement#registerOutParameter(java.lang.String,
* int, java.lang.String)
*/
public void registerOutParameter(String parameterName, int sqlType,
String typeName) throws SQLException {
registerOutParameter(getNamedParamIndex(parameterName, true), sqlType,
typeName);
}
/**
* Issues a second query to retrieve all output parameters.
*
* @throws SQLException
* if an error occurs.
*/
private void retrieveOutParams() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
int numParameters = this.paramInfo.numberOfParameters();
this.parameterIndexToRsIndex = new int[numParameters];
for (int i = 0; i < numParameters; i++) {
this.parameterIndexToRsIndex[i] = NOT_OUTPUT_PARAMETER_INDICATOR;
}
int localParamIndex = 0;
if (numParameters > 0) {
StringBuffer outParameterQuery = new StringBuffer("SELECT "); //$NON-NLS-1$
boolean firstParam = true;
boolean hadOutputParams = false;
for (Iterator<CallableStatementParam> paramIter = this.paramInfo.iterator(); paramIter
.hasNext();) {
CallableStatementParam retrParamInfo = paramIter
.next();
if (retrParamInfo.isOut) {
hadOutputParams = true;
this.parameterIndexToRsIndex[retrParamInfo.index] = localParamIndex++;
if ((retrParamInfo.paramName == null) && (hasParametersView())) {
retrParamInfo.paramName = "nullnp" + retrParamInfo.index;
}
String outParameterName = mangleParameterName(retrParamInfo.paramName);
if (!firstParam) {
outParameterQuery.append(","); //$NON-NLS-1$
} else {
firstParam = false;
}
if (!outParameterName.startsWith("@")) { //$NON-NLS-1$
outParameterQuery.append('@');
}
outParameterQuery.append(outParameterName);
}
}
if (hadOutputParams) {
// We can't use 'ourself' to execute this query, or any
// pending result sets would be overwritten
java.sql.Statement outParameterStmt = null;
java.sql.ResultSet outParamRs = null;
try {
outParameterStmt = this.connection.createStatement();
outParamRs = outParameterStmt
.executeQuery(outParameterQuery.toString());
this.outputParameterResults = ((com.mysql.jdbc.ResultSetInternalMethods) outParamRs)
.copy();
if (!this.outputParameterResults.next()) {
this.outputParameterResults.close();
this.outputParameterResults = null;
}
} finally {
if (outParameterStmt != null) {
outParameterStmt.close();
}
}
} else {
this.outputParameterResults = null;
}
} else {
this.outputParameterResults = null;
}
}
}
/**
* @see java.sql.CallableStatement#setAsciiStream(java.lang.String,
* java.io.InputStream, int)
*/
public void setAsciiStream(String parameterName, InputStream x, int length)
throws SQLException {
setAsciiStream(getNamedParamIndex(parameterName, false), x, length);
}
/**
* @see java.sql.CallableStatement#setBigDecimal(java.lang.String,
* java.math.BigDecimal)
*/
public void setBigDecimal(String parameterName, BigDecimal x)
throws SQLException {
setBigDecimal(getNamedParamIndex(parameterName, false), x);
}
/**
* @see java.sql.CallableStatement#setBinaryStream(java.lang.String,
* java.io.InputStream, int)
*/
public void setBinaryStream(String parameterName, InputStream x, int length)
throws SQLException {
setBinaryStream(getNamedParamIndex(parameterName, false), x, length);
}
/**
* @see java.sql.CallableStatement#setBoolean(java.lang.String, boolean)
*/
public void setBoolean(String parameterName, boolean x) throws SQLException {
setBoolean(getNamedParamIndex(parameterName, false), x);
}
/**
* @see java.sql.CallableStatement#setByte(java.lang.String, byte)
*/
public void setByte(String parameterName, byte x) throws SQLException {
setByte(getNamedParamIndex(parameterName, false), x);
}
/**
* @see java.sql.CallableStatement#setBytes(java.lang.String, byte[])
*/
public void setBytes(String parameterName, byte[] x) throws SQLException {
setBytes(getNamedParamIndex(parameterName, false), x);
}
/**
* @see java.sql.CallableStatement#setCharacterStream(java.lang.String,
* java.io.Reader, int)
*/
public void setCharacterStream(String parameterName, Reader reader,
int length) throws SQLException {
setCharacterStream(getNamedParamIndex(parameterName, false), reader,
length);
}
/**
* @see java.sql.CallableStatement#setDate(java.lang.String, java.sql.Date)
*/
public void setDate(String parameterName, Date x) throws SQLException {
setDate(getNamedParamIndex(parameterName, false), x);
}
/**
* @see java.sql.CallableStatement#setDate(java.lang.String, java.sql.Date,
* java.util.Calendar)
*/
public void setDate(String parameterName, Date x, Calendar cal)
throws SQLException {
setDate(getNamedParamIndex(parameterName, false), x, cal);
}
/**
* @see java.sql.CallableStatement#setDouble(java.lang.String, double)
*/
public void setDouble(String parameterName, double x) throws SQLException {
setDouble(getNamedParamIndex(parameterName, false), x);
}
/**
* @see java.sql.CallableStatement#setFloat(java.lang.String, float)
*/
public void setFloat(String parameterName, float x) throws SQLException {
setFloat(getNamedParamIndex(parameterName, false), x);
}
/**
*
*/
private void setInOutParamsOnServer() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
if (this.paramInfo.numParameters > 0) {
for (Iterator<CallableStatementParam> paramIter = this.paramInfo.iterator(); paramIter
.hasNext();) {
CallableStatementParam inParamInfo = paramIter
.next();
//Fix for 5.5+
if (inParamInfo.isOut && inParamInfo.isIn) {
if ((inParamInfo.paramName == null) && (hasParametersView())) {
inParamInfo.paramName = "nullnp" + inParamInfo.index;
};
String inOutParameterName = mangleParameterName(inParamInfo.paramName);
StringBuffer queryBuf = new StringBuffer(
4 + inOutParameterName.length() + 1 + 1);
queryBuf.append("SET "); //$NON-NLS-1$
queryBuf.append(inOutParameterName);
queryBuf.append("=?"); //$NON-NLS-1$
PreparedStatement setPstmt = null;
try {
setPstmt = (PreparedStatement) this.connection
.clientPrepareStatement(queryBuf.toString());
byte[] parameterAsBytes = getBytesRepresentation(
inParamInfo.index);
if (parameterAsBytes != null) {
if (parameterAsBytes.length > 8
&& parameterAsBytes[0] == '_'
&& parameterAsBytes[1] == 'b'
&& parameterAsBytes[2] == 'i'
&& parameterAsBytes[3] == 'n'
&& parameterAsBytes[4] == 'a'
&& parameterAsBytes[5] == 'r'
&& parameterAsBytes[6] == 'y'
&& parameterAsBytes[7] == '\'') {
setPstmt.setBytesNoEscapeNoQuotes(1,
parameterAsBytes);
} else {
int sqlType = inParamInfo.desiredJdbcType;
switch (sqlType) {
case Types.BIT:
case Types.BINARY:
case Types.BLOB:
case Types.JAVA_OBJECT:
case Types.LONGVARBINARY:
case Types.VARBINARY:
setPstmt.setBytes(1, parameterAsBytes);
break;
default:
// the inherited PreparedStatement methods
// have already escaped and quoted these parameters
setPstmt.setBytesNoEscape(1, parameterAsBytes);
}
}
} else {
setPstmt.setNull(1, Types.NULL);
}
setPstmt.executeUpdate();
} finally {
if (setPstmt != null) {
setPstmt.close();
}
}
}
}
}
}
}
/**
* @see java.sql.CallableStatement#setInt(java.lang.String, int)
*/
public void setInt(String parameterName, int x) throws SQLException {
setInt(getNamedParamIndex(parameterName, false), x);
}
/**
* @see java.sql.CallableStatement#setLong(java.lang.String, long)
*/
public void setLong(String parameterName, long x) throws SQLException {
setLong(getNamedParamIndex(parameterName, false), x);
}
/**
* @see java.sql.CallableStatement#setNull(java.lang.String, int)
*/
public void setNull(String parameterName, int sqlType) throws SQLException {
setNull(getNamedParamIndex(parameterName, false), sqlType);
}
/**
* @see java.sql.CallableStatement#setNull(java.lang.String, int,
* java.lang.String)
*/
public void setNull(String parameterName, int sqlType, String typeName)
throws SQLException {
setNull(getNamedParamIndex(parameterName, false), sqlType, typeName);
}
/**
* @see java.sql.CallableStatement#setObject(java.lang.String,
* java.lang.Object)
*/
public void setObject(String parameterName, Object x) throws SQLException {
setObject(getNamedParamIndex(parameterName, false), x);
}
/**
* @see java.sql.CallableStatement#setObject(java.lang.String,
* java.lang.Object, int)
*/
public void setObject(String parameterName, Object x, int targetSqlType)
throws SQLException {
setObject(getNamedParamIndex(parameterName, false), x, targetSqlType);
}
/**
* @see java.sql.CallableStatement#setObject(java.lang.String,
* java.lang.Object, int, int)
*/
public void setObject(String parameterName, Object x, int targetSqlType,
int scale) throws SQLException {
}
private void setOutParams() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
if (this.paramInfo.numParameters > 0) {
for (Iterator<CallableStatementParam> paramIter = this.paramInfo.iterator(); paramIter
.hasNext();) {
CallableStatementParam outParamInfo = paramIter
.next();
if (!this.callingStoredFunction && outParamInfo.isOut) {
if ((outParamInfo.paramName == null) && (hasParametersView())) {
outParamInfo.paramName = "nullnp" + outParamInfo.index;
};
String outParameterName = mangleParameterName(outParamInfo.paramName);
int outParamIndex = 0;
if (this.placeholderToParameterIndexMap == null) {
outParamIndex = outParamInfo.index + 1;
} else {
// Find it, todo: remove this linear search
boolean found = false;
for (int i = 0; i < this.placeholderToParameterIndexMap.length; i++) {
if (this.placeholderToParameterIndexMap[i] == outParamInfo.index) {
outParamIndex = i + 1; /* JDBC is 1-based */
found = true;
break;
}
}
if (!found) {
throw SQLError.createSQLException("boo!", "S1000", this.connection.getExceptionInterceptor());
}
}
this.setBytesNoEscapeNoQuotes(outParamIndex,
StringUtils.getBytes(outParameterName,
this.charConverter, this.charEncoding,
this.connection
.getServerCharacterEncoding(),
this.connection.parserKnowsUnicode(), getExceptionInterceptor()));
}
}
}
}
}
/**
* @see java.sql.CallableStatement#setShort(java.lang.String, short)
*/
public void setShort(String parameterName, short x) throws SQLException {
setShort(getNamedParamIndex(parameterName, false), x);
}
/**
* @see java.sql.CallableStatement#setString(java.lang.String,
* java.lang.String)
*/
public void setString(String parameterName, String x) throws SQLException {
setString(getNamedParamIndex(parameterName, false), x);
}
/**
* @see java.sql.CallableStatement#setTime(java.lang.String, java.sql.Time)
*/
public void setTime(String parameterName, Time x) throws SQLException {
setTime(getNamedParamIndex(parameterName, false), x);
}
/**
* @see java.sql.CallableStatement#setTime(java.lang.String, java.sql.Time,
* java.util.Calendar)
*/
public void setTime(String parameterName, Time x, Calendar cal)
throws SQLException {
setTime(getNamedParamIndex(parameterName, false), x, cal);
}
/**
* @see java.sql.CallableStatement#setTimestamp(java.lang.String,
* java.sql.Timestamp)
*/
public void setTimestamp(String parameterName, Timestamp x)
throws SQLException {
setTimestamp(getNamedParamIndex(parameterName, false), x);
}
/**
* @see java.sql.CallableStatement#setTimestamp(java.lang.String,
* java.sql.Timestamp, java.util.Calendar)
*/
public void setTimestamp(String parameterName, Timestamp x, Calendar cal)
throws SQLException {
setTimestamp(getNamedParamIndex(parameterName, false), x, cal);
}
/**
* @see java.sql.CallableStatement#setURL(java.lang.String, java.net.URL)
*/
public void setURL(String parameterName, URL val) throws SQLException {
setURL(getNamedParamIndex(parameterName, false), val);
}
/**
* @see java.sql.CallableStatement#wasNull()
*/
public boolean wasNull() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
return this.outputParamWasNull;
}
}
public int[] executeBatch() throws SQLException {
if (this.hasOutputParams) {
throw SQLError.createSQLException("Can't call executeBatch() on CallableStatement with OUTPUT parameters",
SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
}
return super.executeBatch();
}
protected int getParameterIndexOffset() {
if (this.callingStoredFunction) {
return -1;
}
return super.getParameterIndexOffset();
}
public void setAsciiStream(String parameterName, InputStream x) throws SQLException {
setAsciiStream(getNamedParamIndex(parameterName, false), x);
}
public void setAsciiStream(String parameterName, InputStream x, long length) throws SQLException {
setAsciiStream(getNamedParamIndex(parameterName, false), x, length);
}
public void setBinaryStream(String parameterName, InputStream x) throws SQLException {
setBinaryStream(getNamedParamIndex(parameterName, false), x);
}
public void setBinaryStream(String parameterName, InputStream x, long length) throws SQLException {
setBinaryStream(getNamedParamIndex(parameterName, false), x, length);
}
public void setBlob(String parameterName, Blob x) throws SQLException {
setBlob(getNamedParamIndex(parameterName, false), x);
}
public void setBlob(String parameterName, InputStream inputStream) throws SQLException {
setBlob(getNamedParamIndex(parameterName, false), inputStream);
}
public void setBlob(String parameterName, InputStream inputStream, long length) throws SQLException {
setBlob(getNamedParamIndex(parameterName, false), inputStream, length);
}
public void setCharacterStream(String parameterName, Reader reader) throws SQLException {
setCharacterStream(getNamedParamIndex(parameterName, false), reader);
}
public void setCharacterStream(String parameterName, Reader reader, long length) throws SQLException {
setCharacterStream(getNamedParamIndex(parameterName, false), reader, length);
}
public void setClob(String parameterName, Clob x) throws SQLException {
setClob(getNamedParamIndex(parameterName, false), x);
}
public void setClob(String parameterName, Reader reader) throws SQLException {
setClob(getNamedParamIndex(parameterName, false), reader);
}
public void setClob(String parameterName, Reader reader, long length) throws SQLException {
setClob(getNamedParamIndex(parameterName, false), reader, length);
}
public void setNCharacterStream(String parameterName, Reader value) throws SQLException {
setNCharacterStream(getNamedParamIndex(parameterName, false), value);
}
public void setNCharacterStream(String parameterName, Reader value, long length) throws SQLException {
setNCharacterStream(getNamedParamIndex(parameterName, false), value, length);
}
/**
* Check whether the stored procedure alters any data or is safe for read-only usage.
*
* @return true if procedure does not alter data
* @throws SQLException
*/
private boolean checkReadOnlyProcedure() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
if (this.connection.getNoAccessToProcedureBodies()) {
return false;
}
if (this.paramInfo.isReadOnlySafeChecked) {
return this.paramInfo.isReadOnlySafeProcedure;
}
ResultSet rs = null;
java.sql.PreparedStatement ps = null;
try {
String procName = extractProcedureName();
String catalog = this.currentCatalog;
if (procName.indexOf(".") != -1) {
catalog = procName.substring(0, procName.indexOf("."));
if (StringUtils.startsWithIgnoreCaseAndWs(catalog, "`") && catalog.trim().endsWith("`")) {
catalog = catalog.substring(1, catalog.length() - 1);
}
procName = procName.substring(procName.indexOf(".") + 1);
procName = StringUtils.toString(StringUtils.stripEnclosure(
StringUtils.getBytes(procName), "`", "`"));
}
ps = this.connection
.prepareStatement("SELECT SQL_DATA_ACCESS FROM "
+ " information_schema.routines "
+ " WHERE routine_schema = ? "
+ " AND routine_name = ?");
ps.setMaxRows(0);
ps.setFetchSize(0);
ps.setString(1, catalog);
ps.setString(2, procName);
rs = ps.executeQuery();
if (rs.next()) {
String sqlDataAccess = rs.getString(1);
if ("READS SQL DATA".equalsIgnoreCase(sqlDataAccess)
|| "NO SQL".equalsIgnoreCase(sqlDataAccess)) {
synchronized (this.paramInfo) {
this.paramInfo.isReadOnlySafeChecked = true;
this.paramInfo.isReadOnlySafeProcedure = true;
}
return true;
}
}
} catch (SQLException e) {
// swallow the Exception
} finally {
if(rs != null){
rs.close();
}
if(ps != null){
ps.close();
}
}
this.paramInfo.isReadOnlySafeChecked = false;
this.paramInfo.isReadOnlySafeProcedure = false;
}
return false;
}
protected boolean checkReadOnlySafeStatement() throws SQLException {
return (super.checkReadOnlySafeStatement() || this.checkReadOnlyProcedure());
}
private boolean hasParametersView() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
try {
if (this.connection.versionMeetsMinimum(5, 5, 0)) {
java.sql.DatabaseMetaData dbmd1 = new DatabaseMetaDataUsingInfoSchema(this.connection, this.connection.getCatalog());
return ((DatabaseMetaDataUsingInfoSchema)dbmd1).gethasParametersView();
}
return false;
} catch (SQLException e) {
return false;
}
}
}
}