From 00fa448587532cc219977679bb8c573a1dcae11c Mon Sep 17 00:00:00 2001 From: Dave Cramer Date: Mon, 18 Nov 2019 10:29:22 -0500 Subject: [PATCH] fix: NPE as a result of calling executeQuery twice on a statement fixes issue #684 (#1610) --- .../java/org/postgresql/jdbc/PgResultSet.java | 22 ++++++++++++++----- .../java/org/postgresql/jdbc/PgStatement.java | 6 ++--- .../jdbc4/jdbc41/CloseOnCompletionTest.java | 9 ++++++++ 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java b/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java index 9cc490a00e..14a9195ca5 100644 --- a/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java +++ b/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java @@ -1852,17 +1852,27 @@ public boolean next() throws SQLException { public void close() throws SQLException { try { - // release resources held (memory for tuples) - rows = null; - if (cursor != null) { - cursor.close(); - cursor = null; - } + closeInternally(); } finally { ((PgStatement) statement).checkCompletion(); } } + /* + used by PgStatement.closeForNextExecution to avoid + closing the firstUnclosedResult twice. + checkCompletion above modifies firstUnclosedResult + fixes issue #684 + */ + protected void closeInternally() throws SQLException { + // release resources held (memory for tuples) + rows = null; + if (cursor != null) { + cursor.close(); + cursor = null; + } + } + public boolean wasNull() throws SQLException { checkClosed(); return wasNullFlag; diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/PgStatement.java b/pgjdbc/src/main/java/org/postgresql/jdbc/PgStatement.java index 3940e7a2c7..efc0e3364b 100644 --- a/pgjdbc/src/main/java/org/postgresql/jdbc/PgStatement.java +++ b/pgjdbc/src/main/java/org/postgresql/jdbc/PgStatement.java @@ -125,7 +125,7 @@ public class PgStatement implements Statement, BaseStatement { /** * The first unclosed result. */ - protected ResultWrapper firstUnclosedResult = null; + protected volatile ResultWrapper firstUnclosedResult = null; /** * Results returned by a statement that wants generated keys. @@ -327,9 +327,9 @@ protected void closeForNextExecution() throws SQLException { // Close any existing resultsets associated with this statement. synchronized (this) { while (firstUnclosedResult != null) { - ResultSet rs = firstUnclosedResult.getResultSet(); + PgResultSet rs = (PgResultSet)firstUnclosedResult.getResultSet(); if (rs != null) { - rs.close(); + rs.closeInternally(); } firstUnclosedResult = firstUnclosedResult.getNext(); } diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc4/jdbc41/CloseOnCompletionTest.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc4/jdbc41/CloseOnCompletionTest.java index 801d1503a1..5eac284cb0 100644 --- a/pgjdbc/src/test/java/org/postgresql/test/jdbc4/jdbc41/CloseOnCompletionTest.java +++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc4/jdbc41/CloseOnCompletionTest.java @@ -15,6 +15,7 @@ import org.junit.Test; import java.sql.Connection; +import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; @@ -89,4 +90,12 @@ public void testNoResultSet() throws SQLException { stmt.executeUpdate(TestUtil.insertSQL("table1", "1")); assertFalse(stmt.isClosed()); } + + @Test + public void testExecuteTwice() throws SQLException { + PreparedStatement s = conn.prepareStatement("SELECT 1"); + s.closeOnCompletion(); + s.executeQuery(); + s.executeQuery(); + } }