[Git][java-team/libpostgresql-jdbc-java][upstream] New upstream version 42.3.6
Christoph Berg (@myon)
gitlab at salsa.debian.org
Fri May 27 13:57:30 BST 2022
Christoph Berg pushed to branch upstream at Debian Java Maintainers / libpostgresql-jdbc-java
Commits:
3b6f5a1d by Christoph Berg at 2022-05-27T14:17:25+02:00
New upstream version 42.3.6
- - - - -
6 changed files:
- pom.xml
- src/main/java/org/postgresql/jdbc/PgResultSet.java
- src/main/java/org/postgresql/util/DriverInfo.java
- src/main/resources/META-INF/MANIFEST.MF
- src/test/java/org/postgresql/test/TestUtil.java
- src/test/java/org/postgresql/test/jdbc2/RefCursorFetchTest.java
Changes:
=====================================
pom.xml
=====================================
@@ -10,7 +10,7 @@
<artifactId>postgresql</artifactId>
<packaging>jar</packaging>
<name>PostgreSQL JDBC Driver - JDBC 4.2</name>
- <version>42.3.5</version>
+ <version>42.3.6</version>
<description>Java JDBC 4.2 (JRE 8+) driver for PostgreSQL database</description>
<url>https://github.com/pgjdbc/pgjdbc</url>
=====================================
src/main/java/org/postgresql/jdbc/PgResultSet.java
=====================================
@@ -286,23 +286,12 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS
// we have updatable cursors it must be readonly.
ResultSet rs =
connection.execSQLQuery(sb.toString(), resultsettype, ResultSet.CONCUR_READ_ONLY);
-
- /*
- If the user has set a fetch size we can't close the cursor yet.
- Issue https://github.com/pgjdbc/pgjdbc/issues/2227
- */
- if (connection.getDefaultFetchSize() == 0 ) {
- /*
- // In long running transactions these backend cursors take up memory space
- // we could close in rs.close(), but if the transaction is closed before the result set,
- // then the cursor no longer exists
- */
- sb.setLength(0);
- sb.append("CLOSE ");
- Utils.escapeIdentifier(sb, cursorName);
- connection.execSQLUpdate(sb.toString());
- }
((PgResultSet) rs).setRefCursor(cursorName);
+ // In long-running transactions these backend cursors take up memory space
+ // we could close in rs.close(), but if the transaction is closed before the result set,
+ // then
+ // the cursor no longer exists
+ ((PgResultSet) rs).closeRefCursor();
return rs;
}
if ("hstore".equals(type)) {
@@ -2154,6 +2143,10 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS
connection.getQueryExecutor()
.fetch(cursor, new CursorResultHandler(), fetchRows, adaptiveFetch);
+ // .fetch(...) could update this.cursor, and cursor==null means
+ // there are no more rows to fetch
+ closeRefCursor();
+
// After fetch, update last used fetch size (could be useful for adaptive fetch).
lastUsedFetchSize = fetchRows;
@@ -2192,24 +2185,30 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS
rows = null;
JdbcBlackHole.close(deleteStatement);
deleteStatement = null;
+ if (cursor != null) {
+ cursor.close();
+ cursor = null;
+ }
+ closeRefCursor();
+ }
- /* this used to be closed right after reading all of the rows,
- however if fetchSize is set ony fetchSize rows will be read and then
- the cursor will be closed
- We only need to worry about closing it if the transaction is still open
- if it is in error it will get closed eventually. (maybe not ?)
- */
- if ( refCursorName != null && fetchSize != 0) {
+ /**
+ * Closes {@code <unnamed portal 1>} if no more fetch calls expected ({@code cursor==null})
+ * @throws SQLException if portal close fails
+ */
+ private void closeRefCursor() throws SQLException {
+ String refCursorName = this.refCursorName;
+ if (refCursorName == null || cursor != null) {
+ return;
+ }
+ try {
if (connection.getTransactionState() == TransactionState.OPEN) {
StringBuilder sb = new StringBuilder("CLOSE ");
- Utils.escapeIdentifier(sb, castNonNull(refCursorName));
+ Utils.escapeIdentifier(sb, refCursorName);
connection.execSQLUpdate(sb.toString());
- refCursorName = null;
}
- }
- if (cursor != null) {
- cursor.close();
- cursor = null;
+ } finally {
+ this.refCursorName = null;
}
}
=====================================
src/main/java/org/postgresql/util/DriverInfo.java
=====================================
@@ -16,13 +16,13 @@ public final class DriverInfo {
// Driver name
public static final String DRIVER_NAME = "PostgreSQL JDBC Driver";
public static final String DRIVER_SHORT_NAME = "PgJDBC";
- public static final String DRIVER_VERSION = "42.3.5";
+ public static final String DRIVER_VERSION = "42.3.6";
public static final String DRIVER_FULL_NAME = DRIVER_NAME + " " + DRIVER_VERSION;
// Driver version
public static final int MAJOR_VERSION = 42;
public static final int MINOR_VERSION = 3;
- public static final int PATCH_VERSION = 5;
+ public static final int PATCH_VERSION = 6;
// JDBC specification
public static final String JDBC_VERSION = "4.2";
=====================================
src/main/resources/META-INF/MANIFEST.MF
=====================================
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Implementation-Title: PostgreSQL JDBC Driver
Bundle-License: BSD-2-Clause
Automatic-Module-Name: org.postgresql.jdbc
-Implementation-Version: 42.3.5
+Implementation-Version: 42.3.6
Specification-Vendor: Oracle Corporation
Specification-Title: JDBC
Implementation-Vendor-Id: org.postgresql
=====================================
src/test/java/org/postgresql/test/TestUtil.java
=====================================
@@ -654,6 +654,13 @@ public class TestUtil {
dropObject(con, "TYPE", type);
}
+ /*
+ * Drops a function with a given signature.
+ */
+ public static void dropFunction(Connection con, String name, String arguments) throws SQLException {
+ dropObject(con, "FUNCTION", name + "(" + arguments + ")");
+ }
+
private static void dropObject(Connection con, String type, String name) throws SQLException {
Statement stmt = con.createStatement();
try {
@@ -1163,7 +1170,19 @@ public class TestUtil {
}
}
+ /**
+ * Executes given SQL via {@link Statement#execute(String)} on a given connection.
+ * @deprecated prefer {@link #execute(Connection, String)} since it yields easier for read code
+ */
+ @Deprecated
public static void execute(String sql, Connection connection) throws SQLException {
+ execute(connection, sql);
+ }
+
+ /**
+ * Executes given SQL via {@link Statement#execute(String)} on a given connection.
+ */
+ public static void execute(Connection connection, String sql) throws SQLException {
try (Statement stmt = connection.createStatement()) {
stmt.execute(sql);
}
=====================================
src/test/java/org/postgresql/test/jdbc2/RefCursorFetchTest.java
=====================================
@@ -7,115 +7,151 @@ package org.postgresql.test.jdbc2;
import static org.junit.Assert.assertEquals;
-import org.postgresql.PGConnection;
+import org.postgresql.PGProperty;
import org.postgresql.core.ServerVersion;
import org.postgresql.test.TestUtil;
+// import org.checkerframework.checker.nullness.qual.Nullable;
+import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
import java.sql.CallableStatement;
+import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Properties;
+ at RunWith(Parameterized.class)
public class RefCursorFetchTest extends BaseTest4 {
- @BeforeClass
- public static void checkVersion() throws SQLException {
- TestUtil.assumeHaveMinimumServerVersion(ServerVersion.v9_0);
+ private final int numRows;
+ private final /* @Nullable */ Integer defaultFetchSize;
+ private final /* @Nullable */ Integer resultSetFetchSize;
+ private final AutoCommit autoCommit;
+ private final boolean commitAfterExecute;
+
+ public RefCursorFetchTest(BinaryMode binaryMode, int numRows,
+ /* @Nullable */ Integer defaultFetchSize,
+ /* @Nullable */ Integer resultSetFetchSize,
+ AutoCommit autoCommit, boolean commitAfterExecute) {
+ this.numRows = numRows;
+ this.defaultFetchSize = defaultFetchSize;
+ this.resultSetFetchSize = resultSetFetchSize;
+ this.autoCommit = autoCommit;
+ this.commitAfterExecute = commitAfterExecute;
+ setBinaryMode(binaryMode);
+ }
+
+ @Parameterized.Parameters(name = "binary = {0}, numRows = {1}, defaultFetchSize = {2}, resultSetFetchSize = {3}, autoCommit = {4}, commitAfterExecute = {5}")
+ public static Iterable<Object[]> data() {
+ Collection<Object[]> ids = new ArrayList<>();
+ for (BinaryMode binaryMode : BinaryMode.values()) {
+ for (int numRows : new int[]{0, 10, 101}) {
+ for (Integer defaultFetchSize : new Integer[]{null, 0, 9, 50}) {
+ for (AutoCommit autoCommit : AutoCommit.values()) {
+ for (boolean commitAfterExecute : new boolean[]{true, false}) {
+ for (Integer resultSetFetchSize : new Integer[]{null, 0, 9, 50}) {
+ ids.add(new Object[]{binaryMode, numRows, defaultFetchSize, resultSetFetchSize, autoCommit, commitAfterExecute});
+ }
+ }
+ }
+ }
+ }
+ }
+ return ids;
}
@Override
- public void setUp() throws Exception {
- super.setUp();
- assumeCallableStatementsSupported();
+ protected void updateProperties(Properties props) {
+ super.updateProperties(props);
+ if (defaultFetchSize != null) {
+ PGProperty.DEFAULT_ROW_FETCH_SIZE.set(props, defaultFetchSize);
+ }
+ }
- TestUtil.dropTable(con, "test_blob");
- TestUtil.createTable(con, "test_blob", "content bytea");
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ TestUtil.assumeHaveMinimumServerVersion(ServerVersion.v9_0);
+ try (Connection con = TestUtil.openDB();) {
+ TestUtil.createTable(con, "test_blob", "content bytea");
+ TestUtil.execute(con, "");
+ TestUtil.execute(con, "--create function to read data\n"
+ + "CREATE OR REPLACE FUNCTION test_blob(p_cur OUT REFCURSOR, p_limit int4) AS $body$\n"
+ + "BEGIN\n"
+ + "OPEN p_cur FOR SELECT content FROM test_blob LIMIT p_limit;\n"
+ + "END;\n"
+ + "$body$ LANGUAGE plpgsql STABLE");
- // Create a function to read the blob data
- TestUtil.execute("CREATE OR REPLACE FUNCTION test_blob (p_cur OUT REFCURSOR) AS\n"
- + "$body$\n"
- + " BEGIN\n"
- + " OPEN p_cur FOR SELECT content FROM test_blob;\n"
- + " END;\n"
- + "$body$ LANGUAGE plpgsql STABLE", con);
+ TestUtil.execute(con,"--generate 101 rows with 4096 bytes:\n"
+ + "insert into test_blob\n"
+ + "select(select decode(string_agg(lpad(to_hex(width_bucket(random(), 0, 1, 256) - 1), 2, '0'), ''), 'hex')"
+ + " FROM generate_series(1, 4096))\n"
+ + "from generate_series (1, 200)");
+ }
+ }
- // Generate 101 rows with 4096 bytes
- TestUtil.execute("INSERT INTO test_blob (content)\n"
- + "SELECT (SELECT decode(string_agg(lpad(to_hex(width_bucket(random(), 0, 1, 256) - 1), 2, '0'), ''), 'hex')\n"
- + " FROM generate_series(1, 4096)) AS content\n"
- + "FROM generate_series (1, 101)", con);
+ @AfterClass
+ public static void afterClass() throws Exception {
+ try (Connection con = TestUtil.openDB();) {
+ TestUtil.dropTable(con, "test_blob");
+ TestUtil.dropFunction(con,"test_blob", "REFCURSOR, int4");
+ }
}
@Override
- public void tearDown() throws SQLException {
- TestUtil.execute("DROP FUNCTION IF EXISTS test_blob (OUT REFCURSOR)", con);
- TestUtil.dropTable(con, "test_blob");
- super.tearDown();
+ public void setUp() throws Exception {
+ super.setUp();
+ assumeCallableStatementsSupported();
+ con.setAutoCommit(autoCommit == AutoCommit.YES);
}
@Test
- public void testRefCursorWithFetchSize() throws SQLException {
- ((PGConnection)con).setDefaultFetchSize(50);
+ public void fetchAllRows() throws SQLException {
int cnt = 0;
- try (CallableStatement call = con.prepareCall("{? = call test_blob()}")) {
+ try (CallableStatement call = con.prepareCall("{? = call test_blob(?)}")) {
con.setAutoCommit(false); // ref cursors only work if auto commit is off
call.registerOutParameter(1, Types.REF_CURSOR);
+ call.setInt(2, numRows);
call.execute();
- try (ResultSet rs = (ResultSet) call.getObject(1)) {
- while (rs.next()) {
- cnt++;
+ if (commitAfterExecute) {
+ if (autoCommit == AutoCommit.NO) {
+ con.commit();
+ } else {
+ con.setAutoCommit(false);
+ con.setAutoCommit(true);
}
}
- assertEquals(101, cnt);
- }
- }
-
- @Test
- public void testRefCursorWithOutFetchSize() throws SQLException {
- assumeCallableStatementsSupported();
- int cnt = 0;
- try (CallableStatement call = con.prepareCall("{? = call test_blob()}")) {
- con.setAutoCommit(false); // ref cursors only work if auto commit is off
- call.registerOutParameter(1, Types.REF_CURSOR);
- call.execute();
try (ResultSet rs = (ResultSet) call.getObject(1)) {
- while (rs.next()) {
- cnt++;
+ if (resultSetFetchSize != null) {
+ rs.setFetchSize(resultSetFetchSize);
}
- }
- assertEquals(101, cnt);
- }
- }
-
- /*
- test to make sure that close in the result set does not attempt to get rid of the non-existent
- portal
- */
- @Test
- public void testRefCursorWithFetchSizeNoTransaction() throws SQLException {
- assumeCallableStatementsSupported();
- ((PGConnection)con).setDefaultFetchSize(50);
- int cnt = 0;
- try (CallableStatement call = con.prepareCall("{? = call test_blob()}")) {
- con.setAutoCommit(false); // ref cursors only work if auto commit is off
- call.registerOutParameter(1, Types.REF_CURSOR);
- call.execute();
- // end the transaction here, which will get rid of the refcursor
- con.setAutoCommit(true);
- // we should be able to read the first 50 as they were read before the tx was ended
- try (ResultSet rs = (ResultSet) call.getObject(1)) {
while (rs.next()) {
cnt++;
}
- } catch (SQLException ex) {
- // should get an exception here as we try to read more but the portal is gone
- assertEquals("34000", ex.getSQLState());
- } finally {
- assertEquals(50, cnt);
+ assertEquals("number of rows from test_blob(...) call", numRows, cnt);
+ } catch (SQLException e) {
+ if (commitAfterExecute && "34000".equals(e.getSQLState())) {
+ // Transaction commit closes refcursor, so the fetch call is expected to fail
+ // File: postgres.c, Routine: exec_execute_message, Line: 2070
+ // Server SQLState: 34000
+ int expectedRows =
+ defaultFetchSize != null && defaultFetchSize != 0 ? Math.min(defaultFetchSize, numRows) : numRows;
+ assertEquals(
+ "The transaction was committed before processing the results,"
+ + " so expecting ResultSet to buffer fetchSize=" + defaultFetchSize + " rows out of "
+ + numRows,
+ expectedRows,
+ cnt
+ );
+ return;
+ }
+ throw e;
}
}
}
-
}
View it on GitLab: https://salsa.debian.org/java-team/libpostgresql-jdbc-java/-/commit/3b6f5a1d9891d513322ee6a0b2b86a82bf95a1a5
--
View it on GitLab: https://salsa.debian.org/java-team/libpostgresql-jdbc-java/-/commit/3b6f5a1d9891d513322ee6a0b2b86a82bf95a1a5
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20220527/b14e2539/attachment.htm>
More information about the pkg-java-commits
mailing list