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.SQLTimeoutException;
import java.sql.SQLType;
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.CityHash128Key;
import com.microsoft.sqlserver.jdbc.SQLServerConnection.PreparedStatementHandle;
public class SQLServerPreparedStatement extends SQLServerStatement implements ISQLServerPreparedStatement {
private static final long serialVersionUID = -6292257029445685221L;
@SuppressWarnings("unused")
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;
private String preparedTypeDefinitions;
final String userSQL;
final int[] userSQLParamPositions;
private String preparedSQL;
private boolean isExecutedAtLeastOnce = false;
private PreparedStatementHandle cachedPreparedStatementHandle;
private CityHash128Key sqlTextCacheKey;
private ArrayList<String> parameterNames;
final boolean bReturnValueSyntax;
private boolean useFmtOnly = this.connection.getUseFmtOnly();
int outParamIndexAdjustment;
ArrayList<Parameter[]> batchParamValues;
private int prepStmtHandle = 0;
private SQLServerStatement internalStmt = null;
private void setPreparedStatementHandle(int handle) {
this.prepStmtHandle = handle;
}
private boolean useBulkCopyForBatchInsert;
@SuppressWarnings("unused")
private boolean getUseBulkCopyForBatchInsert() throws SQLServerException {
checkClosed();
return useBulkCopyForBatchInsert;
}
@SuppressWarnings("unused")
private void setUseBulkCopyForBatchInsert(boolean useBulkCopyForBatchInsert) throws SQLServerException {
checkClosed();
this.useBulkCopyForBatchInsert = useBulkCopyForBatchInsert;
}
@Override
public int getPreparedStatementHandle() throws SQLServerException {
checkClosed();
return prepStmtHandle;
}
private boolean hasPreparedStatementHandle() {
return 0 < prepStmtHandle;
}
private boolean resetPrepStmtHandle(boolean discardCurrentCacheItem) {
boolean statementPoolingUsed = null != cachedPreparedStatementHandle;
if (statementPoolingUsed) {
if (discardCurrentCacheItem)
cachedPreparedStatementHandle.setIsExplicitlyDiscarded();
}
prepStmtHandle = 0;
return statementPoolingUsed;
}
private boolean expectPrepStmtHandle = false;
private boolean encryptionMetadataIsRetrieved = false;
private String localUserSQL;
private Vector<CryptoMetadata> cryptoMetaBatch = new Vector<>();
String getClassNameInternal() {
return "SQLServerPreparedStatement";
}
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;
sqlTextCacheKey = new CityHash128Key(sql);
ParsedSQLCacheItem parsedSQL = getCachedParsedSQL(sqlTextCacheKey);
if (null != parsedSQL) {
if (null != connection && connection.isStatementPoolingEnabled()) {
isExecutedAtLeastOnce = true;
}
} else {
parsedSQL = parseAndCacheSQL(sqlTextCacheKey, sql);
}
procedureName = parsedSQL.procedureName;
bReturnValueSyntax = parsedSQL.bReturnValueSyntax;
userSQL = parsedSQL.processedSQL;
userSQLParamPositions = parsedSQL.parameterPositions;
initParams(userSQLParamPositions.length);
useBulkCopyForBatchInsert = conn.getUseBulkCopyForBatchInsert();
}
private void closePreparedHandle() {
if (!hasPreparedStatementHandle())
return;
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;
if (resetPrepStmtHandle(false)) {
connection.returnCachedPreparedStatementHandle(cachedPreparedStatementHandle);
}
else if (connection.isPreparedStatementUnprepareBatchingEnabled()) {
connection.enqueueUnprepareStatementHandle(
connection.new PreparedStatementHandle(null, handleToClose, executedSqlDirectly, true));
} else {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.finer(this + ": Closing PreparedHandle:" + handleToClose);
final class PreparedHandleClose extends UninterruptableTDSCommand {
private static final long serialVersionUID = -8944096664249990764L;
PreparedHandleClose() {
super("closePreparedHandle");
}
final boolean doExecute() throws SQLServerException {
TDSWriter tdsWriter = startRequest(TDS.PKT_RPC);
tdsWriter.writeShort((short) 0xFFFF);
tdsWriter.writeShort(
executedSqlDirectly ? TDS.PROCID_SP_UNPREPARE : TDS.PROCID_SP_CURSORUNPREPARE);
tdsWriter.writeByte((byte) 0);
tdsWriter.writeByte((byte) 0);
tdsWriter.sendEnclavePackage(null, null);
tdsWriter.writeRPCInt(null, handleToClose, false);
TDSParser.parse(startResponse(), getLogContext());
return true;
}
}
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);
}
connection.unprepareUnreferencedPreparedStatementHandles(false);
}
}
final void closeInternal() {
super.closeInternal();
closePreparedHandle();
try {
if (null != internalStmt)
internalStmt.close();
} catch (SQLServerException e) {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal
.finer("Ignored error closing internal statement: " + e.getErrorCode() + " " + e.getMessage());
} finally {
internalStmt = null;
}
batchParamValues = null;
}
final void initParams(int nParams) {
inOutParam = new Parameter[nParams];
for (int i = 0; i < nParams; i++) {
inOutParam[i] = new Parameter(Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, connection));
}
}
@Override
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");
}
private boolean buildPreparedStrings(Parameter[] params, boolean renewDefinition) throws SQLServerException {
String newTypeDefinitions = buildParamTypeDefinitions(params, renewDefinition);
if (null != preparedTypeDefinitions && newTypeDefinitions.equalsIgnoreCase(preparedTypeDefinitions))
return false;
preparedTypeDefinitions = newTypeDefinitions;
preparedSQL = connection.replaceParameterMarkers(userSQL, userSQLParamPositions, params, bReturnValueSyntax);
if (bRequestedGeneratedKeys)
preparedSQL = preparedSQL + identityQuery;
return true;
}
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();
}
@Override
public java.sql.ResultSet executeQuery() throws SQLServerException, SQLTimeoutException {
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;
}
final java.sql.ResultSet executeQueryInternal() throws SQLServerException, SQLTimeoutException {
checkClosed();
executeStatement(new PrepStmtExecCmd(this, EXECUTE_QUERY_INTERNAL));
return resultSet;
}
@Override
public int executeUpdate() throws SQLServerException, SQLTimeoutException {
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));
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;
}
@Override
public long executeLargeUpdate() throws SQLServerException, SQLTimeoutException {
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;
}
@Override
public boolean execute() throws SQLServerException, SQLTimeoutException {
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 static final long serialVersionUID = 4098801171124750861L;
private final SQLServerPreparedStatement stmt;
PrepStmtExecCmd(SQLServerPreparedStatement stmt, int executeMethod) {
super(stmt.toString() + " executeXXX", queryTimeout, cancelQueryTimeoutSeconds);
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();
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 (connection.isAEv2() && !isInternalEncryptionQuery) {
this.enclaveCEKs = connection.initEnclaveParameters(preparedSQL, preparedTypeDefinitions, inOutParam,
parameterNames);
encryptionMetadataIsRetrieved = true;
setMaxRowsAndMaxFieldSize();
hasNewTypeDefinitions = buildPreparedStrings(inOutParam, true);
}
if ((Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, connection)) && (0 < inOutParam.length)
&& !isInternalEncryptionQuery) {
if (!encryptionMetadataIsRetrieved) {
getParameterEncryptionMetadata(inOutParam);
encryptionMetadataIsRetrieved = true;
setMaxRowsAndMaxFieldSize();
}
hasNewTypeDefinitions = buildPreparedStrings(inOutParam, true);
}
boolean needsPrepare = true;
for (int attempt = 1; attempt <= 2; ++attempt) {
try {
if (reuseCachedHandle(hasNewTypeDefinitions, 1 < attempt)) {
hasNewTypeDefinitions = false;
}
TDSWriter tdsWriter = command.startRequest(TDS.PKT_RPC);
needsPrepare = doPrepExec(tdsWriter, inOutParam, hasNewTypeDefinitions, hasExistingTypeDefinitions);
ensureExecuteResultsReader(command.startResponse(getIsResponseBufferingAdaptive()));
startResults();
getNextResult(true);
} catch (SQLException e) {
if (retryBasedOnFailedReuseOfCachedHandle(e, attempt, needsPrepare, false))
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);
}
}
private boolean retryBasedOnFailedReuseOfCachedHandle(SQLException e, int attempt, boolean needsPrepare,
boolean isBatch) {
if (needsPrepare && !isBatch)
return false;
return 1 == attempt && (586 == e.getErrorCode() || 8179 == e.getErrorCode())
&& connection.isStatementPoolingEnabled();
}
boolean consumeExecOutParam(TDSReader tdsReader) throws SQLServerException {
final class PrepStmtExecOutParamHandler extends StmtExecOutParamHandler {
boolean onRetValue(TDSReader tdsReader) throws SQLServerException {
if (!expectPrepStmtHandle)
return super.onRetValue(tdsReader);
expectPrepStmtHandle = false;
Parameter param = new Parameter(
Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, connection));
param.skipRetValStatus(tdsReader);
setPreparedStatementHandle(param.getInt(tdsReader));
if (null == cachedPreparedStatementHandle && !isCursorable(executeMethod)) {
cachedPreparedStatementHandle = connection.registerCachedPreparedStatementHandle(
new CityHash128Key(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;
}
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);
tdsWriter.writeShort(TDS.PROCID_SP_CURSORPREPEXEC);
tdsWriter.writeByte((byte) 0);
tdsWriter.writeByte((byte) 0);
tdsWriter.sendEnclavePackage(preparedSQL, enclaveCEKs);
tdsWriter.writeRPCInt(null, getPreparedStatementHandle(), true);
resetPrepStmtHandle(false);
tdsWriter.writeRPCInt(null, 0, true);
tdsWriter.writeRPCStringUnicode((preparedTypeDefinitions.length() > 0) ? preparedTypeDefinitions : null);
tdsWriter.writeRPCStringUnicode(preparedSQL);
tdsWriter.writeRPCInt(null, getResultSetScrollOpt()
& ~((0 == preparedTypeDefinitions.length()) ? TDS.SCROLLOPT_PARAMETERIZED_STMT : 0), false);
tdsWriter.writeRPCInt(null, getResultSetCCOpt(), false);
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);
tdsWriter.writeShort(TDS.PROCID_SP_PREPEXEC);
tdsWriter.writeByte((byte) 0);
tdsWriter.writeByte((byte) 0);
tdsWriter.sendEnclavePackage(preparedSQL, enclaveCEKs);
tdsWriter.writeRPCInt(null, getPreparedStatementHandle(), true);
resetPrepStmtHandle(false);
tdsWriter.writeRPCStringUnicode((preparedTypeDefinitions.length() > 0) ? preparedTypeDefinitions : null);
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);
tdsWriter.writeShort(TDS.PROCID_SP_EXECUTESQL);
tdsWriter.writeByte((byte) 0);
tdsWriter.writeByte((byte) 0);
tdsWriter.sendEnclavePackage(preparedSQL, enclaveCEKs);
resetPrepStmtHandle(false);
tdsWriter.writeRPCStringUnicode(preparedSQL);
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);
tdsWriter.writeShort(TDS.PROCID_SP_CURSOREXECUTE);
tdsWriter.writeByte((byte) 0);
tdsWriter.writeByte((byte) 0);
tdsWriter.sendEnclavePackage(preparedSQL, enclaveCEKs);
assert hasPreparedStatementHandle();
tdsWriter.writeRPCInt(null, getPreparedStatementHandle(), false);
tdsWriter.writeRPCInt(null, 0, true);
tdsWriter.writeRPCInt(null, getResultSetScrollOpt() & ~TDS.SCROLLOPT_PARAMETERIZED_STMT, false);
tdsWriter.writeRPCInt(null, getResultSetCCOpt(), false);
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);
tdsWriter.writeShort(TDS.PROCID_SP_EXECUTE);
tdsWriter.writeByte((byte) 0);
tdsWriter.writeByte((byte) 0);
tdsWriter.sendEnclavePackage(preparedSQL, enclaveCEKs);
assert hasPreparedStatementHandle();
tdsWriter.writeRPCInt(null, getPreparedStatementHandle(), false);
}
private void getParameterEncryptionMetadata(Parameter[] params) throws SQLServerException {
assert connection != null : "Connection should not be null";
try (Statement stmt = connection.prepareCall("exec sp_describe_parameter_encryption ?,?")) {
if (getStatementLogger().isLoggable(java.util.logging.Level.FINE)) {
getStatementLogger().fine(
"Calling stored procedure sp_describe_parameter_encryption to get parameter encryption information.");
}
((SQLServerCallableStatement) stmt).isInternalEncryptionQuery = true;
((SQLServerCallableStatement) stmt).setNString(1, preparedSQL);
((SQLServerCallableStatement) stmt).setNString(2, preparedTypeDefinitions);
try (ResultSet rs = ((SQLServerCallableStatement) stmt).executeQueryInternal()) {
if (null == rs) {
return;
}
Map<Integer, CekTableEntry> cekList = new HashMap<>();
CekTableEntry cekEntry = null;
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.");
}
if (!stmt.getMoreResults()) {
throw new SQLServerException(this,
SQLServerException.getErrString("R_UnexpectedDescribeParamFormat"), null, 0, false);
}
int paramCount = 0;
try (ResultSet secondRs = stmt.getResultSet()) {
while (secondRs.next()) {
paramCount++;
String paramName = secondRs
.getString(DescribeParameterEncryptionResultSet2.ParameterName.value());
int paramIndex = parameterNames.indexOf(paramName);
int cekOrdinal = secondRs
.getInt(DescribeParameterEncryptionResultSet2.ColumnEncryptionKeyOrdinal.value());
cekEntry = cekList.get(cekOrdinal);
if ((null != cekEntry) && (cekList.size() < cekOrdinal)) {
MessageFormat form = new MessageFormat(
SQLServerException.getErrString("R_InvalidEncryptionKeyOrdinal"));
Object[] msgArgs = {cekOrdinal, cekEntry.getSize()};
throw new SQLServerException(this, form.format(msgArgs), null, 0, false);
}
SQLServerEncryptionType encType = SQLServerEncryptionType.of((byte) secondRs
.getInt(DescribeParameterEncryptionResultSet2.ColumnEncrytionType.value()));
if (SQLServerEncryptionType.PlainText != encType) {
params[paramIndex].cryptoMeta = new CryptoMetadata(cekEntry, (short) cekOrdinal,
(byte) secondRs.getInt(
DescribeParameterEncryptionResultSet2.ColumnEncryptionAlgorithm.value()),
null, encType.value, (byte) secondRs.getInt(
DescribeParameterEncryptionResultSet2.NormalizationRuleVersion.value()));
SQLServerSecurityUtility.decryptSymmetricKey(params[paramIndex].cryptoMeta, connection);
} else {
if (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.");
}
}
if (paramCount != params.length) {
MessageFormat form = new MessageFormat(
SQLServerException.getErrString("R_MissingParamEncryptionMetadata"));
Object[] msgArgs = {userSQL};
throw new SQLServerException(this, form.format(msgArgs), null, 0, false);
}
}
} catch (SQLException e) {
if (e instanceof SQLServerException) {
throw (SQLServerException) e;
} else {
throw new SQLServerException(SQLServerException.getErrString("R_UnableRetrieveParameterMetadata"), null,
0, e);
}
}
connection.resetCurrentCommand();
}
private boolean reuseCachedHandle(boolean hasNewTypeDefinitions, boolean discardCurrentCacheItem) {
if (isCursorable(executeMethod))
return false;
if (discardCurrentCacheItem || hasNewTypeDefinitions) {
if (null != cachedPreparedStatementHandle && (discardCurrentCacheItem
|| (hasPreparedStatementHandle() && prepStmtHandle == cachedPreparedStatementHandle.getHandle()))) {
cachedPreparedStatementHandle.removeReference();
}
resetPrepStmtHandle(discardCurrentCacheItem);
cachedPreparedStatementHandle = null;
if (discardCurrentCacheItem)
return false;
}
if (null == cachedPreparedStatementHandle) {
PreparedStatementHandle cachedHandle = connection
.getCachedPreparedStatementHandle(new CityHash128Key(preparedSQL, preparedTypeDefinitions));
if (null != cachedHandle) {
if (!connection.isColumnEncryptionSettingEnabled()
|| (connection.isColumnEncryptionSettingEnabled() && encryptionMetadataIsRetrieved)) {
if (cachedHandle.tryAddReference()) {
setPreparedStatementHandle(cachedHandle.getHandle());
cachedPreparedStatementHandle = cachedHandle;
return true;
}
}
}
}
return false;
}
private ArrayList<byte[]> enclaveCEKs;
private boolean doPrepExec(TDSWriter tdsWriter, Parameter[] params, boolean hasNewTypeDefinitions,
boolean hasExistingTypeDefinitions) throws SQLServerException {
boolean needsPrepare = (hasNewTypeDefinitions && hasExistingTypeDefinitions) || !hasPreparedStatementHandle();
if (isCursorable(executeMethod)) {
if (needsPrepare)
buildServerCursorPrepExecParams(tdsWriter);
else
buildServerCursorExecParams(tdsWriter);
} else {
if (needsPrepare && !connection.getEnablePrepareOnFirstPreparedStatementCall() && !isExecutedAtLeastOnce) {
buildExecSQLParams(tdsWriter);
isExecutedAtLeastOnce = true;
}
else if (needsPrepare)
buildPrepExecParams(tdsWriter);
else
buildExecParams(tdsWriter);
}
sendParamsByRPC(tdsWriter, params);
return needsPrepare;
}
@Override
public final java.sql.ResultSetMetaData getMetaData() throws SQLServerException, SQLTimeoutException {
loggerExternal.entering(getClassNameLogging(), "getMetaData");
checkClosed();
boolean rsclosed = false;
java.sql.ResultSetMetaData rsmd = null;
try {
if (resultSet != null)
resultSet.checkClosed();
} catch (SQLServerException e) {
rsclosed = true;
}
if (resultSet == null || rsclosed) {
SQLServerResultSet emptyResultSet = buildExecuteMetaData();
if (null != emptyResultSet)
rsmd = emptyResultSet.getMetaData();
} else if (resultSet != null) {
rsmd = resultSet.getMetaData();
}
loggerExternal.exiting(getClassNameLogging(), "getMetaData", rsmd);
return rsmd;
}
private SQLServerResultSet buildExecuteMetaData() throws SQLServerException, SQLTimeoutException {
String fmtSQL = userSQL;
SQLServerResultSet emptyResultSet = null;
try {
fmtSQL = replaceMarkerWithNull(fmtSQL);
internalStmt = (SQLServerStatement) connection.createStatement();
emptyResultSet = internalStmt.executeQueryInternal("set fmtonly on " + fmtSQL + "\nset fmtonly off");
} catch (SQLServerException sqle) {
if (!sqle.getMessage().equals(SQLServerException.getErrString("R_noResultset"))) {
throw sqle;
}
}
return emptyResultSet;
}
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);
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
public final void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setBigDecimal", new Object[] {parameterIndex, x});
checkClosed();
setValue(parameterIndex, JDBCType.DECIMAL, x, JavaType.BIGDECIMAL, false);
loggerExternal.exiting(getClassNameLogging(), "setBigDecimal");
}
@Override
public final void setBigDecimal(int parameterIndex, BigDecimal x, int precision,
int scale) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setBigDecimal",
new Object[] {parameterIndex, x, precision, scale});
checkClosed();
setValue(parameterIndex, JDBCType.DECIMAL, x, JavaType.BIGDECIMAL, precision, scale, false);
loggerExternal.exiting(getClassNameLogging(), "setBigDecimal");
}
@Override
public final void setBigDecimal(int parameterIndex, BigDecimal x, int precision, int scale,
boolean forceEncrypt) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setBigDecimal",
new Object[] {parameterIndex, x, precision, scale, forceEncrypt});
checkClosed();
setValue(parameterIndex, JDBCType.DECIMAL, x, JavaType.BIGDECIMAL, precision, scale, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setBigDecimal");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
public final void setGeometry(int n, Geometry x) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setGeometry", new Object[] {n, x});
checkClosed();
setValue(n, JDBCType.GEOMETRY, x, JavaType.STRING, false);
loggerExternal.exiting(getClassNameLogging(), "setGeometry");
}
@Override
public final void setGeography(int n, Geography x) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setGeography", new Object[] {n, x});
checkClosed();
setValue(n, JDBCType.GEOGRAPHY, x, JavaType.STRING, false);
loggerExternal.exiting(getClassNameLogging(), "setGeography");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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 {
Parameter param = setterGetParam(index);
JDBCType targetJDBCType = param.getJdbcType();
String tvpName = null;
if (null == obj) {
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 = getTVPNameFromObject(index, obj);
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);
}
}
@Override
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");
}
@Override
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 = getTVPNameFromObject(n, obj);
}
setObject(setterGetParam(n), obj, JavaType.of(obj), JDBCType.of(jdbcType), null, null, false, n, tvpName);
loggerExternal.exiting(getClassNameLogging(), "setObject");
}
@Override
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();
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");
}
@Override
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();
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");
}
@Override
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();
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;
if ((null != obj) || (JavaType.TVP == javaType)) {
JDBCType objectJDBCType = javaType.getJDBCType(SSType.UNKNOWN, jdbcType);
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:
break;
}
param.setValue(jdbcType, obj, javaType, streamSetterArgs, null, precision, scale, connection, forceEncrypt,
stmtColumnEncriptionSetting, parameterIndex, userSQL, tvpName);
}
else {
assert JavaType.OBJECT == javaType;
if (jdbcType.isUnsupported())
jdbcType = JDBCType.BINARY;
param.setValue(jdbcType, null, JavaType.OBJECT, null, null, precision, scale, connection, false,
stmtColumnEncriptionSetting, parameterIndex, userSQL, tvpName);
}
}
@Override
public final void setObject(int index, Object obj, SQLType jdbcType) throws SQLServerException {
setObject(index, obj, jdbcType.getVendorTypeNumber());
}
@Override
public final void setObject(int parameterIndex, Object x, SQLType targetSqlType,
int scaleOrLength) throws SQLServerException {
setObject(parameterIndex, x, targetSqlType.getVendorTypeNumber(), scaleOrLength);
}
@Override
public final void setObject(int parameterIndex, Object x, SQLType targetSqlType, Integer precision,
Integer scale) throws SQLServerException {
setObject(parameterIndex, x, targetSqlType.getVendorTypeNumber(), precision, scale);
}
@Override
public final void setObject(int parameterIndex, Object x, SQLType targetSqlType, Integer precision, Integer scale,
boolean forceEncrypt) throws SQLServerException {
setObject(parameterIndex, x, targetSqlType.getVendorTypeNumber(), precision, scale, forceEncrypt);
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
public final void setNString(int parameterIndex, String value, boolean forceEncrypt) throws SQLServerException {
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
public final void setDateTimeOffset(int n, microsoft.sql.DateTimeOffset x) throws SQLServerException {
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");
}
@Override
public final void setDateTimeOffset(int n, microsoft.sql.DateTimeOffset x, int scale) throws SQLServerException {
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");
}
@Override
public final void setDateTimeOffset(int n, microsoft.sql.DateTimeOffset x, int scale,
boolean forceEncrypt) throws SQLServerException {
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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 getTVPNameFromObject(int n, Object obj) throws SQLServerException {
String tvpName = null;
if (obj instanceof SQLServerDataTable) {
tvpName = ((SQLServerDataTable) obj).getTvpName();
}
return getTVPNameIfNull(n, tvpName);
}
String getTVPNameIfNull(int n, String tvpName) throws SQLServerException {
if ((null == tvpName) || (0 == tvpName.length())) {
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
@Override
public final void setUnicodeStream(int n, java.io.InputStream x, int length) throws SQLException {
SQLServerException.throwNotSupportedException(connection, this);
}
@Override
public final void addBatch() throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "addBatch");
checkClosed();
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");
}
@Override
public final void clearBatch() throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "clearBatch");
checkClosed();
batchParamValues = null;
loggerExternal.exiting(getClassNameLogging(), "clearBatch");
}
@Override
public int[] executeBatch() throws SQLServerException, BatchUpdateException, SQLTimeoutException {
loggerExternal.entering(getClassNameLogging(), "executeBatch");
if (loggerExternal.isLoggable(Level.FINER) && Util.isActivityTraceOn()) {
loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
}
checkClosed();
discardLastExecutionResults();
int updateCounts[];
localUserSQL = userSQL;
try {
if (this.useBulkCopyForBatchInsert && isInsert(localUserSQL)) {
if (null == batchParamValues) {
updateCounts = new int[0];
loggerExternal.exiting(getClassNameLogging(), "executeBatch", updateCounts);
return updateCounts;
}
for (Parameter[] paramValues : batchParamValues) {
for (Parameter paramValue : paramValues) {
if (paramValue.isOutput()) {
throw new BatchUpdateException(
SQLServerException.getErrString("R_outParamsNotPermittedinBatch"), null, 0, null);
}
}
}
String tableName = parseUserSQLForTableNameDW(false, false, false, false);
ArrayList<String> columnList = parseUserSQLForColumnListDW();
ArrayList<String> valueList = parseUserSQLForValueListDW(false);
checkAdditionalQuery();
try (SQLServerStatement stmt = (SQLServerStatement) connection.createStatement(
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, connection.getHoldability(),
stmtColumnEncriptionSetting);
SQLServerResultSet rs = stmt
.executeQueryInternal("sp_executesql N'SET FMTONLY ON SELECT * FROM "
+ Util.escapeSingleQuotes(tableName) + " '")) {
if (null != columnList && columnList.size() > 0) {
if (columnList.size() != valueList.size()) {
throw new IllegalArgumentException(
"Number of provided columns does not match the table definition.");
}
} else {
if (rs.getColumnCount() != valueList.size()) {
throw new IllegalArgumentException(
"Number of provided columns does not match the table definition.");
}
}
SQLServerBulkBatchInsertRecord batchRecord = new SQLServerBulkBatchInsertRecord(batchParamValues,
columnList, valueList, null);
for (int i = 1; i <= rs.getColumnCount(); i++) {
Column c = rs.getColumn(i);
CryptoMetadata cryptoMetadata = c.getCryptoMetadata();
int jdbctype;
TypeInfo ti = c.getTypeInfo();
checkValidColumns(ti);
if (null != cryptoMetadata) {
jdbctype = cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType().getIntValue();
} else {
jdbctype = ti.getSSType().getJDBCType().getIntValue();
}
batchRecord.addColumnMetadata(i, c.getColumnName(), jdbctype, ti.getPrecision(), ti.getScale());
}
SQLServerBulkCopy bcOperation = new SQLServerBulkCopy(connection);
SQLServerBulkCopyOptions option = new SQLServerBulkCopyOptions();
option.setBulkCopyTimeout(queryTimeout);
bcOperation.setBulkCopyOptions(option);
bcOperation.setDestinationTableName(tableName);
bcOperation.setStmtColumnEncriptionSetting(this.getStmtColumnEncriptionSetting());
bcOperation.setDestinationTableMetadata(rs);
bcOperation.writeToServer(batchRecord);
bcOperation.close();
updateCounts = new int[batchParamValues.size()];
for (int i = 0; i < batchParamValues.size(); ++i) {
updateCounts[i] = 1;
}
batchParamValues = null;
loggerExternal.exiting(getClassNameLogging(), "executeBatch", updateCounts);
return updateCounts;
}
}
} catch (SQLException e) {
throw new BatchUpdateException(e.getMessage(), null, 0, null);
} catch (IllegalArgumentException e) {
if (getStatementLogger().isLoggable(java.util.logging.Level.FINE)) {
getStatementLogger().fine("Parsing user's Batch Insert SQL Query failed: " + e.getMessage());
getStatementLogger().fine("Falling back to the original implementation for Batch Insert.");
}
}
if (null == batchParamValues)
updateCounts = new int[0];
else
try {
for (Parameter[] paramValues : batchParamValues) {
for (Parameter paramValue : paramValues) {
if (paramValue.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];
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;
}
@Override
public long[] executeLargeBatch() throws SQLServerException, BatchUpdateException, SQLTimeoutException {
loggerExternal.entering(getClassNameLogging(), "executeLargeBatch");
if (loggerExternal.isLoggable(Level.FINER) && Util.isActivityTraceOn()) {
loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
}
checkClosed();
discardLastExecutionResults();
long updateCounts[];
localUserSQL = userSQL;
try {
if (this.useBulkCopyForBatchInsert && isInsert(localUserSQL)) {
if (null == batchParamValues) {
updateCounts = new long[0];
loggerExternal.exiting(getClassNameLogging(), "executeLargeBatch", updateCounts);
return updateCounts;
}
for (Parameter[] paramValues : batchParamValues) {
for (Parameter paramValue : paramValues) {
if (paramValue.isOutput()) {
throw new BatchUpdateException(
SQLServerException.getErrString("R_outParamsNotPermittedinBatch"), null, 0, null);
}
}
}
String tableName = parseUserSQLForTableNameDW(false, false, false, false);
ArrayList<String> columnList = parseUserSQLForColumnListDW();
ArrayList<String> valueList = parseUserSQLForValueListDW(false);
checkAdditionalQuery();
try (SQLServerStatement stmt = (SQLServerStatement) connection.createStatement(
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, connection.getHoldability(),
stmtColumnEncriptionSetting);
SQLServerResultSet rs = stmt
.executeQueryInternal("sp_executesql N'SET FMTONLY ON SELECT * FROM "
+ Util.escapeSingleQuotes(tableName) + " '")) {
if (null != columnList && columnList.size() > 0) {
if (columnList.size() != valueList.size()) {
throw new IllegalArgumentException(
"Number of provided columns does not match the table definition.");
}
} else {
if (rs.getColumnCount() != valueList.size()) {
throw new IllegalArgumentException(
"Number of provided columns does not match the table definition.");
}
}
SQLServerBulkBatchInsertRecord batchRecord = new SQLServerBulkBatchInsertRecord(batchParamValues,
columnList, valueList, null);
for (int i = 1; i <= rs.getColumnCount(); i++) {
Column c = rs.getColumn(i);
CryptoMetadata cryptoMetadata = c.getCryptoMetadata();
int jdbctype;
TypeInfo ti = c.getTypeInfo();
checkValidColumns(ti);
if (null != cryptoMetadata) {
jdbctype = cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType().getIntValue();
} else {
jdbctype = ti.getSSType().getJDBCType().getIntValue();
}
batchRecord.addColumnMetadata(i, c.getColumnName(), jdbctype, ti.getPrecision(), ti.getScale());
}
SQLServerBulkCopy bcOperation = new SQLServerBulkCopy(connection);
SQLServerBulkCopyOptions option = new SQLServerBulkCopyOptions();
option.setBulkCopyTimeout(queryTimeout);
bcOperation.setBulkCopyOptions(option);
bcOperation.setDestinationTableName(tableName);
bcOperation.setStmtColumnEncriptionSetting(this.getStmtColumnEncriptionSetting());
bcOperation.setDestinationTableMetadata(rs);
bcOperation.writeToServer(batchRecord);
bcOperation.close();
updateCounts = new long[batchParamValues.size()];
for (int i = 0; i < batchParamValues.size(); ++i) {
updateCounts[i] = 1;
}
batchParamValues = null;
loggerExternal.exiting(getClassNameLogging(), "executeLargeBatch", updateCounts);
return updateCounts;
}
}
} catch (SQLException e) {
throw new BatchUpdateException(e.getMessage(), null, 0, null);
} catch (IllegalArgumentException e) {
if (getStatementLogger().isLoggable(java.util.logging.Level.FINE)) {
getStatementLogger().fine("Parsing user's Batch Insert SQL Query failed: " + e.getMessage());
getStatementLogger().fine("Falling back to the original implementation for Batch Insert.");
}
}
if (null == batchParamValues)
updateCounts = new long[0];
else
try {
for (Parameter[] paramValues : batchParamValues) {
for (Parameter paramValue : paramValues) {
if (paramValue.isOutput()) {
throw new BatchUpdateException(
SQLServerException.getErrString("R_outParamsNotPermittedinBatch"), null, 0, null);
}
}
}
PrepStmtBatchExecCmd batchCommand = new PrepStmtBatchExecCmd(this);
executeStatement(batchCommand);
updateCounts = new long[batchCommand.updateCounts.length];
System.arraycopy(batchCommand.updateCounts, 0, updateCounts, 0, batchCommand.updateCounts.length);
if (null != batchCommand.batchException) {
DriverJDBCVersion.throwBatchUpdateException(batchCommand.batchException, updateCounts);
}
} finally {
batchParamValues = null;
}
loggerExternal.exiting(getClassNameLogging(), "executeLargeBatch", updateCounts);
return updateCounts;
}
private void checkValidColumns(TypeInfo ti) throws SQLServerException {
int jdbctype = ti.getSSType().getJDBCType().getIntValue();
String typeName;
MessageFormat form;
switch (jdbctype) {
case microsoft.sql.Types.MONEY:
case microsoft.sql.Types.SMALLMONEY:
case java.sql.Types.DATE:
case microsoft.sql.Types.DATETIME:
case microsoft.sql.Types.DATETIMEOFFSET:
case microsoft.sql.Types.SMALLDATETIME:
case java.sql.Types.TIME:
typeName = ti.getSSTypeName();
form = new MessageFormat(SQLServerException.getErrString("R_BulkTypeNotSupportedDW"));
throw new IllegalArgumentException(form.format(new Object[] {typeName}));
case java.sql.Types.INTEGER:
case java.sql.Types.SMALLINT:
case java.sql.Types.BIGINT:
case java.sql.Types.BIT:
case java.sql.Types.TINYINT:
case java.sql.Types.DOUBLE:
case java.sql.Types.REAL:
case java.sql.Types.DECIMAL:
case java.sql.Types.NUMERIC:
case microsoft.sql.Types.GUID:
case java.sql.Types.CHAR:
case java.sql.Types.NCHAR:
case java.sql.Types.LONGVARCHAR:
case java.sql.Types.VARCHAR:
case java.sql.Types.LONGNVARCHAR:
case java.sql.Types.NVARCHAR:
case java.sql.Types.BINARY:
case java.sql.Types.LONGVARBINARY:
case java.sql.Types.VARBINARY:
typeName = ti.getSSTypeName();
if ("geometry".equalsIgnoreCase(typeName) || "geography".equalsIgnoreCase(typeName)) {
form = new MessageFormat(SQLServerException.getErrString("R_BulkTypeNotSupported"));
throw new IllegalArgumentException(form.format(new Object[] {typeName}));
}
case java.sql.Types.TIMESTAMP:
case 2013:
case 2014:
case microsoft.sql.Types.SQL_VARIANT:
return;
default: {
form = new MessageFormat(SQLServerException.getErrString("R_BulkTypeNotSupported"));
String unsupportedDataType = JDBCType.of(jdbctype).toString();
throw new IllegalArgumentException(form.format(new Object[] {unsupportedDataType}));
}
}
}
private void checkAdditionalQuery() {
while (checkAndRemoveCommentsAndSpace(true)) {}
if (localUserSQL.length() > 0) {
throw new IllegalArgumentException("Multiple queries are not allowed.");
}
}
private String parseUserSQLForTableNameDW(boolean hasInsertBeenFound, boolean hasIntoBeenFound,
boolean hasTableBeenFound, boolean isExpectingTableName) {
while (checkAndRemoveCommentsAndSpace(false)) {}
StringBuilder sb = new StringBuilder();
if (hasTableBeenFound && !isExpectingTableName) {
if (checkSQLLength(1) && ".".equalsIgnoreCase(localUserSQL.substring(0, 1))) {
sb.append(".");
localUserSQL = localUserSQL.substring(1);
return sb.toString() + parseUserSQLForTableNameDW(true, true, true, true);
} else {
return "";
}
}
if (!hasInsertBeenFound && checkSQLLength(6) && "insert".equalsIgnoreCase(localUserSQL.substring(0, 6))) {
localUserSQL = localUserSQL.substring(6);
return parseUserSQLForTableNameDW(true, hasIntoBeenFound, hasTableBeenFound, isExpectingTableName);
}
if (!hasIntoBeenFound && checkSQLLength(6) && "into".equalsIgnoreCase(localUserSQL.substring(0, 4))) {
if (Character.isWhitespace(localUserSQL.charAt(4))
|| (localUserSQL.charAt(4) == '/' && localUserSQL.charAt(5) == '*')) {
localUserSQL = localUserSQL.substring(4);
return parseUserSQLForTableNameDW(hasInsertBeenFound, true, hasTableBeenFound, isExpectingTableName);
}
return parseUserSQLForTableNameDW(hasInsertBeenFound, true, hasTableBeenFound, isExpectingTableName);
}
if (checkSQLLength(1) && "[".equalsIgnoreCase(localUserSQL.substring(0, 1))) {
int tempint = localUserSQL.indexOf("]", 1);
if (tempint < 0) {
throw new IllegalArgumentException("Invalid SQL Query.");
}
while (tempint >= 0 && checkSQLLength(tempint + 2) && localUserSQL.charAt(tempint + 1) == ']') {
tempint = localUserSQL.indexOf("]", tempint + 2);
}
sb.append(localUserSQL.substring(0, tempint + 1));
localUserSQL = localUserSQL.substring(tempint + 1);
return sb.toString() + parseUserSQLForTableNameDW(true, true, true, false);
}
if (checkSQLLength(1) && "\"".equalsIgnoreCase(localUserSQL.substring(0, 1))) {
int tempint = localUserSQL.indexOf("\"", 1);
if (tempint < 0) {
throw new IllegalArgumentException("Invalid SQL Query.");
}
while (tempint >= 0 && checkSQLLength(tempint + 2) && localUserSQL.charAt(tempint + 1) == '\"') {
tempint = localUserSQL.indexOf("\"", tempint + 2);
}
sb.append(localUserSQL.substring(0, tempint + 1));
localUserSQL = localUserSQL.substring(tempint + 1);
return sb.toString() + parseUserSQLForTableNameDW(true, true, true, false);
}
while (localUserSQL.length() > 0) {
if (localUserSQL.charAt(0) == '.' || Character.isWhitespace(localUserSQL.charAt(0))
|| checkAndRemoveCommentsAndSpace(false)) {
return sb.toString() + parseUserSQLForTableNameDW(true, true, true, false);
} else if (localUserSQL.charAt(0) == ';') {
throw new IllegalArgumentException("End of query detected before VALUES have been found.");
} else {
sb.append(localUserSQL.charAt(0));
localUserSQL = localUserSQL.substring(1);
}
}
throw new IllegalArgumentException("Invalid SQL Query.");
}
private ArrayList<String> parseUserSQLForColumnListDW() {
while (checkAndRemoveCommentsAndSpace(false)) {}
if (checkSQLLength(1) && "(".equalsIgnoreCase(localUserSQL.substring(0, 1))) {
localUserSQL = localUserSQL.substring(1);
return parseUserSQLForColumnListDWHelper(new ArrayList<String>());
}
return null;
}
private ArrayList<String> parseUserSQLForColumnListDWHelper(ArrayList<String> listOfColumns) {
while (checkAndRemoveCommentsAndSpace(false)) {}
StringBuilder sb = new StringBuilder();
while (localUserSQL.length() > 0) {
while (checkAndRemoveCommentsAndSpace(false)) {}
if (checkSQLLength(1) && localUserSQL.charAt(0) == ')') {
localUserSQL = localUserSQL.substring(1);
return listOfColumns;
}
if (localUserSQL.charAt(0) == ',') {
localUserSQL = localUserSQL.substring(1);
while (checkAndRemoveCommentsAndSpace(false)) {}
}
if (localUserSQL.charAt(0) == '[') {
int tempint = localUserSQL.indexOf("]", 1);
if (tempint < 0) {
throw new IllegalArgumentException("Invalid SQL Query.");
}
while (tempint >= 0 && checkSQLLength(tempint + 2) && localUserSQL.charAt(tempint + 1) == ']') {
localUserSQL = localUserSQL.substring(0, tempint) + localUserSQL.substring(tempint + 1);
tempint = localUserSQL.indexOf("]", tempint + 1);
}
String tempstr = localUserSQL.substring(1, tempint);
localUserSQL = localUserSQL.substring(tempint + 1);
listOfColumns.add(tempstr);
continue;
}
if (localUserSQL.charAt(0) == '\"') {
int tempint = localUserSQL.indexOf("\"", 1);
if (tempint < 0) {
throw new IllegalArgumentException("Invalid SQL Query.");
}
while (tempint >= 0 && checkSQLLength(tempint + 2) && localUserSQL.charAt(tempint + 1) == '\"') {
localUserSQL = localUserSQL.substring(0, tempint) + localUserSQL.substring(tempint + 1);
tempint = localUserSQL.indexOf("\"", tempint + 1);
}
String tempstr = localUserSQL.substring(1, tempint);
localUserSQL = localUserSQL.substring(tempint + 1);
listOfColumns.add(tempstr);
continue;
}
while (localUserSQL.length() > 0) {
if (checkAndRemoveCommentsAndSpace(false)) {
continue;
}
if (localUserSQL.charAt(0) == ',') {
localUserSQL = localUserSQL.substring(1);
listOfColumns.add(sb.toString());
sb.setLength(0);
break;
} else if (localUserSQL.charAt(0) == ')') {
localUserSQL = localUserSQL.substring(1);
listOfColumns.add(sb.toString());
return listOfColumns;
} else {
sb.append(localUserSQL.charAt(0));
localUserSQL = localUserSQL.substring(1);
localUserSQL = localUserSQL.trim();
}
}
}
throw new IllegalArgumentException("Invalid SQL Query.");
}
private ArrayList<String> parseUserSQLForValueListDW(boolean hasValuesBeenFound) {
if (checkAndRemoveCommentsAndSpace(false)) {}
if (!hasValuesBeenFound) {
if (checkSQLLength(6) && "VALUES".equalsIgnoreCase(localUserSQL.substring(0, 6))) {
localUserSQL = localUserSQL.substring(6);
while (checkAndRemoveCommentsAndSpace(false)) {}
if (checkSQLLength(1) && "(".equalsIgnoreCase(localUserSQL.substring(0, 1))) {
localUserSQL = localUserSQL.substring(1);
return parseUserSQLForValueListDWHelper(new ArrayList<String>());
}
}
} else {
while (checkAndRemoveCommentsAndSpace(false)) {}
if (checkSQLLength(1) && "(".equalsIgnoreCase(localUserSQL.substring(0, 1))) {
localUserSQL = localUserSQL.substring(1);
return parseUserSQLForValueListDWHelper(new ArrayList<String>());
}
}
throw new IllegalArgumentException("Invalid SQL Query.");
}
private ArrayList<String> parseUserSQLForValueListDWHelper(ArrayList<String> listOfValues) {
while (checkAndRemoveCommentsAndSpace(false)) {}
StringBuilder sb = new StringBuilder();
while (localUserSQL.length() > 0) {
if (checkAndRemoveCommentsAndSpace(false)) {
continue;
}
if (localUserSQL.charAt(0) == ',' || localUserSQL.charAt(0) == ')') {
if (localUserSQL.charAt(0) == ',') {
localUserSQL = localUserSQL.substring(1);
if (!"?".equals(sb.toString())) {
throw new IllegalArgumentException(
"Only fully parameterized queries are allowed for using Bulk Copy API for batch insert at the moment.");
}
listOfValues.add(sb.toString());
sb.setLength(0);
} else {
localUserSQL = localUserSQL.substring(1);
listOfValues.add(sb.toString());
return listOfValues;
}
} else {
sb.append(localUserSQL.charAt(0));
localUserSQL = localUserSQL.substring(1);
localUserSQL = localUserSQL.trim();
}
}
throw new IllegalArgumentException("Invalid SQL Query.");
}
private boolean checkAndRemoveCommentsAndSpace(boolean checkForSemicolon) {
localUserSQL = localUserSQL.trim();
while (checkForSemicolon && null != localUserSQL && localUserSQL.length() > 0
&& localUserSQL.charAt(0) == ';') {
localUserSQL = localUserSQL.substring(1);
}
if (null == localUserSQL || localUserSQL.length() < 2) {
return false;
}
if ("/*".equalsIgnoreCase(localUserSQL.substring(0, 2))) {
int temp = localUserSQL.indexOf("*/") + 2;
if (temp <= 0) {
localUserSQL = "";
return false;
}
localUserSQL = localUserSQL.substring(temp);
return true;
}
if ("--".equalsIgnoreCase(localUserSQL.substring(0, 2))) {
int temp = localUserSQL.indexOf("\n") + 1;
if (temp <= 0) {
localUserSQL = "";
return false;
}
localUserSQL = localUserSQL.substring(temp);
return true;
}
return false;
}
private boolean checkSQLLength(int length) {
if (null == localUserSQL || localUserSQL.length() < length) {
throw new IllegalArgumentException("Invalid SQL Query.");
}
return true;
}
private final class PrepStmtBatchExecCmd extends TDSCommand {
private static final long serialVersionUID = 5225705304799552318L;
private final SQLServerPreparedStatement stmt;
SQLServerException batchException;
long updateCounts[];
PrepStmtBatchExecCmd(SQLServerPreparedStatement stmt) {
super(stmt.toString() + " executeBatch", queryTimeout, cancelQueryTimeoutSeconds);
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;
int numBatchesPrepared = 0;
int numBatchesExecuted = 0;
if (isSelect(userSQL)) {
SQLServerException.makeFromDriverError(connection, this,
SQLServerException.getErrString("R_selectNotPermittedinBatch"), null, true);
}
connection.setMaxRows(0);
if (loggerExternal.isLoggable(Level.FINER) && Util.isActivityTraceOn()) {
loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
}
Parameter[] batchParam = new Parameter[inOutParam.length];
TDSWriter tdsWriter = null;
while (numBatchesExecuted < numBatches) {
Parameter paramValues[] = batchParamValues.get(numBatchesPrepared);
assert paramValues.length == batchParam.length;
System.arraycopy(paramValues, 0, batchParam, 0, paramValues.length);
boolean hasExistingTypeDefinitions = preparedTypeDefinitions != null;
boolean hasNewTypeDefinitions = buildPreparedStrings(batchParam, false);
if ((0 == numBatchesExecuted) && !isInternalEncryptionQuery && connection.isAEv2()
&& !encryptionMetadataIsRetrieved) {
this.enclaveCEKs = connection.initEnclaveParameters(preparedSQL, preparedTypeDefinitions, batchParam,
parameterNames);
encryptionMetadataIsRetrieved = true;
buildPreparedStrings(batchParam, true);
for (Parameter aBatchParam : batchParam) {
cryptoMetaBatch.add(aBatchParam.cryptoMeta);
}
}
if ((0 == numBatchesExecuted) && (Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, connection))
&& (0 < batchParam.length) && !isInternalEncryptionQuery && !encryptionMetadataIsRetrieved) {
encryptionMetadataIsRetrieved = true;
getParameterEncryptionMetadata(batchParam);
buildPreparedStrings(batchParam, true);
for (Parameter aBatchParam : batchParam) {
cryptoMetaBatch.add(aBatchParam.cryptoMeta);
}
} else {
for (int i = 0; i < cryptoMetaBatch.size(); i++) {
batchParam[i].cryptoMeta = cryptoMetaBatch.get(i);
}
}
boolean needsPrepare = true;
for (int attempt = 1; attempt <= 2; ++attempt) {
try {
if (reuseCachedHandle(hasNewTypeDefinitions, 1 < attempt)) {
hasNewTypeDefinitions = false;
}
if (numBatchesExecuted < numBatchesPrepared) {
tdsWriter.writeByte((byte) nBatchStatementDelimiter);
} else {
resetForReexecute();
tdsWriter = batchCommand.startRequest(TDS.PKT_RPC);
}
++numBatchesPrepared;
needsPrepare = doPrepExec(tdsWriter, batchParam, hasNewTypeDefinitions, hasExistingTypeDefinitions);
if (needsPrepare || numBatchesPrepared == numBatches) {
ensureExecuteResultsReader(batchCommand.startResponse(getIsResponseBufferingAdaptive()));
boolean retry = false;
while (numBatchesExecuted < numBatchesPrepared) {
startResults();
try {
if (!getNextResult(true))
return;
if (null != resultSet) {
SQLServerException.makeFromDriverError(connection, this,
SQLServerException.getErrString("R_resultsetGeneratedForUpdate"), null,
false);
}
} catch (SQLServerException e) {
if (connection.isSessionUnAvailable() || connection.rolledBackTransaction())
throw e;
if (retryBasedOnFailedReuseOfCachedHandle(e, attempt, needsPrepare, true)) {
numBatchesPrepared = numBatchesExecuted;
retry = true;
break;
}
updateCount = Statement.EXECUTE_FAILED;
if (null == batchCommand.batchException)
batchCommand.batchException = e;
}
batchCommand.updateCounts[numBatchesExecuted] = (-1 == updateCount) ? Statement.SUCCESS_NO_INFO
: updateCount;
processBatch();
numBatchesExecuted++;
}
if (retry)
continue;
assert numBatchesExecuted == numBatchesPrepared;
}
} catch (SQLException e) {
if (retryBasedOnFailedReuseOfCachedHandle(e, attempt, needsPrepare, true)
&& connection.isStatementPoolingEnabled()) {
numBatchesPrepared = numBatchesExecuted;
continue;
} else if (null != batchCommand.batchException) {
numBatchesExecuted = numBatchesPrepared;
attempt++;
continue;
} else {
throw e;
}
}
break;
}
}
}
@Override
public final void setUseFmtOnly(boolean useFmtOnly) throws SQLServerException {
checkClosed();
this.useFmtOnly = useFmtOnly;
}
@Override
public final boolean getUseFmtOnly() throws SQLServerException {
checkClosed();
return this.useFmtOnly;
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
public final void setRef(int i, java.sql.Ref x) throws SQLException {
SQLServerException.throwNotSupportedException(connection, this);
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
public final void setArray(int i, java.sql.Array x) throws SQLException {
SQLServerException.throwNotSupportedException(connection, this);
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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");
}
@Override
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;
}
}
@Override
public final ParameterMetaData getParameterMetaData() throws SQLServerException {
return getParameterMetaData(false);
}
@Override
public final void setURL(int parameterIndex, java.net.URL x) throws SQLException {
SQLServerException.throwNotSupportedException(connection, this);
}
@Override
public final void setRowId(int parameterIndex, RowId x) throws SQLException {
SQLServerException.throwNotSupportedException(connection, this);
}
@Override
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");
}
@Override
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);
}
@Override
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);
}
@Override
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);
}
@Override
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);
}
}