com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement Maven / Gradle / Ivy
Show all versions of mssql-jdbc Show documentation
/*
* Microsoft JDBC Driver for SQL Server
*
* Copyright(c) Microsoft Corporation All rights reserved.
*
* This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information.
*/
package com.microsoft.sqlserver.jdbc;
import static com.microsoft.sqlserver.jdbc.SQLServerConnection.getCachedParsedSQL;
import static com.microsoft.sqlserver.jdbc.SQLServerConnection.parseAndCacheSQL;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.sql.BatchUpdateException;
import java.sql.NClob;
import java.sql.ParameterMetaData;
import java.sql.ResultSet;
import java.sql.RowId;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.SQLXML;
import java.sql.Statement;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import java.util.logging.Level;
import com.microsoft.sqlserver.jdbc.SQLServerConnection.PreparedStatementHandle;
import com.microsoft.sqlserver.jdbc.SQLServerConnection.Sha1HashKey;
/**
* SQLServerPreparedStatement provides JDBC prepared statement functionality. SQLServerPreparedStatement provides methods for the user to supply
* parameters as any native Java type and many Java object types.
*
* SQLServerPreparedStatement prepares a statement using SQL Server's sp_prepexec and re-uses the returned statement handle for each subsequent
* execution of the statement (typically using different parameters provided by the user)
*
* SQLServerPreparedStatement supports batching whereby a set of prepared statements are executed in a single database round trip to improve runtime
* performance.
*
* The API javadoc for JDBC API methods that this class implements are not repeated here. Please see Sun's JDBC API interfaces javadoc for those
* details.
*/
public class SQLServerPreparedStatement extends SQLServerStatement implements ISQLServerPreparedStatement {
/** Flag to indicate that it is an internal query to retrieve encryption metadata. */
boolean isInternalEncryptionQuery = false;
/** delimiter for multiple statements in a single batch */
private static final int BATCH_STATEMENT_DELIMITER_TDS_71 = 0x80;
private static final int BATCH_STATEMENT_DELIMITER_TDS_72 = 0xFF;
final int nBatchStatementDelimiter = BATCH_STATEMENT_DELIMITER_TDS_72;
/** The prepared type definitions */
private String preparedTypeDefinitions;
/** Processed SQL statement text, may not be same as what user initially passed. */
final String userSQL;
/** SQL statement with expanded parameter tokens */
private String preparedSQL;
/** True if this execute has been called for this statement at least once */
private boolean isExecutedAtLeastOnce = false;
/** Reference to cache item for statement handle pooling. Only used to decrement ref count on statement close. */
private PreparedStatementHandle cachedPreparedStatementHandle;
/** Hash of user supplied SQL statement used for various cache lookups */
private Sha1HashKey sqlTextCacheKey;
/**
* Array with parameter names generated in buildParamTypeDefinitions For mapping encryption information to parameters, as the second result set
* returned by sp_describe_parameter_encryption doesn't depend on order of input parameter
**/
private ArrayList parameterNames;
/** Set to true if the statement is a stored procedure call that expects a return value */
final boolean bReturnValueSyntax;
/**
* The number of OUT parameters to skip in the response to get to the first app-declared OUT parameter.
*
* When executing prepared and callable statements and/or statements that produce cursored results, the first OUT parameters returned by the
* server contain the internal values like the prepared statement handle and the cursor ID and row count. This value indicates how many of those
* internal OUT parameters were in the response.
*/
int outParamIndexAdjustment;
/** Set of parameter values in the current batch */
ArrayList batchParamValues;
/** The prepared statement handle returned by the server */
private int prepStmtHandle = 0;
private void setPreparedStatementHandle(int handle) {
this.prepStmtHandle = handle;
}
/** The server handle for this prepared statement. If a value {@literal <} 1 is returned no handle has been created.
*
* @return
* Per the description.
* @throws SQLServerException when an error occurs
*/
public int getPreparedStatementHandle() throws SQLServerException {
checkClosed();
return prepStmtHandle;
}
/** Returns true if this statement has a server handle.
*
* @return
* Per the description.
*/
private boolean hasPreparedStatementHandle() {
return 0 < prepStmtHandle;
}
/** Resets the server handle for this prepared statement to no handle.
*/
private void resetPrepStmtHandle() {
prepStmtHandle = 0;
}
/** Flag set to true when statement execution is expected to return the prepared statement handle */
private boolean expectPrepStmtHandle = false;
/**
* Flag set to true when all encryption metadata of inOutParam is retrieved
*/
private boolean encryptionMetadataIsRetrieved = false;
// Internal function used in tracing
String getClassNameInternal() {
return "SQLServerPreparedStatement";
}
/**
* Create a new prepaed statement.
*
* @param conn
* the connection
* @param sql
* the user's sql
* @param nRSType
* the result set type
* @param nRSConcur
* the result set concurrency
* @param stmtColEncSetting
* the statement column encryption setting
* @throws SQLServerException
* when an error occurs
*/
SQLServerPreparedStatement(SQLServerConnection conn,
String sql,
int nRSType,
int nRSConcur,
SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException {
super(conn, nRSType, nRSConcur, stmtColEncSetting);
if (null == sql) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_NullValue"));
Object[] msgArgs1 = {"Statement SQL"};
throw new SQLServerException(form.format(msgArgs1), null);
}
stmtPoolable = true;
// Create a cache key for this statement.
sqlTextCacheKey = new Sha1HashKey(sql);
// Parse or fetch SQL metadata from cache.
ParsedSQLCacheItem parsedSQL = getCachedParsedSQL(sqlTextCacheKey);
if(null != parsedSQL) {
isExecutedAtLeastOnce = true;
}
else {
parsedSQL = parseAndCacheSQL(sqlTextCacheKey, sql);
}
// Retrieve meta data from cache item.
procedureName = parsedSQL.procedureName;
bReturnValueSyntax = parsedSQL.bReturnValueSyntax;
userSQL = parsedSQL.processedSQL;
initParams(parsedSQL.parameterCount);
}
/**
* Close the prepared statement's prepared handle.
*/
private void closePreparedHandle() {
if (!hasPreparedStatementHandle())
return;
// If the connection is already closed, don't bother trying to close
// the prepared handle. We won't be able to, and it's already closed
// on the server anyway.
if (connection.isSessionUnAvailable()) {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.finer(this + ": Not closing PreparedHandle:" + prepStmtHandle + "; connection is already closed.");
}
else {
isExecutedAtLeastOnce = false;
final int handleToClose = prepStmtHandle;
resetPrepStmtHandle();
// Handle unprepare actions through statement pooling.
if (null != cachedPreparedStatementHandle) {
connection.returnCachedPreparedStatementHandle(cachedPreparedStatementHandle);
}
// If no reference to a statement pool cache item is found handle unprepare actions through batching @ connection level.
else if(connection.isPreparedStatementUnprepareBatchingEnabled()) {
connection.enqueueUnprepareStatementHandle(connection.new PreparedStatementHandle(null, handleToClose, executedSqlDirectly, true));
}
else {
// Non batched behavior (same as pre batch clean-up implementation)
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.finer(this + ": Closing PreparedHandle:" + handleToClose);
final class PreparedHandleClose extends UninterruptableTDSCommand {
PreparedHandleClose() {
super("closePreparedHandle");
}
final boolean doExecute() throws SQLServerException {
TDSWriter tdsWriter = startRequest(TDS.PKT_RPC);
tdsWriter.writeShort((short) 0xFFFF); // procedure name length -> use ProcIDs
tdsWriter.writeShort(executedSqlDirectly ? TDS.PROCID_SP_UNPREPARE : TDS.PROCID_SP_CURSORUNPREPARE);
tdsWriter.writeByte((byte) 0); // RPC procedure option 1
tdsWriter.writeByte((byte) 0); // RPC procedure option 2
tdsWriter.writeRPCInt(null, handleToClose, false);
TDSParser.parse(startResponse(), getLogContext());
return true;
}
}
// Try to close the server cursor. Any failure is caught, logged, and ignored.
try {
executeCommand(new PreparedHandleClose());
}
catch (SQLServerException e) {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.log(Level.FINER, this + ": Error (ignored) closing PreparedHandle:" + handleToClose, e);
}
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.finer(this + ": Closed PreparedHandle:" + handleToClose);
}
// Always run any outstanding discard actions as statement pooling always uses batched sp_unprepare.
connection.unprepareUnreferencedPreparedStatementHandles(false);
}
}
/**
* Closes this prepared statement.
*
* Note that the public Statement.close() method performs all of the cleanup work through this internal method which cannot throw any exceptions.
* This is done deliberately to ensure that ALL of the object's client-side and server-side state is cleaned up as best as possible, even under
* conditions which would normally result in exceptions being thrown.
*/
final void closeInternal() {
super.closeInternal();
// If we have a prepared statement handle, close it.
closePreparedHandle();
// Clean up client-side state
batchParamValues = null;
}
/**
* Intialize the statement parameters.
*
* @param nParams
* Number of parameters to Intialize.
*/
/* L0 */ final void initParams(int nParams) {
inOutParam = new Parameter[nParams];
for (int i = 0; i < nParams; i++) {
inOutParam[i] = new Parameter(Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, connection));
}
}
/* L0 */ public final void clearParameters() throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "clearParameters");
checkClosed();
encryptionMetadataIsRetrieved = false;
int i;
if (inOutParam == null)
return;
for (i = 0; i < inOutParam.length; i++) {
inOutParam[i].clearInputValue();
}
loggerExternal.exiting(getClassNameLogging(), "clearParameters");
}
/**
* Determines whether the statement needs to be reprepared based on a change in any of the type definitions of any of the parameters due to
* changes in scale, length, etc., and, if so, sets the new type definition string.
*/
private boolean buildPreparedStrings(Parameter[] params,
boolean renewDefinition) throws SQLServerException {
String newTypeDefinitions = buildParamTypeDefinitions(params, renewDefinition);
if (null != preparedTypeDefinitions && newTypeDefinitions.equals(preparedTypeDefinitions))
return false;
preparedTypeDefinitions = newTypeDefinitions;
/* Replace the parameter marker '?' with the param numbers @p1, @p2 etc */
preparedSQL = connection.replaceParameterMarkers(userSQL, params, bReturnValueSyntax);
if (bRequestedGeneratedKeys)
preparedSQL = preparedSQL + identityQuery;
return true;
}
/**
* Build the parameter type definitons for a JDBC prepared statement that will be used to prepare the statement.
*
* @param params
* the statement parameters
* @param renewDefinition
* True if renewing parameter definition, False otherwise
* @throws SQLServerException
* when an error occurs.
* @return the required data type defintions.
*/
private String buildParamTypeDefinitions(Parameter[] params,
boolean renewDefinition) throws SQLServerException {
StringBuilder sb = new StringBuilder();
int nCols = params.length;
char cParamName[] = new char[10];
parameterNames = new ArrayList();
for (int i = 0; i < nCols; i++) {
if (i > 0)
sb.append(',');
int l = SQLServerConnection.makeParamName(i, cParamName, 0);
for (int j = 0; j < l; j++)
sb.append(cParamName[j]);
sb.append(' ');
parameterNames.add(i, (new String(cParamName)).trim());
params[i].renewDefinition = renewDefinition;
String typeDefinition = params[i].getTypeDefinition(connection, resultsReader());
if (null == typeDefinition) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_valueNotSetForParameter"));
Object[] msgArgs = {i + 1};
SQLServerException.makeFromDriverError(connection, this, form.format(msgArgs), null, false);
}
sb.append(typeDefinition);
if (params[i].isOutput())
sb.append(" OUTPUT");
}
return sb.toString();
}
/**
* Execute a query.
*
* @throws SQLServerException
* when an error occurs
* @return ResultSet
*/
public java.sql.ResultSet executeQuery() throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "executeQuery");
if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) {
loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
}
checkClosed();
executeStatement(new PrepStmtExecCmd(this, EXECUTE_QUERY));
loggerExternal.exiting(getClassNameLogging(), "executeQuery");
return resultSet;
}
/**
* Execute a query without cursoring for metadata.
*
* @throws SQLServerException
* @return ResultSet
*/
final java.sql.ResultSet executeQueryInternal() throws SQLServerException {
checkClosed();
executeStatement(new PrepStmtExecCmd(this, EXECUTE_QUERY_INTERNAL));
return resultSet;
}
public int executeUpdate() throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "executeUpdate");
if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) {
loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
}
checkClosed();
executeStatement(new PrepStmtExecCmd(this, EXECUTE_UPDATE));
// this shouldn't happen, caller probably meant to call executeLargeUpdate
if (updateCount < Integer.MIN_VALUE || updateCount > Integer.MAX_VALUE)
SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_updateCountOutofRange"), null, true);
loggerExternal.exiting(getClassNameLogging(), "executeUpdate", updateCount);
return (int) updateCount;
}
public long executeLargeUpdate() throws SQLServerException {
DriverJDBCVersion.checkSupportsJDBC42();
loggerExternal.entering(getClassNameLogging(), "executeLargeUpdate");
if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) {
loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
}
checkClosed();
executeStatement(new PrepStmtExecCmd(this, EXECUTE_UPDATE));
loggerExternal.exiting(getClassNameLogging(), "executeLargeUpdate", updateCount);
return updateCount;
}
/**
* Execute a query or non query statement.
*
* @throws SQLServerException
* when an error occurs
* @return true if the statement returned a result set
*/
public boolean execute() throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "execute");
if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) {
loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
}
checkClosed();
executeStatement(new PrepStmtExecCmd(this, EXECUTE));
loggerExternal.exiting(getClassNameLogging(), "execute", null != resultSet);
return null != resultSet;
}
private final class PrepStmtExecCmd extends TDSCommand {
private final SQLServerPreparedStatement stmt;
PrepStmtExecCmd(SQLServerPreparedStatement stmt,
int executeMethod) {
super(stmt.toString() + " executeXXX", queryTimeout);
this.stmt = stmt;
stmt.executeMethod = executeMethod;
}
final boolean doExecute() throws SQLServerException {
stmt.doExecutePreparedStatement(this);
return false;
}
final void processResponse(TDSReader tdsReader) throws SQLServerException {
ensureExecuteResultsReader(tdsReader);
processExecuteResults();
}
}
final void doExecutePreparedStatement(PrepStmtExecCmd command) throws SQLServerException {
resetForReexecute();
// If this request might be a query (as opposed to an update) then make
// sure we set the max number of rows and max field size for any ResultSet
// that may be returned.
//
// If the app uses Statement.execute to execute an UPDATE or DELETE statement
// and has called Statement.setMaxRows to limit the number of rows from an
// earlier query, then the number of rows updated/deleted will be limited as
// well.
//
// Note: similar logic in SQLServerStatement.doExecuteStatement
setMaxRowsAndMaxFieldSize();
if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) {
loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
}
boolean hasExistingTypeDefinitions = preparedTypeDefinitions != null;
boolean hasNewTypeDefinitions = true;
if (!encryptionMetadataIsRetrieved) {
hasNewTypeDefinitions = buildPreparedStrings(inOutParam, false);
}
if ((Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, connection)) && (0 < inOutParam.length) && !isInternalEncryptionQuery) {
// retrieve paramater encryption metadata if they are not retrieved yet
if (!encryptionMetadataIsRetrieved) {
getParameterEncryptionMetadata(inOutParam);
encryptionMetadataIsRetrieved = true;
// maxRows is set to 0 when retreving encryption metadata,
// need to set it back
setMaxRowsAndMaxFieldSize();
}
// fix an issue when inserting unicode into non-encrypted nchar column using setString() and AE is on on Connection
hasNewTypeDefinitions = buildPreparedStrings(inOutParam, true);
}
// Retry execution if existing handle could not be re-used.
for(int attempt = 1; attempt <= 2; ++attempt) {
try {
// Re-use handle if available, requires parameter definitions which are not available until here.
if (reuseCachedHandle(hasNewTypeDefinitions, 1 < attempt)) {
hasNewTypeDefinitions = false;
}
// Start the request and detach the response reader so that we can
// continue using it after we return.
TDSWriter tdsWriter = command.startRequest(TDS.PKT_RPC);
doPrepExec(tdsWriter, inOutParam, hasNewTypeDefinitions, hasExistingTypeDefinitions);
ensureExecuteResultsReader(command.startResponse(getIsResponseBufferingAdaptive()));
startResults();
getNextResult();
}
catch(SQLException e) {
if (retryBasedOnFailedReuseOfCachedHandle(e, attempt))
continue;
else
throw e;
}
break;
}
if (EXECUTE_QUERY == executeMethod && null == resultSet) {
SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_noResultset"), null, true);
}
else if (EXECUTE_UPDATE == executeMethod && null != resultSet) {
SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_resultsetGeneratedForUpdate"), null, false);
}
}
/** Should the execution be retried because the re-used cached handle could not be re-used due to server side state changes? */
private boolean retryBasedOnFailedReuseOfCachedHandle(SQLException e, int attempt) {
// Only retry based on these error codes:
// 586: The prepared statement handle %d is not valid in this context. Please verify that current database, user default schema, and ANSI_NULLS and QUOTED_IDENTIFIER set options are not changed since the handle is prepared.
// 8179: Could not find prepared statement with handle %d.
// 99586: Error used for testing.
return 1 == attempt && (586 == e.getErrorCode() || 8179 == e.getErrorCode() || 99586 == e.getErrorCode());
}
/**
* Consume the OUT parameter for the statement object itself.
*
* When a prepared statement handle is expected as the first OUT parameter from PreparedStatement or CallableStatement execution, then it gets
* consumed here.
*/
boolean consumeExecOutParam(TDSReader tdsReader) throws SQLServerException {
final class PrepStmtExecOutParamHandler extends StmtExecOutParamHandler {
boolean onRetValue(TDSReader tdsReader) throws SQLServerException {
// If no prepared statement handle is expected at this time
// then don't consume this OUT parameter as it does not contain
// a prepared statement handle.
if (!expectPrepStmtHandle)
return super.onRetValue(tdsReader);
// If a prepared statement handle is expected then consume it
// and continue processing.
expectPrepStmtHandle = false;
Parameter param = new Parameter(Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, connection));
param.skipRetValStatus(tdsReader);
setPreparedStatementHandle(param.getInt(tdsReader));
// Cache the reference to the newly created handle, NOT for cursorable handles.
if (null == cachedPreparedStatementHandle && !isCursorable(executeMethod)) {
cachedPreparedStatementHandle = connection.registerCachedPreparedStatementHandle(new Sha1HashKey(preparedSQL, preparedTypeDefinitions), prepStmtHandle, executedSqlDirectly);
}
param.skipValue(tdsReader, true);
if (getStatementLogger().isLoggable(java.util.logging.Level.FINER))
getStatementLogger().finer(toString() + ": Setting PreparedHandle:" + prepStmtHandle);
return true;
}
}
if (expectPrepStmtHandle || expectCursorOutParams) {
TDSParser.parse(tdsReader, new PrepStmtExecOutParamHandler());
return true;
}
return false;
}
/**
* Send the statement parameters by RPC
*/
void sendParamsByRPC(TDSWriter tdsWriter,
Parameter[] params) throws SQLServerException {
char cParamName[];
for (int index = 0; index < params.length; index++) {
if (JDBCType.TVP == params[index].getJdbcType()) {
cParamName = new char[10];
int paramNameLen = SQLServerConnection.makeParamName(index, cParamName, 0);
tdsWriter.writeByte((byte) paramNameLen);
tdsWriter.writeString(new String(cParamName, 0, paramNameLen));
}
params[index].sendByRPC(tdsWriter, connection);
}
}
private void buildServerCursorPrepExecParams(TDSWriter tdsWriter) throws SQLServerException {
if (getStatementLogger().isLoggable(java.util.logging.Level.FINE))
getStatementLogger().fine(toString() + ": calling sp_cursorprepexec: PreparedHandle:" + getPreparedStatementHandle() + ", SQL:" + preparedSQL);
expectPrepStmtHandle = true;
executedSqlDirectly = false;
expectCursorOutParams = true;
outParamIndexAdjustment = 7;
tdsWriter.writeShort((short) 0xFFFF); // procedure name length -> use ProcIDs
tdsWriter.writeShort(TDS.PROCID_SP_CURSORPREPEXEC);
tdsWriter.writeByte((byte) 0); // RPC procedure option 1
tdsWriter.writeByte((byte) 0); // RPC procedure option 2
//
// IN (reprepare): Old handle to unprepare before repreparing
// OUT: The newly prepared handle
tdsWriter.writeRPCInt(null, getPreparedStatementHandle(), true);
resetPrepStmtHandle();
// OUT
tdsWriter.writeRPCInt(null, 0, true); // cursor ID (OUTPUT)
// IN
tdsWriter.writeRPCStringUnicode((preparedTypeDefinitions.length() > 0) ? preparedTypeDefinitions : null);
// IN
tdsWriter.writeRPCStringUnicode(preparedSQL);
// IN
// Note: we must strip out SCROLLOPT_PARAMETERIZED_STMT if we don't
// actually have any parameters.
tdsWriter.writeRPCInt(null,
getResultSetScrollOpt() & ~((0 == preparedTypeDefinitions.length()) ? TDS.SCROLLOPT_PARAMETERIZED_STMT : 0), false);
// IN
tdsWriter.writeRPCInt(null, getResultSetCCOpt(), false);
// OUT
tdsWriter.writeRPCInt(null, 0, true);
}
private void buildPrepExecParams(TDSWriter tdsWriter) throws SQLServerException {
if (getStatementLogger().isLoggable(java.util.logging.Level.FINE))
getStatementLogger().fine(toString() + ": calling sp_prepexec: PreparedHandle:" + getPreparedStatementHandle() + ", SQL:" + preparedSQL);
expectPrepStmtHandle = true;
executedSqlDirectly = true;
expectCursorOutParams = false;
outParamIndexAdjustment = 3;
tdsWriter.writeShort((short) 0xFFFF); // procedure name length -> use ProcIDs
tdsWriter.writeShort(TDS.PROCID_SP_PREPEXEC);
tdsWriter.writeByte((byte) 0); // RPC procedure option 1
tdsWriter.writeByte((byte) 0); // RPC procedure option 2
//
// IN (reprepare): Old handle to unprepare before repreparing
// OUT: The newly prepared handle
tdsWriter.writeRPCInt(null, getPreparedStatementHandle(), true);
resetPrepStmtHandle();
// IN
tdsWriter.writeRPCStringUnicode((preparedTypeDefinitions.length() > 0) ? preparedTypeDefinitions : null);
// IN
tdsWriter.writeRPCStringUnicode(preparedSQL);
}
private void buildExecSQLParams(TDSWriter tdsWriter) throws SQLServerException {
if (getStatementLogger().isLoggable(java.util.logging.Level.FINE))
getStatementLogger().fine(toString() + ": calling sp_executesql: SQL:" + preparedSQL);
expectPrepStmtHandle = false;
executedSqlDirectly = true;
expectCursorOutParams = false;
outParamIndexAdjustment = 2;
tdsWriter.writeShort((short) 0xFFFF); // procedure name length -> use ProcIDs
tdsWriter.writeShort(TDS.PROCID_SP_EXECUTESQL);
tdsWriter.writeByte((byte) 0); // RPC procedure option 1
tdsWriter.writeByte((byte) 0); // RPC procedure option 2
// No handle used.
resetPrepStmtHandle();
// IN
tdsWriter.writeRPCStringUnicode(preparedSQL);
// IN
if (preparedTypeDefinitions.length() > 0)
tdsWriter.writeRPCStringUnicode(preparedTypeDefinitions);
}
private void buildServerCursorExecParams(TDSWriter tdsWriter) throws SQLServerException {
if (getStatementLogger().isLoggable(java.util.logging.Level.FINE))
getStatementLogger().fine(toString() + ": calling sp_cursorexecute: PreparedHandle:" + getPreparedStatementHandle() + ", SQL:" + preparedSQL);
expectPrepStmtHandle = false;
executedSqlDirectly = false;
expectCursorOutParams = true;
outParamIndexAdjustment = 5;
tdsWriter.writeShort((short) 0xFFFF); // procedure name length -> use ProcIDs
tdsWriter.writeShort(TDS.PROCID_SP_CURSOREXECUTE);
tdsWriter.writeByte((byte) 0); // RPC procedure option 1
tdsWriter.writeByte((byte) 0); // RPC procedure option 2 */
// IN
assert hasPreparedStatementHandle();
tdsWriter.writeRPCInt(null, getPreparedStatementHandle(), false);
// OUT
tdsWriter.writeRPCInt(null, 0, true);
// IN
tdsWriter.writeRPCInt(null, getResultSetScrollOpt() & ~TDS.SCROLLOPT_PARAMETERIZED_STMT, false);
// IN
tdsWriter.writeRPCInt(null, getResultSetCCOpt(), false);
// OUT
tdsWriter.writeRPCInt(null, 0, true);
}
private void buildExecParams(TDSWriter tdsWriter) throws SQLServerException {
if (getStatementLogger().isLoggable(java.util.logging.Level.FINE))
getStatementLogger().fine(toString() + ": calling sp_execute: PreparedHandle:" + getPreparedStatementHandle() + ", SQL:" + preparedSQL);
expectPrepStmtHandle = false;
executedSqlDirectly = true;
expectCursorOutParams = false;
outParamIndexAdjustment = 1;
tdsWriter.writeShort((short) 0xFFFF); // procedure name length -> use ProcIDs
tdsWriter.writeShort(TDS.PROCID_SP_EXECUTE);
tdsWriter.writeByte((byte) 0); // RPC procedure option 1
tdsWriter.writeByte((byte) 0); // RPC procedure option 2 */
// IN
assert hasPreparedStatementHandle();
tdsWriter.writeRPCInt(null, getPreparedStatementHandle(), false);
}
private void getParameterEncryptionMetadata(Parameter[] params) throws SQLServerException {
/*
* The parameter list is created from the data types provided by the user for the parameters. the data types do not need to be the same as in
* the table definition. Also, when string is sent to an int field, the parameter is defined as nvarchar(). Same for varchar
* datatypes, exact length is used.
*/
SQLServerResultSet rs = null;
SQLServerCallableStatement stmt = null;
assert connection != null : "Connection should not be null";
try {
if (getStatementLogger().isLoggable(java.util.logging.Level.FINE)) {
getStatementLogger().fine("Calling stored procedure sp_describe_parameter_encryption to get parameter encryption information.");
}
stmt = (SQLServerCallableStatement) connection.prepareCall("exec sp_describe_parameter_encryption ?,?");
stmt.isInternalEncryptionQuery = true;
stmt.setNString(1, preparedSQL);
stmt.setNString(2, preparedTypeDefinitions);
rs = (SQLServerResultSet) stmt.executeQueryInternal();
}
catch (SQLException e) {
if (e instanceof SQLServerException) {
throw (SQLServerException) e;
}
else {
throw new SQLServerException(SQLServerException.getErrString("R_UnableRetrieveParameterMetadata"), null, 0, e);
}
}
if (null == rs) {
// No results. Meaning no parameter.
// Should never happen.
return;
}
Map cekList = new HashMap();
CekTableEntry cekEntry = null;
try {
while (rs.next()) {
int currentOrdinal = rs.getInt(DescribeParameterEncryptionResultSet1.KeyOrdinal.value());
if (!cekList.containsKey(currentOrdinal)) {
cekEntry = new CekTableEntry(currentOrdinal);
cekList.put(cekEntry.ordinal, cekEntry);
}
else {
cekEntry = cekList.get(currentOrdinal);
}
cekEntry.add(rs.getBytes(DescribeParameterEncryptionResultSet1.EncryptedKey.value()),
rs.getInt(DescribeParameterEncryptionResultSet1.DbId.value()), rs.getInt(DescribeParameterEncryptionResultSet1.KeyId.value()),
rs.getInt(DescribeParameterEncryptionResultSet1.KeyVersion.value()),
rs.getBytes(DescribeParameterEncryptionResultSet1.KeyMdVersion.value()),
rs.getString(DescribeParameterEncryptionResultSet1.KeyPath.value()),
rs.getString(DescribeParameterEncryptionResultSet1.ProviderName.value()),
rs.getString(DescribeParameterEncryptionResultSet1.KeyEncryptionAlgorithm.value()));
}
if (getStatementLogger().isLoggable(java.util.logging.Level.FINE)) {
getStatementLogger().fine("Matadata of CEKs is retrieved.");
}
}
catch (SQLException e) {
if (e instanceof SQLServerException) {
throw (SQLServerException) e;
}
else {
throw new SQLServerException(SQLServerException.getErrString("R_UnableRetrieveParameterMetadata"), null, 0, e);
}
}
// Process the second resultset.
if (!stmt.getMoreResults()) {
throw new SQLServerException(this, SQLServerException.getErrString("R_UnexpectedDescribeParamFormat"), null, 0, false);
}
// Parameter count in the result set.
int paramCount = 0;
try {
rs = (SQLServerResultSet) stmt.getResultSet();
while (rs.next()) {
paramCount++;
String paramName = rs.getString(DescribeParameterEncryptionResultSet2.ParameterName.value());
int paramIndex = parameterNames.indexOf(paramName);
int cekOrdinal = rs.getInt(DescribeParameterEncryptionResultSet2.ColumnEncryptionKeyOrdinal.value());
cekEntry = cekList.get(cekOrdinal);
// cekEntry will be null if none of the parameters are encrypted.
if ((null != cekEntry) && (cekList.size() < cekOrdinal)) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidEncryptionKeyOridnal"));
Object[] msgArgs = {cekOrdinal, cekEntry.getSize()};
throw new SQLServerException(this, form.format(msgArgs), null, 0, false);
}
SQLServerEncryptionType encType = SQLServerEncryptionType
.of((byte) rs.getInt(DescribeParameterEncryptionResultSet2.ColumnEncrytionType.value()));
if (SQLServerEncryptionType.PlainText != encType) {
params[paramIndex].cryptoMeta = new CryptoMetadata(cekEntry, (short) cekOrdinal,
(byte) rs.getInt(DescribeParameterEncryptionResultSet2.ColumnEncryptionAlgorithm.value()), null, encType.value,
(byte) rs.getInt(DescribeParameterEncryptionResultSet2.NormalizationRuleVersion.value()));
// Decrypt the symmetric key.(This will also validate and throw if needed).
SQLServerSecurityUtility.decryptSymmetricKey(params[paramIndex].cryptoMeta, connection);
}
else {
if (true == params[paramIndex].getForceEncryption()) {
MessageFormat form = new MessageFormat(
SQLServerException.getErrString("R_ForceEncryptionTrue_HonorAETrue_UnencryptedColumn"));
Object[] msgArgs = {userSQL, paramIndex + 1};
SQLServerException.makeFromDriverError(connection, this, form.format(msgArgs), null, true);
}
}
}
if (getStatementLogger().isLoggable(java.util.logging.Level.FINE)) {
getStatementLogger().fine("Parameter encryption metadata is set.");
}
}
catch (SQLException e) {
if (e instanceof SQLServerException) {
throw (SQLServerException) e;
}
else {
throw new SQLServerException(SQLServerException.getErrString("R_UnableRetrieveParameterMetadata"), null, 0, e);
}
}
if (paramCount != params.length) {
// Encryption metadata wasn't sent by the server.
// We expect the metadata to be sent for all the parameters in the original sp_describe_parameter_encryption.
// For parameters that don't need encryption, the encryption type is set to plaintext.
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_MissingParamEncryptionMetadata"));
Object[] msgArgs = {userSQL};
throw new SQLServerException(this, form.format(msgArgs), null, 0, false);
}
// Null check for rs is done already.
rs.close();
if (null != stmt) {
stmt.close();
}
connection.resetCurrentCommand();
}
/** Manage re-using cached handles */
private boolean reuseCachedHandle(boolean hasNewTypeDefinitions, boolean discardCurrentCacheItem) {
// No re-use of caching for cursorable statements (statements that WILL use sp_cursor*)
if (isCursorable(executeMethod))
return false;
// If current cache item should be discarded make sure it is not used again.
if (discardCurrentCacheItem && null != cachedPreparedStatementHandle) {
cachedPreparedStatementHandle.removeReference();
// Make sure the cached handle does not get re-used more.
resetPrepStmtHandle();
cachedPreparedStatementHandle.setIsExplicitlyDiscarded();
cachedPreparedStatementHandle = null;
return false;
}
// New type definitions and existing cached handle reference then deregister cached handle.
if(hasNewTypeDefinitions) {
if (null != cachedPreparedStatementHandle && hasPreparedStatementHandle() && prepStmtHandle == cachedPreparedStatementHandle.getHandle()) {
cachedPreparedStatementHandle.removeReference();
cachedPreparedStatementHandle.setIsExplicitlyDiscarded();
}
cachedPreparedStatementHandle = null;
}
// Check for new cache reference.
if (null == cachedPreparedStatementHandle) {
PreparedStatementHandle cachedHandle = connection.getCachedPreparedStatementHandle(new Sha1HashKey(preparedSQL, preparedTypeDefinitions));
// If handle was found then re-use, only if AE is not on and is not a batch query with new type definitions (We shouldn't reuse handle
// if it is batch query and has new type definition, or if it is on, make sure encryptionMetadataIsRetrieved is retrieved.
if (null != cachedHandle) {
if (!connection.isColumnEncryptionSettingEnabled()
|| (connection.isColumnEncryptionSettingEnabled() && encryptionMetadataIsRetrieved)) {
if (cachedHandle.tryAddReference()) {
setPreparedStatementHandle(cachedHandle.getHandle());
cachedPreparedStatementHandle = cachedHandle;
return true;
}
}
}
}
return false;
}
private boolean doPrepExec(TDSWriter tdsWriter,
Parameter[] params,
boolean hasNewTypeDefinitions,
boolean hasExistingTypeDefinitions) throws SQLServerException {
boolean needsPrepare = (hasNewTypeDefinitions && hasExistingTypeDefinitions) || !hasPreparedStatementHandle();
// Cursors don't use statement pooling.
if (isCursorable(executeMethod)) {
if (needsPrepare)
buildServerCursorPrepExecParams(tdsWriter);
else
buildServerCursorExecParams(tdsWriter);
}
else {
// Move overhead of needing to do prepare & unprepare to only use cases that need more than one execution.
// First execution, use sp_executesql, optimizing for asumption we will not re-use statement.
if (needsPrepare
&& !connection.getEnablePrepareOnFirstPreparedStatementCall()
&& !isExecutedAtLeastOnce
) {
buildExecSQLParams(tdsWriter);
isExecutedAtLeastOnce = true;
}
// Second execution, use prepared statements since we seem to be re-using it.
else if(needsPrepare)
buildPrepExecParams(tdsWriter);
else
buildExecParams(tdsWriter);
}
sendParamsByRPC(tdsWriter, params);
return needsPrepare;
}
/* L0 */ public final java.sql.ResultSetMetaData getMetaData() throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "getMetaData");
checkClosed();
boolean rsclosed = false;
java.sql.ResultSetMetaData rsmd = null;
try {
// if the result is closed, cant get the metadata from it.
if (resultSet != null)
resultSet.checkClosed();
}
catch (SQLServerException e) {
rsclosed = true;
}
if (resultSet == null || rsclosed) {
SQLServerResultSet emptyResultSet = (SQLServerResultSet) buildExecuteMetaData();
if (null != emptyResultSet)
rsmd = emptyResultSet.getMetaData();
}
else if (resultSet != null) {
rsmd = resultSet.getMetaData();
}
loggerExternal.exiting(getClassNameLogging(), "getMetaData", rsmd);
return rsmd;
}
/**
* Retreive meta data for the statement before executing it. This is called in cases where the driver needs the meta data prior to executing the
* statement.
*
* @throws SQLServerException
* @return the result set containing the meta data
*/
/* L0 */ private ResultSet buildExecuteMetaData() throws SQLServerException {
String fmtSQL = userSQL;
ResultSet emptyResultSet = null;
try {
fmtSQL = replaceMarkerWithNull(fmtSQL);
SQLServerStatement stmt = (SQLServerStatement) connection.createStatement();
emptyResultSet = stmt.executeQueryInternal("set fmtonly on " + fmtSQL + "\nset fmtonly off");
}
catch (SQLException sqle) {
if (false == sqle.getMessage().equals(SQLServerException.getErrString("R_noResultset"))) {
// if the error is not no resultset then throw a processings error.
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_processingError"));
Object[] msgArgs = {sqle.getMessage()};
SQLServerException.makeFromDriverError(connection, this, form.format(msgArgs), null, true);
}
}
return emptyResultSet;
}
/* -------------- JDBC API Implementation ------------------ */
/**
* Set the parameter value for a statement.
*
* @param index
* The index of the parameter to set starting at 1.
* @return A reference the to Parameter object created or referenced.
* @exception SQLServerException
* The index specified was outside the number of paramters for the statement.
*/
/* L0 */ final Parameter setterGetParam(int index) throws SQLServerException {
if (index < 1 || index > inOutParam.length) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_indexOutOfRange"));
Object[] msgArgs = {index};
SQLServerException.makeFromDriverError(connection, this, form.format(msgArgs), "07009", false);
}
return inOutParam[index - 1];
}
final void setValue(int parameterIndex,
JDBCType jdbcType,
Object value,
JavaType javaType,
String tvpName) throws SQLServerException {
setterGetParam(parameterIndex).setValue(jdbcType, value, javaType, null, null, null, null, connection, false, stmtColumnEncriptionSetting,
parameterIndex, userSQL, tvpName);
}
final void setValue(int parameterIndex,
JDBCType jdbcType,
Object value,
JavaType javaType,
boolean forceEncrypt) throws SQLServerException {
setterGetParam(parameterIndex).setValue(jdbcType, value, javaType, null, null, null, null, connection, forceEncrypt,
stmtColumnEncriptionSetting, parameterIndex, userSQL, null);
}
final void setValue(int parameterIndex,
JDBCType jdbcType,
Object value,
JavaType javaType,
Integer precision,
Integer scale,
boolean forceEncrypt) throws SQLServerException {
setterGetParam(parameterIndex).setValue(jdbcType, value, javaType, null, null, precision, scale, connection, forceEncrypt,
stmtColumnEncriptionSetting, parameterIndex, userSQL, null);
}
final void setValue(int parameterIndex,
JDBCType jdbcType,
Object value,
JavaType javaType,
Calendar cal,
boolean forceEncrypt) throws SQLServerException {
setterGetParam(parameterIndex).setValue(jdbcType, value, javaType, null, cal, null, null, connection, forceEncrypt,
stmtColumnEncriptionSetting, parameterIndex, userSQL, null);
}
final void setStream(int parameterIndex,
StreamType streamType,
Object streamValue,
JavaType javaType,
long length) throws SQLServerException {
setterGetParam(parameterIndex).setValue(streamType.getJDBCType(), streamValue, javaType, new StreamSetterArgs(streamType, length), null, null,
null, connection, false, stmtColumnEncriptionSetting, parameterIndex, userSQL, null);
}
final void setSQLXMLInternal(int parameterIndex,
SQLXML value) throws SQLServerException {
setterGetParam(parameterIndex).setValue(JDBCType.SQLXML, value, JavaType.SQLXML,
new StreamSetterArgs(StreamType.SQLXML, DataTypes.UNKNOWN_STREAM_LENGTH), null, null, null, connection, false,
stmtColumnEncriptionSetting, parameterIndex, userSQL, null);
}
public final void setAsciiStream(int parameterIndex,
InputStream x) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setAsciiStream", new Object[] {parameterIndex, x});
checkClosed();
setStream(parameterIndex, StreamType.ASCII, x, JavaType.INPUTSTREAM, DataTypes.UNKNOWN_STREAM_LENGTH);
loggerExternal.exiting(getClassNameLogging(), "setAsciiStream");
}
public final void setAsciiStream(int n,
java.io.InputStream x,
int length) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setAsciiStream", new Object[] {n, x, length});
checkClosed();
setStream(n, StreamType.ASCII, x, JavaType.INPUTSTREAM, length);
loggerExternal.exiting(getClassNameLogging(), "setAsciiStream");
}
public final void setAsciiStream(int parameterIndex,
InputStream x,
long length) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setAsciiStream", new Object[] {parameterIndex, x, length});
checkClosed();
setStream(parameterIndex, StreamType.ASCII, x, JavaType.INPUTSTREAM, length);
loggerExternal.exiting(getClassNameLogging(), "setAsciiStream");
}
private Parameter getParam(int index) throws SQLServerException {
index--;
if (index < 0 || index >= inOutParam.length) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_indexOutOfRange"));
Object[] msgArgs = {index + 1};
SQLServerException.makeFromDriverError(connection, this, form.format(msgArgs), "07009", false);
}
return inOutParam[index];
}
public final void setBigDecimal(int n,
BigDecimal x) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setBigDecimal", new Object[] {n, x});
checkClosed();
setValue(n, JDBCType.DECIMAL, x, JavaType.BIGDECIMAL, false);
loggerExternal.exiting(getClassNameLogging(), "setBigDecimal");
}
/**
* Sets the designated parameter to the given java.math.BigDecimal
value. The driver converts this to an SQL NUMERIC
* value when it sends it to the database.
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @param precision
* the precision of the column
* @param scale
* the scale of the column
* @throws SQLServerException
* when an error occurs
*/
public final void setBigDecimal(int n,
BigDecimal x,
int precision,
int scale) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setBigDecimal", new Object[] {n, x, precision, scale});
checkClosed();
setValue(n, JDBCType.DECIMAL, x, JavaType.BIGDECIMAL, precision, scale, false);
loggerExternal.exiting(getClassNameLogging(), "setBigDecimal");
}
/**
* Sets the designated parameter to the given java.math.BigDecimal
value. The driver converts this to an SQL NUMERIC
* value when it sends it to the database.
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @param precision
* the precision of the column
* @param scale
* the scale of the column
* @param forceEncrypt
* If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always
* Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force
* encryption on parameters.
* @throws SQLServerException
* when an error occurs
*/
public final void setBigDecimal(int n,
BigDecimal x,
int precision,
int scale,
boolean forceEncrypt) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setBigDecimal", new Object[] {n, x, precision, scale, forceEncrypt});
checkClosed();
setValue(n, JDBCType.DECIMAL, x, JavaType.BIGDECIMAL, precision, scale, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setBigDecimal");
}
/**
* Sets the designated parameter to the given java.math.BigDecimal
value. The driver converts this to an SQL NUMERIC
* value when it sends it to the database.
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @throws SQLServerException
* when an error occurs
*/
public final void setMoney(int n,
BigDecimal x) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setMoney", new Object[] {n, x});
checkClosed();
setValue(n, JDBCType.MONEY, x, JavaType.BIGDECIMAL, false);
loggerExternal.exiting(getClassNameLogging(), "setMoney");
}
/**
* Sets the designated parameter to the given java.math.BigDecimal
value. The driver converts this to an SQL NUMERIC
* value when it sends it to the database.
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @param forceEncrypt
* If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always
* Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force
* encryption on parameters.
* @throws SQLServerException
* when an error occurs
*/
public final void setMoney(int n,
BigDecimal x,
boolean forceEncrypt) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setMoney", new Object[] {n, x, forceEncrypt});
checkClosed();
setValue(n, JDBCType.MONEY, x, JavaType.BIGDECIMAL, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setMoney");
}
/**
* Sets the designated parameter to the given java.math.BigDecimal
value. The driver converts this to an SQL NUMERIC
* value when it sends it to the database.
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @throws SQLServerException
* when an error occurs
*/
public final void setSmallMoney(int n,
BigDecimal x) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setSmallMoney", new Object[] {n, x});
checkClosed();
setValue(n, JDBCType.SMALLMONEY, x, JavaType.BIGDECIMAL, false);
loggerExternal.exiting(getClassNameLogging(), "setSmallMoney");
}
/**
* Sets the designated parameter to the given java.math.BigDecimal
value. The driver converts this to an SQL NUMERIC
* value when it sends it to the database.
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @param forceEncrypt
* If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always
* Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force
* encryption on parameters.
* @throws SQLServerException
* when an error occurs
*/
public final void setSmallMoney(int n,
BigDecimal x,
boolean forceEncrypt) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setSmallMoney", new Object[] {n, x, forceEncrypt});
checkClosed();
setValue(n, JDBCType.SMALLMONEY, x, JavaType.BIGDECIMAL, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setSmallMoney");
}
public final void setBinaryStream(int parameterIndex,
InputStream x) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setBinaryStreaml", new Object[] {parameterIndex, x});
checkClosed();
setStream(parameterIndex, StreamType.BINARY, x, JavaType.INPUTSTREAM, DataTypes.UNKNOWN_STREAM_LENGTH);
loggerExternal.exiting(getClassNameLogging(), "setBinaryStream");
}
public final void setBinaryStream(int n,
java.io.InputStream x,
int length) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setBinaryStream", new Object[] {n, x, length});
checkClosed();
setStream(n, StreamType.BINARY, x, JavaType.INPUTSTREAM, length);
loggerExternal.exiting(getClassNameLogging(), "setBinaryStream");
}
public final void setBinaryStream(int parameterIndex,
InputStream x,
long length) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setBinaryStream", new Object[] {parameterIndex, x, length});
checkClosed();
setStream(parameterIndex, StreamType.BINARY, x, JavaType.INPUTSTREAM, length);
loggerExternal.exiting(getClassNameLogging(), "setBinaryStream");
}
public final void setBoolean(int n,
boolean x) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setBoolean", new Object[] {n, x});
checkClosed();
setValue(n, JDBCType.BIT, x, JavaType.BOOLEAN, false);
loggerExternal.exiting(getClassNameLogging(), "setBoolean");
}
/**
* Sets the designated parameter to the given Java boolean
value. The driver converts this to an SQL BIT
or
* BOOLEAN
value when it sends it to the database.
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @param forceEncrypt
* If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always
* Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force
* encryption on parameters.
* @throws SQLServerException
* when an error occurs
*/
public final void setBoolean(int n,
boolean x,
boolean forceEncrypt) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setBoolean", new Object[] {n, x, forceEncrypt});
checkClosed();
setValue(n, JDBCType.BIT, x, JavaType.BOOLEAN, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setBoolean");
}
public final void setByte(int n,
byte x) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setByte", new Object[] {n, x});
checkClosed();
setValue(n, JDBCType.TINYINT, x, JavaType.BYTE, false);
loggerExternal.exiting(getClassNameLogging(), "setByte");
}
/**
* Sets the designated parameter to the given Java byte
value. The driver converts this to an SQL TINYINT
value when it
* sends it to the database.
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @param forceEncrypt
* If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always
* Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force
* encryption on parameters.
* @throws SQLServerException
* when an error occurs
*/
public final void setByte(int n,
byte x,
boolean forceEncrypt) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setByte", new Object[] {n, x, forceEncrypt});
checkClosed();
setValue(n, JDBCType.TINYINT, x, JavaType.BYTE, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setByte");
}
public final void setBytes(int n,
byte x[]) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setBytes", new Object[] {n, x});
checkClosed();
setValue(n, JDBCType.BINARY, x, JavaType.BYTEARRAY, false);
loggerExternal.exiting(getClassNameLogging(), "setBytes");
}
/**
* Sets the designated parameter to the given Java array of bytes. The driver converts this to an SQL VARBINARY
or
* LONGVARBINARY
(depending on the argument's size relative to the driver's limits on VARBINARY
values) when it sends it
* to the database.
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @param forceEncrypt
* If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always
* Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force
* encryption on parameters.
* @throws SQLServerException
* when an error occurs
*/
public final void setBytes(int n,
byte x[],
boolean forceEncrypt) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setBytes", new Object[] {n, x, forceEncrypt});
checkClosed();
setValue(n, JDBCType.BINARY, x, JavaType.BYTEARRAY, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setBytes");
}
/**
* Sets the designated parameter to the given String. The driver converts this to an SQL GUID
*
* @param index
* the first parameter is 1, the second is 2, ...
* @param guid
* string representation of the uniqueIdentifier value
* @throws SQLServerException
* when an error occurs
*/
public final void setUniqueIdentifier(int index,
String guid) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setUniqueIdentifier", new Object[] {index, guid});
checkClosed();
setValue(index, JDBCType.GUID, guid, JavaType.STRING, false);
loggerExternal.exiting(getClassNameLogging(), "setUniqueIdentifier");
}
/**
* Sets the designated parameter to the given String. The driver converts this to an SQL GUID
*
* @param index
* the first parameter is 1, the second is 2, ...
* @param guid
* string representation of the uniqueIdentifier value
* @param forceEncrypt
* If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always
* Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force
* encryption on parameters.
* @throws SQLServerException
* when an error occurs
*/
public final void setUniqueIdentifier(int index,
String guid,
boolean forceEncrypt) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setUniqueIdentifier", new Object[] {index, guid, forceEncrypt});
checkClosed();
setValue(index, JDBCType.GUID, guid, JavaType.STRING, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setUniqueIdentifier");
}
public final void setDouble(int n,
double x) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setDouble", new Object[] {n, x});
checkClosed();
setValue(n, JDBCType.DOUBLE, x, JavaType.DOUBLE, false);
loggerExternal.exiting(getClassNameLogging(), "setDouble");
}
/**
* Sets the designated parameter to the given Java double
value. The driver converts this to an SQL DOUBLE
value when it
* sends it to the database.
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @param forceEncrypt
* If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always
* Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force
* encryption on parameters.
* @throws SQLServerException
* when an error occurs
*/
public final void setDouble(int n,
double x,
boolean forceEncrypt) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setDouble", new Object[] {n, x, forceEncrypt});
checkClosed();
setValue(n, JDBCType.DOUBLE, x, JavaType.DOUBLE, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setDouble");
}
public final void setFloat(int n,
float x) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setFloat", new Object[] {n, x});
checkClosed();
setValue(n, JDBCType.REAL, x, JavaType.FLOAT, false);
loggerExternal.exiting(getClassNameLogging(), "setFloat");
}
/**
* Sets the designated parameter to the given Java float
value. The driver converts this to an SQL REAL
value when it
* sends it to the database.
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @param forceEncrypt
* If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always
* Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force
* encryption on parameters.
* @throws SQLServerException
* when an error occurs
*/
public final void setFloat(int n,
float x,
boolean forceEncrypt) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setFloat", new Object[] {n, x, forceEncrypt});
checkClosed();
setValue(n, JDBCType.REAL, x, JavaType.FLOAT, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setFloat");
}
public final void setInt(int n,
int value) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setInt", new Object[] {n, value});
checkClosed();
setValue(n, JDBCType.INTEGER, value, JavaType.INTEGER, false);
loggerExternal.exiting(getClassNameLogging(), "setInt");
}
/**
* Sets the designated parameter to the given Java int
value. The driver converts this to an SQL INTEGER
value when it
* sends it to the database.
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param value
* the parameter value
* @param forceEncrypt
* If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always
* Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force
* encryption on parameters.
* @throws SQLServerException
* when an error occurs
*/
public final void setInt(int n,
int value,
boolean forceEncrypt) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setInt", new Object[] {n, value, forceEncrypt});
checkClosed();
setValue(n, JDBCType.INTEGER, value, JavaType.INTEGER, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setInt");
}
public final void setLong(int n,
long x) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setLong", new Object[] {n, x});
checkClosed();
setValue(n, JDBCType.BIGINT, x, JavaType.LONG, false);
loggerExternal.exiting(getClassNameLogging(), "setLong");
}
/**
* Sets the designated parameter to the given Java long
value. The driver converts this to an SQL BIGINT
value when it
* sends it to the database.
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @param forceEncrypt
* If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always
* Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force
* encryption on parameters.
* @throws SQLServerException
* when an error occurs
*/
public final void setLong(int n,
long x,
boolean forceEncrypt) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setLong", new Object[] {n, x, forceEncrypt});
checkClosed();
setValue(n, JDBCType.BIGINT, x, JavaType.LONG, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setLong");
}
public final void setNull(int index,
int jdbcType) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setNull", new Object[] {index, jdbcType});
checkClosed();
setObject(setterGetParam(index), null, JavaType.OBJECT, JDBCType.of(jdbcType), null, null, false, index, null);
loggerExternal.exiting(getClassNameLogging(), "setNull");
}
final void setObjectNoType(int index,
Object obj,
boolean forceEncrypt) throws SQLServerException {
// Default to the JDBC type of the parameter, determined by a previous setter call or through registerOutParam.
// This avoids repreparing unnecessarily for null values.
Parameter param = setterGetParam(index);
JDBCType targetJDBCType = param.getJdbcType();
String tvpName = null;
if (null == obj) {
// If the JDBC type of the parameter is UNKNOWN (i.e. this is the first time the parameter is being set),
// then use a JDBC type the converts to most server types with a null value.
if (JDBCType.UNKNOWN == targetJDBCType)
targetJDBCType = JDBCType.CHAR;
setObject(param, null, JavaType.OBJECT, targetJDBCType, null, null, forceEncrypt, index, null);
}
else {
JavaType javaType = JavaType.of(obj);
if (JavaType.TVP == javaType) {
tvpName = getTVPNameIfNull(index, null); // will return null if called from preparedStatement
if ((null == tvpName) && (obj instanceof ResultSet)) {
throw new SQLServerException(SQLServerException.getErrString("R_TVPnotWorkWithSetObjectResultSet"), null);
}
}
targetJDBCType = javaType.getJDBCType(SSType.UNKNOWN, targetJDBCType);
if (JDBCType.UNKNOWN == targetJDBCType) {
if (obj instanceof java.util.UUID) {
javaType = JavaType.STRING;
targetJDBCType = JDBCType.GUID;
}
}
setObject(param, obj, javaType, targetJDBCType, null, null, forceEncrypt, index, tvpName);
}
}
public final void setObject(int index,
Object obj) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setObject", new Object[] {index, obj});
checkClosed();
setObjectNoType(index, obj, false);
loggerExternal.exiting(getClassNameLogging(), "setObject");
}
public final void setObject(int n,
Object obj,
int jdbcType) throws SQLServerException {
String tvpName = null;
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setObject", new Object[] {n, obj, jdbcType});
checkClosed();
if (microsoft.sql.Types.STRUCTURED == jdbcType)
tvpName = getTVPNameIfNull(n, null);
setObject(setterGetParam(n), obj, JavaType.of(obj), JDBCType.of(jdbcType), null, null, false, n, tvpName);
loggerExternal.exiting(getClassNameLogging(), "setObject");
}
public final void setObject(int parameterIndex,
Object x,
int targetSqlType,
int scaleOrLength) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setObject", new Object[] {parameterIndex, x, targetSqlType, scaleOrLength});
checkClosed();
// scaleOrLength - for java.sql.Types.DECIMAL, java.sql.Types.NUMERIC or temporal types,
// this is the number of digits after the decimal point. For Java Object types
// InputStream and Reader, this is the length of the data in the stream or reader.
// For all other types, this value will be ignored.
setObject(setterGetParam(parameterIndex), x, JavaType.of(x), JDBCType.of(targetSqlType),
(java.sql.Types.NUMERIC == targetSqlType || java.sql.Types.DECIMAL == targetSqlType || java.sql.Types.TIMESTAMP == targetSqlType
|| java.sql.Types.TIME == targetSqlType || microsoft.sql.Types.DATETIMEOFFSET == targetSqlType
|| InputStream.class.isInstance(x) || Reader.class.isInstance(x)) ? scaleOrLength : null,
null, false, parameterIndex, null);
loggerExternal.exiting(getClassNameLogging(), "setObject");
}
/**
*
* Sets the value of the designated parameter with the given object.
*
*
* The given Java object will be converted to the given targetSqlType before being sent to the database.
*
* If the object has a custom mapping (is of a class implementing the interface SQLData
), the JDBC driver should call the method
* SQLData.writeSQL
to write it to the SQL data stream. If, on the other hand, the object is of a class implementing
* Ref
, Blob
, Clob
, NClob
, Struct
, java.net.URL
, or
* Array
, the driver should pass it to the database as a value of the corresponding SQL type.
*
*
* Note that this method may be used to pass database-specific abstract data types.
*
* @param parameterIndex
* the first parameter is 1, the second is 2, ...
* @param x
* the object containing the input parameter value
* @param targetSqlType
* the SQL type (as defined in java.sql.Types) to be sent to the database. The scale argument may further qualify this type.
* @param precision
* the precision of the column
* @param scale
* scale of the column
* @throws SQLServerException
* when an error occurs
*/
public final void setObject(int parameterIndex,
Object x,
int targetSqlType,
Integer precision,
int scale) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setObject", new Object[] {parameterIndex, x, targetSqlType, precision, scale});
checkClosed();
// scale - for java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types,
// this is the number of digits after the decimal point. For Java Object types
// InputStream and Reader, this is the length of the data in the stream or reader.
// For all other types, this value will be ignored.
setObject(setterGetParam(parameterIndex), x, JavaType.of(x),
JDBCType.of(targetSqlType), (java.sql.Types.NUMERIC == targetSqlType || java.sql.Types.DECIMAL == targetSqlType
|| InputStream.class.isInstance(x) || Reader.class.isInstance(x)) ? scale : null,
precision, false, parameterIndex, null);
loggerExternal.exiting(getClassNameLogging(), "setObject");
}
/**
*
* Sets the value of the designated parameter with the given object.
*
*
* The given Java object will be converted to the given targetSqlType before being sent to the database.
*
* If the object has a custom mapping (is of a class implementing the interface SQLData
), the JDBC driver should call the method
* SQLData.writeSQL
to write it to the SQL data stream. If, on the other hand, the object is of a class implementing
* Ref
, Blob
, Clob
, NClob
, Struct
, java.net.URL
, or
* Array
, the driver should pass it to the database as a value of the corresponding SQL type.
*
*
* Note that this method may be used to pass database-specific abstract data types.
*
* @param parameterIndex
* the first parameter is 1, the second is 2, ...
* @param x
* the object containing the input parameter value
* @param targetSqlType
* the SQL type (as defined in java.sql.Types) to be sent to the database. The scale argument may further qualify this type.
* @param precision
* the precision of the column
* @param scale
* scale of the column
* @param forceEncrypt
* If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always
* Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force
* encryption on parameters.
* @throws SQLServerException
* when an error occurs
*/
public final void setObject(int parameterIndex,
Object x,
int targetSqlType,
Integer precision,
int scale,
boolean forceEncrypt) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setObject",
new Object[] {parameterIndex, x, targetSqlType, precision, scale, forceEncrypt});
checkClosed();
// scale - for java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types,
// this is the number of digits after the decimal point. For Java Object types
// InputStream and Reader, this is the length of the data in the stream or reader.
// For all other types, this value will be ignored.
setObject(setterGetParam(parameterIndex), x, JavaType.of(x),
JDBCType.of(targetSqlType), (java.sql.Types.NUMERIC == targetSqlType || java.sql.Types.DECIMAL == targetSqlType
|| InputStream.class.isInstance(x) || Reader.class.isInstance(x)) ? scale : null,
precision, forceEncrypt, parameterIndex, null);
loggerExternal.exiting(getClassNameLogging(), "setObject");
}
final void setObject(Parameter param,
Object obj,
JavaType javaType,
JDBCType jdbcType,
Integer scale,
Integer precision,
boolean forceEncrypt,
int parameterIndex,
String tvpName) throws SQLServerException {
assert JDBCType.UNKNOWN != jdbcType;
// For non-null values, infer the object's JDBC type from its Java type
// and check whether the object is settable via the specified JDBC type.
if ((null != obj) || (JavaType.TVP == javaType)) {
// Returns the static JDBC type that is assigned to this java type (the parameters has no effect)
JDBCType objectJDBCType = javaType.getJDBCType(SSType.UNKNOWN, jdbcType);
// Check convertability of the value to the desired JDBC type.
if (!objectJDBCType.convertsTo(jdbcType))
DataTypes.throwConversionError(objectJDBCType.toString(), jdbcType.toString());
StreamSetterArgs streamSetterArgs = null;
switch (javaType) {
case READER:
streamSetterArgs = new StreamSetterArgs(StreamType.CHARACTER, DataTypes.UNKNOWN_STREAM_LENGTH);
break;
case INPUTSTREAM:
streamSetterArgs = new StreamSetterArgs(jdbcType.isTextual() ? StreamType.CHARACTER : StreamType.BINARY,
DataTypes.UNKNOWN_STREAM_LENGTH);
break;
case SQLXML:
streamSetterArgs = new StreamSetterArgs(StreamType.SQLXML, DataTypes.UNKNOWN_STREAM_LENGTH);
break;
default:
// Do nothing
break;
}
// typeInfo is set as null
param.setValue(jdbcType, obj, javaType, streamSetterArgs, null, precision, scale, connection, forceEncrypt, stmtColumnEncriptionSetting,
parameterIndex, userSQL, tvpName);
}
// For null values, use the specified JDBC type directly, with the exception
// of unsupported JDBC types, which are mapped to BINARY so that they are minimally supported.
else {
assert JavaType.OBJECT == javaType;
if (jdbcType.isUnsupported())
jdbcType = JDBCType.BINARY;
// typeInfo is set as null
param.setValue(jdbcType, null, JavaType.OBJECT, null, null, precision, scale, connection, false, stmtColumnEncriptionSetting,
parameterIndex, userSQL, tvpName);
}
}
public final void setShort(int index,
short x) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setShort", new Object[] {index, x});
checkClosed();
setValue(index, JDBCType.SMALLINT, x, JavaType.SHORT, false);
loggerExternal.exiting(getClassNameLogging(), "setShort");
}
/**
* Sets the designated parameter to the given Java short
value. The driver converts this to an SQL SMALLINT
value when
* it sends it to the database.
*
* @param index
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @param forceEncrypt
* If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always
* Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force
* encryption on parameters.
* @throws SQLServerException
* when an error occurs
*/
public final void setShort(int index,
short x,
boolean forceEncrypt) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setShort", new Object[] {index, x, forceEncrypt});
checkClosed();
setValue(index, JDBCType.SMALLINT, x, JavaType.SHORT, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setShort");
}
public final void setString(int index,
String str) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setString", new Object[] {index, str});
checkClosed();
setValue(index, JDBCType.VARCHAR, str, JavaType.STRING, false);
loggerExternal.exiting(getClassNameLogging(), "setString");
}
/**
* Sets the designated parameter to the given Java String
value. The driver converts this to an SQL VARCHAR
or
* LONGVARCHAR
value (depending on the argument's size relative to the driver's limits on VARCHAR
values) when it sends
* it to the database.
*
* @param index
* the first parameter is 1, the second is 2, ...
* @param str
* the parameter value
* @param forceEncrypt
* If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always
* Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force
* encryption on parameters.
* @throws SQLServerException
* when an error occurs
*/
public final void setString(int index,
String str,
boolean forceEncrypt) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setString", new Object[] {index, str, forceEncrypt});
checkClosed();
setValue(index, JDBCType.VARCHAR, str, JavaType.STRING, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setString");
}
public final void setNString(int parameterIndex,
String value) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setNString", new Object[] {parameterIndex, value});
checkClosed();
setValue(parameterIndex, JDBCType.NVARCHAR, value, JavaType.STRING, false);
loggerExternal.exiting(getClassNameLogging(), "setNString");
}
/**
* Sets the designated parameter to the given String
object. The driver converts this to a SQL NCHAR
or
* NVARCHAR
or LONGNVARCHAR
value (depending on the argument's size relative to the driver's limits on
* NVARCHAR
values) when it sends it to the database.
*
* @param parameterIndex
* of the first parameter is 1, the second is 2, ...
* @param value
* the parameter value
* @param forceEncrypt
* If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always
* Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force
* encryption on parameters.
* @throws SQLException
* when an error occurs
*/
public final void setNString(int parameterIndex,
String value,
boolean forceEncrypt) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setNString", new Object[] {parameterIndex, value, forceEncrypt});
checkClosed();
setValue(parameterIndex, JDBCType.NVARCHAR, value, JavaType.STRING, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setNString");
}
public final void setTime(int n,
java.sql.Time x) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setTime", new Object[] {n, x});
checkClosed();
setValue(n, JDBCType.TIME, x, JavaType.TIME, false);
loggerExternal.exiting(getClassNameLogging(), "setTime");
}
/**
* Sets the designated parameter to the given java.sql.Time
value
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @param scale
* the scale of the column
* @throws SQLServerException
* when an error occurs
*/
public final void setTime(int n,
java.sql.Time x,
int scale) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setTime", new Object[] {n, x, scale});
checkClosed();
setValue(n, JDBCType.TIME, x, JavaType.TIME, null, scale, false);
loggerExternal.exiting(getClassNameLogging(), "setTime");
}
/**
* Sets the designated parameter to the given java.sql.Time
value
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @param scale
* the scale of the column
* @param forceEncrypt
* If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always
* Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force
* encryption on parameters.
* @throws SQLServerException
* when an error occurs
*/
public final void setTime(int n,
java.sql.Time x,
int scale,
boolean forceEncrypt) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setTime", new Object[] {n, x, scale, forceEncrypt});
checkClosed();
setValue(n, JDBCType.TIME, x, JavaType.TIME, null, scale, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setTime");
}
public final void setTimestamp(int n,
java.sql.Timestamp x) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setTimestamp", new Object[] {n, x});
checkClosed();
setValue(n, JDBCType.TIMESTAMP, x, JavaType.TIMESTAMP, false);
loggerExternal.exiting(getClassNameLogging(), "setTimestamp");
}
/**
* Sets the designated parameter to the given java.sql.Timestamp
value
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @param scale
* the scale of the column
* @throws SQLServerException
* when an error occurs
*/
public final void setTimestamp(int n,
java.sql.Timestamp x,
int scale) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setTimestamp", new Object[] {n, x, scale});
checkClosed();
setValue(n, JDBCType.TIMESTAMP, x, JavaType.TIMESTAMP, null, scale, false);
loggerExternal.exiting(getClassNameLogging(), "setTimestamp");
}
/**
* Sets the designated parameter to the given java.sql.Timestamp
value
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @param scale
* the scale of the column
* @param forceEncrypt
* If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always
* Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force
* encryption on parameters.
* @throws SQLServerException
* when an error occurs
*/
public final void setTimestamp(int n,
java.sql.Timestamp x,
int scale,
boolean forceEncrypt) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setTimestamp", new Object[] {n, x, scale, forceEncrypt});
checkClosed();
setValue(n, JDBCType.TIMESTAMP, x, JavaType.TIMESTAMP, null, scale, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setTimestamp");
}
/**
* Sets the designated parameter to the given microsoft.sql.DatetimeOffset
value
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @throws SQLException
* if an error occurs.
*/
public final void setDateTimeOffset(int n,
microsoft.sql.DateTimeOffset x) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setDateTimeOffset", new Object[] {n, x});
checkClosed();
setValue(n, JDBCType.DATETIMEOFFSET, x, JavaType.DATETIMEOFFSET, false);
loggerExternal.exiting(getClassNameLogging(), "setDateTimeOffset");
}
/**
* Sets the designated parameter to the given microsoft.sql.DatetimeOffset
value
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @param scale
* the scale of the column
* @throws SQLException
* when an error occurs
*/
public final void setDateTimeOffset(int n,
microsoft.sql.DateTimeOffset x,
int scale) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setDateTimeOffset", new Object[] {n, x, scale});
checkClosed();
setValue(n, JDBCType.DATETIMEOFFSET, x, JavaType.DATETIMEOFFSET, null, scale, false);
loggerExternal.exiting(getClassNameLogging(), "setDateTimeOffset");
}
/**
* Sets the designated parameter to the given microsoft.sql.DatetimeOffset
value
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @param scale
* the scale of the column
* @param forceEncrypt
* If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always
* Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force
* encryption on parameters.
* @throws SQLException
* when an error occurs
*/
public final void setDateTimeOffset(int n,
microsoft.sql.DateTimeOffset x,
int scale,
boolean forceEncrypt) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setDateTimeOffset", new Object[] {n, x, scale, forceEncrypt});
checkClosed();
setValue(n, JDBCType.DATETIMEOFFSET, x, JavaType.DATETIMEOFFSET, null, scale, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setDateTimeOffset");
}
public final void setDate(int n,
java.sql.Date x) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setDate", new Object[] {n, x});
checkClosed();
setValue(n, JDBCType.DATE, x, JavaType.DATE, false);
loggerExternal.exiting(getClassNameLogging(), "setDate");
}
/**
* Sets the designated parameter to the given java.sql.Timestamp
value
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @throws SQLServerException
* when an error occurs
*/
public final void setDateTime(int n,
java.sql.Timestamp x) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setDateTime", new Object[] {n, x});
checkClosed();
setValue(n, JDBCType.DATETIME, x, JavaType.TIMESTAMP, false);
loggerExternal.exiting(getClassNameLogging(), "setDateTime");
}
/**
* Sets the designated parameter to the given java.sql.Timestamp
value
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @param forceEncrypt
* If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always
* Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force
* encryption on parameters.
* @throws SQLServerException
* when an error occurs
*/
public final void setDateTime(int n,
java.sql.Timestamp x,
boolean forceEncrypt) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setDateTime", new Object[] {n, x, forceEncrypt});
checkClosed();
setValue(n, JDBCType.DATETIME, x, JavaType.TIMESTAMP, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setDateTime");
}
/**
* Sets the designated parameter to the given java.sql.Timestamp
value
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @throws SQLServerException
* when an error occurs
*/
public final void setSmallDateTime(int n,
java.sql.Timestamp x) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setSmallDateTime", new Object[] {n, x});
checkClosed();
setValue(n, JDBCType.SMALLDATETIME, x, JavaType.TIMESTAMP, false);
loggerExternal.exiting(getClassNameLogging(), "setSmallDateTime");
}
/**
* Sets the designated parameter to the given java.sql.Timestamp
value
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @param forceEncrypt
* If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always
* Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force
* encryption on parameters.
* @throws SQLServerException
* when an error occurs
*/
public final void setSmallDateTime(int n,
java.sql.Timestamp x,
boolean forceEncrypt) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setSmallDateTime", new Object[] {n, x, forceEncrypt});
checkClosed();
setValue(n, JDBCType.SMALLDATETIME, x, JavaType.TIMESTAMP, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setSmallDateTime");
}
/**
* Populates a table valued parameter with a data table
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param tvpName
* the name of the table valued parameter
* @param tvpDataTable
* the source datatable object
* @throws SQLServerException
* when an error occurs
*/
public final void setStructured(int n,
String tvpName,
SQLServerDataTable tvpDataTable) throws SQLServerException {
tvpName = getTVPNameIfNull(n, tvpName);
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setStructured", new Object[] {n, tvpName, tvpDataTable});
checkClosed();
setValue(n, JDBCType.TVP, tvpDataTable, JavaType.TVP, tvpName);
loggerExternal.exiting(getClassNameLogging(), "setStructured");
}
/**
* Populates a table valued parameter with a data table
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param tvpName
* the name of the table valued parameter
* @param tvpResultSet
* the source resultset object
* @throws SQLServerException
* when an error occurs
*/
public final void setStructured(int n,
String tvpName,
ResultSet tvpResultSet) throws SQLServerException {
tvpName = getTVPNameIfNull(n, tvpName);
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setStructured", new Object[] {n, tvpName, tvpResultSet});
checkClosed();
setValue(n, JDBCType.TVP, tvpResultSet, JavaType.TVP, tvpName);
loggerExternal.exiting(getClassNameLogging(), "setStructured");
}
/**
* Populates a table valued parameter with a data table
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param tvpName
* the name of the table valued parameter
* @param tvpBulkRecord
* an ISQLServerDataRecord object
* @throws SQLServerException
* when an error occurs
*/
public final void setStructured(int n,
String tvpName,
ISQLServerDataRecord tvpBulkRecord) throws SQLServerException {
tvpName = getTVPNameIfNull(n, tvpName);
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setStructured", new Object[] {n, tvpName, tvpBulkRecord});
checkClosed();
setValue(n, JDBCType.TVP, tvpBulkRecord, JavaType.TVP, tvpName);
loggerExternal.exiting(getClassNameLogging(), "setStructured");
}
String getTVPNameIfNull(int n,
String tvpName) throws SQLServerException {
if ((null == tvpName) || (0 == tvpName.length())) {
// Check if the CallableStatement/PreparedStatement is a stored procedure call
if(null != this.procedureName) {
SQLServerParameterMetaData pmd = (SQLServerParameterMetaData) this.getParameterMetaData();
pmd.isTVP = true;
if (!pmd.procedureIsFound) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_StoredProcedureNotFound"));
Object[] msgArgs = {this.procedureName};
SQLServerException.makeFromDriverError(connection, pmd, form.format(msgArgs), null, false);
}
try {
String tvpNameWithoutSchema = pmd.getParameterTypeName(n);
String tvpSchema = pmd.getTVPSchemaFromStoredProcedure(n);
if (null != tvpSchema) {
tvpName = "[" + tvpSchema + "].[" + tvpNameWithoutSchema + "]";
}
else {
tvpName = tvpNameWithoutSchema;
}
}
catch (SQLException e) {
throw new SQLServerException(SQLServerException.getErrString("R_metaDataErrorForParameter"), null, 0, e);
}
}
}
return tvpName;
}
@Deprecated
public final void setUnicodeStream(int n,
java.io.InputStream x,
int length) throws SQLException {
NotImplemented();
}
public final void addBatch() throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "addBatch");
checkClosed();
// Create the list of batch parameter values first time through
if (batchParamValues == null)
batchParamValues = new ArrayList();
final int numParams = inOutParam.length;
Parameter paramValues[] = new Parameter[numParams];
for (int i = 0; i < numParams; i++)
paramValues[i] = inOutParam[i].cloneForBatch();
batchParamValues.add(paramValues);
loggerExternal.exiting(getClassNameLogging(), "addBatch");
}
/* L0 */ public final void clearBatch() throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "clearBatch");
checkClosed();
batchParamValues = null;
loggerExternal.exiting(getClassNameLogging(), "clearBatch");
}
public int[] executeBatch() throws SQLServerException, BatchUpdateException {
loggerExternal.entering(getClassNameLogging(), "executeBatch");
if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) {
loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
}
checkClosed();
discardLastExecutionResults();
int updateCounts[];
if (batchParamValues == null)
updateCounts = new int[0];
else
try {
// From the JDBC spec, section 9.1.4 - Making Batch Updates:
// The CallableStatement.executeBatch method (inherited from PreparedStatement) will
// throw a BatchUpdateException if the stored procedure returns anything other than an
// update count or takes OUT or INOUT parameters.
//
// Non-update count results (e.g. ResultSets) are treated as individual batch errors
// when they are encountered in the response.
//
// OUT and INOUT parameter checking is done here, before executing the batch. If any
// OUT or INOUT are present, the entire batch fails.
for (int batch = 0; batch < batchParamValues.size(); ++batch) {
Parameter paramValues[] = batchParamValues.get(batch);
for (int param = 0; param < paramValues.length; ++param) {
if (paramValues[param].isOutput()) {
throw new BatchUpdateException(SQLServerException.getErrString("R_outParamsNotPermittedinBatch"), null, 0, null);
}
}
}
PrepStmtBatchExecCmd batchCommand = new PrepStmtBatchExecCmd(this);
executeStatement(batchCommand);
updateCounts = new int[batchCommand.updateCounts.length];
for (int i = 0; i < batchCommand.updateCounts.length; ++i)
updateCounts[i] = (int) batchCommand.updateCounts[i];
// Transform the SQLException into a BatchUpdateException with the update counts.
if (null != batchCommand.batchException) {
throw new BatchUpdateException(batchCommand.batchException.getMessage(), batchCommand.batchException.getSQLState(),
batchCommand.batchException.getErrorCode(), updateCounts);
}
}
finally {
batchParamValues = null;
}
loggerExternal.exiting(getClassNameLogging(), "executeBatch", updateCounts);
return updateCounts;
}
public long[] executeLargeBatch() throws SQLServerException, BatchUpdateException {
DriverJDBCVersion.checkSupportsJDBC42();
loggerExternal.entering(getClassNameLogging(), "executeLargeBatch");
if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) {
loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
}
checkClosed();
discardLastExecutionResults();
long updateCounts[];
if (batchParamValues == null)
updateCounts = new long[0];
else
try {
// From the JDBC spec, section 9.1.4 - Making Batch Updates:
// The CallableStatement.executeBatch method (inherited from PreparedStatement) will
// throw a BatchUpdateException if the stored procedure returns anything other than an
// update count or takes OUT or INOUT parameters.
//
// Non-update count results (e.g. ResultSets) are treated as individual batch errors
// when they are encountered in the response.
//
// OUT and INOUT parameter checking is done here, before executing the batch. If any
// OUT or INOUT are present, the entire batch fails.
for (int batch = 0; batch < batchParamValues.size(); ++batch) {
Parameter paramValues[] = batchParamValues.get(batch);
for (int param = 0; param < paramValues.length; ++param) {
if (paramValues[param].isOutput()) {
throw new BatchUpdateException(SQLServerException.getErrString("R_outParamsNotPermittedinBatch"), null, 0, null);
}
}
}
PrepStmtBatchExecCmd batchCommand = new PrepStmtBatchExecCmd(this);
executeStatement(batchCommand);
updateCounts = new long[batchCommand.updateCounts.length];
for (int i = 0; i < batchCommand.updateCounts.length; ++i)
updateCounts[i] = batchCommand.updateCounts[i];
// Transform the SQLException into a BatchUpdateException with the update counts.
if (null != batchCommand.batchException) {
DriverJDBCVersion.throwBatchUpdateException(batchCommand.batchException, updateCounts);
}
}
finally {
batchParamValues = null;
}
loggerExternal.exiting(getClassNameLogging(), "executeLargeBatch", updateCounts);
return updateCounts;
}
private final class PrepStmtBatchExecCmd extends TDSCommand {
private final SQLServerPreparedStatement stmt;
SQLServerException batchException;
long updateCounts[];
PrepStmtBatchExecCmd(SQLServerPreparedStatement stmt) {
super(stmt.toString() + " executeBatch", queryTimeout);
this.stmt = stmt;
}
final boolean doExecute() throws SQLServerException {
stmt.doExecutePreparedStatementBatch(this);
return true;
}
final void processResponse(TDSReader tdsReader) throws SQLServerException {
ensureExecuteResultsReader(tdsReader);
processExecuteResults();
}
}
final void doExecutePreparedStatementBatch(PrepStmtBatchExecCmd batchCommand) throws SQLServerException {
executeMethod = EXECUTE_BATCH;
batchCommand.batchException = null;
final int numBatches = batchParamValues.size();
batchCommand.updateCounts = new long[numBatches];
for (int i = 0; i < numBatches; i++)
batchCommand.updateCounts[i] = Statement.EXECUTE_FAILED; // Init to unknown status EXECUTE_FAILED
int numBatchesPrepared = 0;
int numBatchesExecuted = 0;
Vector cryptoMetaBatch = new Vector();
if (isSelect(userSQL)) {
SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_selectNotPermittedinBatch"), null, true);
}
// Make sure any previous maxRows limitation on the connection is removed.
connection.setMaxRows(0);
if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) {
loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
}
// Create the parameter array that we'll use for all the items in this batch.
Parameter[] batchParam = new Parameter[inOutParam.length];
TDSWriter tdsWriter = null;
while (numBatchesExecuted < numBatches) {
// Fill in the parameter values for this batch
Parameter paramValues[] = batchParamValues.get(numBatchesPrepared);
assert paramValues.length == batchParam.length;
for (int i = 0; i < paramValues.length; i++)
batchParam[i] = paramValues[i];
boolean hasExistingTypeDefinitions = preparedTypeDefinitions != null;
boolean hasNewTypeDefinitions = buildPreparedStrings(batchParam, false);
// Get the encryption metadata for the first batch only.
if ((0 == numBatchesExecuted) && (Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, connection)) && (0 < batchParam.length)
&& !isInternalEncryptionQuery && !encryptionMetadataIsRetrieved) {
getParameterEncryptionMetadata(batchParam);
// fix an issue when inserting unicode into non-encrypted nchar column using setString() and AE is on on Connection
buildPreparedStrings(batchParam, true);
// Save the crypto metadata retrieved for the first batch. We will re-use these for the rest of the batches.
for (int i = 0; i < batchParam.length; i++) {
cryptoMetaBatch.add(batchParam[i].cryptoMeta);
}
}
// Update the crypto metadata for this batch.
if (0 < numBatchesExecuted) {
// cryptoMetaBatch will be empty for non-AE connections/statements.
for (int i = 0; i < cryptoMetaBatch.size(); i++) {
batchParam[i].cryptoMeta = cryptoMetaBatch.get(i);
}
}
// Retry execution if existing handle could not be re-used.
for(int attempt = 1; attempt <= 2; ++attempt) {
try {
// Re-use handle if available, requires parameter definitions which are not available until here.
if (reuseCachedHandle(hasNewTypeDefinitions, 1 < attempt)) {
hasNewTypeDefinitions = false;
}
if (numBatchesExecuted < numBatchesPrepared) {
// assert null != tdsWriter;
tdsWriter.writeByte((byte) nBatchStatementDelimiter);
}
else {
resetForReexecute();
tdsWriter = batchCommand.startRequest(TDS.PKT_RPC);
}
// If we have to (re)prepare the statement then we must execute it so
// that we get back a (new) prepared statement handle to use to
// execute additional batches.
//
// We must always prepare the statement the first time through.
// But we may also need to reprepare the statement if, for example,
// the size of a batch's string parameter values changes such
// that repreparation is necessary.
++numBatchesPrepared;
if (doPrepExec(tdsWriter, batchParam, hasNewTypeDefinitions, hasExistingTypeDefinitions) || numBatchesPrepared == numBatches) {
ensureExecuteResultsReader(batchCommand.startResponse(getIsResponseBufferingAdaptive()));
boolean retry = false;
while (numBatchesExecuted < numBatchesPrepared) {
// NOTE:
// When making changes to anything below, consider whether similar changes need
// to be made to Statement batch execution.
startResults();
try {
// Get the first result from the batch. If there is no result for this batch
// then bail, leaving EXECUTE_FAILED in the current and remaining slots of
// the update count array.
if (!getNextResult())
return;
// If the result is a ResultSet (rather than an update count) then throw an
// exception for this result. The exception gets caught immediately below and
// translated into (or added to) a BatchUpdateException.
if (null != resultSet) {
SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_resultsetGeneratedForUpdate"),
null, false);
}
}
catch (SQLServerException e) {
// If the failure was severe enough to close the connection or roll back a
// manual transaction, then propagate the error up as a SQLServerException
// now, rather than continue with the batch.
if (connection.isSessionUnAvailable() || connection.rolledBackTransaction())
throw e;
// Retry if invalid handle exception.
if (retryBasedOnFailedReuseOfCachedHandle(e, attempt)) {
//reset number of batches prepare
numBatchesPrepared = numBatchesExecuted;
retry = true;
break;
}
// Otherwise, the connection is OK and the transaction is still intact,
// so just record the failure for the particular batch item.
updateCount = Statement.EXECUTE_FAILED;
if (null == batchCommand.batchException)
batchCommand.batchException = e;
}
// In batch execution, we have a special update count
// to indicate that no information was returned
batchCommand.updateCounts[numBatchesExecuted] = (-1 == updateCount) ? Statement.SUCCESS_NO_INFO : updateCount;
processBatch();
numBatchesExecuted++;
}
if(retry)
continue;
// Only way to proceed with preparing the next set of batches is if
// we successfully executed the previously prepared set.
assert numBatchesExecuted == numBatchesPrepared;
}
}
catch(SQLException e) {
if (retryBasedOnFailedReuseOfCachedHandle(e, attempt)) {
// Reset number of batches prepared.
numBatchesPrepared = numBatchesExecuted;
continue;
}
else
throw e;
}
break;
}
}
}
public final void setCharacterStream(int parameterIndex,
Reader reader) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setCharacterStream", new Object[] {parameterIndex, reader});
checkClosed();
setStream(parameterIndex, StreamType.CHARACTER, reader, JavaType.READER, DataTypes.UNKNOWN_STREAM_LENGTH);
loggerExternal.exiting(getClassNameLogging(), "setCharacterStream");
}
public final void setCharacterStream(int n,
java.io.Reader reader,
int length) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setCharacterStream", new Object[] {n, reader, length});
checkClosed();
setStream(n, StreamType.CHARACTER, reader, JavaType.READER, length);
loggerExternal.exiting(getClassNameLogging(), "setCharacterStream");
}
public final void setCharacterStream(int parameterIndex,
Reader reader,
long length) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setCharacterStream", new Object[] {parameterIndex, reader, length});
checkClosed();
setStream(parameterIndex, StreamType.CHARACTER, reader, JavaType.READER, length);
loggerExternal.exiting(getClassNameLogging(), "setCharacterStream");
}
public final void setNCharacterStream(int parameterIndex,
Reader value) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setNCharacterStream", new Object[] {parameterIndex, value});
checkClosed();
setStream(parameterIndex, StreamType.NCHARACTER, value, JavaType.READER, DataTypes.UNKNOWN_STREAM_LENGTH);
loggerExternal.exiting(getClassNameLogging(), "setNCharacterStream");
}
public final void setNCharacterStream(int parameterIndex,
Reader value,
long length) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setNCharacterStream", new Object[] {parameterIndex, value, length});
checkClosed();
setStream(parameterIndex, StreamType.NCHARACTER, value, JavaType.READER, length);
loggerExternal.exiting(getClassNameLogging(), "setNCharacterStream");
}
/* L0 */ public final void setRef(int i,
java.sql.Ref x) throws SQLServerException {
NotImplemented();
}
public final void setBlob(int i,
java.sql.Blob x) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setBlob", new Object[] {i, x});
checkClosed();
setValue(i, JDBCType.BLOB, x, JavaType.BLOB, false);
loggerExternal.exiting(getClassNameLogging(), "setBlob");
}
public final void setBlob(int parameterIndex,
InputStream inputStream) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setBlob", new Object[] {parameterIndex, inputStream});
checkClosed();
setStream(parameterIndex, StreamType.BINARY, inputStream, JavaType.INPUTSTREAM, DataTypes.UNKNOWN_STREAM_LENGTH);
loggerExternal.exiting(getClassNameLogging(), "setBlob");
}
public final void setBlob(int parameterIndex,
InputStream inputStream,
long length) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setBlob", new Object[] {parameterIndex, inputStream, length});
checkClosed();
setStream(parameterIndex, StreamType.BINARY, inputStream, JavaType.INPUTSTREAM, length);
loggerExternal.exiting(getClassNameLogging(), "setBlob");
}
public final void setClob(int parameterIndex,
java.sql.Clob clobValue) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setClob", new Object[] {parameterIndex, clobValue});
checkClosed();
setValue(parameterIndex, JDBCType.CLOB, clobValue, JavaType.CLOB, false);
loggerExternal.exiting(getClassNameLogging(), "setClob");
}
public final void setClob(int parameterIndex,
Reader reader) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setClob", new Object[] {parameterIndex, reader});
checkClosed();
setStream(parameterIndex, StreamType.CHARACTER, reader, JavaType.READER, DataTypes.UNKNOWN_STREAM_LENGTH);
loggerExternal.exiting(getClassNameLogging(), "setClob");
}
public final void setClob(int parameterIndex,
Reader reader,
long length) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setClob", new Object[] {parameterIndex, reader, length});
checkClosed();
setStream(parameterIndex, StreamType.CHARACTER, reader, JavaType.READER, length);
loggerExternal.exiting(getClassNameLogging(), "setClob");
}
public final void setNClob(int parameterIndex,
NClob value) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setNClob", new Object[] {parameterIndex, value});
checkClosed();
setValue(parameterIndex, JDBCType.NCLOB, value, JavaType.NCLOB, false);
loggerExternal.exiting(getClassNameLogging(), "setNClob");
}
public final void setNClob(int parameterIndex,
Reader reader) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setNClob", new Object[] {parameterIndex, reader});
checkClosed();
setStream(parameterIndex, StreamType.NCHARACTER, reader, JavaType.READER, DataTypes.UNKNOWN_STREAM_LENGTH);
loggerExternal.exiting(getClassNameLogging(), "setNClob");
}
public final void setNClob(int parameterIndex,
Reader reader,
long length) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setNClob", new Object[] {parameterIndex, reader, length});
checkClosed();
setStream(parameterIndex, StreamType.NCHARACTER, reader, JavaType.READER, length);
loggerExternal.exiting(getClassNameLogging(), "setNClob");
}
/* L0 */ public final void setArray(int i,
java.sql.Array x) throws SQLServerException {
NotImplemented();
}
public final void setDate(int n,
java.sql.Date x,
java.util.Calendar cal) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setDate", new Object[] {n, x, cal});
checkClosed();
setValue(n, JDBCType.DATE, x, JavaType.DATE, cal, false);
loggerExternal.exiting(getClassNameLogging(), "setDate");
}
/**
* Sets the designated parameter to the given java.sql.Date
value, using the given Calendar
object. The driver uses the
* Calendar
object to construct an SQL DATE
value, which the driver then sends to the database. With a
* Calendar
object, the driver can calculate the date taking into account a custom timezone. If no Calendar
object is
* specified, the driver uses the default timezone, which is that of the virtual machine running the application.
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @param cal
* the Calendar
object the driver will use to construct the date
* @param forceEncrypt
* If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always
* Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force
* encryption on parameters.
* @throws SQLServerException
* when an error occurs
*/
public final void setDate(int n,
java.sql.Date x,
java.util.Calendar cal,
boolean forceEncrypt) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setDate", new Object[] {n, x, cal, forceEncrypt});
checkClosed();
setValue(n, JDBCType.DATE, x, JavaType.DATE, cal, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setDate");
}
public final void setTime(int n,
java.sql.Time x,
java.util.Calendar cal) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setTime", new Object[] {n, x, cal});
checkClosed();
setValue(n, JDBCType.TIME, x, JavaType.TIME, cal, false);
loggerExternal.exiting(getClassNameLogging(), "setTime");
}
/**
* Sets the designated parameter to the given java.sql.Time
value. The driver converts this to an SQL TIME
value when it
* sends it to the database.
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @param cal
* the Calendar
object the driver will use to construct the date
* @param forceEncrypt
* If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always
* Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force
* encryption on parameters.
* @throws SQLServerException
* when an error occurs
*/
public final void setTime(int n,
java.sql.Time x,
java.util.Calendar cal,
boolean forceEncrypt) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setTime", new Object[] {n, x, cal, forceEncrypt});
checkClosed();
setValue(n, JDBCType.TIME, x, JavaType.TIME, cal, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setTime");
}
public final void setTimestamp(int n,
java.sql.Timestamp x,
java.util.Calendar cal) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setTimestamp", new Object[] {n, x, cal});
checkClosed();
setValue(n, JDBCType.TIMESTAMP, x, JavaType.TIMESTAMP, cal, false);
loggerExternal.exiting(getClassNameLogging(), "setTimestamp");
}
/**
* Sets the designated parameter to the given java.sql.Timestamp
value. The driver converts this to an SQL TIMESTAMP
* value when it sends it to the database.
*
* @param n
* the first parameter is 1, the second is 2, ...
* @param x
* the parameter value
* @param cal
* the Calendar
object the driver will use to construct the date
* @param forceEncrypt
* If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always
* Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force
* encryption on parameters.
* @throws SQLServerException
* when an error occurs
*/
public final void setTimestamp(int n,
java.sql.Timestamp x,
java.util.Calendar cal,
boolean forceEncrypt) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setTimestamp", new Object[] {n, x, cal, forceEncrypt});
checkClosed();
setValue(n, JDBCType.TIMESTAMP, x, JavaType.TIMESTAMP, cal, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setTimestamp");
}
public final void setNull(int paramIndex,
int sqlType,
String typeName) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setNull", new Object[] {paramIndex, sqlType, typeName});
checkClosed();
if (microsoft.sql.Types.STRUCTURED == sqlType) {
setObject(setterGetParam(paramIndex), null, JavaType.TVP, JDBCType.of(sqlType), null, null, false, paramIndex, typeName);
}
else {
setObject(setterGetParam(paramIndex), null, JavaType.OBJECT, JDBCType.of(sqlType), null, null, false, paramIndex, typeName);
}
loggerExternal.exiting(getClassNameLogging(), "setNull");
}
/**
* Returns parameter metadata for the prepared statement.
*
* @param forceRefresh:
* If true the cache will not be used to retrieve the metadata.
*
* @return
* Per the description.
*
* @throws SQLServerException when an error occurs
*/
public final ParameterMetaData getParameterMetaData(boolean forceRefresh) throws SQLServerException {
SQLServerParameterMetaData pmd = this.connection.getCachedParameterMetadata(sqlTextCacheKey);
if (!forceRefresh && null != pmd) {
return pmd;
}
else {
loggerExternal.entering(getClassNameLogging(), "getParameterMetaData");
checkClosed();
pmd = new SQLServerParameterMetaData(this, userSQL);
connection.registerCachedParameterMetadata(sqlTextCacheKey, pmd);
loggerExternal.exiting(getClassNameLogging(), "getParameterMetaData", pmd);
return pmd;
}
}
/* JDBC 3.0 */
/* L3 */ public final ParameterMetaData getParameterMetaData() throws SQLServerException {
return getParameterMetaData(false);
}
/* L3 */ public final void setURL(int parameterIndex,
java.net.URL x) throws SQLServerException {
NotImplemented();
}
public final void setRowId(int parameterIndex,
RowId x) throws SQLException {
// Not implemented
throw new SQLFeatureNotSupportedException(SQLServerException.getErrString("R_notSupported"));
}
public final void setSQLXML(int parameterIndex,
SQLXML xmlObject) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setSQLXML", new Object[] {parameterIndex, xmlObject});
checkClosed();
setSQLXMLInternal(parameterIndex, xmlObject);
loggerExternal.exiting(getClassNameLogging(), "setSQLXML");
}
/* make sure we throw here */
/* L0 */ public final int executeUpdate(String sql) throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "executeUpdate", sql);
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_cannotTakeArgumentsPreparedOrCallable"));
Object[] msgArgs = {"executeUpdate()"};
throw new SQLServerException(this, form.format(msgArgs), null, 0, false);
}
/* L0 */ public final boolean execute(String sql) throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "execute", sql);
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_cannotTakeArgumentsPreparedOrCallable"));
Object[] msgArgs = {"execute()"};
throw new SQLServerException(this, form.format(msgArgs), null, 0, false);
}
/* L0 */ public final java.sql.ResultSet executeQuery(String sql) throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "executeQuery", sql);
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_cannotTakeArgumentsPreparedOrCallable"));
Object[] msgArgs = {"executeQuery()"};
throw new SQLServerException(this, form.format(msgArgs), null, 0, false);
}
/* L0 */ public void addBatch(String sql) throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "addBatch", sql);
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_cannotTakeArgumentsPreparedOrCallable"));
Object[] msgArgs = {"addBatch()"};
throw new SQLServerException(this, form.format(msgArgs), null, 0, false);
}
}