From 1ae3ae3b827227ff671e1399979b7d3de9a2f04a Mon Sep 17 00:00:00 2001 From: lilgreenbird Date: Fri, 21 Jan 2022 20:06:04 -0800 Subject: [PATCH 1/3] sonarqube fixes --- .../jdbc/ISQLServerEnclaveProvider.java | 73 ++++++++++--------- .../sqlserver/jdbc/SQLServerBulkCopy.java | 17 ++--- 2 files changed, 43 insertions(+), 47 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerEnclaveProvider.java b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerEnclaveProvider.java index 45a9d33f1..150e92245 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerEnclaveProvider.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerEnclaveProvider.java @@ -180,17 +180,18 @@ default ResultSet executeSDPEv1(PreparedStatement stmt, String userSql, * if error */ default void processSDPEv1(String userSql, String preparedTypeDefinitions, Parameter[] params, - ArrayList parameterNames, SQLServerConnection connection, SQLServerStatement sqlServerStatement, PreparedStatement stmt, ResultSet rs, - ArrayList enclaveRequestedCEKs) throws SQLException { + ArrayList parameterNames, SQLServerConnection connection, SQLServerStatement sqlServerStatement, + PreparedStatement stmt, ResultSet rs, ArrayList enclaveRequestedCEKs) throws SQLException { Map cekList = new HashMap<>(); CekTableEntry cekEntry = null; boolean isRequestedByEnclave = false; SQLServerStatement statement = (SQLServerStatement) ((SQLServerPreparedStatement) stmt); if (null != sqlServerStatement && sqlServerStatement.hasColumnEncryptionKeyStoreProvidersRegistered()) { - statement.registerColumnEncryptionKeyStoreProvidersOnStatement(sqlServerStatement.statementColumnEncryptionKeyStoreProviders); + statement.registerColumnEncryptionKeyStoreProvidersOnStatement( + sqlServerStatement.statementColumnEncryptionKeyStoreProviders); } - + while (rs.next()) { int currentOrdinal = rs.getInt(DescribeParameterEncryptionResultSet1.KeyOrdinal.value()); if (!cekList.containsKey(currentOrdinal)) { @@ -223,8 +224,8 @@ default void processSDPEv1(String userSql, String preparedTypeDefinitions, Param if (isRequestedByEnclave) { byte[] keySignature = rs.getBytes(DescribeParameterEncryptionResultSet1.EnclaveCMKSignature.value()); String serverName = connection.getTrustedServerNameAE(); - SQLServerSecurityUtility.verifyColumnMasterKeyMetadata(connection, statement, keyStoreName, keyPath, serverName, - isRequestedByEnclave, keySignature); + SQLServerSecurityUtility.verifyColumnMasterKeyMetadata(connection, statement, keyStoreName, keyPath, + serverName, isRequestedByEnclave, keySignature); // DBID(4) + MDVER(8) + KEYID(2) + CEK(32) = 46 ByteBuffer aev2CekEntry = ByteBuffer.allocate(46); @@ -232,7 +233,8 @@ default void processSDPEv1(String userSql, String preparedTypeDefinitions, Param aev2CekEntry.put(mdVer); aev2CekEntry.putShort((short) keyID); - SQLServerColumnEncryptionKeyStoreProvider provider = SQLServerSecurityUtility.getColumnEncryptionKeyStoreProvider(keyStoreName, connection, statement); + SQLServerColumnEncryptionKeyStoreProvider provider = SQLServerSecurityUtility + .getColumnEncryptionKeyStoreProvider(keyStoreName, connection, statement); aev2CekEntry.put(provider.decryptColumnEncryptionKey(keyPath, algo, encryptedKey)); enclaveRequestedCEKs.add(aev2CekEntry.array()); } @@ -244,35 +246,36 @@ default void processSDPEv1(String userSql, String preparedTypeDefinitions, Param 0, false); } - rs = (SQLServerResultSet) stmt.getResultSet(); - while (rs.next() && null != params) { - String paramName = rs.getString(DescribeParameterEncryptionResultSet2.ParameterName.value()); - int paramIndex = parameterNames.indexOf(paramName); - int cekOrdinal = rs.getInt(DescribeParameterEncryptionResultSet2.ColumnEncryptionKeyOrdinal.value()); - cekEntry = cekList.get(cekOrdinal); - - // cekEntry will be null if none of the parameters are encrypted. - if ((null != cekEntry) && (cekList.size() < cekOrdinal)) { - MessageFormat form = new MessageFormat( - SQLServerException.getErrString("R_InvalidEncryptionKeyOrdinal")); - Object[] msgArgs = {cekOrdinal, cekEntry.getSize()}; - throw new SQLServerException(null, form.format(msgArgs), null, 0, false); - } - SQLServerEncryptionType encType = SQLServerEncryptionType - .of((byte) rs.getInt(DescribeParameterEncryptionResultSet2.ColumnEncrytionType.value())); - if (SQLServerEncryptionType.PlainText != encType) { - params[paramIndex].cryptoMeta = new CryptoMetadata(cekEntry, (short) cekOrdinal, - (byte) rs.getInt(DescribeParameterEncryptionResultSet2.ColumnEncryptionAlgorithm.value()), null, - encType.value, - (byte) rs.getInt(DescribeParameterEncryptionResultSet2.NormalizationRuleVersion.value())); - // Decrypt the symmetric key.(This will also validate and throw if needed). - SQLServerSecurityUtility.decryptSymmetricKey(params[paramIndex].cryptoMeta, connection, statement); - } else { - if (params[paramIndex].getForceEncryption()) { + try (ResultSet rs2 = stmt.getResultSet()) { + while (rs2.next() && null != params) { + String paramName = rs2.getString(DescribeParameterEncryptionResultSet2.ParameterName.value()); + int paramIndex = parameterNames.indexOf(paramName); + int cekOrdinal = rs2.getInt(DescribeParameterEncryptionResultSet2.ColumnEncryptionKeyOrdinal.value()); + cekEntry = cekList.get(cekOrdinal); + + // cekEntry will be null if none of the parameters are encrypted. + if ((null != cekEntry) && (cekList.size() < cekOrdinal)) { MessageFormat form = new MessageFormat( - SQLServerException.getErrString("R_ForceEncryptionTrue_HonorAETrue_UnencryptedColumn")); - Object[] msgArgs = {userSql, paramIndex + 1}; - SQLServerException.makeFromDriverError(null, connection, form.format(msgArgs), "0", true); + SQLServerException.getErrString("R_InvalidEncryptionKeyOrdinal")); + Object[] msgArgs = {cekOrdinal, cekEntry.getSize()}; + throw new SQLServerException(null, form.format(msgArgs), null, 0, false); + } + SQLServerEncryptionType encType = SQLServerEncryptionType + .of((byte) rs2.getInt(DescribeParameterEncryptionResultSet2.ColumnEncrytionType.value())); + if (SQLServerEncryptionType.PlainText != encType) { + params[paramIndex].cryptoMeta = new CryptoMetadata(cekEntry, (short) cekOrdinal, + (byte) rs2.getInt(DescribeParameterEncryptionResultSet2.ColumnEncryptionAlgorithm.value()), + null, encType.value, + (byte) rs2.getInt(DescribeParameterEncryptionResultSet2.NormalizationRuleVersion.value())); + // Decrypt the symmetric key.(This will also validate and throw if needed). + SQLServerSecurityUtility.decryptSymmetricKey(params[paramIndex].cryptoMeta, connection, statement); + } else { + if (params[paramIndex].getForceEncryption()) { + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_ForceEncryptionTrue_HonorAETrue_UnencryptedColumn")); + Object[] msgArgs = {userSql, paramIndex + 1}; + SQLServerException.makeFromDriverError(null, connection, form.format(msgArgs), "0", true); + } } } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java index ea18f4a79..cf6e6de8e 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java @@ -2273,14 +2273,7 @@ else if (null != sourceCryptoMeta) { || (SSType.VARBINARYMAX == destSSType) || (SSType.IMAGE == destSSType)) { tdsWriter.writeNonUnicodeReader(reader, DataTypes.UNKNOWN_STREAM_LENGTH, true); } else { - SQLCollation destCollation = destColumnMetadata.get(destColOrdinal).collation; - if (null != destCollation) { - tdsWriter.writeNonUnicodeReader(reader, DataTypes.UNKNOWN_STREAM_LENGTH, - false); - } else { - tdsWriter.writeNonUnicodeReader(reader, DataTypes.UNKNOWN_STREAM_LENGTH, - false); - } + tdsWriter.writeNonUnicodeReader(reader, DataTypes.UNKNOWN_STREAM_LENGTH, false); } } reader.close(); @@ -2296,9 +2289,9 @@ else if (null != sourceCryptoMeta) { String colValueStr; if (colValue instanceof LocalDateTime) { - colValueStr = ((LocalDateTime)colValue).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME); + colValueStr = ((LocalDateTime) colValue).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME); } else if (colValue instanceof LocalTime) { - colValueStr = ((LocalTime)colValue).format(DateTimeFormatter.ISO_LOCAL_TIME); + colValueStr = ((LocalTime) colValue).format(DateTimeFormatter.ISO_LOCAL_TIME); } else { colValueStr = colValue.toString(); } @@ -3095,8 +3088,8 @@ else if (null != serverBulkData && (null == destCryptoMeta)) { } // normalize the values before encrypting them colValue = SQLServerSecurityUtility.encryptWithKey(normalizedValue(destJdbcType, colValue, - baseSrcJdbcType, destTypeInfo.getPrecision(), destTypeInfo.getScale(), destName), destCryptoMeta, - connection, null); + baseSrcJdbcType, destTypeInfo.getPrecision(), destTypeInfo.getScale(), destName), + destCryptoMeta, connection, null); } } writeColumnToTdsWriter(tdsWriter, srcPrecision, srcScale, srcJdbcType, srcNullable, srcColOrdinal, From f4597f502ecb24c029db047d01b83233bd2de19e Mon Sep 17 00:00:00 2001 From: lilgreenbird Date: Sat, 22 Jan 2022 00:32:59 -0800 Subject: [PATCH 2/3] more sonarqube fixes --- .../microsoft/sqlserver/jdbc/IOBuffer.java | 18 ++++++++++-- .../jdbc/IdleConnectionResiliency.java | 5 +++- ...rColumnEncryptionJavaKeyStoreProvider.java | 10 +++---- .../sqlserver/jdbc/SQLServerConnection.java | 13 +++++++-- .../jdbc/SQLServerConnectionPoolProxy.java | 28 +++++++++++-------- .../jdbc/SQLServerDatabaseMetaData.java | 11 +++++--- .../sqlserver/jdbc/SQLServerMSAL4JUtils.java | 12 ++++++++ .../sqlserver/jdbc/SQLServerResultSet.java | 8 +++--- .../sqlserver/jdbc/SQLServerSQLXML.java | 7 +++++ .../jdbc/SQLServerSecurityUtility.java | 3 ++ 10 files changed, 86 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java index 1a2617c25..d3fa5a08b 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java @@ -6366,6 +6366,13 @@ byte[] writeEncryptedScaledTemporal(GregorianCalendar cal, int subSecondNanos, i System.arraycopy(encodedNanoBytes, 0, encodedBytesForEncryption, 0, encodedNanoBytes.length); } } + + if (encodedBytesForEncryption == null) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_NullValue")); + Object[] msgArgs1 = {"encodedBytesForEncryption"}; + throw new SQLServerException(form.format(msgArgs1), null); + } + // Copy the 3 byte date value System.arraycopy(encodedBytes, 0, encodedBytesForEncryption, (encodedBytesForEncryption.length - 3), 3); @@ -6388,6 +6395,12 @@ byte[] writeEncryptedScaledTemporal(GregorianCalendar cal, int subSecondNanos, i } } + if (encodedBytesForEncryption == null) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_NullValue")); + Object[] msgArgs1 = {"encodedBytesForEncryption"}; + throw new SQLServerException(form.format(msgArgs1), null); + } + // Copy the 3 byte date value System.arraycopy(encodedBytes, 0, encodedBytesForEncryption, (encodedBytesForEncryption.length - 5), 3); // Copy the 2 byte minutesOffset value @@ -6949,7 +6962,7 @@ synchronized final boolean readPacket() throws SQLServerException { lastPacket = newPacket; // When logging, append the payload to the log buffer and write out the whole thing. - if (tdsChannel.isLoggingPackets()) { + if (tdsChannel.isLoggingPackets() && logBuffer != null) { System.arraycopy(newPacket.payload, 0, logBuffer, TDS.PACKET_HEADER_SIZE, newPacket.payloadLength); tdsChannel.logPacket(logBuffer, 0, packetLength, this.toString() + " received Packet:" + packetNum + " (" + newPacket.payloadLength + " bytes)"); @@ -7542,7 +7555,8 @@ protected void interrupt() throws Exception { } else { // If the timer wasn't canceled before it ran out of // time then interrupt the registered command. - command.interrupt(SQLServerException.getErrString("R_queryTimedOut")); + if (null != command) + command.interrupt(SQLServerException.getErrString("R_queryTimedOut")); } } catch (SQLServerException e) { // Request failed to time out and SQLServerConnection does not exist diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/IdleConnectionResiliency.java b/src/main/java/com/microsoft/sqlserver/jdbc/IdleConnectionResiliency.java index 43dae2029..8d7f5baf6 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/IdleConnectionResiliency.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/IdleConnectionResiliency.java @@ -255,7 +255,7 @@ void updateSessionState(TDSReader tdsReader, short sessionStateId, int sessionSt } else { // Not a first time state update hence if only there is a transition in state do we update the count. if (fRecoverable != sessionStateDelta[sessionStateId].isRecoverable()) { - if(fRecoverable) + if (fRecoverable) unRecoverableSessionStateCount.decrementAndGet(); else unRecoverableSessionStateCount.incrementAndGet(); @@ -424,6 +424,9 @@ public void run() { Thread.sleep(con.getRetryInterval() * 1000); } } catch (InterruptedException ie) { + // re-interrupt thread + Thread.currentThread().interrupt(); + this.eReceived = new SQLServerException(SQLServerException.getErrString("R_queryTimedOut"), SQLState.STATEMENT_CANCELED, DriverError.NOT_SET, null); keepRetrying = false; diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionJavaKeyStoreProvider.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionJavaKeyStoreProvider.java index 5ec068292..63c3d0b3a 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionJavaKeyStoreProvider.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionJavaKeyStoreProvider.java @@ -155,6 +155,11 @@ private CertificateDetails getCertificateDetails(String masterKeyPath) throws SQ catch (IOException e) {} } + if (certificateDetails == null) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_CertificateError")); + Object[] msgArgs = {masterKeyPath, name}; + throw new SQLServerException(this, form.format(msgArgs), null, 0, false); + } return certificateDetails; } @@ -177,7 +182,6 @@ private CertificateDetails getCertificateDetailsByAlias(KeyStore keyStore, Strin return new CertificateDetails(publicCertificate, keyPrivate); } catch (UnrecoverableKeyException unrecoverableKeyException) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_UnrecoverableKeyAE")); Object[] msgArgs = {alias}; throw new SQLServerException(this, form.format(msgArgs), null, 0, false); @@ -198,15 +202,11 @@ public byte[] encryptColumnEncryptionKey(String masterKeyPath, String encryption KeyStoreProviderCommon.validateNonEmptyMasterKeyPath(masterKeyPath); if (null == plainTextColumnEncryptionKey) { - throw new SQLServerException(null, SQLServerException.getErrString("R_NullColumnEncryptionKey"), null, 0, false); - } else if (0 == plainTextColumnEncryptionKey.length) { - throw new SQLServerException(null, SQLServerException.getErrString("R_EmptyColumnEncryptionKey"), null, 0, false); - } KeyStoreProviderCommon.validateEncryptionAlgorithm(encryptionAlgorithm, true); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java index c9e36b280..194c333d3 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java @@ -543,7 +543,12 @@ public String toString() { class ActiveDirectoryAuthentication { static final String JDBC_FEDAUTH_CLIENT_ID = "7f98cb04-cd1e-40df-9140-3bf7e2cea4db"; - static final String AZURE_REST_MSI_URL = "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01"; + + /** + * Managed Identities endpoint URL + * https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/how-to-use-vm-token + */ + static final String AZURE_REST_MSI_URL = "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01"; // NOSONAR static final String ACCESS_TOKEN_IDENTIFIER = "\"access_token\":\""; static final String ACCESS_TOKEN_EXPIRES_IN_IDENTIFIER = "\"expires_in\":\""; static final String ACCESS_TOKEN_EXPIRES_ON_IDENTIFIER = "\"expires_on\":\""; @@ -3184,7 +3189,8 @@ private InetSocketAddress connectHelper(ServerPortPlaceHolder serverInfo, int ti // Java's NativeSeedGenerator can sometimes fail on getSeedBytes(). Exact reason is unknown but high system // load seems to contribute to likelihood. Retry once to mitigate. if (connectionlogger.isLoggable(Level.FINER)) { - connectionlogger.finer(toString() + " Generating a random UUID has failed due to : " + e.getMessage() + "Retrying once."); + connectionlogger.finer(toString() + " Generating a random UUID has failed due to : " + e.getMessage() + + "Retrying once."); } clientConnectionId = UUID.randomUUID(); } @@ -3759,6 +3765,9 @@ boolean executeCommand(TDSCommand newCommand) throws SQLServerException { try { sessionRecovery.getReconnectThread().join(); } catch (InterruptedException e) { + // re-interrupt thread + Thread.currentThread().interrupt(); + // Keep compiler happy, something's probably seriously wrong if this line is run SQLServerException.makeFromDriverError(this, sessionRecovery.getReconnectThread(), e.getMessage(), null, false); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionPoolProxy.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionPoolProxy.java index d6bad4ec4..d31a429cc 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionPoolProxy.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionPoolProxy.java @@ -150,18 +150,24 @@ public void abort(Executor executor) throws SQLException { bIsOpen = false; - executor.execute(new Runnable() { - public void run() { - if (wrappedConnection.getConnectionLogger().isLoggable(java.util.logging.Level.FINER)) - wrappedConnection.getConnectionLogger().finer(toString() + " Connection proxy aborted "); - try { - wrappedConnection.poolCloseEventNotify(); - wrappedConnection = null; - } catch (SQLException e) { - throw new RuntimeException(e); + if (null == executor) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidArgument")); + Object[] msgArgs = {"executor"}; + SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), null, false); + } else { + executor.execute(new Runnable() { + public void run() { + if (wrappedConnection.getConnectionLogger().isLoggable(java.util.logging.Level.FINER)) + wrappedConnection.getConnectionLogger().finer(toString() + " Connection proxy aborted "); + try { + wrappedConnection.poolCloseEventNotify(); + wrappedConnection = null; + } catch (SQLException e) { + throw new RuntimeException(e); + } } - } - }); + }); + } } @Override diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDatabaseMetaData.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDatabaseMetaData.java index ab43fa600..984e00744 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDatabaseMetaData.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDatabaseMetaData.java @@ -345,16 +345,19 @@ private SQLServerResultSet getResultSetFromStoredProc(String catalog, CallableHa SQLServerCallableStatement call = (SQLServerCallableStatement) getCallableStatementHandle(procedure, catalog); - for (int i = 1; i <= arguments.length; i++) { - // note individual arguments can be null. - call.setString(i, arguments[i - 1]); + if (call != null) { + for (int i = 1; i <= arguments.length; i++) { + // note individual arguments can be null. + call.setString(i, arguments[i - 1]); + } + rs = (SQLServerResultSet) call.executeQueryInternal(); } - rs = (SQLServerResultSet) call.executeQueryInternal(); } finally { if (null != orgCat) { connection.setCatalog(orgCat); } } + return rs; } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerMSAL4JUtils.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerMSAL4JUtils.java index 3c9bfa2a3..e7fae94a9 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerMSAL4JUtils.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerMSAL4JUtils.java @@ -60,6 +60,9 @@ static SqlFedAuthToken getSqlFedAuthToken(SqlFedAuthInfo fedAuthInfo, String use final IAuthenticationResult authenticationResult = future.get(); return new SqlFedAuthToken(authenticationResult.accessToken(), authenticationResult.expiresOnDate()); } catch (MalformedURLException | InterruptedException e) { + // re-interrupt thread + Thread.currentThread().interrupt(); + throw new SQLServerException(e.getMessage(), e); } catch (ExecutionException e) { throw getCorrectedException(e, user, authenticationString); @@ -86,6 +89,9 @@ static SqlFedAuthToken getSqlFedAuthTokenPrincipal(SqlFedAuthInfo fedAuthInfo, S final IAuthenticationResult authenticationResult = future.get(); return new SqlFedAuthToken(authenticationResult.accessToken(), authenticationResult.expiresOnDate()); } catch (MalformedURLException | InterruptedException e) { + // re-interrupt thread + Thread.currentThread().interrupt(); + throw new SQLServerException(e.getMessage(), e); } catch (ExecutionException e) { throw getCorrectedException(e, aadPrincipalID, authenticationString); @@ -120,6 +126,9 @@ static SqlFedAuthToken getSqlFedAuthTokenIntegrated(SqlFedAuthInfo fedAuthInfo, final IAuthenticationResult authenticationResult = future.get(); return new SqlFedAuthToken(authenticationResult.accessToken(), authenticationResult.expiresOnDate()); } catch (InterruptedException | IOException e) { + // re-interrupt thread + Thread.currentThread().interrupt(); + throw new SQLServerException(e.getMessage(), e); } catch (ExecutionException e) { throw getCorrectedException(e, "", authenticationString); @@ -178,6 +187,9 @@ static SqlFedAuthToken getSqlFedAuthTokenInteractive(SqlFedAuthInfo fedAuthInfo, return new SqlFedAuthToken(authenticationResult.accessToken(), authenticationResult.expiresOnDate()); } catch (MalformedURLException | InterruptedException | URISyntaxException e) { + // re-interrupt thread + Thread.currentThread().interrupt(); + throw new SQLServerException(e.getMessage(), e); } catch (ExecutionException e) { throw getCorrectedException(e, user, authenticationString); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet.java index 2429f06a9..42e655719 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet.java @@ -3086,8 +3086,8 @@ private boolean currentRowDeleted() throws SQLServerException { // Having a current row implies we have a fetch buffer in which that row exists. assert null != tdsReader; - return deletedCurrentRow - || (0 != serverCursorId && TDS.ROWSTAT_FETCH_MISSING == loadColumn(columns.length).getInt(tdsReader, stmt)); + return deletedCurrentRow || (0 != serverCursorId + && TDS.ROWSTAT_FETCH_MISSING == loadColumn(columns.length).getInt(tdsReader, stmt)); } /* ---------------- Column updates ---------------------- */ @@ -5388,7 +5388,7 @@ boolean onDone(TDSReader tdsReader) throws SQLServerException { // Response is completely processed, hence decrement unprocessed response count. stmt.connection.getSessionRecovery().decrementUnprocessedResponseCount(); } - + // Done with all the rows in this fetch buffer and done with parsing // unless it's a server cursor, in which case there is a RETSTAT and // another DONE token to follow. @@ -5582,7 +5582,7 @@ final void doServerFetch(int fetchType, int startRow, int numRows) throws SQLSer if (numRows < 0 || startRow < 0) { // Scroll past all the returned rows, caching in the scroll window as we go. try { - while (scrollWindow.next(this)); + while (scrollWindow != null && scrollWindow.next(this)); } catch (SQLException e) { // If there is a row error in the results, don't throw an exception from here. // Ignore it for now and defer the exception until the app encounters the diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSQLXML.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSQLXML.java index b3a00f726..340bc9aa4 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSQLXML.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSQLXML.java @@ -466,6 +466,13 @@ private SAXResult getSAXResult() throws SQLException { Object[] msgArgs = {e.toString()}; SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true); } + + if (handler == null) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_noParserSupport")); + Object[] msgArgs = {"null"}; + SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true); + } + outputStreamValue = new ByteArrayOutputStreamToInputStream(); handler.setResult(new StreamResult(outputStreamValue)); SAXResult result = new SAXResult(handler); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSecurityUtility.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSecurityUtility.java index d0b64a4fb..be8e147dc 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSecurityUtility.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSecurityUtility.java @@ -436,6 +436,9 @@ static SqlFedAuthToken getMSIAuthToken(String resource, String msiClientId) thro : retryTimeoutInMs; Thread.sleep(retryTimeoutInMs); } catch (InterruptedException ex) { + // re-interrupt thread + Thread.currentThread().interrupt(); + // Throw runtime exception as driver must not be interrupted here throw new RuntimeException(ex); } From f4cd96d82242e7c60d37b17511c4a6531b5780fc Mon Sep 17 00:00:00 2001 From: lilgreenbird Date: Sat, 22 Jan 2022 13:55:31 -0800 Subject: [PATCH 3/3] more sonarqube stuff --- .../java/com/microsoft/sqlserver/jdbc/AE.java | 43 ++--- .../sqlserver/jdbc/AuthenticationJNI.java | 5 +- .../microsoft/sqlserver/jdbc/IOBuffer.java | 18 +- .../jdbc/ISQLServerEnclaveProvider.java | 34 ++-- .../sqlserver/jdbc/ParameterUtils.java | 28 +-- .../jdbc/SQLServerCertificateUtils.java | 10 +- ...rColumnEncryptionJavaKeyStoreProvider.java | 3 - .../sqlserver/jdbc/SQLServerConnection.java | 12 +- .../jdbc/SQLServerDatabaseMetaData.java | 167 ++++++++++-------- .../jdbc/SQLServerParameterMetaData.java | 46 +++-- .../jdbc/SQLServerPreparedStatement.java | 38 ++-- .../sqlserver/jdbc/SQLServerResultSet.java | 3 +- .../jdbc/SQLServerSecurityUtility.java | 66 ++++--- .../jdbc/SQLServerSpatialDatatype.java | 15 +- 14 files changed, 262 insertions(+), 226 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/AE.java b/src/main/java/com/microsoft/sqlserver/jdbc/AE.java index c75e3c46d..10222d321 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/AE.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/AE.java @@ -224,7 +224,7 @@ short getOrdinal() { encryptionKeyInfo = null; } - boolean IsAlgorithmInitialized() { + boolean isAlgorithmInitialized() { return null != cipherAlgorithm; } } @@ -234,17 +234,17 @@ boolean IsAlgorithmInitialized() { // We expect the server to return the fields in the resultset in the same order as mentioned below. // If the server changes the below order, then transparent parameter encryption will break. enum DescribeParameterEncryptionResultSet1 { - KeyOrdinal, - DbId, - KeyId, - KeyVersion, - KeyMdVersion, - EncryptedKey, - ProviderName, - KeyPath, - KeyEncryptionAlgorithm, - IsRequestedByEnclave, - EnclaveCMKSignature; + KEYORDINAL, + DBID, + KEYID, + KEYVERSION, + KEYMDVERSION, + ENCRYPTEDKEY, + PROVIDERNAME, + KEYPATH, + KEYENCRYPTIONALGORITHM, + ISREQUESTEDBYENCLAVE, + ENCLAVECMKSIGNATURE; int value() { // Column indexing starts from 1; @@ -257,12 +257,12 @@ int value() { // We expect the server to return the fields in the resultset in the same order as mentioned below. // If the server changes the below order, then transparent parameter encryption will break. enum DescribeParameterEncryptionResultSet2 { - ParameterOrdinal, - ParameterName, - ColumnEncryptionAlgorithm, - ColumnEncrytionType, - ColumnEncryptionKeyOrdinal, - NormalizationRuleVersion; + PARAMETERORDINAL, + PARAMETERNAME, + COLUMNENCRYPTIONALGORITHM, + COLUMNENCRYPTIONTYPE, + COLUMNENCRYPTIONKEYORDINAL, + NORMALIZATIONRULEVERSION; int value() { // Column indexing starts from 1; @@ -270,10 +270,11 @@ int value() { } } + enum ColumnEncryptionVersion { - AE_NotSupported, - AE_v1, - AE_v2; + AE_NOTSUPPORTED, + AE_V1, + AE_V2; int value() { // Column indexing starts from 1; diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/AuthenticationJNI.java b/src/main/java/com/microsoft/sqlserver/jdbc/AuthenticationJNI.java index 834859802..4c02eae69 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/AuthenticationJNI.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/AuthenticationJNI.java @@ -5,7 +5,6 @@ package com.microsoft.sqlserver.jdbc; -import java.lang.reflect.Array; import java.text.MessageFormat; import java.util.logging.Level; @@ -25,12 +24,12 @@ class FedAuthDllInfo { * Encapsulation of the JNI native calls for trusted authentication. */ final class AuthenticationJNI extends SSPIAuthentication { - private static final int maximumpointersize = 128; // we keep the SNI_Sec pointer + private static final int MAXPOINTERSIZE = 128; // we keep the SNI_Sec pointer private static boolean enabled = false; private static java.util.logging.Logger authLogger = java.util.logging.Logger .getLogger("com.microsoft.sqlserver.jdbc.internals.AuthenticationJNI"); private static int sspiBlobMaxlen = 0; - private byte[] sniSec = new byte[maximumpointersize]; + private byte[] sniSec = new byte[MAXPOINTERSIZE]; private int[] sniSecLen = {0}; private final String dnsName; private final int port; diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java index d3fa5a08b..1bb797c2a 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java @@ -5645,15 +5645,6 @@ void writeRPCByteArray(String sName, byte bValue[], boolean bOut, JDBCType jdbcT collation = null; } else switch (jdbcType) { - case BINARY: - case VARBINARY: - case LONGVARBINARY: - case BLOB: - default: - tdsType = (isShortValue || usePLP) ? TDSType.BIGVARBINARY : TDSType.IMAGE; - collation = null; - break; - case CHAR: case VARCHAR: case LONGVARCHAR: @@ -5671,6 +5662,15 @@ void writeRPCByteArray(String sName, byte bValue[], boolean bOut, JDBCType jdbcT if (null == collation) collation = con.getDatabaseCollation(); break; + + case BINARY: + case VARBINARY: + case LONGVARBINARY: + case BLOB: + default: + tdsType = (isShortValue || usePLP) ? TDSType.BIGVARBINARY : TDSType.IMAGE; + collation = null; + break; } writeRPCNameValType(sName, bOut, tdsType); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerEnclaveProvider.java b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerEnclaveProvider.java index 150e92245..fa3f747d3 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerEnclaveProvider.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerEnclaveProvider.java @@ -193,7 +193,7 @@ default void processSDPEv1(String userSql, String preparedTypeDefinitions, Param } while (rs.next()) { - int currentOrdinal = rs.getInt(DescribeParameterEncryptionResultSet1.KeyOrdinal.value()); + int currentOrdinal = rs.getInt(DescribeParameterEncryptionResultSet1.KEYORDINAL.value()); if (!cekList.containsKey(currentOrdinal)) { cekEntry = new CekTableEntry(currentOrdinal); cekList.put(cekEntry.ordinal, cekEntry); @@ -201,28 +201,28 @@ default void processSDPEv1(String userSql, String preparedTypeDefinitions, Param cekEntry = cekList.get(currentOrdinal); } - String keyStoreName = rs.getString(DescribeParameterEncryptionResultSet1.ProviderName.value()); - String algo = rs.getString(DescribeParameterEncryptionResultSet1.KeyEncryptionAlgorithm.value()); - String keyPath = rs.getString(DescribeParameterEncryptionResultSet1.KeyPath.value()); + String keyStoreName = rs.getString(DescribeParameterEncryptionResultSet1.PROVIDERNAME.value()); + String algo = rs.getString(DescribeParameterEncryptionResultSet1.KEYENCRYPTIONALGORITHM.value()); + String keyPath = rs.getString(DescribeParameterEncryptionResultSet1.KEYPATH.value()); - int dbID = rs.getInt(DescribeParameterEncryptionResultSet1.DbId.value()); - byte[] mdVer = rs.getBytes(DescribeParameterEncryptionResultSet1.KeyMdVersion.value()); - int keyID = rs.getInt(DescribeParameterEncryptionResultSet1.KeyId.value()); - byte[] encryptedKey = rs.getBytes(DescribeParameterEncryptionResultSet1.EncryptedKey.value()); + int dbID = rs.getInt(DescribeParameterEncryptionResultSet1.DBID.value()); + byte[] mdVer = rs.getBytes(DescribeParameterEncryptionResultSet1.KEYMDVERSION.value()); + int keyID = rs.getInt(DescribeParameterEncryptionResultSet1.KEYID.value()); + byte[] encryptedKey = rs.getBytes(DescribeParameterEncryptionResultSet1.ENCRYPTEDKEY.value()); - cekEntry.add(encryptedKey, dbID, keyID, rs.getInt(DescribeParameterEncryptionResultSet1.KeyVersion.value()), + cekEntry.add(encryptedKey, dbID, keyID, rs.getInt(DescribeParameterEncryptionResultSet1.KEYVERSION.value()), mdVer, keyPath, keyStoreName, algo); // servers supporting enclave computations should always return a boolean indicating whether the key // is // required by enclave or not. - if (ColumnEncryptionVersion.AE_v2.value() <= connection.getServerColumnEncryptionVersion().value()) { + if (ColumnEncryptionVersion.AE_V2.value() <= connection.getServerColumnEncryptionVersion().value()) { isRequestedByEnclave = rs - .getBoolean(DescribeParameterEncryptionResultSet1.IsRequestedByEnclave.value()); + .getBoolean(DescribeParameterEncryptionResultSet1.ISREQUESTEDBYENCLAVE.value()); } if (isRequestedByEnclave) { - byte[] keySignature = rs.getBytes(DescribeParameterEncryptionResultSet1.EnclaveCMKSignature.value()); + byte[] keySignature = rs.getBytes(DescribeParameterEncryptionResultSet1.ENCLAVECMKSIGNATURE.value()); String serverName = connection.getTrustedServerNameAE(); SQLServerSecurityUtility.verifyColumnMasterKeyMetadata(connection, statement, keyStoreName, keyPath, serverName, isRequestedByEnclave, keySignature); @@ -248,9 +248,9 @@ default void processSDPEv1(String userSql, String preparedTypeDefinitions, Param try (ResultSet rs2 = stmt.getResultSet()) { while (rs2.next() && null != params) { - String paramName = rs2.getString(DescribeParameterEncryptionResultSet2.ParameterName.value()); + String paramName = rs2.getString(DescribeParameterEncryptionResultSet2.PARAMETERNAME.value()); int paramIndex = parameterNames.indexOf(paramName); - int cekOrdinal = rs2.getInt(DescribeParameterEncryptionResultSet2.ColumnEncryptionKeyOrdinal.value()); + int cekOrdinal = rs2.getInt(DescribeParameterEncryptionResultSet2.COLUMNENCRYPTIONKEYORDINAL.value()); cekEntry = cekList.get(cekOrdinal); // cekEntry will be null if none of the parameters are encrypted. @@ -261,12 +261,12 @@ default void processSDPEv1(String userSql, String preparedTypeDefinitions, Param throw new SQLServerException(null, form.format(msgArgs), null, 0, false); } SQLServerEncryptionType encType = SQLServerEncryptionType - .of((byte) rs2.getInt(DescribeParameterEncryptionResultSet2.ColumnEncrytionType.value())); + .of((byte) rs2.getInt(DescribeParameterEncryptionResultSet2.COLUMNENCRYPTIONTYPE.value())); if (SQLServerEncryptionType.PlainText != encType) { params[paramIndex].cryptoMeta = new CryptoMetadata(cekEntry, (short) cekOrdinal, - (byte) rs2.getInt(DescribeParameterEncryptionResultSet2.ColumnEncryptionAlgorithm.value()), + (byte) rs2.getInt(DescribeParameterEncryptionResultSet2.COLUMNENCRYPTIONALGORITHM.value()), null, encType.value, - (byte) rs2.getInt(DescribeParameterEncryptionResultSet2.NormalizationRuleVersion.value())); + (byte) rs2.getInt(DescribeParameterEncryptionResultSet2.NORMALIZATIONRULEVERSION.value())); // Decrypt the symmetric key.(This will also validate and throw if needed). SQLServerSecurityUtility.decryptSymmetricKey(params[paramIndex].cryptoMeta, connection, statement); } else { diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ParameterUtils.java b/src/main/java/com/microsoft/sqlserver/jdbc/ParameterUtils.java index 1b6c08ecb..702382520 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ParameterUtils.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ParameterUtils.java @@ -69,6 +69,20 @@ static int scanSQLForChar(char ch, String sql, int offset) { while (offset < len) { switch (chTmp = sql.charAt(offset++)) { + case '[': + chTmp = ']'; + case '\'': + case '"': + chQuote = chTmp; + while (offset < len) { + if (sql.charAt(offset++) == chQuote) { + if (len == offset || sql.charAt(offset) != chQuote) + break; + + ++offset; + } + } + break; case '/': if (offset == len) break; @@ -102,20 +116,6 @@ static int scanSQLForChar(char ch, String sql, int offset) { if (ch == chTmp) return offset - 1; break; - case '[': - chTmp = ']'; - case '\'': - case '"': - chQuote = chTmp; - while (offset < len) { - if (sql.charAt(offset++) == chQuote) { - if (len == offset || sql.charAt(offset) != chQuote) - break; - - ++offset; - } - } - break; } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerCertificateUtils.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerCertificateUtils.java index a7d878060..fd7134e7c 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerCertificateUtils.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerCertificateUtils.java @@ -96,7 +96,7 @@ private static KeyManager[] readPKCS12Certificate(String certPath, private static KeyManager[] readPKCS8Certificate(String certPath, String keyPath, String keyPassword) throws IOException, GeneralSecurityException, SQLServerException { Certificate clientCertificate = loadCertificate(certPath); - ((X509Certificate)clientCertificate).checkValidity(); + ((X509Certificate) clientCertificate).checkValidity(); PrivateKey privateKey = loadPrivateKey(keyPath, keyPassword); KeyStore keyStore = KeyStore.getInstance(JAVA_KEY_STORE); @@ -130,9 +130,7 @@ private static void deleteFirst(StringBuilder sb, String str) { private static PrivateKey loadPrivateKeyFromPKCS1(String key, String keyPass) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { SQLServerBouncyCastleLoader.loadBouncyCastle(); - PEMParser pemParser = null; - try { - pemParser = new PEMParser(new StringReader(key)); + try (PEMParser pemParser = new PEMParser(new StringReader(key))) { Object object = pemParser.readObject(); JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC"); KeyPair kp; @@ -143,10 +141,6 @@ private static PrivateKey loadPrivateKeyFromPKCS1(String key, kp = converter.getKeyPair((PEMKeyPair) object); } return kp.getPrivate(); - } finally { - if (null != pemParser) { - pemParser.close(); - } } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionJavaKeyStoreProvider.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionJavaKeyStoreProvider.java index 63c3d0b3a..f96eb92ee 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionJavaKeyStoreProvider.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionJavaKeyStoreProvider.java @@ -348,9 +348,6 @@ public boolean verifyColumnMasterKeyMetadata(String masterKeyPath, boolean allow KeyStoreProviderCommon.validateNonEmptyMasterKeyPath(masterKeyPath); CertificateDetails certificateDetails = getCertificateDetails(masterKeyPath); - if (null == certificateDetails) { - return false; - } try { MessageDigest md = MessageDigest.getInstance("SHA-256"); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java index 194c333d3..04d1cd88f 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java @@ -822,13 +822,13 @@ boolean getSendTemporalDataTypesAsStringForBulkCopy() { String keyStorePrincipalId = null; /** server column encryption version */ - private ColumnEncryptionVersion serverColumnEncryptionVersion = ColumnEncryptionVersion.AE_NotSupported; + private ColumnEncryptionVersion serverColumnEncryptionVersion = ColumnEncryptionVersion.AE_NOTSUPPORTED; /** Enclave type */ private String enclaveType = null; boolean getServerSupportsColumnEncryption() { - return (serverColumnEncryptionVersion.value() > ColumnEncryptionVersion.AE_NotSupported.value()); + return (serverColumnEncryptionVersion.value() > ColumnEncryptionVersion.AE_NOTSUPPORTED.value()); } ColumnEncryptionVersion getServerColumnEncryptionVersion() { @@ -3767,7 +3767,7 @@ boolean executeCommand(TDSCommand newCommand) throws SQLServerException { } catch (InterruptedException e) { // re-interrupt thread Thread.currentThread().interrupt(); - + // Keep compiler happy, something's probably seriously wrong if this line is run SQLServerException.makeFromDriverError(this, sessionRecovery.getReconnectThread(), e.getMessage(), null, false); @@ -5576,13 +5576,13 @@ private void onFeatureExtAck(byte featureId, byte[] data) throws SQLServerExcept throw new SQLServerException(SQLServerException.getErrString("R_InvalidAEVersionNumber"), null); } - serverColumnEncryptionVersion = ColumnEncryptionVersion.AE_v1; + serverColumnEncryptionVersion = ColumnEncryptionVersion.AE_V1; if (null != enclaveAttestationUrl) { if (aeVersion < TDS.COLUMNENCRYPTION_VERSION2) { throw new SQLServerException(SQLServerException.getErrString("R_enclaveNotSupported"), null); } else { - serverColumnEncryptionVersion = ColumnEncryptionVersion.AE_v2; + serverColumnEncryptionVersion = ColumnEncryptionVersion.AE_V2; enclaveType = new String(data, 2, data.length - 2, UTF_16LE); } @@ -6500,7 +6500,7 @@ public int getNetworkTimeout() throws SQLException { @Override public void setNetworkTimeout(Executor executor, int timeout) throws SQLException { - loggerExternal.entering(loggingClassName, "setNetworkTimeout", timeout); + loggerExternal.entering(loggingClassName, SET_NETWORK_TIMEOUT_PERM, timeout); if (timeout < 0) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidSocketTimeout")); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDatabaseMetaData.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDatabaseMetaData.java index 984e00744..a16fe339e 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDatabaseMetaData.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDatabaseMetaData.java @@ -259,6 +259,13 @@ private void checkClosed() throws SQLServerException { private static final String FUNCTION_TYPE = "FUNCTION_TYPE"; private static final String SS_IS_SPARSE = "SS_IS_SPARSE"; private static final String SS_IS_COLUMN_SET = "SS_IS_COLUMN_SET"; + private static final String SS_UDT_CATALOG_NAME = "SS_UDT_CATALOG_NAME"; + private static final String SS_UDT_SCHEMA_NAME = "SS_UDT_SCHEMA_NAME"; + private static final String SS_UDT_ASSEMBLY_TYPE_NAME = "SS_UDT_ASSEMBLY_TYPE_NAME"; + private static final String SS_XML_SCHEMACOLLECTION_CATALOG_NAME = "SS_XML_SCHEMACOLLECTION_CATALOG_NAME"; + private static final String SS_XML_SCHEMACOLLECTION_SCHEMA_NAME = "SS_XML_SCHEMACOLLECTION_SCHEMA_NAME"; + private static final String SS_XML_SCHEMACOLLECTION_NAME = "SS_XML_SCHEMACOLLECTION_NAME"; + private static final String IS_GENERATEDCOLUMN = "IS_GENERATEDCOLUMN"; private static final String IS_AUTOINCREMENT = "IS_AUTOINCREMENT"; private static final String SQL_KEYWORDS = createSqlKeyWords(); @@ -367,8 +374,10 @@ private SQLServerResultSet getResultSetWithProvidedColumnNames(String catalog, C SQLServerResultSet rs = getResultSetFromStoredProc(catalog, procedure, arguments); // Rename the columns - for (int i = 0; i < columnNames.length; i++) - rs.setColumnName(1 + i, columnNames[i]); + if (null != rs) { + for (int i = 0; i < columnNames.length; i++) + rs.setColumnName(1 + i, columnNames[i]); + } return rs; } @@ -686,42 +695,42 @@ public java.sql.ResultSet getColumns(String catalog, String schema, String table synchronized (SQLServerDatabaseMetaData.class) { if (null == getColumnsDWColumns) { getColumnsDWColumns = new LinkedHashMap<>(); - getColumnsDWColumns.put(1, "TABLE_CAT"); - getColumnsDWColumns.put(2, "TABLE_SCHEM"); - getColumnsDWColumns.put(3, "TABLE_NAME"); - getColumnsDWColumns.put(4, "COLUMN_NAME"); - getColumnsDWColumns.put(5, "DATA_TYPE"); - getColumnsDWColumns.put(6, "TYPE_NAME"); - getColumnsDWColumns.put(7, "COLUMN_SIZE"); - getColumnsDWColumns.put(8, "BUFFER_LENGTH"); - getColumnsDWColumns.put(9, "DECIMAL_DIGITS"); - getColumnsDWColumns.put(10, "NUM_PREC_RADIX"); - getColumnsDWColumns.put(11, "NULLABLE"); - getColumnsDWColumns.put(12, "REMARKS"); - getColumnsDWColumns.put(13, "COLUMN_DEF"); - getColumnsDWColumns.put(14, "SQL_DATA_TYPE"); - getColumnsDWColumns.put(15, "SQL_DATETIME_SUB"); - getColumnsDWColumns.put(16, "CHAR_OCTET_LENGTH"); - getColumnsDWColumns.put(17, "ORDINAL_POSITION"); - getColumnsDWColumns.put(18, "IS_NULLABLE"); + getColumnsDWColumns.put(1, TABLE_CAT); + getColumnsDWColumns.put(2, TABLE_SCHEM); + getColumnsDWColumns.put(3, TABLE_NAME); + getColumnsDWColumns.put(4, COLUMN_NAME); + getColumnsDWColumns.put(5, DATA_TYPE); + getColumnsDWColumns.put(6, TYPE_NAME); + getColumnsDWColumns.put(7, COLUMN_SIZE); + getColumnsDWColumns.put(8, BUFFER_LENGTH); + getColumnsDWColumns.put(9, DECIMAL_DIGITS); + getColumnsDWColumns.put(10, NUM_PREC_RADIX); + getColumnsDWColumns.put(11, NULLABLE); + getColumnsDWColumns.put(12, REMARKS); + getColumnsDWColumns.put(13, COLUMN_DEF); + getColumnsDWColumns.put(14, SQL_DATA_TYPE); + getColumnsDWColumns.put(15, SQL_DATETIME_SUB); + getColumnsDWColumns.put(16, CHAR_OCTET_LENGTH); + getColumnsDWColumns.put(17, ORDINAL_POSITION); + getColumnsDWColumns.put(18, IS_NULLABLE); /* * Use negative value keys to indicate that this column doesn't exist in SQL Server and should just * be queried as 'NULL' */ - getColumnsDWColumns.put(-1, "SCOPE_CATALOG"); - getColumnsDWColumns.put(-2, "SCOPE_SCHEMA"); - getColumnsDWColumns.put(-3, "SCOPE_TABLE"); - getColumnsDWColumns.put(29, "SOURCE_DATA_TYPE"); - getColumnsDWColumns.put(22, "IS_AUTOINCREMENT"); - getColumnsDWColumns.put(21, "IS_GENERATEDCOLUMN"); - getColumnsDWColumns.put(19, "SS_IS_SPARSE"); - getColumnsDWColumns.put(20, "SS_IS_COLUMN_SET"); - getColumnsDWColumns.put(23, "SS_UDT_CATALOG_NAME"); - getColumnsDWColumns.put(24, "SS_UDT_SCHEMA_NAME"); - getColumnsDWColumns.put(25, "SS_UDT_ASSEMBLY_TYPE_NAME"); - getColumnsDWColumns.put(26, "SS_XML_SCHEMACOLLECTION_CATALOG_NAME"); - getColumnsDWColumns.put(27, "SS_XML_SCHEMACOLLECTION_SCHEMA_NAME"); - getColumnsDWColumns.put(28, "SS_XML_SCHEMACOLLECTION_NAME"); + getColumnsDWColumns.put(-1, SCOPE_CATALOG); + getColumnsDWColumns.put(-2, SCOPE_SCHEMA); + getColumnsDWColumns.put(-3, SCOPE_TABLE); + getColumnsDWColumns.put(29, SOURCE_DATA_TYPE); + getColumnsDWColumns.put(22, IS_AUTOINCREMENT); + getColumnsDWColumns.put(21, IS_GENERATEDCOLUMN); + getColumnsDWColumns.put(19, SS_IS_SPARSE); + getColumnsDWColumns.put(20, SS_IS_COLUMN_SET); + getColumnsDWColumns.put(23, SS_UDT_CATALOG_NAME); + getColumnsDWColumns.put(24, SS_UDT_SCHEMA_NAME); + getColumnsDWColumns.put(25, SS_UDT_ASSEMBLY_TYPE_NAME); + getColumnsDWColumns.put(26, SS_XML_SCHEMACOLLECTION_CATALOG_NAME); + getColumnsDWColumns.put(27, SS_XML_SCHEMACOLLECTION_SCHEMA_NAME); + getColumnsDWColumns.put(28, SS_XML_SCHEMACOLLECTION_NAME); } } @@ -882,12 +891,14 @@ public java.sql.ResultSet getFunctionColumns(String catalog, String schemaPatter // Hook in a filter on the DATA_TYPE column of the result set we're // going to return that converts the ODBC values from sp_columns // into JDBC values. Also for the precision - rs.getColumn(6).setFilter(new DataTypeFilter()); + if (null != rs) { + rs.getColumn(6).setFilter(new DataTypeFilter()); - if (connection.isKatmaiOrLater()) { - rs.getColumn(8).setFilter(new ZeroFixupFilter()); - rs.getColumn(9).setFilter(new ZeroFixupFilter()); - rs.getColumn(17).setFilter(new ZeroFixupFilter()); + if (connection.isKatmaiOrLater()) { + rs.getColumn(8).setFilter(new ZeroFixupFilter()); + rs.getColumn(9).setFilter(new ZeroFixupFilter()); + rs.getColumn(17).setFilter(new ZeroFixupFilter()); + } } return rs; } @@ -938,7 +949,9 @@ public java.sql.ResultSet getBestRowIdentifier(String catalog, String schema, St // Hook in a filter on the DATA_TYPE column of the result set we're // going to return that converts the ODBC values from sp_columns // into JDBC values. - rs.getColumn(3).setFilter(new DataTypeFilter()); + if (null != rs) { + rs.getColumn(3).setFilter(new DataTypeFilter()); + } return rs; } @@ -1077,20 +1090,20 @@ private ResultSet executeSPFkeys(String[] procParams) throws SQLException, SQLTi synchronized (SQLServerDatabaseMetaData.class) { if (null == getImportedKeysDWColumns) { getImportedKeysDWColumns = new LinkedHashMap<>(); - getImportedKeysDWColumns.put(1, "PKTABLE_CAT"); - getImportedKeysDWColumns.put(2, "PKTABLE_SCHEM"); - getImportedKeysDWColumns.put(3, "PKTABLE_NAME"); - getImportedKeysDWColumns.put(4, "PKCOLUMN_NAME"); - getImportedKeysDWColumns.put(5, "FKTABLE_CAT"); - getImportedKeysDWColumns.put(6, "FKTABLE_SCHEM"); - getImportedKeysDWColumns.put(7, "FKTABLE_NAME"); - getImportedKeysDWColumns.put(8, "FKCOLUMN_NAME"); - getImportedKeysDWColumns.put(9, "KEY_SEQ"); - getImportedKeysDWColumns.put(10, "UPDATE_RULE"); - getImportedKeysDWColumns.put(11, "DELETE_RULE"); - getImportedKeysDWColumns.put(12, "FK_NAME"); - getImportedKeysDWColumns.put(13, "PK_NAME"); - getImportedKeysDWColumns.put(14, "DEFERRABILITY"); + getImportedKeysDWColumns.put(1, PKTABLE_CAT); + getImportedKeysDWColumns.put(2, PKTABLE_SCHEM); + getImportedKeysDWColumns.put(3, PKTABLE_NAME); + getImportedKeysDWColumns.put(4, PKCOLUMN_NAME); + getImportedKeysDWColumns.put(5, FKTABLE_CAT); + getImportedKeysDWColumns.put(6, FKTABLE_SCHEM); + getImportedKeysDWColumns.put(7, FKTABLE_NAME); + getImportedKeysDWColumns.put(8, FKCOLUMN_NAME); + getImportedKeysDWColumns.put(9, KEY_SEQ); + getImportedKeysDWColumns.put(10, UPDATE_RULE); + getImportedKeysDWColumns.put(11, DELETE_RULE); + getImportedKeysDWColumns.put(12, FK_NAME); + getImportedKeysDWColumns.put(13, PK_NAME); + getImportedKeysDWColumns.put(14, DEFERRABILITY); } } azureDwSelectBuilder.append(generateAzureDWEmptyRS(getImportedKeysDWColumns)); @@ -1355,13 +1368,14 @@ public java.sql.ResultSet getProcedureColumns(String catalog, String schema, Str // Hook in a filter on the DATA_TYPE column of the result set we're // going to return that converts the ODBC values from sp_columns // into JDBC values. Also for the precision - rs.getColumn(6).setFilter(new DataTypeFilter()); - if (connection.isKatmaiOrLater()) { - rs.getColumn(8).setFilter(new ZeroFixupFilter()); - rs.getColumn(9).setFilter(new ZeroFixupFilter()); - rs.getColumn(17).setFilter(new ZeroFixupFilter()); + if (null != rs) { + rs.getColumn(6).setFilter(new DataTypeFilter()); + if (connection.isKatmaiOrLater()) { + rs.getColumn(8).setFilter(new ZeroFixupFilter()); + rs.getColumn(9).setFilter(new ZeroFixupFilter()); + rs.getColumn(17).setFilter(new ZeroFixupFilter()); + } } - return rs; } @@ -1739,7 +1753,9 @@ public java.sql.ResultSet getVersionColumns(String catalog, String schema, // Hook in a filter on the DATA_TYPE column of the result set we're // going to return that converts the ODBC values from sp_columns // into JDBC values. - rs.getColumn(3).setFilter(new DataTypeFilter()); + if (null != rs) { + rs.getColumn(3).setFilter(new DataTypeFilter()); + } return rs; } @@ -2149,8 +2165,9 @@ public boolean supportsTransactionIsolationLevel(int level) throws SQLServerExce case Connection.TRANSACTION_SERIALIZABLE: case SQLServerConnection.TRANSACTION_SNAPSHOT: return true; + default: + return false; } - return false; } @Override @@ -2199,8 +2216,9 @@ public boolean supportsResultSetType(int type) throws SQLServerException { case SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY: case SQLServerResultSet.TYPE_SS_SCROLL_DYNAMIC: return true; + default: + return false; } - return false; } @Override @@ -2221,9 +2239,10 @@ public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQ // synonym case SQLServerResultSet.TYPE_SS_DIRECT_FORWARD_ONLY: return (ResultSet.CONCUR_READ_ONLY == concurrency); + default: + // per spec if we do not know we do not support. + return false; } - // per spec if we do not know we do not support. - return false; } @Override @@ -2307,11 +2326,12 @@ private void checkResultType(int type) throws SQLServerException { case SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY: case SQLServerResultSet.TYPE_SS_SCROLL_DYNAMIC: return; + default: + // if the value is outside of the valid values throw error. + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidArgument")); + Object[] msgArgs = {type}; + throw new SQLServerException(null, form.format(msgArgs), null, 0, true); } - // if the value is outside of the valid values throw error. - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidArgument")); - Object[] msgArgs = {type}; - throw new SQLServerException(null, form.format(msgArgs), null, 0, true); } // Check the concurrency values and make sure the value is a supported @@ -2325,11 +2345,12 @@ private void checkConcurrencyType(int type) throws SQLServerException { case SQLServerResultSet.CONCUR_SS_SCROLL_LOCKS: case SQLServerResultSet.CONCUR_SS_OPTIMISTIC_CCVAL: return; + default: + // if the value is outside of the valid values throw error. + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidArgument")); + Object[] msgArgs = {type}; + throw new SQLServerException(null, form.format(msgArgs), null, 0, true); } - // if the value is outside of the valid values throw error. - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidArgument")); - Object[] msgArgs = {type}; - throw new SQLServerException(null, form.format(msgArgs), null, 0, true); } @Override diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerParameterMetaData.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerParameterMetaData.java index cd5debe8b..475693361 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerParameterMetaData.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerParameterMetaData.java @@ -25,9 +25,9 @@ * The API javadoc for JDBC API methods that this class implements are not repeated here. Please see Sun's JDBC API * interfaces javadoc for those details. * - * For SQL Servers versioned below SQL Server 2012, prepared statements are executed with SET FMT ONLY to - * retrieve column meta data Callable statements : - * sp_sp_sproc_columns is called to retrieve names and meta data for the procedures params. + * For SQL Servers versioned below SQL Server 2012, prepared statements are executed with SET FMT ONLY to retrieve + * column meta data Callable statements : sp_sp_sproc_columns is called to retrieve names and meta data for the + * procedures params. * * For SQL Server 2012 and above, sp_describe_undeclared_parameter is used to retrieve parameter metadata. */ @@ -36,6 +36,14 @@ public final class SQLServerParameterMetaData implements ParameterMetaData { private final static int SQL_SERVER_2012_VERSION = 11; + private static final String DATA_TYPE = "DATA_TYPE"; + private static final String COLUMN_TYPE = "COLUMN_TYPE"; + private static final String TYPE_NAME = "TYPE_NAME"; + private static final String PRECISION = "PRECISION"; + private static final String SCALE = "SCALE"; + private static final String NULLABLE = "NULLABLE"; + private static final String SS_TYPE_SCHEMA_NAME = "SS_TYPE_SCHEMA_NAME"; + private final SQLServerPreparedStatement stmtParent; private SQLServerConnection con; @@ -321,13 +329,13 @@ private void checkClosed() throws SQLServerException { while (rsProcedureMeta.next()) { procMetadata.add(new HashMap() { { - put("DATA_TYPE", rsProcedureMeta.getShort("DATA_TYPE")); - put("COLUMN_TYPE", rsProcedureMeta.getInt("COLUMN_TYPE")); - put("TYPE_NAME", rsProcedureMeta.getString("TYPE_NAME")); - put("PRECISION", rsProcedureMeta.getInt("PRECISION")); - put("SCALE", rsProcedureMeta.getInt("SCALE")); - put("NULLABLE", rsProcedureMeta.getInt("NULLABLE")); - put("SS_TYPE_SCHEMA_NAME", rsProcedureMeta.getString("SS_TYPE_SCHEMA_NAME")); + put(DATA_TYPE, rsProcedureMeta.getShort(DATA_TYPE)); + put(COLUMN_TYPE, rsProcedureMeta.getInt(COLUMN_TYPE)); + put(TYPE_NAME, rsProcedureMeta.getString(TYPE_NAME)); + put(PRECISION, rsProcedureMeta.getInt(PRECISION)); + put(SCALE, rsProcedureMeta.getInt(SCALE)); + put(NULLABLE, rsProcedureMeta.getInt(NULLABLE)); + put(SS_TYPE_SCHEMA_NAME, rsProcedureMeta.getString(SS_TYPE_SCHEMA_NAME)); } }); } @@ -433,7 +441,7 @@ public String getParameterClassName(int param) throws SQLServerException { if (null == procMetadata) { return queryMetaMap.get(param).parameterClassName; } else { - return JDBCType.of((short) getParameterInfo(param).get("DATA_TYPE")).className(); + return JDBCType.of((short) getParameterInfo(param).get(DATA_TYPE)).className(); } } catch (SQLServerException e) { SQLServerException.makeFromDriverError(con, stmtParent, e.getMessage(), null, false); @@ -460,7 +468,7 @@ public int getParameterMode(int param) throws SQLServerException { // if it is not a stored procedure, the @param can only be input. return parameterModeIn; } else { - int n = (int) getParameterInfo(param).get("COLUMN_TYPE"); + int n = (int) getParameterInfo(param).get(COLUMN_TYPE); if (n == 1) return parameterModeIn; else if (n == 2) @@ -478,7 +486,7 @@ public int getParameterType(int param) throws SQLServerException { if (null == procMetadata) { parameterType = queryMetaMap.get(param).parameterType; } else { - parameterType = (short) getParameterInfo(param).get("DATA_TYPE"); + parameterType = (short) getParameterInfo(param).get(DATA_TYPE); } if (0 != parameterType) { switch (parameterType) { @@ -507,7 +515,7 @@ public String getParameterTypeName(int param) throws SQLServerException { if (null == procMetadata) { return queryMetaMap.get(param).parameterTypeName; } else { - return getParameterInfo(param).get("TYPE_NAME").toString(); + return getParameterInfo(param).get(TYPE_NAME).toString(); } } @@ -518,7 +526,7 @@ public int getPrecision(int param) throws SQLServerException { if (null == procMetadata) { return queryMetaMap.get(param).precision; } else { - return (int) getParameterInfo(param).get("PRECISION"); + return (int) getParameterInfo(param).get(PRECISION); } } @@ -529,7 +537,7 @@ public int getScale(int param) throws SQLServerException { if (null == procMetadata) { return queryMetaMap.get(param).scale; } else { - return (int) getParameterInfo(param).get("SCALE"); + return (int) getParameterInfo(param).get(SCALE); } } @@ -540,7 +548,7 @@ public int isNullable(int param) throws SQLServerException { if (procMetadata == null) { return queryMetaMap.get(param).isNullable; } else { - return (int) getParameterInfo(param).get("NULLABLE"); + return (int) getParameterInfo(param).get(NULLABLE); } } @@ -561,7 +569,7 @@ public boolean isSigned(int param) throws SQLServerException { if (null == procMetadata) { return queryMetaMap.get(param).isSigned; } else { - return JDBCType.of((short) getParameterInfo(param).get("DATA_TYPE")).isSigned(); + return JDBCType.of((short) getParameterInfo(param).get(DATA_TYPE)).isSigned(); } } catch (SQLException e) { SQLServerException.makeFromDriverError(con, stmtParent, e.getMessage(), null, false); @@ -572,6 +580,6 @@ public boolean isSigned(int param) throws SQLServerException { String getTVPSchemaFromStoredProcedure(int param) throws SQLServerException { checkClosed(); checkParam(param); - return (String) getParameterInfo(param).get("SS_TYPE_SCHEMA_NAME"); + return (String) getParameterInfo(param).get(SS_TYPE_SCHEMA_NAME); } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java index 8273b4b9d..17bd4a5fe 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java @@ -885,7 +885,8 @@ private void getParameterEncryptionMetadata(Parameter[] params) throws SQLServer // pass registered custom provider to stmt if (this.hasColumnEncryptionKeyStoreProvidersRegistered()) { - ((SQLServerCallableStatement) stmt).registerColumnEncryptionKeyStoreProvidersOnStatement(this.statementColumnEncryptionKeyStoreProviders); + ((SQLServerCallableStatement) stmt).registerColumnEncryptionKeyStoreProvidersOnStatement( + this.statementColumnEncryptionKeyStoreProviders); } ((SQLServerCallableStatement) stmt).isInternalEncryptionQuery = true; @@ -901,21 +902,21 @@ private void getParameterEncryptionMetadata(Parameter[] params) throws SQLServer Map cekList = new HashMap<>(); CekTableEntry cekEntry = null; while (rs.next()) { - int currentOrdinal = rs.getInt(DescribeParameterEncryptionResultSet1.KeyOrdinal.value()); + 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())); + 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."); @@ -933,10 +934,10 @@ private void getParameterEncryptionMetadata(Parameter[] params) throws SQLServer while (secondRs.next()) { paramCount++; String paramName = secondRs - .getString(DescribeParameterEncryptionResultSet2.ParameterName.value()); + .getString(DescribeParameterEncryptionResultSet2.PARAMETERNAME.value()); int paramIndex = parameterNames.indexOf(paramName); int cekOrdinal = secondRs - .getInt(DescribeParameterEncryptionResultSet2.ColumnEncryptionKeyOrdinal.value()); + .getInt(DescribeParameterEncryptionResultSet2.COLUMNENCRYPTIONKEYORDINAL.value()); cekEntry = cekList.get(cekOrdinal); // cekEntry will be null if none of the parameters are encrypted. @@ -947,17 +948,18 @@ private void getParameterEncryptionMetadata(Parameter[] params) throws SQLServer throw new SQLServerException(this, form.format(msgArgs), null, 0, false); } SQLServerEncryptionType encType = SQLServerEncryptionType.of((byte) secondRs - .getInt(DescribeParameterEncryptionResultSet2.ColumnEncrytionType.value())); + .getInt(DescribeParameterEncryptionResultSet2.COLUMNENCRYPTIONTYPE.value())); if (SQLServerEncryptionType.PlainText != encType) { params[paramIndex].cryptoMeta = new CryptoMetadata(cekEntry, (short) cekOrdinal, (byte) secondRs.getInt( - DescribeParameterEncryptionResultSet2.ColumnEncryptionAlgorithm.value()), + DescribeParameterEncryptionResultSet2.COLUMNENCRYPTIONALGORITHM.value()), null, encType.value, (byte) secondRs.getInt( - DescribeParameterEncryptionResultSet2.NormalizationRuleVersion.value())); + DescribeParameterEncryptionResultSet2.NORMALIZATIONRULEVERSION.value())); SQLServerStatement statement = (SQLServerStatement) stmt; // Decrypt the symmetric key.(This will also validate and throw if needed). - SQLServerSecurityUtility.decryptSymmetricKey(params[paramIndex].cryptoMeta, connection, statement); + SQLServerSecurityUtility.decryptSymmetricKey(params[paramIndex].cryptoMeta, connection, + statement); } else { if (params[paramIndex].getForceEncryption()) { MessageFormat form = new MessageFormat(SQLServerException @@ -2752,8 +2754,8 @@ final void doExecutePreparedStatementBatch(PrepStmtBatchExecCmd batchCommand) th if ((0 == numBatchesExecuted) && !isInternalEncryptionQuery && connection.isAEv2() && !encryptionMetadataIsRetrieved) { - this.enclaveCEKs = connection.initEnclaveParameters(this, preparedSQL, preparedTypeDefinitions, batchParam, - parameterNames); + this.enclaveCEKs = connection.initEnclaveParameters(this, preparedSQL, preparedTypeDefinitions, + batchParam, parameterNames); encryptionMetadataIsRetrieved = true; /* diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet.java index 42e655719..3f2b44d19 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet.java @@ -5599,7 +5599,8 @@ final void doServerFetch(int fetchType, int startRow, int numRows) throws SQLSer } // Put the scroll window back before the first row. - scrollWindow.reset(); + if (null != scrollWindow) + scrollWindow.reset(); } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSecurityUtility.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSecurityUtility.java index be8e147dc..b8110f781 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSecurityUtility.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSecurityUtility.java @@ -98,7 +98,8 @@ static boolean compareBytes(byte[] buffer1, byte[] buffer2, int buffer2Index, in } - static SQLServerColumnEncryptionKeyStoreProvider getColumnEncryptionKeyStoreProvider(String providerName, SQLServerConnection connection, SQLServerStatement statement) throws SQLServerException { + static SQLServerColumnEncryptionKeyStoreProvider getColumnEncryptionKeyStoreProvider(String providerName, + SQLServerConnection connection, SQLServerStatement statement) throws SQLServerException { assert providerName != null && providerName.length() != 0 : "Provider name should not be null or empty"; // check statement level KeyStoreProvider if statement is not null. @@ -109,12 +110,15 @@ static SQLServerColumnEncryptionKeyStoreProvider getColumnEncryptionKeyStoreProv return connection.getColumnEncryptionKeyStoreProviderOnConnection(providerName); } - static boolean shouldUseInstanceLevelProviderFlow(String keyStoreName, SQLServerConnection connection, SQLServerStatement statement) { - return !keyStoreName.equalsIgnoreCase(WINDOWS_KEY_STORE_NAME) - && (connection.hasConnectionColumnEncryptionKeyStoreProvidersRegistered() || (null != statement && statement.hasColumnEncryptionKeyStoreProvidersRegistered())); + static boolean shouldUseInstanceLevelProviderFlow(String keyStoreName, SQLServerConnection connection, + SQLServerStatement statement) { + return !keyStoreName.equalsIgnoreCase(WINDOWS_KEY_STORE_NAME) + && (connection.hasConnectionColumnEncryptionKeyStoreProvidersRegistered() + || (null != statement && statement.hasColumnEncryptionKeyStoreProvidersRegistered())); } - static SQLServerSymmetricKey getKeyFromLocalProviders(EncryptionKeyInfo keyInfo, SQLServerConnection connection, SQLServerStatement statement) throws SQLServerException { + static SQLServerSymmetricKey getKeyFromLocalProviders(EncryptionKeyInfo keyInfo, SQLServerConnection connection, + SQLServerStatement statement) throws SQLServerException { String serverName = connection.getTrustedServerNameAE(); assert null != serverName : "serverName should not be null in getKey."; @@ -122,9 +126,11 @@ static SQLServerSymmetricKey getKeyFromLocalProviders(EncryptionKeyInfo keyInfo, connectionlogger.fine("Checking trusted master key path..."); } Boolean[] hasEntry = new Boolean[1]; - List trustedKeyPaths = SQLServerConnection.getColumnEncryptionTrustedMasterKeyPaths(serverName, hasEntry); + List trustedKeyPaths = SQLServerConnection.getColumnEncryptionTrustedMasterKeyPaths(serverName, + hasEntry); if (hasEntry[0]) { - if ((null == trustedKeyPaths) || (0 == trustedKeyPaths.size()) || (!trustedKeyPaths.contains(keyInfo.keyPath))) { + if ((null == trustedKeyPaths) || (0 == trustedKeyPaths.size()) + || (!trustedKeyPaths.contains(keyInfo.keyPath))) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_UntrustedKeyPath")); Object[] msgArgs = {keyInfo.keyPath, serverName}; throw new SQLServerException(null, form.format(msgArgs), null, 0, false); @@ -134,40 +140,42 @@ static SQLServerSymmetricKey getKeyFromLocalProviders(EncryptionKeyInfo keyInfo, SQLServerException lastException = null; SQLServerColumnEncryptionKeyStoreProvider provider = null; byte[] plaintextKey = null; - + try { provider = getColumnEncryptionKeyStoreProvider(keyInfo.keyStoreName, connection, statement); - plaintextKey = provider.decryptColumnEncryptionKey(keyInfo.keyPath, keyInfo.algorithmName, keyInfo.encryptedKey); - + plaintextKey = provider.decryptColumnEncryptionKey(keyInfo.keyPath, keyInfo.algorithmName, + keyInfo.encryptedKey); + } catch (SQLServerException e) { lastException = e; } - + if (null == plaintextKey) { if (null != lastException) { throw lastException; } else { - throw new SQLServerException(null, SQLServerException.getErrString("R_CEKDecryptionFailed"), null, 0, false); + throw new SQLServerException(null, SQLServerException.getErrString("R_CEKDecryptionFailed"), null, 0, + false); } } - + return new SQLServerSymmetricKey(plaintextKey); } /* * Encrypts the ciphertext. */ - static byte[] encryptWithKey(byte[] plainText, CryptoMetadata md, - SQLServerConnection connection, SQLServerStatement statement) throws SQLServerException { + static byte[] encryptWithKey(byte[] plainText, CryptoMetadata md, SQLServerConnection connection, + SQLServerStatement statement) throws SQLServerException { String serverName = connection.getTrustedServerNameAE(); assert serverName != null : "Server name should not be null in EncryptWithKey"; // Initialize cipherAlgo if not already done. - if (!md.IsAlgorithmInitialized()) { + if (!md.isAlgorithmInitialized()) { SQLServerSecurityUtility.decryptSymmetricKey(md, connection, statement); } - assert md.IsAlgorithmInitialized(); + assert md.isAlgorithmInitialized(); byte[] cipherText = md.cipherAlgorithm.encryptData(plainText); // this call succeeds or throws. if (null == cipherText || 0 == cipherText.length) { throw new SQLServerException(null, SQLServerException.getErrString("R_NullCipherTextAE"), null, 0, false); @@ -205,7 +213,8 @@ private static String ValidateAndGetEncryptionAlgorithmName(byte cipherAlgorithm * @param statement * The statemenet */ - static void decryptSymmetricKey(CryptoMetadata md, SQLServerConnection connection, SQLServerStatement statement) throws SQLServerException { + static void decryptSymmetricKey(CryptoMetadata md, SQLServerConnection connection, + SQLServerStatement statement) throws SQLServerException { assert null != md : "md should not be null in DecryptSymmetricKey."; assert null != md.cekTableEntry : "md.EncryptionInfo should not be null in DecryptSymmetricKey."; assert null != md.cekTableEntry.columnEncryptionKeyValues : "md.EncryptionInfo.ColumnEncryptionKeyValues should not be null in DecryptSymmetricKey."; @@ -218,9 +227,9 @@ static void decryptSymmetricKey(CryptoMetadata md, SQLServerConnection connectio while (it.hasNext()) { EncryptionKeyInfo keyInfo = it.next(); try { - symKey = shouldUseInstanceLevelProviderFlow(keyInfo.keyStoreName, connection, statement) ? - getKeyFromLocalProviders(keyInfo, connection, statement) : - globalCEKCache.getKey(keyInfo, connection); + symKey = shouldUseInstanceLevelProviderFlow(keyInfo.keyStoreName, connection, + statement) ? getKeyFromLocalProviders(keyInfo, connection, statement) + : globalCEKCache.getKey(keyInfo, connection); if (null != symKey) { encryptionkeyInfoChosen = keyInfo; @@ -259,17 +268,17 @@ static void decryptSymmetricKey(CryptoMetadata md, SQLServerConnection connectio /* * Decrypts the ciphertext. */ - static byte[] decryptWithKey(byte[] cipherText, CryptoMetadata md, - SQLServerConnection connection, SQLServerStatement statement) throws SQLServerException { + static byte[] decryptWithKey(byte[] cipherText, CryptoMetadata md, SQLServerConnection connection, + SQLServerStatement statement) throws SQLServerException { String serverName = connection.getTrustedServerNameAE(); assert null != serverName : "serverName should not be null in DecryptWithKey."; // Initialize cipherAlgo if not already done. - if (!md.IsAlgorithmInitialized()) { + if (!md.isAlgorithmInitialized()) { SQLServerSecurityUtility.decryptSymmetricKey(md, connection, statement); } - assert md.IsAlgorithmInitialized() : "Decryption Algorithm is not initialized"; + assert md.isAlgorithmInitialized() : "Decryption Algorithm is not initialized"; byte[] plainText = md.cipherAlgorithm.decryptData(cipherText); // this call succeeds or throws. if (null == plainText) { throw new SQLServerException(null, SQLServerException.getErrString("R_PlainTextNullAE"), null, 0, false); @@ -281,8 +290,9 @@ static byte[] decryptWithKey(byte[] cipherText, CryptoMetadata md, /* * Verify the signature for the CMK */ - static void verifyColumnMasterKeyMetadata(SQLServerConnection connection, SQLServerStatement statement, String keyStoreName, String keyPath, - String serverName, boolean isEnclaveEnabled, byte[] CMKSignature) throws SQLServerException { + static void verifyColumnMasterKeyMetadata(SQLServerConnection connection, SQLServerStatement statement, + String keyStoreName, String keyPath, String serverName, boolean isEnclaveEnabled, + byte[] CMKSignature) throws SQLServerException { // check trusted key paths Boolean[] hasEntry = new Boolean[1]; @@ -438,7 +448,7 @@ static SqlFedAuthToken getMSIAuthToken(String resource, String msiClientId) thro } catch (InterruptedException ex) { // re-interrupt thread Thread.currentThread().interrupt(); - + // Throw runtime exception as driver must not be interrupted here throw new RuntimeException(ex); } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSpatialDatatype.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSpatialDatatype.java index ee9cb9670..a5992f4e1 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSpatialDatatype.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSpatialDatatype.java @@ -115,6 +115,9 @@ abstract class SQLServerSpatialDatatype { private List version_one_shape_indexes = new ArrayList(); + private static final String FULLGLOBE = "FULLGLOBE"; + private static final String EMPTY = "EMPTY"; + /** * Serializes the Geogemetry/Geography instance to internal SQL Server format (CLR). * @@ -797,7 +800,7 @@ void constructWKT(SQLServerSpatialDatatype sd, InternalSpatialDatatype isd, int MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_illegalTypeForGeometry")); throw new SQLServerException(form.format(new Object[] {"Fullglobe"}), null, 0, null); } else { - appendToWKTBuffers("FULLGLOBE"); + appendToWKTBuffers(FULLGLOBE); return; } } @@ -901,7 +904,7 @@ void parseWKTForSerialization(SQLServerSpatialDatatype sd, int startPos, int par } // check for FULLGLOBE before reading the first open bracket, since FULLGLOBE doesn't have one. - if ("FULLGLOBE".equals(nextToken)) { + if (FULLGLOBE.equals(nextToken)) { if (sd instanceof Geometry) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_illegalTypeForGeometry")); throw new SQLServerException(form.format(new Object[] {"Fullglobe"}), null, 0, null); @@ -1101,7 +1104,7 @@ void constructShapeWKT(int figureStartIndex, int figureEndIndex) { void constructMultiShapeWKT(int shapeStartIndex, int shapeEndIndex) { for (int i = shapeStartIndex + 1; i < shapeEndIndex; i++) { if (shapes[i].getFigureOffset() == -1) { // EMPTY - appendToWKTBuffers("EMPTY"); + appendToWKTBuffers(EMPTY); } else { constructShapeWKT(shapes[i].getFigureOffset(), shapes[i].getFigureOffset() + 1); } @@ -1165,7 +1168,7 @@ void constructMultipolygonWKT(int shapeStartIndex, int shapeEndIndex) { for (int i = shapeStartIndex + 1; i < shapeEndIndex; i++) { figureEndIndex = figures.length; if (shapes[i].getFigureOffset() == -1) { // EMPTY - appendToWKTBuffers("EMPTY"); + appendToWKTBuffers(EMPTY); if (!(i == shapeEndIndex - 1)) { // not the last exterior polygon of this multipolygon, add a comma appendToWKTBuffers(", "); } @@ -2209,7 +2212,7 @@ void determineInternalType() { boolean checkEmptyKeyword(int parentShapeIndex, InternalSpatialDatatype isd, boolean isInsideAnotherShape) throws SQLServerException { String potentialEmptyKeyword = getNextStringToken().toUpperCase(Locale.US); - if ("EMPTY".equals(potentialEmptyKeyword)) { + if (EMPTY.equals(potentialEmptyKeyword)) { byte typeCode = 0; @@ -2440,7 +2443,7 @@ private void constructGeometryCollectionWKThelper(int shapeEndIndex) throws SQLS currentShapeIndex++; break; case FULLGLOBE: - appendToWKTBuffers("FULLGLOBE"); + appendToWKTBuffers(FULLGLOBE); break; default: break;