From b40780eed6df0e70f8087af489c2d1fa0faa24b4 Mon Sep 17 00:00:00 2001 From: David Engel Date: Thu, 12 Aug 2021 09:28:05 -0700 Subject: [PATCH 1/2] Fix NPE with Statement.closeOnCompletion() --- .../sqlserver/jdbc/SQLServerConnection.java | 4 +++ .../sqlserver/jdbc/SQLServerStatement.java | 3 +- .../jdbc/unit/statement/StatementTest.java | 35 +++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java index ef7b3a839..6681e0309 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java @@ -1215,6 +1215,10 @@ final SQLCollation getDatabaseCollation() { static final private java.util.logging.Logger loggerExternal = java.util.logging.Logger .getLogger("com.microsoft.sqlserver.jdbc.Connection"); private static String loggingClassNameBase = "com.microsoft.sqlserver.jdbc.SQLServerConnection"; + + /** + * Instance loggingClassName that is appended with the connection ID for log context + */ private String loggingClassName = loggingClassNameBase; /** diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatement.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatement.java index afc97fa83..721bbf2a3 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatement.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatement.java @@ -139,7 +139,7 @@ final boolean wasExecuted() { */ private volatile TDSCommand currentCommand = null; - /** last statment exec command */ + /** last statement exec command */ private TDSCommand lastStmtExecCmd = null; final void discardLastExecutionResults() { @@ -1314,6 +1314,7 @@ final void ensureExecuteResultsReader(TDSReader tdsReader) { final void processExecuteResults() throws SQLServerException { if (wasExecuted()) { processBatch(); + checkClosed(); // processBatch could have resulted in a closed connection if isCloseOnCompletion is set TDSParser.parse(resultsReader(), "batch completion"); ensureExecuteResultsReader(null); } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/StatementTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/StatementTest.java index 338a688fa..f294d739e 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/StatementTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/StatementTest.java @@ -7,6 +7,7 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.fail; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.StringReader; @@ -2052,6 +2053,40 @@ public void testClosedResultSet() throws Exception { } } + /** + * Tests reusing Statement after being automatically closed via closeOnCompletion(). + * + * @throws Exception + */ + @Test + public void testReuseAfterCloseOnCompletion() throws Exception { + try (Connection conn = getConnection(); Statement stmt = conn.createStatement()) { + + // enable isCloseOnCompletion + try { + stmt.closeOnCompletion(); + } catch (Exception e) { + fail(TestResource.getResource("R_unexpectedException") + e.getMessage()); + } + + SQLServerResultSet rs = (SQLServerResultSet) stmt.executeQuery("SELECT 1"); + assertNotNull(rs, TestResource.getResource("R_resultsetNull")); + + try { + // Executing a new command should close the previous ResultSet + // ... and closing the original ResultSet should close the Statement + // ... so this should fail with an error indicating that the Statement is closed. + stmt.executeQuery("SELECT 1"); + fail(TestResource.getResource("R_expectedExceptionNotThrown")); + } catch (SQLException e) { + assertEquals(TestResource.getResource("R_statementClosed"), e.getMessage()); + } catch (Exception e) { + e.printStackTrace(); + fail(TestResource.getResource("R_unexpectedException") + e.getMessage()); + } + } + } + /** * Tests closing statement will close resultset * From 4538304e6121e54c62ff90a84eed52763c4ec845 Mon Sep 17 00:00:00 2001 From: David Engel Date: Fri, 1 Oct 2021 12:10:34 -0700 Subject: [PATCH 2/2] Use try with resources --- .../jdbc/unit/statement/StatementTest.java | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/StatementTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/StatementTest.java index f294d739e..6185271b7 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/StatementTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/StatementTest.java @@ -2069,20 +2069,21 @@ public void testReuseAfterCloseOnCompletion() throws Exception { fail(TestResource.getResource("R_unexpectedException") + e.getMessage()); } - SQLServerResultSet rs = (SQLServerResultSet) stmt.executeQuery("SELECT 1"); - assertNotNull(rs, TestResource.getResource("R_resultsetNull")); + try (SQLServerResultSet rs = (SQLServerResultSet) stmt.executeQuery("SELECT 1")) { + assertNotNull(rs, TestResource.getResource("R_resultsetNull")); - try { - // Executing a new command should close the previous ResultSet - // ... and closing the original ResultSet should close the Statement - // ... so this should fail with an error indicating that the Statement is closed. - stmt.executeQuery("SELECT 1"); - fail(TestResource.getResource("R_expectedExceptionNotThrown")); - } catch (SQLException e) { - assertEquals(TestResource.getResource("R_statementClosed"), e.getMessage()); - } catch (Exception e) { - e.printStackTrace(); - fail(TestResource.getResource("R_unexpectedException") + e.getMessage()); + try { + // Executing a new command should close the previous ResultSet + // ... and closing the original ResultSet should close the Statement + // ... so this should fail with an error indicating that the Statement is closed. + stmt.executeQuery("SELECT 1"); + fail(TestResource.getResource("R_expectedExceptionNotThrown")); + } catch (SQLException e) { + assertEquals(TestResource.getResource("R_statementClosed"), e.getMessage()); + } catch (Exception e) { + e.printStackTrace(); + fail(TestResource.getResource("R_unexpectedException") + e.getMessage()); + } } } }