/* * Copyright (c) 2002, 2024, 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 designed to work with certain software 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 either included with the program or referenced in the documentation. * * 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.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 java.util.concurrent.locks.Lock; import com.mysql.cj.BindValue; import com.mysql.cj.CancelQueryTask; import com.mysql.cj.ClientPreparedQuery; import com.mysql.cj.Messages; import com.mysql.cj.MysqlType; import com.mysql.cj.NativeQueryBindValue; import com.mysql.cj.NativeQueryBindings; import com.mysql.cj.NativeSession; import com.mysql.cj.PreparedQuery; import com.mysql.cj.Query; import com.mysql.cj.QueryBindings; import com.mysql.cj.QueryInfo; import com.mysql.cj.QueryReturnType; 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.telemetry.TelemetryAttribute; import com.mysql.cj.telemetry.TelemetryScope; import com.mysql.cj.telemetry.TelemetrySpan; import com.mysql.cj.telemetry.TelemetrySpanName; 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 cachedQueryInfo * already created {@link QueryInfo} or null. * @return ClientPreparedStatement instance * @throws SQLException * if a database access error occurs */ protected static ClientPreparedStatement getInstance(JdbcConnection conn, String sql, String db, QueryInfo cachedQueryInfo) throws SQLException { return new ClientPreparedStatement(conn, sql, db, cachedQueryInfo); } @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 cachedQueryInfo * already created {@link QueryInfo} or null. * * @throws SQLException * if a database access error occurs */ public ClientPreparedStatement(JdbcConnection conn, String sql, String db, QueryInfo cachedQueryInfo) throws SQLException { this(conn, db); try { ((PreparedQuery) this.query).checkNullOrEmptyQuery(sql); ((PreparedQuery) this.query).setOriginalSql(sql); ((PreparedQuery) this.query).setQueryInfo(cachedQueryInfo != null ? cachedQueryInfo : new QueryInfo(sql, this.session, this.charEncoding)); } catch (CJException e) { throw SQLExceptionsMapping.translateException(e, this.exceptionInterceptor); } this.doPingInstead = sql.startsWith(PING_MARKER); initializeFromQueryInfo(); } @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(": "); buf.append(((PreparedQuery) this.query).asSql()); return buf.toString(); } @Override public void addBatch() throws SQLException { Lock connectionLock = checkClosed().getConnectionLock(); connectionLock.lock(); try { QueryBindings queryBindings = ((PreparedQuery) this.query).getQueryBindings(); queryBindings.checkAllParametersSet(); this.query.addBatch(queryBindings.clone()); } finally { connectionLock.unlock(); } } @Override public void addBatch(String sql) throws SQLException { Lock connectionLock = checkClosed().getConnectionLock(); connectionLock.lock(); try { this.batchHasPlainStatements = true; super.addBatch(sql); } finally { connectionLock.unlock(); } } @Override public void clearBatch() throws SQLException { Lock connectionLock = checkClosed().getConnectionLock(); connectionLock.lock(); try { this.batchHasPlainStatements = false; super.clearBatch(); } finally { connectionLock.unlock(); } } @Override public void clearParameters() throws SQLException { Lock connectionLock = checkClosed().getConnectionLock(); connectionLock.lock(); try { for (BindValue bv : ((PreparedQuery) this.query).getQueryBindings().getBindValues()) { bv.reset(); } } finally { connectionLock.unlock(); } } /** * Check to see if the statement is safe for read-only replicas 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 { Lock connectionLock = checkClosed().getConnectionLock(); connectionLock.lock(); try { return QueryInfo.isReadOnlySafeQuery(((PreparedQuery) this.query).getOriginalSql(), this.session.getServerSession().isNoBackslashEscapesSet()) || !this.connection.isReadOnly(); } finally { connectionLock.unlock(); } } @Override public boolean execute() throws SQLException { Lock connectionLock = checkClosed().getConnectionLock(); connectionLock.lock(); try { TelemetrySpan span = getSession().getTelemetryHandler().startSpan(TelemetrySpanName.STMT_EXECUTE_PREPARED); try (TelemetryScope scope = span.makeCurrent()) { String dbOperation = getQueryInfo().getStatementKeyword(); span.setAttribute(TelemetryAttribute.DB_NAME, getCurrentDatabase()); span.setAttribute(TelemetryAttribute.DB_OPERATION, dbOperation); span.setAttribute(TelemetryAttribute.DB_STATEMENT, dbOperation + TelemetryAttribute.STATEMENT_SUFFIX); span.setAttribute(TelemetryAttribute.DB_SYSTEM, TelemetryAttribute.DB_SYSTEM_DEFAULT); span.setAttribute(TelemetryAttribute.DB_USER, this.connection.getUser()); span.setAttribute(TelemetryAttribute.THREAD_ID, Thread.currentThread().getId()); span.setAttribute(TelemetryAttribute.THREAD_NAME, Thread.currentThread().getName()); JdbcConnection locallyScopedConn = this.connection; if (!this.doPingInstead && !checkReadOnlySafeStatement()) { throw SQLError.createSQLException(Messages.getString("PreparedStatement.20") + Messages.getString("PreparedStatement.21"), MysqlErrorNumbers.SQLSTATE_CONNJ_ILLEGAL_ARGUMENT, this.exceptionInterceptor); } ResultSetInternalMethods rs = null; this.lastQueryIsOnDupKeyUpdate = false; if (this.retrieveGeneratedKeys) { this.lastQueryIsOnDupKeyUpdate = containsOnDuplicateKeyUpdate(); } this.batchedGeneratedKeys = null; resetCancelledState(); implicitlyCloseAllOpenResults(); clearWarnings(); if (this.doPingInstead) { doPingInstead(); return true; } setupStreamingTimeout(locallyScopedConn); Message sendPacket = ((PreparedQuery) this.query).fillSendPacket(((PreparedQuery) this.query).getQueryBindings()); String oldDb = null; if (!locallyScopedConn.getDatabase().equals(getCurrentDatabase())) { oldDb = locallyScopedConn.getDatabase(); locallyScopedConn.setDatabase(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(getQueryInfo().getFirstStmtChar() == 'S' ? this.maxRows : -1); rs = executeInternal(this.maxRows, sendPacket, createStreamingResultSet(), getQueryInfo().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(getQueryInfo().getFirstStmtChar()); } if (oldDb != null) { locallyScopedConn.setDatabase(oldDb); } if (rs != null) { this.lastInsertId = rs.getUpdateID(); this.results = rs; } return rs != null && rs.hasRows(); } catch (Throwable t) { span.setError(t); throw t; } finally { span.end(); } } finally { connectionLock.unlock(); } } @Override protected long[] executeBatchInternal() throws SQLException { Lock connectionLock = checkClosed().getConnectionLock(); connectionLock.lock(); try { TelemetrySpan span = getSession().getTelemetryHandler().startSpan(TelemetrySpanName.STMT_EXECUTE_BATCH_PREPARED); try (TelemetryScope scope = span.makeCurrent()) { span.setAttribute(TelemetryAttribute.DB_NAME, getCurrentDatabase()); span.setAttribute(TelemetryAttribute.DB_OPERATION, TelemetryAttribute.OPERATION_BATCH); span.setAttribute(TelemetryAttribute.DB_STATEMENT, TelemetryAttribute.OPERATION_BATCH); span.setAttribute(TelemetryAttribute.DB_SYSTEM, TelemetryAttribute.DB_SYSTEM_DEFAULT); span.setAttribute(TelemetryAttribute.DB_USER, this.connection.getUser()); span.setAttribute(TelemetryAttribute.THREAD_ID, Thread.currentThread().getId()); span.setAttribute(TelemetryAttribute.THREAD_NAME, Thread.currentThread().getName()); if (this.connection.isReadOnly()) { throw new SQLException(Messages.getString("PreparedStatement.25") + Messages.getString("PreparedStatement.26"), MysqlErrorNumbers.SQLSTATE_CONNJ_ILLEGAL_ARGUMENT); } if (this.query.getBatchedArgs() == null || this.query.getBatchedArgs().size() == 0) { return new long[0]; } // we timeout the entire batch, not individual statements long batchTimeout = getTimeoutInMillis(); setTimeoutInMillis(0); resetCancelledState(); try { statementBegins(); clearWarnings(); if (!this.batchHasPlainStatements && this.rewriteBatchedStatements.getValue()) { if (getQueryInfo().isRewritableWithMultiValuesClause()) { return executeBatchWithMultiValuesClause(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(); } } catch (Throwable t) { span.setError(t); throw t; } finally { span.end(); } } finally { connectionLock.unlock(); } } /** * Rewrites the already prepared statement into a multi-statement query 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(long batchTimeout) throws SQLException { Lock connectionLock = checkClosed().getConnectionLock(); connectionLock.lock(); try { // 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 * getQueryInfo().getNumberOfQueries()]; 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(); } } finally { connectionLock.unlock(); } } protected int setOneBatchedParameterSet(java.sql.PreparedStatement batchedStatement, int batchedParamIndex, Object paramSet) throws SQLException { BindValue[] bindValues = ((QueryBindings) paramSet).getBindValues(); QueryBindings batchedStatementBindings = ((PreparedQuery) ((ClientPreparedStatement) batchedStatement).getQuery()).getQueryBindings(); for (int j = 0; j < bindValues.length; j++) { batchedStatementBindings.setFromBindValue(batchedParamIndex++ - 1, bindValues[j]); } return batchedParamIndex; } private String generateMultiStatementForBatch(int numBatches) throws SQLException { Lock connectionLock = checkClosed().getConnectionLock(); connectionLock.lock(); try { 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(); } finally { connectionLock.unlock(); } } /** * Rewrites the already prepared statement into a multi-values clause INSERT/REPLACE statement 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[] executeBatchWithMultiValuesClause(long batchTimeout) throws SQLException { Lock connectionLock = checkClosed().getConnectionLock(); connectionLock.lock(); try { JdbcConnection locallyScopedConn = this.connection; 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(); } } finally { connectionLock.unlock(); } } /** * 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(long batchTimeout) throws SQLException { Lock connectionLock = checkClosed().getConnectionLock(); connectionLock.lock(); try { 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(containsOnDuplicateKeyUpdate() ? 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]; } finally { connectionLock.unlock(); } } /** * Actually execute the prepared statement. This is here so server-side * PreparedStatements can re-use most of the code from this class. * * @paramtrue if the query produces a result set, false otherwise.
*/
protected boolean isResultSetProducingQuery() {
QueryReturnType queryReturnType = getQueryInfo().getQueryReturnType();
return queryReturnType == QueryReturnType.PRODUCES_RESULT_SET || queryReturnType == QueryReturnType.MAY_PRODUCE_RESULT_SET;
}
/**
* Checks if the given SQL query does not return a result set.
*
* @return
* true if the query does not produce a result set, false otherwise.
*/
private boolean isNonResultSetProducingQuery() {
QueryReturnType queryReturnType = getQueryInfo().getQueryReturnType();
return queryReturnType == QueryReturnType.DOES_NOT_PRODUCE_RESULT_SET || queryReturnType == QueryReturnType.MAY_PRODUCE_RESULT_SET;
}
@Override
public ParameterMetaData getParameterMetaData() throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
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;
} finally {
connectionLock.unlock();
}
}
@Override
public QueryInfo getQueryInfo() {
return ((PreparedQuery) this.query).getQueryInfo();
}
private void initializeFromQueryInfo() throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
int parameterCount = getQueryInfo().getStaticSqlParts().length - 1;
((PreparedQuery) this.query).setParameterCount(parameterCount);
((PreparedQuery) this.query).setQueryBindings(new NativeQueryBindings(parameterCount, this.session, NativeQueryBindValue::new));
clearParameters();
} finally {
connectionLock.unlock();
}
}
@Override
public boolean isNull(int paramIndex) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
return ((PreparedQuery) this.query).getQueryBindings().getBindValues()[getCoreParameterIndex(paramIndex)].isNull();
} finally {
connectionLock.unlock();
}
}
@Override
public void realClose(boolean calledExplicitly, boolean closeOpenResults) throws SQLException {
JdbcConnection locallyScopedConn = this.connection;
if (locallyScopedConn == null) {
return; // already closed
}
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
// additional check in case Statement was closed
// while current thread was waiting for lock
if (this.isClosed) {
return;
}
if (this.useUsageAdvisor) {
QueryBindings qb = ((PreparedQuery) this.query).getQueryBindings();
if (qb == null || qb.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);
} finally {
connectionLock.unlock();
}
}
@Override
public String getPreparedSql() {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
if (this.rewrittenBatchSize == 0) {
return ((PreparedQuery) this.query).getOriginalSql();
}
return getQueryInfo().getSqlForBatch();
} finally {
connectionLock.unlock();
}
}
@Override
public int getUpdateCount() throws SQLException {
int count = super.getUpdateCount();
if (containsOnDuplicateKeyUpdate() && this.compensateForOnDuplicateKeyUpdate) {
if (count == 2 || count == 0) {
count = 1;
}
}
return count;
}
@Override
public long executeLargeUpdate() throws SQLException {
return executeUpdateInternal(true, false);
}
@Override
public ParameterBindings getParameterBindings() throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
return new ParameterBindingsImpl((PreparedQuery) this.query, this.session, this.resultSetFactory);
} finally {
connectionLock.unlock();
}
}
/**
* 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 {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
if (paramIndex < 1) {
throw SQLError.createSQLException(Messages.getString("PreparedStatement.49") + paramIndex + Messages.getString("PreparedStatement.50"),
MysqlErrorNumbers.SQLSTATE_CONNJ_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.SQLSTATE_CONNJ_ILLEGAL_ARGUMENT, this.exceptionInterceptor);
} else if (parameterIndexOffset == -1 && paramIndex == 1) {
throw SQLError.createSQLException(Messages.getString("PreparedStatement.63"), MysqlErrorNumbers.SQLSTATE_CONNJ_ILLEGAL_ARGUMENT,
this.exceptionInterceptor);
}
} finally {
connectionLock.unlock();
}
}
public 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 {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setAsciiStream(getCoreParameterIndex(parameterIndex), x, -1);
} finally {
connectionLock.unlock();
}
}
@Override
public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setAsciiStream(getCoreParameterIndex(parameterIndex), x, length);
} finally {
connectionLock.unlock();
}
}
@Override
public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setAsciiStream(getCoreParameterIndex(parameterIndex), x, (int) length);
} finally {
connectionLock.unlock();
}
}
@Override
public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setBigDecimal(getCoreParameterIndex(parameterIndex), x);
} finally {
connectionLock.unlock();
}
}
@Override
public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setBinaryStream(getCoreParameterIndex(parameterIndex), x, -1);
} finally {
connectionLock.unlock();
}
}
@Override
public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setBinaryStream(getCoreParameterIndex(parameterIndex), x, length);
} finally {
connectionLock.unlock();
}
}
@Override
public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setBinaryStream(getCoreParameterIndex(parameterIndex), x, (int) length);
} finally {
connectionLock.unlock();
}
}
@Override
public void setBlob(int i, java.sql.Blob x) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setBlob(getCoreParameterIndex(i), x);
} finally {
connectionLock.unlock();
}
}
@Override
public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setBinaryStream(getCoreParameterIndex(parameterIndex), inputStream, -1);
} finally {
connectionLock.unlock();
}
}
@Override
public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setBinaryStream(getCoreParameterIndex(parameterIndex), inputStream, (int) length);
} finally {
connectionLock.unlock();
}
}
@Override
public void setBoolean(int parameterIndex, boolean x) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setBoolean(getCoreParameterIndex(parameterIndex), x);
} finally {
connectionLock.unlock();
}
}
@Override
public void setByte(int parameterIndex, byte x) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setByte(getCoreParameterIndex(parameterIndex), x);
} finally {
connectionLock.unlock();
}
}
@Override
public void setBytes(int parameterIndex, byte[] x) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setBytes(getCoreParameterIndex(parameterIndex), x, true);
} finally {
connectionLock.unlock();
}
}
@Override
public void setBytes(int parameterIndex, byte[] x, boolean escapeIfNeeded) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setBytes(getCoreParameterIndex(parameterIndex), x, escapeIfNeeded);
} finally {
connectionLock.unlock();
}
}
@Override
public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setCharacterStream(getCoreParameterIndex(parameterIndex), reader, -1);
} finally {
connectionLock.unlock();
}
}
@Override
public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setCharacterStream(getCoreParameterIndex(parameterIndex), reader, length);
} finally {
connectionLock.unlock();
}
}
@Override
public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setCharacterStream(getCoreParameterIndex(parameterIndex), reader, (int) length);
} finally {
connectionLock.unlock();
}
}
@Override
public void setClob(int parameterIndex, Reader reader) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setCharacterStream(getCoreParameterIndex(parameterIndex), reader, -1);
} finally {
connectionLock.unlock();
}
}
@Override
public void setClob(int parameterIndex, Reader reader, long length) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setCharacterStream(getCoreParameterIndex(parameterIndex), reader, (int) length);
} finally {
connectionLock.unlock();
}
}
@Override
public void setClob(int i, Clob x) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setClob(getCoreParameterIndex(i), x);
} finally {
connectionLock.unlock();
}
}
@Override
public void setDate(int parameterIndex, Date x) throws java.sql.SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setDate(getCoreParameterIndex(parameterIndex), x, null);
} finally {
connectionLock.unlock();
}
}
@Override
public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setDate(getCoreParameterIndex(parameterIndex), x, cal);
} finally {
connectionLock.unlock();
}
}
@Override
public void setDouble(int parameterIndex, double x) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setDouble(getCoreParameterIndex(parameterIndex), x);
} finally {
connectionLock.unlock();
}
}
@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 {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setInt(getCoreParameterIndex(parameterIndex), x);
} finally {
connectionLock.unlock();
}
}
@Override
public void setLong(int parameterIndex, long x) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setLong(getCoreParameterIndex(parameterIndex), x);
} finally {
connectionLock.unlock();
}
}
@Override
public void setBigInteger(int parameterIndex, BigInteger x) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setBigInteger(getCoreParameterIndex(parameterIndex), x);
} finally {
connectionLock.unlock();
}
}
@Override
public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setNCharacterStream(getCoreParameterIndex(parameterIndex), value, -1);
} finally {
connectionLock.unlock();
}
}
@Override
public void setNCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setNCharacterStream(getCoreParameterIndex(parameterIndex), reader, length);
} finally {
connectionLock.unlock();
}
}
@Override
public void setNClob(int parameterIndex, Reader reader) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setNCharacterStream(getCoreParameterIndex(parameterIndex), reader, -1);
} finally {
connectionLock.unlock();
}
}
@Override
public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setNCharacterStream(getCoreParameterIndex(parameterIndex), reader, length);
} finally {
connectionLock.unlock();
}
}
@Override
public void setNClob(int parameterIndex, NClob value) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setNClob(getCoreParameterIndex(parameterIndex), value);
} finally {
connectionLock.unlock();
}
}
/**
* 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 {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setNString(getCoreParameterIndex(parameterIndex), x);
} finally {
connectionLock.unlock();
}
}
@Override
public void setNull(int parameterIndex, int sqlType) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setNull(getCoreParameterIndex(parameterIndex)); // MySQL ignores sqlType
} finally {
connectionLock.unlock();
}
}
@Override
public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setNull(getCoreParameterIndex(parameterIndex));
} finally {
connectionLock.unlock();
}
}
@Override
public void setNull(int parameterIndex, MysqlType mysqlType) throws SQLException {
setNull(parameterIndex, mysqlType.getJdbcType());
}
@Override
public void setObject(int parameterIndex, Object parameterObj) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setObject(getCoreParameterIndex(parameterIndex), parameterObj);
} finally {
connectionLock.unlock();
}
}
@Override
public void setObject(int parameterIndex, Object parameterObj, int targetSqlType) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
try {
((PreparedQuery) this.query).getQueryBindings().setObject(getCoreParameterIndex(parameterIndex), parameterObj,
MysqlType.getByJdbcType(targetSqlType), -1);
} catch (FeatureNotAvailableException nae) {
throw SQLError.createSQLFeatureNotSupportedException(Messages.getString("Statement.UnsupportedSQLType") + JDBCType.valueOf(targetSqlType),
MysqlErrorNumbers.SQLSTATE_CONNJ_DRIVER_NOT_CAPABLE, this.exceptionInterceptor);
}
} finally {
connectionLock.unlock();
}
}
@Override
public void setObject(int parameterIndex, Object parameterObj, SQLType targetSqlType) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
if (targetSqlType instanceof MysqlType) {
((PreparedQuery) this.query).getQueryBindings().setObject(getCoreParameterIndex(parameterIndex), parameterObj, (MysqlType) targetSqlType, -1);
} else {
setObject(parameterIndex, parameterObj, targetSqlType.getVendorTypeNumber());
}
} finally {
connectionLock.unlock();
}
}
@Override
public void setObject(int parameterIndex, Object parameterObj, int targetSqlType, int scale) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
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.SQLSTATE_CONNJ_DRIVER_NOT_CAPABLE, this.exceptionInterceptor);
}
} finally {
connectionLock.unlock();
}
}
@Override
public void setObject(int parameterIndex, Object x, SQLType targetSqlType, int scaleOrLength) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
if (targetSqlType instanceof MysqlType) {
((PreparedQuery) this.query).getQueryBindings().setObject(getCoreParameterIndex(parameterIndex), x, (MysqlType) targetSqlType, scaleOrLength);
} else {
setObject(parameterIndex, x, targetSqlType.getVendorTypeNumber(), scaleOrLength);
}
} finally {
connectionLock.unlock();
}
}
@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 {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setShort(getCoreParameterIndex(parameterIndex), x);
} finally {
connectionLock.unlock();
}
}
@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 {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setString(getCoreParameterIndex(parameterIndex), x);
} finally {
connectionLock.unlock();
}
}
@Override
public void setTime(int parameterIndex, Time x) throws java.sql.SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setTime(getCoreParameterIndex(parameterIndex), x, null);
} finally {
connectionLock.unlock();
}
}
@Override
public void setTime(int parameterIndex, java.sql.Time x, Calendar cal) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setTime(getCoreParameterIndex(parameterIndex), x, cal);
} finally {
connectionLock.unlock();
}
}
@Override
public void setTimestamp(int parameterIndex, Timestamp x) throws java.sql.SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setTimestamp(getCoreParameterIndex(parameterIndex), x, null, null, MysqlType.TIMESTAMP);
} finally {
connectionLock.unlock();
}
}
@Override
public void setTimestamp(int parameterIndex, java.sql.Timestamp x, Calendar cal) throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
((PreparedQuery) this.query).getQueryBindings().setTimestamp(getCoreParameterIndex(parameterIndex), x, cal, null, MysqlType.TIMESTAMP);
} finally {
connectionLock.unlock();
}
}
@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);
}
@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);
}
}
}