com.mysql.cj.jdbc.ClientPreparedStatement Maven / Gradle / Ivy
/*
* Copyright (c) 2002, 2020, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
* Free Software Foundation.
*
* This program is also distributed with certain software (including but not
* limited to OpenSSL) that is licensed under separate terms, as designated in a
* particular file or component or in included license documentation. The
* authors of MySQL hereby grant you an additional permission to link the
* program and your derivative works with the separately licensed software that
* they have included with MySQL.
*
* Without limiting anything contained in the foregoing, this file, which is
* part of MySQL Connector/J, is also subject to the Universal FOSS Exception,
* version 1.0, a copy of which can be found at
* http://oss.oracle.com/licenses/universal-foss-exception.
*
* 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, version 2.0,
* 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.cj.jdbc;
import java.io.InputStream;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URL;
import java.sql.Array;
import java.sql.Clob;
import java.sql.Date;
import java.sql.JDBCType;
import java.sql.NClob;
import java.sql.ParameterMetaData;
import java.sql.Ref;
import java.sql.RowId;
import java.sql.SQLException;
import java.sql.SQLType;
import java.sql.SQLXML;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Wrapper;
import java.util.ArrayList;
import java.util.Calendar;
import com.mysql.cj.BindValue;
import com.mysql.cj.CancelQueryTask;
import com.mysql.cj.ClientPreparedQuery;
import com.mysql.cj.ClientPreparedQueryBindings;
import com.mysql.cj.Messages;
import com.mysql.cj.MysqlType;
import com.mysql.cj.NativeSession;
import com.mysql.cj.ParseInfo;
import com.mysql.cj.PreparedQuery;
import com.mysql.cj.Query;
import com.mysql.cj.QueryBindings;
import com.mysql.cj.conf.PropertyKey;
import com.mysql.cj.exceptions.CJException;
import com.mysql.cj.exceptions.FeatureNotAvailableException;
import com.mysql.cj.exceptions.MysqlErrorNumbers;
import com.mysql.cj.exceptions.StatementIsClosedException;
import com.mysql.cj.jdbc.exceptions.MySQLStatementCancelledException;
import com.mysql.cj.jdbc.exceptions.MySQLTimeoutException;
import com.mysql.cj.jdbc.exceptions.SQLError;
import com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping;
import com.mysql.cj.jdbc.result.CachedResultSetMetaData;
import com.mysql.cj.jdbc.result.ResultSetInternalMethods;
import com.mysql.cj.jdbc.result.ResultSetMetaData;
import com.mysql.cj.log.ProfilerEvent;
import com.mysql.cj.protocol.ColumnDefinition;
import com.mysql.cj.protocol.Message;
import com.mysql.cj.protocol.a.NativePacketPayload;
import com.mysql.cj.result.Field;
import com.mysql.cj.util.StringUtils;
import com.mysql.cj.util.Util;
/**
* A SQL Statement is pre-compiled and stored in a PreparedStatement object. This object can then be used to efficiently execute this statement multiple times.
*
*
* Note: The setXXX methods for setting IN parameter values must specify types that are compatible with the defined SQL type of the input parameter. For
* instance, if the IN parameter has SQL type Integer, then setInt should be used.
*
*
*
* If arbitrary parameter type conversions are required, then the setObject method should be used with a target SQL type.
*
*/
public class ClientPreparedStatement extends com.mysql.cj.jdbc.StatementImpl implements JdbcPreparedStatement {
/**
* Does the batch (if any) contain "plain" statements added by
* Statement.addBatch(String)?
*
* If so, we can't re-write it to use multi-value or multi-queries.
*/
protected boolean batchHasPlainStatements = false;
protected MysqlParameterMetadata parameterMetaData;
private java.sql.ResultSetMetaData pstmtResultMetaData;
protected String batchedValuesClause;
private boolean doPingInstead;
private boolean compensateForOnDuplicateKeyUpdate = false;
protected int rewrittenBatchSize = 0;
/**
* Creates a prepared statement instance
*
* @param conn
* the connection creating this statement
* @param sql
* the SQL for this statement
* @param db
* the database this statement should be issued against
* @return ClientPreparedStatement
* @throws SQLException
* if a database access error occurs
*/
protected static ClientPreparedStatement getInstance(JdbcConnection conn, String sql, String db) throws SQLException {
return new ClientPreparedStatement(conn, sql, db);
}
/**
* Creates a prepared statement instance
*
* @param conn
* the connection creating this statement
* @param sql
* the SQL for this statement
* @param db
* the database this statement should be issued against
* @param cachedParseInfo
* already created parseInfo or null.
* @return ClientPreparedStatement instance
* @throws SQLException
* if a database access error occurs
*/
protected static ClientPreparedStatement getInstance(JdbcConnection conn, String sql, String db, ParseInfo cachedParseInfo) throws SQLException {
return new ClientPreparedStatement(conn, sql, db, cachedParseInfo);
}
@Override
protected void initQuery() {
this.query = new ClientPreparedQuery(this.session);
}
/**
* Constructor used by server-side prepared statements
*
* @param conn
* the connection that created us
* @param db
* the database in use when we were created
*
* @throws SQLException
* if an error occurs
*/
protected ClientPreparedStatement(JdbcConnection conn, String db) throws SQLException {
super(conn, db);
setPoolable(true);
this.compensateForOnDuplicateKeyUpdate = this.session.getPropertySet().getBooleanProperty(PropertyKey.compensateOnDuplicateKeyUpdateCounts).getValue();
}
/**
* Constructor for the PreparedStatement class.
*
* @param conn
* the connection creating this statement
* @param sql
* the SQL for this statement
* @param db
* the database this statement should be issued against
*
* @throws SQLException
* if a database error occurs.
*/
public ClientPreparedStatement(JdbcConnection conn, String sql, String db) throws SQLException {
this(conn, sql, db, null);
}
/**
* Creates a new PreparedStatement object.
*
* @param conn
* the connection creating this statement
* @param sql
* the SQL for this statement
* @param db
* the database this statement should be issued against
* @param cachedParseInfo
* already created parseInfo or null.
*
* @throws SQLException
* if a database access error occurs
*/
public ClientPreparedStatement(JdbcConnection conn, String sql, String db, ParseInfo cachedParseInfo) throws SQLException {
this(conn, db);
try {
((PreparedQuery>) this.query).checkNullOrEmptyQuery(sql);
((PreparedQuery>) this.query).setOriginalSql(sql);
((PreparedQuery>) this.query).setParseInfo(cachedParseInfo != null ? cachedParseInfo : new ParseInfo(sql, this.session, this.charEncoding));
} catch (CJException e) {
throw SQLExceptionsMapping.translateException(e, this.exceptionInterceptor);
}
this.doPingInstead = sql.startsWith(PING_MARKER);
initializeFromParseInfo();
}
@Override
public QueryBindings> getQueryBindings() {
return ((PreparedQuery>) this.query).getQueryBindings();
}
/**
* Returns this PreparedStatement represented as a string.
*
* @return this PreparedStatement represented as a string.
*/
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append(this.getClass().getName());
buf.append(": ");
try {
buf.append(asSql());
} catch (SQLException sqlEx) {
buf.append("EXCEPTION: " + sqlEx.toString());
}
return buf.toString();
}
@Override
public void addBatch() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
QueryBindings> queryBindings = ((PreparedQuery>) this.query).getQueryBindings();
queryBindings.checkAllParametersSet();
this.query.addBatch(queryBindings.clone());
}
}
@Override
public void addBatch(String sql) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
this.batchHasPlainStatements = true;
super.addBatch(sql);
}
}
public String asSql() throws SQLException {
return ((PreparedQuery>) this.query).asSql(false);
}
public String asSql(boolean quoteStreamsAndUnknowns) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
return ((PreparedQuery>) this.query).asSql(quoteStreamsAndUnknowns);
}
}
@Override
public void clearBatch() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
this.batchHasPlainStatements = false;
super.clearBatch();
}
}
@Override
public void clearParameters() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
for (BindValue bv : ((PreparedQuery>) this.query).getQueryBindings().getBindValues()) {
bv.reset();
}
}
}
/**
* Check to see if the statement is safe for read-only slaves after failover.
*
* @return true if safe for read-only.
* @throws SQLException
* if a database access error occurs or this method is called on a closed PreparedStatement
*/
protected boolean checkReadOnlySafeStatement() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
return ((PreparedQuery>) this.query).getParseInfo().getFirstStmtChar() == 'S' || !this.connection.isReadOnly();
}
}
@Override
public boolean execute() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
JdbcConnection locallyScopedConn = this.connection;
if (!this.doPingInstead && !checkReadOnlySafeStatement()) {
throw SQLError.createSQLException(Messages.getString("PreparedStatement.20") + Messages.getString("PreparedStatement.21"),
MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor);
}
ResultSetInternalMethods rs = null;
this.lastQueryIsOnDupKeyUpdate = false;
if (this.retrieveGeneratedKeys) {
this.lastQueryIsOnDupKeyUpdate = containsOnDuplicateKeyUpdateInSQL();
}
this.batchedGeneratedKeys = null;
resetCancelledState();
implicitlyCloseAllOpenResults();
clearWarnings();
if (this.doPingInstead) {
doPingInstead();
return true;
}
setupStreamingTimeout(locallyScopedConn);
Message sendPacket = ((PreparedQuery>) this.query).fillSendPacket();
String oldDb = null;
if (!locallyScopedConn.getDatabase().equals(this.getCurrentDatabase())) {
oldDb = locallyScopedConn.getDatabase();
locallyScopedConn.setDatabase(this.getCurrentDatabase());
}
//
// Check if we have cached metadata for this query...
//
CachedResultSetMetaData cachedMetadata = null;
boolean cacheResultSetMetadata = locallyScopedConn.getPropertySet().getBooleanProperty(PropertyKey.cacheResultSetMetadata).getValue();
if (cacheResultSetMetadata) {
cachedMetadata = locallyScopedConn.getCachedMetaData(((PreparedQuery>) this.query).getOriginalSql());
}
//
// Only apply max_rows to selects
//
locallyScopedConn.setSessionMaxRows(((PreparedQuery>) this.query).getParseInfo().getFirstStmtChar() == 'S' ? this.maxRows : -1);
rs = executeInternal(this.maxRows, sendPacket, createStreamingResultSet(),
(((PreparedQuery>) this.query).getParseInfo().getFirstStmtChar() == 'S'), cachedMetadata, false);
if (cachedMetadata != null) {
locallyScopedConn.initializeResultsMetadataFromCache(((PreparedQuery>) this.query).getOriginalSql(), cachedMetadata, rs);
} else {
if (rs.hasRows() && cacheResultSetMetadata) {
locallyScopedConn.initializeResultsMetadataFromCache(((PreparedQuery>) this.query).getOriginalSql(), null /* will be created */, rs);
}
}
if (this.retrieveGeneratedKeys) {
rs.setFirstCharOfQuery(((PreparedQuery>) this.query).getParseInfo().getFirstStmtChar());
}
if (oldDb != null) {
locallyScopedConn.setDatabase(oldDb);
}
if (rs != null) {
this.lastInsertId = rs.getUpdateID();
this.results = rs;
}
return ((rs != null) && rs.hasRows());
}
}
@Override
protected long[] executeBatchInternal() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
if (this.connection.isReadOnly()) {
throw new SQLException(Messages.getString("PreparedStatement.25") + Messages.getString("PreparedStatement.26"),
MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT);
}
if (this.query.getBatchedArgs() == null || this.query.getBatchedArgs().size() == 0) {
return new long[0];
}
// we timeout the entire batch, not individual statements
int batchTimeout = getTimeoutInMillis();
setTimeoutInMillis(0);
resetCancelledState();
try {
statementBegins();
clearWarnings();
if (!this.batchHasPlainStatements && this.rewriteBatchedStatements.getValue()) {
if (((PreparedQuery>) this.query).getParseInfo().canRewriteAsMultiValueInsertAtSqlLevel()) {
return executeBatchedInserts(batchTimeout);
}
if (!this.batchHasPlainStatements && this.query.getBatchedArgs() != null
&& this.query.getBatchedArgs().size() > 3 /* cost of option setting rt-wise */) {
return executePreparedBatchAsMultiStatement(batchTimeout);
}
}
return executeBatchSerially(batchTimeout);
} finally {
this.query.getStatementExecuting().set(false);
clearBatch();
}
}
}
/**
* Rewrites the already prepared statement into a multi-statement
* query of 'statementsPerBatch' values and executes the entire batch
* using this new statement.
*
* @param batchTimeout
* timeout for the batch execution
* @return update counts in the same fashion as executeBatch()
*
* @throws SQLException
* if a database access error occurs or this method is called on a closed PreparedStatement
*/
protected long[] executePreparedBatchAsMultiStatement(int batchTimeout) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
// This is kind of an abuse, but it gets the job done
if (this.batchedValuesClause == null) {
this.batchedValuesClause = ((PreparedQuery>) this.query).getOriginalSql() + ";";
}
JdbcConnection locallyScopedConn = this.connection;
boolean multiQueriesEnabled = locallyScopedConn.getPropertySet().getBooleanProperty(PropertyKey.allowMultiQueries).getValue();
CancelQueryTask timeoutTask = null;
try {
clearWarnings();
int numBatchedArgs = this.query.getBatchedArgs().size();
if (this.retrieveGeneratedKeys) {
this.batchedGeneratedKeys = new ArrayList<>(numBatchedArgs);
}
int numValuesPerBatch = ((PreparedQuery>) this.query).computeBatchSize(numBatchedArgs);
if (numBatchedArgs < numValuesPerBatch) {
numValuesPerBatch = numBatchedArgs;
}
java.sql.PreparedStatement batchedStatement = null;
int batchedParamIndex = 1;
int numberToExecuteAsMultiValue = 0;
int batchCounter = 0;
int updateCountCounter = 0;
long[] updateCounts = new long[numBatchedArgs * ((PreparedQuery>) this.query).getParseInfo().numberOfQueries];
SQLException sqlEx = null;
try {
if (!multiQueriesEnabled) {
((NativeSession) locallyScopedConn.getSession()).enableMultiQueries();
}
batchedStatement = this.retrieveGeneratedKeys
? ((Wrapper) locallyScopedConn.prepareStatement(generateMultiStatementForBatch(numValuesPerBatch), RETURN_GENERATED_KEYS))
.unwrap(java.sql.PreparedStatement.class)
: ((Wrapper) locallyScopedConn.prepareStatement(generateMultiStatementForBatch(numValuesPerBatch)))
.unwrap(java.sql.PreparedStatement.class);
timeoutTask = startQueryTimer((StatementImpl) batchedStatement, batchTimeout);
numberToExecuteAsMultiValue = numBatchedArgs < numValuesPerBatch ? numBatchedArgs : numBatchedArgs / numValuesPerBatch;
int numberArgsToExecute = numberToExecuteAsMultiValue * numValuesPerBatch;
for (int i = 0; i < numberArgsToExecute; i++) {
if (i != 0 && i % numValuesPerBatch == 0) {
try {
batchedStatement.execute();
} catch (SQLException ex) {
sqlEx = handleExceptionForBatch(batchCounter, numValuesPerBatch, updateCounts, ex);
}
updateCountCounter = processMultiCountsAndKeys((StatementImpl) batchedStatement, updateCountCounter, updateCounts);
batchedStatement.clearParameters();
batchedParamIndex = 1;
}
batchedParamIndex = setOneBatchedParameterSet(batchedStatement, batchedParamIndex, this.query.getBatchedArgs().get(batchCounter++));
}
try {
batchedStatement.execute();
} catch (SQLException ex) {
sqlEx = handleExceptionForBatch(batchCounter - 1, numValuesPerBatch, updateCounts, ex);
}
updateCountCounter = processMultiCountsAndKeys((StatementImpl) batchedStatement, updateCountCounter, updateCounts);
batchedStatement.clearParameters();
numValuesPerBatch = numBatchedArgs - batchCounter;
if (timeoutTask != null) {
// we need to check the cancel state now because we loose if after the following batchedStatement.close()
((JdbcPreparedStatement) batchedStatement).checkCancelTimeout();
}
} finally {
if (batchedStatement != null) {
batchedStatement.close();
batchedStatement = null;
}
}
try {
if (numValuesPerBatch > 0) {
batchedStatement = this.retrieveGeneratedKeys
? locallyScopedConn.prepareStatement(generateMultiStatementForBatch(numValuesPerBatch), RETURN_GENERATED_KEYS)
: locallyScopedConn.prepareStatement(generateMultiStatementForBatch(numValuesPerBatch));
if (timeoutTask != null) {
timeoutTask.setQueryToCancel((Query) batchedStatement);
}
batchedParamIndex = 1;
while (batchCounter < numBatchedArgs) {
batchedParamIndex = setOneBatchedParameterSet(batchedStatement, batchedParamIndex, this.query.getBatchedArgs().get(batchCounter++));
}
try {
batchedStatement.execute();
} catch (SQLException ex) {
sqlEx = handleExceptionForBatch(batchCounter - 1, numValuesPerBatch, updateCounts, ex);
}
updateCountCounter = processMultiCountsAndKeys((StatementImpl) batchedStatement, updateCountCounter, updateCounts);
batchedStatement.clearParameters();
}
if (timeoutTask != null) {
stopQueryTimer(timeoutTask, true, true);
timeoutTask = null;
}
if (sqlEx != null) {
throw SQLError.createBatchUpdateException(sqlEx, updateCounts, this.exceptionInterceptor);
}
return updateCounts;
} finally {
if (batchedStatement != null) {
batchedStatement.close();
}
}
} finally {
stopQueryTimer(timeoutTask, false, false);
resetCancelledState();
if (!multiQueriesEnabled) {
((NativeSession) locallyScopedConn.getSession()).disableMultiQueries();
}
clearBatch();
}
}
}
protected int setOneBatchedParameterSet(java.sql.PreparedStatement batchedStatement, int batchedParamIndex, Object paramSet) throws SQLException {
QueryBindings> paramArg = (QueryBindings>) paramSet;
BindValue[] bindValues = paramArg.getBindValues();
for (int j = 0; j < bindValues.length; j++) {
if (bindValues[j].isNull()) {
batchedStatement.setNull(batchedParamIndex++, MysqlType.NULL.getJdbcType());
} else {
if (bindValues[j].isStream()) {
batchedStatement.setBinaryStream(batchedParamIndex++, bindValues[j].getStreamValue(), bindValues[j].getStreamLength());
} else {
((JdbcPreparedStatement) batchedStatement).setBytesNoEscapeNoQuotes(batchedParamIndex++, bindValues[j].getByteValue());
}
}
}
return batchedParamIndex;
}
private String generateMultiStatementForBatch(int numBatches) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
String origSql = ((PreparedQuery>) this.query).getOriginalSql();
StringBuilder newStatementSql = new StringBuilder((origSql.length() + 1) * numBatches);
newStatementSql.append(origSql);
for (int i = 0; i < numBatches - 1; i++) {
newStatementSql.append(';');
newStatementSql.append(origSql);
}
return newStatementSql.toString();
}
}
/**
* Rewrites the already prepared statement into a multi-value insert
* statement of 'statementsPerBatch' values and executes the entire batch
* using this new statement.
*
* @param batchTimeout
* timeout for the batch execution
* @return update counts in the same fashion as executeBatch()
*
* @throws SQLException
* if a database access error occurs or this method is called on a closed PreparedStatement
*/
protected long[] executeBatchedInserts(int batchTimeout) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
String valuesClause = ((PreparedQuery>) this.query).getParseInfo().getValuesClause();
JdbcConnection locallyScopedConn = this.connection;
if (valuesClause == null) {
return executeBatchSerially(batchTimeout);
}
int numBatchedArgs = this.query.getBatchedArgs().size();
if (this.retrieveGeneratedKeys) {
this.batchedGeneratedKeys = new ArrayList<>(numBatchedArgs);
}
int numValuesPerBatch = ((PreparedQuery>) this.query).computeBatchSize(numBatchedArgs);
if (numBatchedArgs < numValuesPerBatch) {
numValuesPerBatch = numBatchedArgs;
}
JdbcPreparedStatement batchedStatement = null;
int batchedParamIndex = 1;
long updateCountRunningTotal = 0;
int numberToExecuteAsMultiValue = 0;
int batchCounter = 0;
CancelQueryTask timeoutTask = null;
SQLException sqlEx = null;
long[] updateCounts = new long[numBatchedArgs];
try {
try {
batchedStatement = /* FIXME -if we ever care about folks proxying our JdbcConnection */
prepareBatchedInsertSQL(locallyScopedConn, numValuesPerBatch);
timeoutTask = startQueryTimer(batchedStatement, batchTimeout);
numberToExecuteAsMultiValue = numBatchedArgs < numValuesPerBatch ? numBatchedArgs : numBatchedArgs / numValuesPerBatch;
int numberArgsToExecute = numberToExecuteAsMultiValue * numValuesPerBatch;
for (int i = 0; i < numberArgsToExecute; i++) {
if (i != 0 && i % numValuesPerBatch == 0) {
try {
updateCountRunningTotal += batchedStatement.executeLargeUpdate();
} catch (SQLException ex) {
sqlEx = handleExceptionForBatch(batchCounter - 1, numValuesPerBatch, updateCounts, ex);
}
getBatchedGeneratedKeys(batchedStatement);
batchedStatement.clearParameters();
batchedParamIndex = 1;
}
batchedParamIndex = setOneBatchedParameterSet(batchedStatement, batchedParamIndex, this.query.getBatchedArgs().get(batchCounter++));
}
try {
updateCountRunningTotal += batchedStatement.executeLargeUpdate();
} catch (SQLException ex) {
sqlEx = handleExceptionForBatch(batchCounter - 1, numValuesPerBatch, updateCounts, ex);
}
getBatchedGeneratedKeys(batchedStatement);
numValuesPerBatch = numBatchedArgs - batchCounter;
} finally {
if (batchedStatement != null) {
batchedStatement.close();
batchedStatement = null;
}
}
try {
if (numValuesPerBatch > 0) {
batchedStatement = prepareBatchedInsertSQL(locallyScopedConn, numValuesPerBatch);
if (timeoutTask != null) {
timeoutTask.setQueryToCancel(batchedStatement);
}
batchedParamIndex = 1;
while (batchCounter < numBatchedArgs) {
batchedParamIndex = setOneBatchedParameterSet(batchedStatement, batchedParamIndex, this.query.getBatchedArgs().get(batchCounter++));
}
try {
updateCountRunningTotal += batchedStatement.executeLargeUpdate();
} catch (SQLException ex) {
sqlEx = handleExceptionForBatch(batchCounter - 1, numValuesPerBatch, updateCounts, ex);
}
getBatchedGeneratedKeys(batchedStatement);
}
if (sqlEx != null) {
throw SQLError.createBatchUpdateException(sqlEx, updateCounts, this.exceptionInterceptor);
}
if (numBatchedArgs > 1) {
long updCount = updateCountRunningTotal > 0 ? java.sql.Statement.SUCCESS_NO_INFO : 0;
for (int j = 0; j < numBatchedArgs; j++) {
updateCounts[j] = updCount;
}
} else {
updateCounts[0] = updateCountRunningTotal;
}
return updateCounts;
} finally {
if (batchedStatement != null) {
batchedStatement.close();
}
}
} finally {
stopQueryTimer(timeoutTask, false, false);
resetCancelledState();
}
}
}
/**
* Executes the current batch of statements by executing them one-by-one.
*
* @param batchTimeout
* timeout for the batch execution
* @return a list of update counts
* @throws SQLException
* if an error occurs
*/
protected long[] executeBatchSerially(int batchTimeout) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
if (this.connection == null) {
checkClosed();
}
long[] updateCounts = null;
if (this.query.getBatchedArgs() != null) {
int nbrCommands = this.query.getBatchedArgs().size();
updateCounts = new long[nbrCommands];
for (int i = 0; i < nbrCommands; i++) {
updateCounts[i] = -3;
}
SQLException sqlEx = null;
CancelQueryTask timeoutTask = null;
try {
timeoutTask = startQueryTimer(this, batchTimeout);
if (this.retrieveGeneratedKeys) {
this.batchedGeneratedKeys = new ArrayList<>(nbrCommands);
}
int batchCommandIndex = ((PreparedQuery>) this.query).getBatchCommandIndex();
for (batchCommandIndex = 0; batchCommandIndex < nbrCommands; batchCommandIndex++) {
((PreparedQuery>) this.query).setBatchCommandIndex(batchCommandIndex);
Object arg = this.query.getBatchedArgs().get(batchCommandIndex);
try {
if (arg instanceof String) {
updateCounts[batchCommandIndex] = executeUpdateInternal((String) arg, true, this.retrieveGeneratedKeys);
// limit one generated key per OnDuplicateKey statement
getBatchedGeneratedKeys(this.results.getFirstCharOfQuery() == 'I' && containsOnDuplicateKeyInString((String) arg) ? 1 : 0);
} else {
QueryBindings> queryBindings = (QueryBindings>) arg;
updateCounts[batchCommandIndex] = executeUpdateInternal(queryBindings, true);
// limit one generated key per OnDuplicateKey statement
getBatchedGeneratedKeys(containsOnDuplicateKeyUpdateInSQL() ? 1 : 0);
}
} catch (SQLException ex) {
updateCounts[batchCommandIndex] = EXECUTE_FAILED;
if (this.continueBatchOnError && !(ex instanceof MySQLTimeoutException) && !(ex instanceof MySQLStatementCancelledException)
&& !hasDeadlockOrTimeoutRolledBackTx(ex)) {
sqlEx = ex;
} else {
long[] newUpdateCounts = new long[batchCommandIndex];
System.arraycopy(updateCounts, 0, newUpdateCounts, 0, batchCommandIndex);
throw SQLError.createBatchUpdateException(ex, newUpdateCounts, this.exceptionInterceptor);
}
}
}
if (sqlEx != null) {
throw SQLError.createBatchUpdateException(sqlEx, updateCounts, this.exceptionInterceptor);
}
} catch (NullPointerException npe) {
try {
checkClosed();
} catch (StatementIsClosedException connectionClosedEx) {
int batchCommandIndex = ((PreparedQuery>) this.query).getBatchCommandIndex();
updateCounts[batchCommandIndex] = EXECUTE_FAILED;
long[] newUpdateCounts = new long[batchCommandIndex];
System.arraycopy(updateCounts, 0, newUpdateCounts, 0, batchCommandIndex);
throw SQLError.createBatchUpdateException(SQLExceptionsMapping.translateException(connectionClosedEx), newUpdateCounts,
this.exceptionInterceptor);
}
throw npe; // we don't know why this happened, punt
} finally {
((PreparedQuery>) this.query).setBatchCommandIndex(-1);
stopQueryTimer(timeoutTask, false, false);
resetCancelledState();
}
}
return (updateCounts != null) ? updateCounts : new long[0];
}
}
/**
* Actually execute the prepared statement. This is here so server-side
* PreparedStatements can re-use most of the code from this class.
*
* @param
* extends {@link Message}
*
* @param maxRowsToRetrieve
* the max number of rows to return
* @param sendPacket
* the packet to send
* @param createStreamingResultSet
* should a 'streaming' result set be created?
* @param queryIsSelectOnly
* is this query doing a SELECT?
* @param metadata
* use this metadata instead of the one provided on wire
* @param isBatch
* is this a batch query?
*
* @return the results as a ResultSet
*
* @throws SQLException
* if an error occurs.
*/
protected ResultSetInternalMethods executeInternal(int maxRowsToRetrieve, M sendPacket, boolean createStreamingResultSet,
boolean queryIsSelectOnly, ColumnDefinition metadata, boolean isBatch) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
try {
JdbcConnection locallyScopedConnection = this.connection;
((PreparedQuery>) this.query).getQueryBindings()
.setNumberOfExecutions(((PreparedQuery>) this.query).getQueryBindings().getNumberOfExecutions() + 1);
ResultSetInternalMethods rs;
CancelQueryTask timeoutTask = null;
try {
timeoutTask = startQueryTimer(this, getTimeoutInMillis());
if (!isBatch) {
statementBegins();
}
rs = ((NativeSession) locallyScopedConnection.getSession()).execSQL(this, null, maxRowsToRetrieve, (NativePacketPayload) sendPacket,
createStreamingResultSet, getResultSetFactory(), metadata, isBatch);
if (timeoutTask != null) {
stopQueryTimer(timeoutTask, true, true);
timeoutTask = null;
}
} finally {
if (!isBatch) {
this.query.getStatementExecuting().set(false);
}
stopQueryTimer(timeoutTask, false, false);
}
return rs;
} catch (NullPointerException npe) {
checkClosed(); // we can't synchronize ourselves against async connection-close due to deadlock issues, so this is the next best thing for
// this particular corner case.
throw npe;
}
}
}
@Override
public java.sql.ResultSet executeQuery() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
JdbcConnection locallyScopedConn = this.connection;
checkForDml(((PreparedQuery>) this.query).getOriginalSql(), ((PreparedQuery>) this.query).getParseInfo().getFirstStmtChar());
this.batchedGeneratedKeys = null;
resetCancelledState();
implicitlyCloseAllOpenResults();
clearWarnings();
if (this.doPingInstead) {
doPingInstead();
return this.results;
}
setupStreamingTimeout(locallyScopedConn);
Message sendPacket = ((PreparedQuery>) this.query).fillSendPacket();
String oldDb = null;
if (!locallyScopedConn.getDatabase().equals(this.getCurrentDatabase())) {
oldDb = locallyScopedConn.getDatabase();
locallyScopedConn.setDatabase(this.getCurrentDatabase());
}
//
// Check if we have cached metadata for this query...
//
CachedResultSetMetaData cachedMetadata = null;
boolean cacheResultSetMetadata = locallyScopedConn.getPropertySet().getBooleanProperty(PropertyKey.cacheResultSetMetadata).getValue();
String origSql = ((PreparedQuery>) this.query).getOriginalSql();
if (cacheResultSetMetadata) {
cachedMetadata = locallyScopedConn.getCachedMetaData(origSql);
}
locallyScopedConn.setSessionMaxRows(this.maxRows);
this.results = executeInternal(this.maxRows, sendPacket, createStreamingResultSet(), true, cachedMetadata, false);
if (oldDb != null) {
locallyScopedConn.setDatabase(oldDb);
}
if (cachedMetadata != null) {
locallyScopedConn.initializeResultsMetadataFromCache(origSql, cachedMetadata, this.results);
} else {
if (cacheResultSetMetadata) {
locallyScopedConn.initializeResultsMetadataFromCache(origSql, null /* will be created */, this.results);
}
}
this.lastInsertId = this.results.getUpdateID();
return this.results;
}
}
@Override
public int executeUpdate() throws SQLException {
return Util.truncateAndConvertToInt(executeLargeUpdate());
}
/*
* We need this variant, because ServerPreparedStatement calls this for
* batched updates, which will end up clobbering the warnings and generated
* keys we need to gather for the batch.
*/
protected long executeUpdateInternal(boolean clearBatchedGeneratedKeysAndWarnings, boolean isBatch) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
if (clearBatchedGeneratedKeysAndWarnings) {
clearWarnings();
this.batchedGeneratedKeys = null;
}
return executeUpdateInternal(((PreparedQuery>) this.query).getQueryBindings(), isBatch);
}
}
/**
* Added to allow batch-updates
*
* @param bindings
* bindings object
* @param isReallyBatch
* is it a batched statement?
*
* @return the update count
*
* @throws SQLException
* if a database error occurs
*/
protected long executeUpdateInternal(QueryBindings> bindings, boolean isReallyBatch) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
JdbcConnection locallyScopedConn = this.connection;
if (locallyScopedConn.isReadOnly(false)) {
throw SQLError.createSQLException(Messages.getString("PreparedStatement.34") + Messages.getString("PreparedStatement.35"),
MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor);
}
if ((((PreparedQuery>) this.query).getParseInfo().getFirstStmtChar() == 'S') && isSelectQuery()) {
throw SQLError.createSQLException(Messages.getString("PreparedStatement.37"), "01S03", this.exceptionInterceptor);
}
resetCancelledState();
implicitlyCloseAllOpenResults();
ResultSetInternalMethods rs = null;
Message sendPacket = ((PreparedQuery>) this.query).fillSendPacket(bindings);
String oldDb = null;
if (!locallyScopedConn.getDatabase().equals(this.getCurrentDatabase())) {
oldDb = locallyScopedConn.getDatabase();
locallyScopedConn.setDatabase(this.getCurrentDatabase());
}
//
// Only apply max_rows to selects
//
locallyScopedConn.setSessionMaxRows(-1);
rs = executeInternal(-1, sendPacket, false, false, null, isReallyBatch);
if (this.retrieveGeneratedKeys) {
rs.setFirstCharOfQuery(((PreparedQuery>) this.query).getParseInfo().getFirstStmtChar());
}
if (oldDb != null) {
locallyScopedConn.setDatabase(oldDb);
}
this.results = rs;
this.updateCount = rs.getUpdateCount();
if (containsOnDuplicateKeyUpdateInSQL() && this.compensateForOnDuplicateKeyUpdate) {
if (this.updateCount == 2 || this.updateCount == 0) {
this.updateCount = 1;
}
}
this.lastInsertId = rs.getUpdateID();
return this.updateCount;
}
}
protected boolean containsOnDuplicateKeyUpdateInSQL() {
return ((PreparedQuery>) this.query).getParseInfo().containsOnDuplicateKeyUpdateInSQL();
}
/**
* Returns a prepared statement for the number of batched parameters, used when re-writing batch INSERTs.
*
* @param localConn
* the connection creating this statement
* @param numBatches
* number of entries in a batch
* @return new ClientPreparedStatement
* @throws SQLException
* if a database access error occurs or this method is called on a closed PreparedStatement
*/
protected ClientPreparedStatement prepareBatchedInsertSQL(JdbcConnection localConn, int numBatches) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ClientPreparedStatement pstmt = new ClientPreparedStatement(localConn, "Rewritten batch of: " + ((PreparedQuery>) this.query).getOriginalSql(),
this.getCurrentDatabase(), ((PreparedQuery>) this.query).getParseInfo().getParseInfoForBatch(numBatches));
pstmt.setRetrieveGeneratedKeys(this.retrieveGeneratedKeys);
pstmt.rewrittenBatchSize = numBatches;
return pstmt;
}
}
protected void setRetrieveGeneratedKeys(boolean flag) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
this.retrieveGeneratedKeys = flag;
}
}
@Override
public byte[] getBytesRepresentation(int parameterIndex) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
return ((PreparedQuery>) this.query).getQueryBindings().getBytesRepresentation(getCoreParameterIndex(parameterIndex));
}
}
@Override
public byte[] getOrigBytes(int parameterIndex) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
return ((PreparedQuery>) this.query).getQueryBindings().getOrigBytes(getCoreParameterIndex(parameterIndex));
}
}
@Override
public java.sql.ResultSetMetaData getMetaData() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
//
// We could just tack on a LIMIT 0 here no matter what the statement, and check if a result set was returned or not, but I'm not comfortable with
// that, myself, so we take the "safer" road, and only allow metadata for _actual_ SELECTS (but not SHOWs).
//
// CALL's are trapped further up and you end up with a CallableStatement anyway.
//
if (!isSelectQuery()) {
return null;
}
JdbcPreparedStatement mdStmt = null;
java.sql.ResultSet mdRs = null;
if (this.pstmtResultMetaData == null) {
try {
mdStmt = new ClientPreparedStatement(this.connection, ((PreparedQuery>) this.query).getOriginalSql(), this.getCurrentDatabase(),
((PreparedQuery>) this.query).getParseInfo());
mdStmt.setMaxRows(1);
int paramCount = ((PreparedQuery>) this.query).getParameterCount();
for (int i = 1; i <= paramCount; i++) {
mdStmt.setString(i, null);
}
boolean hadResults = mdStmt.execute();
if (hadResults) {
mdRs = mdStmt.getResultSet();
this.pstmtResultMetaData = mdRs.getMetaData();
} else {
this.pstmtResultMetaData = new ResultSetMetaData(this.session, new Field[0],
this.session.getPropertySet().getBooleanProperty(PropertyKey.useOldAliasMetadataBehavior).getValue(),
this.session.getPropertySet().getBooleanProperty(PropertyKey.yearIsDateType).getValue(), this.exceptionInterceptor);
}
} finally {
SQLException sqlExRethrow = null;
if (mdRs != null) {
try {
mdRs.close();
} catch (SQLException sqlEx) {
sqlExRethrow = sqlEx;
}
mdRs = null;
}
if (mdStmt != null) {
try {
mdStmt.close();
} catch (SQLException sqlEx) {
sqlExRethrow = sqlEx;
}
mdStmt = null;
}
if (sqlExRethrow != null) {
throw sqlExRethrow;
}
}
}
return this.pstmtResultMetaData;
}
}
protected boolean isSelectQuery() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
return StringUtils.startsWithIgnoreCaseAndWs(
StringUtils.stripComments(((PreparedQuery>) this.query).getOriginalSql(), "'\"", "'\"", true, false, true, true), "SELECT");
}
}
@Override
public ParameterMetaData getParameterMetaData() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
if (this.parameterMetaData == null) {
if (this.session.getPropertySet().getBooleanProperty(PropertyKey.generateSimpleParameterMetadata).getValue()) {
this.parameterMetaData = new MysqlParameterMetadata(((PreparedQuery>) this.query).getParameterCount());
} else {
this.parameterMetaData = new MysqlParameterMetadata(this.session, null, ((PreparedQuery>) this.query).getParameterCount(),
this.exceptionInterceptor);
}
}
return this.parameterMetaData;
}
}
@Override
public ParseInfo getParseInfo() {
return ((PreparedQuery>) this.query).getParseInfo();
}
@SuppressWarnings("unchecked")
private void initializeFromParseInfo() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
int parameterCount = ((PreparedQuery) this.query).getParseInfo().getStaticSql().length - 1;
((PreparedQuery>) this.query).setParameterCount(parameterCount);
((PreparedQuery) this.query).setQueryBindings(new ClientPreparedQueryBindings(parameterCount, this.session));
((ClientPreparedQuery) this.query).getQueryBindings().setLoadDataQuery(((PreparedQuery>) this.query).getParseInfo().isFoundLoadData());
clearParameters();
}
}
@Override
public boolean isNull(int paramIndex) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
return ((PreparedQuery>) this.query).getQueryBindings().getBindValues()[getCoreParameterIndex(paramIndex)].isNull();
}
}
@Override
public void realClose(boolean calledExplicitly, boolean closeOpenResults) throws SQLException {
JdbcConnection locallyScopedConn = this.connection;
if (locallyScopedConn == null) {
return; // already closed
}
synchronized (locallyScopedConn.getConnectionMutex()) {
// additional check in case Statement was closed
// while current thread was waiting for lock
if (this.isClosed) {
return;
}
if (this.useUsageAdvisor) {
if (((PreparedQuery>) this.query).getQueryBindings().getNumberOfExecutions() <= 1) {
this.session.getProfilerEventHandler().processEvent(ProfilerEvent.TYPE_USAGE, this.session, this, null, 0, new Throwable(),
Messages.getString("PreparedStatement.43"));
}
}
super.realClose(calledExplicitly, closeOpenResults);
((PreparedQuery>) this.query).setOriginalSql(null);
((PreparedQuery>) this.query).setQueryBindings(null);
}
}
@Override
public String getPreparedSql() {
synchronized (checkClosed().getConnectionMutex()) {
if (this.rewrittenBatchSize == 0) {
return ((PreparedQuery>) this.query).getOriginalSql();
}
try {
return ((PreparedQuery>) this.query).getParseInfo().getSqlForBatch();
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}
@Override
public int getUpdateCount() throws SQLException {
int count = super.getUpdateCount();
if (containsOnDuplicateKeyUpdateInSQL() && this.compensateForOnDuplicateKeyUpdate) {
if (count == 2 || count == 0) {
count = 1;
}
}
return count;
}
@Override
public long executeLargeUpdate() throws SQLException {
return executeUpdateInternal(true, false);
}
public ParameterBindings getParameterBindings() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
return new ParameterBindingsImpl((PreparedQuery>) this.query, this.session, this.resultSetFactory);
}
}
/**
* For calling stored functions, this will be -1 as Connector/J does not count
* the first '?' parameter marker, but JDBC counts it * as 1, otherwise it will return 0
*
* @return offset
*/
protected int getParameterIndexOffset() {
return 0;
}
protected void checkBounds(int paramIndex, int parameterIndexOffset) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
if ((paramIndex < 1)) {
throw SQLError.createSQLException(Messages.getString("PreparedStatement.49") + paramIndex + Messages.getString("PreparedStatement.50"),
MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor);
} else if (paramIndex > ((PreparedQuery>) this.query).getParameterCount()) {
throw SQLError.createSQLException(
Messages.getString("PreparedStatement.51") + paramIndex + Messages.getString("PreparedStatement.52")
+ ((PreparedQuery>) this.query).getParameterCount() + Messages.getString("PreparedStatement.53"),
MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor);
} else if (parameterIndexOffset == -1 && paramIndex == 1) {
throw SQLError.createSQLException(Messages.getString("PreparedStatement.63"), MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT,
this.exceptionInterceptor);
}
}
}
protected final int getCoreParameterIndex(int paramIndex) throws SQLException {
int parameterIndexOffset = getParameterIndexOffset();
checkBounds(paramIndex, parameterIndexOffset);
return paramIndex - 1 + parameterIndexOffset;
}
@Override
public void setArray(int i, Array x) throws SQLException {
throw SQLError.createSQLFeatureNotSupportedException();
}
@Override
public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setAsciiStream(getCoreParameterIndex(parameterIndex), x);
}
}
@Override
public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setAsciiStream(getCoreParameterIndex(parameterIndex), x, length);
}
}
@Override
public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setAsciiStream(getCoreParameterIndex(parameterIndex), x, length);
}
}
@Override
public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setBigDecimal(getCoreParameterIndex(parameterIndex), x);
}
}
@Override
public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setBinaryStream(getCoreParameterIndex(parameterIndex), x);
}
}
@Override
public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setBinaryStream(getCoreParameterIndex(parameterIndex), x, length);
}
}
@Override
public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setBinaryStream(getCoreParameterIndex(parameterIndex), x, length);
}
}
@Override
public void setBlob(int i, java.sql.Blob x) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setBlob(getCoreParameterIndex(i), x);
}
}
@Override
public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setBlob(getCoreParameterIndex(parameterIndex), inputStream);
}
}
@Override
public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setBlob(getCoreParameterIndex(parameterIndex), inputStream, length);
}
}
@Override
public void setBoolean(int parameterIndex, boolean x) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setBoolean(getCoreParameterIndex(parameterIndex), x);
}
}
@Override
public void setByte(int parameterIndex, byte x) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setByte(getCoreParameterIndex(parameterIndex), x);
}
}
@Override
public void setBytes(int parameterIndex, byte[] x) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setBytes(getCoreParameterIndex(parameterIndex), x);
}
}
@Override
public void setBytes(int parameterIndex, byte[] x, boolean checkForIntroducer, boolean escapeForMBChars) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setBytes(getCoreParameterIndex(parameterIndex), x, checkForIntroducer, escapeForMBChars);
}
}
@Override
public void setBytesNoEscape(int parameterIndex, byte[] parameterAsBytes) throws SQLException {
((PreparedQuery>) this.query).getQueryBindings().setBytesNoEscape(getCoreParameterIndex(parameterIndex), parameterAsBytes);
}
@Override
public void setBytesNoEscapeNoQuotes(int parameterIndex, byte[] parameterAsBytes) throws SQLException {
((PreparedQuery>) this.query).getQueryBindings().setBytesNoEscapeNoQuotes(getCoreParameterIndex(parameterIndex), parameterAsBytes);
}
@Override
public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setCharacterStream(getCoreParameterIndex(parameterIndex), reader);
}
}
@Override
public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setCharacterStream(getCoreParameterIndex(parameterIndex), reader, length);
}
}
@Override
public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setCharacterStream(getCoreParameterIndex(parameterIndex), reader, length);
}
}
@Override
public void setClob(int parameterIndex, Reader reader) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setCharacterStream(getCoreParameterIndex(parameterIndex), reader);
}
}
@Override
public void setClob(int parameterIndex, Reader reader, long length) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setCharacterStream(getCoreParameterIndex(parameterIndex), reader, length);
}
}
@Override
public void setClob(int i, Clob x) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setClob(getCoreParameterIndex(i), x);
}
}
@Override
public void setDate(int parameterIndex, Date x) throws java.sql.SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setDate(getCoreParameterIndex(parameterIndex), x);
}
}
@Override
public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setDate(getCoreParameterIndex(parameterIndex), x, cal);
}
}
@Override
public void setDouble(int parameterIndex, double x) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setDouble(getCoreParameterIndex(parameterIndex), x);
}
}
@Override
public void setFloat(int parameterIndex, float x) throws SQLException {
((PreparedQuery>) this.query).getQueryBindings().setFloat(getCoreParameterIndex(parameterIndex), x);
}
@Override
public void setInt(int parameterIndex, int x) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setInt(getCoreParameterIndex(parameterIndex), x);
}
}
@Override
public void setLong(int parameterIndex, long x) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setLong(getCoreParameterIndex(parameterIndex), x);
}
}
@Override
public void setBigInteger(int parameterIndex, BigInteger x) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setBigInteger(getCoreParameterIndex(parameterIndex), x);
}
}
@Override
public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setNCharacterStream(getCoreParameterIndex(parameterIndex), value);
}
}
@Override
public void setNCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setNCharacterStream(getCoreParameterIndex(parameterIndex), reader, length);
}
}
@Override
public void setNClob(int parameterIndex, Reader reader) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setNClob(getCoreParameterIndex(parameterIndex), reader);
}
}
@Override
public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setNClob(getCoreParameterIndex(parameterIndex), reader, length);
}
}
@Override
public void setNClob(int parameterIndex, NClob value) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setNClob(getCoreParameterIndex(parameterIndex), value);
}
}
/**
* Set a parameter to a Java String value. The driver converts this to a SQL
* VARCHAR or LONGVARCHAR value with introducer _utf8 (depending on the
* arguments size relative to the driver's limits on VARCHARs) when it sends
* it to the database. If charset is set as utf8, this method just call setString.
*
* @param parameterIndex
* the first parameter is 1...
* @param x
* the parameter value
*
* @exception SQLException
* if a database access error occurs
*/
@Override
public void setNString(int parameterIndex, String x) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setNString(getCoreParameterIndex(parameterIndex), x);
}
}
@Override
public void setNull(int parameterIndex, int sqlType) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setNull(getCoreParameterIndex(parameterIndex)); // MySQL ignores sqlType
}
}
@Override
public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setNull(getCoreParameterIndex(parameterIndex));
}
}
@Override
public void setNull(int parameterIndex, MysqlType mysqlType) throws SQLException {
setNull(parameterIndex, mysqlType.getJdbcType());
}
@Override
public void setObject(int parameterIndex, Object parameterObj) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setObject(getCoreParameterIndex(parameterIndex), parameterObj);
}
}
@Override
public void setObject(int parameterIndex, Object parameterObj, int targetSqlType) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
try {
((PreparedQuery>) this.query).getQueryBindings().setObject(getCoreParameterIndex(parameterIndex), parameterObj,
MysqlType.getByJdbcType(targetSqlType));
} catch (FeatureNotAvailableException nae) {
throw SQLError.createSQLFeatureNotSupportedException(Messages.getString("Statement.UnsupportedSQLType") + JDBCType.valueOf(targetSqlType),
MysqlErrorNumbers.SQL_STATE_DRIVER_NOT_CAPABLE, this.exceptionInterceptor);
}
}
}
@Override
public void setObject(int parameterIndex, Object parameterObj, SQLType targetSqlType) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
if (targetSqlType instanceof MysqlType) {
((PreparedQuery>) this.query).getQueryBindings().setObject(getCoreParameterIndex(parameterIndex), parameterObj, (MysqlType) targetSqlType);
} else {
setObject(parameterIndex, parameterObj, targetSqlType.getVendorTypeNumber());
}
}
}
@Override
public void setObject(int parameterIndex, Object parameterObj, int targetSqlType, int scale) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
try {
((PreparedQuery>) this.query).getQueryBindings().setObject(getCoreParameterIndex(parameterIndex), parameterObj,
MysqlType.getByJdbcType(targetSqlType), scale);
} catch (FeatureNotAvailableException nae) {
throw SQLError.createSQLFeatureNotSupportedException(Messages.getString("Statement.UnsupportedSQLType") + JDBCType.valueOf(targetSqlType),
MysqlErrorNumbers.SQL_STATE_DRIVER_NOT_CAPABLE, this.exceptionInterceptor);
}
}
}
@Override
public void setObject(int parameterIndex, Object x, SQLType targetSqlType, int scaleOrLength) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
if (targetSqlType instanceof MysqlType) {
((PreparedQuery>) this.query).getQueryBindings().setObject(getCoreParameterIndex(parameterIndex), x, (MysqlType) targetSqlType,
scaleOrLength);
} else {
setObject(parameterIndex, x, targetSqlType.getVendorTypeNumber(), scaleOrLength);
}
}
}
@Override
public void setRef(int i, Ref x) throws SQLException {
throw SQLError.createSQLFeatureNotSupportedException();
}
@Override
public void setRowId(int parameterIndex, RowId x) throws SQLException {
throw SQLError.createSQLFeatureNotSupportedException();
}
@Override
public void setShort(int parameterIndex, short x) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setShort(getCoreParameterIndex(parameterIndex), x);
}
}
@Override
public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException {
if (xmlObject == null) {
setNull(parameterIndex, MysqlType.VARCHAR);
} else {
// FIXME: Won't work for Non-MYSQL SQLXMLs
setCharacterStream(parameterIndex, ((MysqlSQLXML) xmlObject).serializeAsCharacterStream());
}
}
@Override
public void setString(int parameterIndex, String x) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setString(getCoreParameterIndex(parameterIndex), x);
}
}
@Override
public void setTime(int parameterIndex, Time x) throws java.sql.SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setTime(getCoreParameterIndex(parameterIndex), x);
}
}
@Override
public void setTime(int parameterIndex, java.sql.Time x, Calendar cal) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setTime(getCoreParameterIndex(parameterIndex), x, cal);
}
}
@Override
public void setTimestamp(int parameterIndex, Timestamp x) throws java.sql.SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setTimestamp(getCoreParameterIndex(parameterIndex), x);
}
}
@Override
public void setTimestamp(int parameterIndex, java.sql.Timestamp x, Calendar cal) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setTimestamp(getCoreParameterIndex(parameterIndex), x, cal);
}
}
public void setTimestamp(int parameterIndex, Timestamp x, Calendar targetCalendar, int fractionalLength) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
((PreparedQuery>) this.query).getQueryBindings().setTimestamp(getCoreParameterIndex(parameterIndex), x, targetCalendar, fractionalLength);
}
}
@Deprecated
@Override
public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException {
setBinaryStream(parameterIndex, x, length);
((PreparedQuery>) this.query).getQueryBindings().getBindValues()[getCoreParameterIndex(parameterIndex)].setMysqlType(MysqlType.TEXT); // TODO was Types.CLOB
}
@Override
public void setURL(int parameterIndex, URL arg) throws SQLException {
if (arg == null) {
setNull(parameterIndex, MysqlType.VARCHAR);
} else {
setString(parameterIndex, arg.toString());
((PreparedQuery>) this.query).getQueryBindings().getBindValues()[getCoreParameterIndex(parameterIndex)].setMysqlType(MysqlType.VARCHAR); // TODO was Types.DATALINK
}
}
}