[Git][java-team/libpostgresql-jdbc-java][master] 3 commits: New upstream version 42.4.1

Christoph Berg (@myon) gitlab at salsa.debian.org
Mon Aug 8 14:08:00 BST 2022



Christoph Berg pushed to branch master at Debian Java Maintainers / libpostgresql-jdbc-java


Commits:
9f8fba40 by Christoph Berg at 2022-08-08T14:53:23+02:00
New upstream version 42.4.1
- - - - -
2d1910ee by Christoph Berg at 2022-08-08T14:53:28+02:00
Update upstream source from tag 'upstream/42.4.1'

Update to upstream version '42.4.1'
with Debian dir 825b16c80ca272b00a5c7a790cb37e3ccbf25179
- - - - -
c03c688e by Christoph Berg at 2022-08-08T15:07:21+02:00
releasing package libpgjava version 42.4.1-1

- - - - -


28 changed files:

- debian/changelog
- debian/patches/missing-test-deps
- pom.xml
- src/main/java/org/postgresql/Driver.java
- src/main/java/org/postgresql/gss/GssAction.java
- src/main/java/org/postgresql/gss/GssEncAction.java
- src/main/java/org/postgresql/gss/MakeGSS.java
- src/main/java/org/postgresql/jdbc/PgConnection.java
- src/main/java/org/postgresql/jdbc/PgPreparedStatement.java
- src/main/java/org/postgresql/jdbc/PgResultSet.java
- src/main/java/org/postgresql/util/DriverInfo.java
- src/main/java/org/postgresql/util/StreamWrapper.java
- src/main/resources/META-INF/MANIFEST.MF
- + src/test/java/org/postgresql/test/XaTests.java
- src/test/java/org/postgresql/test/jdbc2/BaseTest4.java
- src/test/java/org/postgresql/test/jdbc2/CallableStmtTest.java
- src/test/java/org/postgresql/test/jdbc2/ConnectTimeoutTest.java
- src/test/java/org/postgresql/test/jdbc2/DriverTest.java
- src/test/java/org/postgresql/test/jdbc2/RefCursorFetchTest.java
- src/test/java/org/postgresql/test/jdbc2/RefCursorTest.java
- + src/test/java/org/postgresql/test/jdbc2/ResultSetRefreshTest.java
- src/test/java/org/postgresql/test/jdbc3/Jdbc3CallableStatementTest.java
- src/test/java/org/postgresql/test/jdbc3/ProcedureTransactionTest.java
- src/test/java/org/postgresql/test/xa/XADataSourceTest.java
- src/test/java/org/postgresql/util/OSUtilTest.java
- src/test/java/org/postgresql/util/PGPropertyPasswordParserTest.java
- src/test/java/org/postgresql/util/PGPropertyServiceParserTest.java
- + src/test/java/org/postgresql/util/StubEnvironmentAndProperties.java


Changes:

=====================================
debian/changelog
=====================================
@@ -1,3 +1,18 @@
+libpgjava (42.4.1-1) unstable; urgency=medium
+
+  * New upstream version 42.4.1
+
+    Fixes SQL generated in PgResultSet.refresh() to escape column identifiers
+    so as to prevent SQL injection.
+    (Closes: #1016662, CVE-2022-31197, reported by Sho Kato)
+
+    Previously, the column names for both key and data columns in the table
+    were copied as-is into the generated SQL. This allowed a malicious table
+    with column names that include statement terminator to be parsed and
+    executed as multiple separate commands.
+
+ -- Christoph Berg <myon at debian.org>  Mon, 08 Aug 2022 14:53:28 +0200
+
 libpgjava (42.4.0-1) unstable; urgency=medium
 
   * New upstream version 42.4.0.


=====================================
debian/patches/missing-test-deps
=====================================
@@ -24,30 +24,30 @@ junit: Packaged, but mvn doesn't find it
 -        <dependency>
 -            <groupId>org.junit.jupiter</groupId>
 -            <artifactId>junit-jupiter-api</artifactId>
--            <version>5.6.0</version>
+-            <version>5.8.2</version>
 -            <scope>test</scope>
 -        </dependency>
 -        <dependency>
 -            <groupId>uk.org.webcompere</groupId>
 -            <artifactId>system-stubs-jupiter</artifactId>
--            <version>1.2.0</version>
+-            <version>2.0.1</version>
 -        </dependency>
 -        <dependency>
 -            <groupId>org.junit.jupiter</groupId>
 -            <artifactId>junit-jupiter-params</artifactId>
--            <version>5.6.0</version>
+-            <version>5.8.2</version>
 -            <scope>test</scope>
 -        </dependency>
 -        <dependency>
 -            <groupId>org.junit.jupiter</groupId>
 -            <artifactId>junit-jupiter-engine</artifactId>
--            <version>5.6.0</version>
+-            <version>5.8.2</version>
 -            <scope>test</scope>
 -        </dependency>
 -        <dependency>
 -            <groupId>org.junit.vintage</groupId>
 -            <artifactId>junit-vintage-engine</artifactId>
--            <version>5.6.0</version>
+-            <version>5.8.2</version>
 -            <scope>test</scope>
 -        </dependency>
      </dependencies>


=====================================
pom.xml
=====================================
@@ -10,7 +10,7 @@
     <artifactId>postgresql</artifactId>
     <packaging>jar</packaging>
     <name>PostgreSQL JDBC Driver - JDBC 4.2</name>
-    <version>42.4.0</version>
+    <version>42.4.1</version>
     <description>Java JDBC 4.2 (JRE 8+) driver for PostgreSQL database</description>
     <url>https://github.com/pgjdbc/pgjdbc</url>
 
@@ -60,30 +60,30 @@
         <dependency>
             <groupId>org.junit.jupiter</groupId>
             <artifactId>junit-jupiter-api</artifactId>
-            <version>5.6.0</version>
+            <version>5.8.2</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>uk.org.webcompere</groupId>
             <artifactId>system-stubs-jupiter</artifactId>
-            <version>1.2.0</version>
+            <version>2.0.1</version>
         </dependency>
         <dependency>
             <groupId>org.junit.jupiter</groupId>
             <artifactId>junit-jupiter-params</artifactId>
-            <version>5.6.0</version>
+            <version>5.8.2</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.junit.jupiter</groupId>
             <artifactId>junit-jupiter-engine</artifactId>
-            <version>5.6.0</version>
+            <version>5.8.2</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.junit.vintage</groupId>
             <artifactId>junit-vintage-engine</artifactId>
-            <version>5.6.0</version>
+            <version>5.8.2</version>
             <scope>test</scope>
         </dependency>
     </dependencies>


=====================================
src/main/java/org/postgresql/Driver.java
=====================================
@@ -23,8 +23,9 @@ import org.postgresql.util.URLCoder;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.net.URL;
-import java.security.AccessController;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
 import java.sql.Connection;
@@ -88,18 +89,47 @@ public class Driver implements java.sql.Driver {
     // Make sure we load properties with the maximum possible privileges..
     try {
       defaultProperties =
-          AccessController.doPrivileged(new PrivilegedExceptionAction<Properties>() {
+          doPrivileged(new PrivilegedExceptionAction<Properties>() {
             public Properties run() throws IOException {
               return loadDefaultProperties();
             }
           });
     } catch (PrivilegedActionException e) {
-      throw (IOException) e.getException();
+      Exception ex = e.getException();
+      if (ex instanceof IOException) {
+        throw (IOException) ex;
+      }
+      throw new RuntimeException(e);
+    } catch (Throwable e) {
+      if (e instanceof IOException) {
+        throw (IOException) e;
+      }
+      if (e instanceof RuntimeException) {
+        throw (RuntimeException) e;
+      }
+      if (e instanceof Error) {
+        throw (Error) e;
+      }
+      throw new RuntimeException(e);
     }
 
     return defaultProperties;
   }
 
+  private static <T> T doPrivileged(PrivilegedExceptionAction<T> action) throws Throwable {
+    try {
+      Class<?> accessControllerClass = Class.forName("java.security.AccessController");
+      Method doPrivileged = accessControllerClass.getMethod("doPrivileged",
+          PrivilegedExceptionAction.class);
+      //noinspection unchecked
+      return (T) doPrivileged.invoke(null, action);
+    } catch (ClassNotFoundException e) {
+      return action.run();
+    } catch (InvocationTargetException e) {
+      throw castNonNull(e.getCause());
+    }
+  }
+
   private Properties loadDefaultProperties() throws IOException {
     Properties merged = new Properties();
 
@@ -241,7 +271,7 @@ public class Driver implements java.sql.Driver {
     // parse URL and add more properties
     if ((props = parseURL(url, props)) == null) {
       throw new PSQLException(
-          GT.tr("Unable to parse URL "),
+          GT.tr("Unable to parse URL {0}", url),
           PSQLState.UNEXPECTED_ERROR);
     }
     try {
@@ -271,12 +301,14 @@ public class Driver implements java.sql.Driver {
       // re-throw the exception, otherwise it will be caught next, and a
       // org.postgresql.unusual error will be returned instead.
       throw ex1;
-    } catch (java.security.AccessControlException ace) {
-      throw new PSQLException(
-          GT.tr(
-              "Your security policy has prevented the connection from being attempted.  You probably need to grant the connect java.net.SocketPermission to the database server host and port that you wish to connect to."),
-          PSQLState.UNEXPECTED_ERROR, ace);
     } catch (Exception ex2) {
+      if ("java.security.AccessControlException".equals(ex2.getClass().getName())) {
+        // java.security.AccessControlException has been deprecated for removal, so compare the class name
+        throw new PSQLException(
+            GT.tr(
+                "Your security policy has prevented the connection from being attempted.  You probably need to grant the connect java.net.SocketPermission to the database server host and port that you wish to connect to."),
+            PSQLState.UNEXPECTED_ERROR, ex2);
+      }
       LOGGER.log(Level.FINE, "Unexpected connection error: ", ex2);
       throw new PSQLException(
           GT.tr(


=====================================
src/main/java/org/postgresql/gss/GssAction.java
=====================================
@@ -37,10 +37,10 @@ class GssAction implements PrivilegedAction</* @Nullable */ Exception> {
   private final String kerberosServerName;
   private final String user;
   private final boolean useSpnego;
-  private final Subject subject;
+  private final /* @Nullable */ Subject subject;
   private final boolean logServerErrorDetail;
 
-  GssAction(PGStream pgStream, Subject subject, String host, String user,
+  GssAction(PGStream pgStream, /* @Nullable */ Subject subject, String host, String user,
       String kerberosServerName, boolean useSpnego, boolean logServerErrorDetail) {
     this.pgStream = pgStream;
     this.subject = subject;


=====================================
src/main/java/org/postgresql/gss/GssEncAction.java
=====================================
@@ -23,22 +23,23 @@ import java.security.Principal;
 import java.security.PrivilegedAction;
 import java.util.Iterator;
 import java.util.Set;
+import java.util.concurrent.Callable;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import javax.security.auth.Subject;
 
-public class GssEncAction implements PrivilegedAction</* @Nullable */ Exception> {
+public class GssEncAction implements PrivilegedAction</* @Nullable */ Exception>, Callable</* @Nullable */ Exception> {
   private static final Logger LOGGER = Logger.getLogger(GssAction.class.getName());
   private final PGStream pgStream;
   private final String host;
   private final String user;
   private final String kerberosServerName;
   private final boolean useSpnego;
-  private final Subject subject;
+  private final /* @Nullable */ Subject subject;
   private final boolean logServerErrorDetail;
 
-  public GssEncAction(PGStream pgStream,  Subject subject,
+  public GssEncAction(PGStream pgStream, /* @Nullable */ Subject subject,
       String host, String user,
       String kerberosServerName, boolean useSpnego, boolean logServerErrorDetail) {
     this.pgStream = pgStream;
@@ -150,4 +151,8 @@ public class GssEncAction implements PrivilegedAction</* @Nullable */ Exception>
     return null;
   }
 
+  @Override
+  public /* @Nullable */ Exception call() throws Exception {
+    return run();
+  }
 }


=====================================
src/main/java/org/postgresql/gss/MakeGSS.java
=====================================
@@ -13,13 +13,18 @@ import org.postgresql.util.GT;
 import org.postgresql.util.PSQLException;
 import org.postgresql.util.PSQLState;
 
+// import org.checkerframework.checker.nullness.qual.NonNull;
 // import org.checkerframework.checker.nullness.qual.Nullable;
 import org.ietf.jgss.GSSCredential;
 
 import java.io.IOException;
-import java.security.AccessController;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
 import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
 import java.util.Set;
+import java.util.concurrent.Callable;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -28,6 +33,87 @@ import javax.security.auth.login.LoginContext;
 
 public class MakeGSS {
   private static final Logger LOGGER = Logger.getLogger(MakeGSS.class.getName());
+  private static final /* @Nullable */ MethodHandle SUBJECT_CURRENT;
+  private static final /* @Nullable */ MethodHandle ACCESS_CONTROLLER_GET_CONTEXT;
+  private static final /* @Nullable */ MethodHandle SUBJECT_GET_SUBJECT;
+  // Java <18
+  private static final /* @Nullable */ MethodHandle SUBJECT_DO_AS;
+  // Java 18+, see https://bugs.openjdk.org/browse/JDK-8267108
+  private static final /* @Nullable */ MethodHandle SUBJECT_CALL_AS;
+
+  static {
+    MethodHandle subjectCurrent = null;
+    try {
+      subjectCurrent = MethodHandles.lookup()
+          .findStatic(Subject.class, "current", MethodType.methodType(Subject.class));
+    } catch (NoSuchMethodException | IllegalAccessException ignore) {
+      // E.g. pre Java 18
+    }
+    SUBJECT_CURRENT = subjectCurrent;
+
+    MethodHandle accessControllerGetContext = null;
+    MethodHandle subjectGetSubject = null;
+
+    try {
+      Class<?> accessControllerClass = Class.forName("java.security.AccessController");
+      Class<?> accessControlContextClass =
+          Class.forName("java.security.AccessControlContext");
+      accessControllerGetContext = MethodHandles.lookup()
+          .findStatic(accessControllerClass, "getContext",
+              MethodType.methodType(accessControlContextClass));
+      subjectGetSubject = MethodHandles.lookup()
+          .findStatic(Subject.class, "getSubject",
+              MethodType.methodType(Subject.class, accessControlContextClass));
+    } catch (NoSuchMethodException | IllegalAccessException | ClassNotFoundException ignore) {
+      // E.g. pre Java 18+
+    }
+
+    ACCESS_CONTROLLER_GET_CONTEXT = accessControllerGetContext;
+    SUBJECT_GET_SUBJECT = subjectGetSubject;
+
+    MethodHandle subjectDoAs = null;
+    try {
+      subjectDoAs = MethodHandles.lookup().findStatic(Subject.class, "doAs",
+          MethodType.methodType(Object.class, Subject.class, PrivilegedExceptionAction.class));
+    } catch (NoSuchMethodException | IllegalAccessException ignore) {
+    }
+    SUBJECT_DO_AS = subjectDoAs;
+
+    MethodHandle subjectCallAs = null;
+    try {
+      subjectDoAs = MethodHandles.lookup().findStatic(Subject.class, "callAs",
+          MethodType.methodType(Object.class, Subject.class, Callable.class));
+    } catch (NoSuchMethodException | IllegalAccessException ignore) {
+    }
+    SUBJECT_CALL_AS = subjectCallAs;
+  }
+
+  /**
+   * Use {@code Subject.current()} in Java 18+, and
+   * {@code Subject.getSubject(AccessController.getContext())} in Java before 18.
+   * @return current Subject or null
+   */
+  private static /* @Nullable */ Subject getCurrentSubject() {
+    try {
+      if (SUBJECT_CURRENT != null) {
+        return (Subject) SUBJECT_CURRENT.invokeExact();
+      }
+      if (SUBJECT_GET_SUBJECT == null || ACCESS_CONTROLLER_GET_CONTEXT == null) {
+        return null;
+      }
+      return (Subject) SUBJECT_GET_SUBJECT.invoke(
+          ACCESS_CONTROLLER_GET_CONTEXT.invokeExact()
+      );
+    } catch (Throwable e) {
+      if (e instanceof RuntimeException) {
+        throw (RuntimeException) e;
+      }
+      if (e instanceof Error) {
+        throw (Error) e;
+      }
+      throw new RuntimeException(e);
+    }
+  }
 
   public static void authenticate(boolean encrypted,
       PGStream pgStream, String host, String user, char /* @Nullable */ [] password,
@@ -49,7 +135,7 @@ public class MakeGSS {
       boolean performAuthentication = jaasLogin;
 
       //Check if we can get credential from subject to avoid login.
-      Subject sub = Subject.getSubject(AccessController.getContext());
+      Subject sub = getCurrentSubject();
       if (sub != null) {
         Set<GSSCredential> gssCreds = sub.getPrivateCredentials(GSSCredential.class);
         if (gssCreds != null && !gssCreds.isEmpty()) {
@@ -62,18 +148,28 @@ public class MakeGSS {
         sub = lc.getSubject();
       }
 
+      PrivilegedAction</* @Nullable */ Exception> action;
       if ( encrypted ) {
-        PrivilegedAction</* @Nullable */ Exception> action = new GssEncAction(pgStream, sub, host, user,
+        action = new GssEncAction(pgStream, sub, host, user,
             kerberosServerName, useSpnego, logServerErrorDetail);
-
-        result = Subject.doAs(sub, action);
       } else {
-        PrivilegedAction</* @Nullable */ Exception> action = new GssAction(pgStream, sub, host, user,
+        action = new GssAction(pgStream, sub, host, user,
             kerberosServerName, useSpnego, logServerErrorDetail);
-
-        result = Subject.doAs(sub, action);
       }
-    } catch (Exception e) {
+      //noinspection ConstantConditions
+      @SuppressWarnings({"cast.unsafe", "assignment.type.incompatible"})
+      /* @NonNull */ Subject subject = sub;
+      if (SUBJECT_DO_AS != null) {
+        result = (Exception) SUBJECT_DO_AS.invoke(subject, action);
+      } else if (SUBJECT_CALL_AS != null) {
+        //noinspection ConstantConditions,unchecked
+        result = (Exception) SUBJECT_CALL_AS.invoke(subject, (Callable<Exception>) action);
+      } else {
+        throw new PSQLException(
+            GT.tr("Neither Subject.doAs (Java before 18) nor Subject.callAs (Java 18+) method found"),
+            PSQLState.OBJECT_NOT_IN_STATE);
+      }
+    } catch (Throwable e) {
       throw new PSQLException(GT.tr("GSS Authentication failed"), PSQLState.CONNECTION_FAILURE, e);
     }
 


=====================================
src/main/java/org/postgresql/jdbc/PgConnection.java
=====================================
@@ -47,6 +47,10 @@ import org.postgresql.xml.PGXmlFactoryFactory;
 // import org.checkerframework.dataflow.qual.Pure;
 
 import java.io.IOException;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.security.Permission;
 import java.sql.Array;
 import java.sql.Blob;
 import java.sql.CallableStatement;
@@ -89,6 +93,26 @@ public class PgConnection implements BaseConnection {
   private static final SQLPermission SQL_PERMISSION_ABORT = new SQLPermission("callAbort");
   private static final SQLPermission SQL_PERMISSION_NETWORK_TIMEOUT = new SQLPermission("setNetworkTimeout");
 
+  private static final /* @Nullable */ MethodHandle SYSTEM_GET_SECURITY_MANAGER;
+  private static final /* @Nullable */ MethodHandle SECURITY_MANAGER_CHECK_PERMISSION;
+
+  static {
+    MethodHandle systemGetSecurityManagerHandle = null;
+    MethodHandle securityManagerCheckPermission = null;
+    try {
+      Class<?> securityManagerClass = Class.forName("java.lang.SecurityManager");
+      systemGetSecurityManagerHandle =
+          MethodHandles.lookup().findStatic(System.class, "getSecurityManager",
+              MethodType.methodType(securityManagerClass));
+      securityManagerCheckPermission =
+          MethodHandles.lookup().findVirtual(securityManagerClass, "checkPermission",
+              MethodType.methodType(void.class, Permission.class));
+    } catch (NoSuchMethodException | IllegalAccessException | ClassNotFoundException ignore) {
+    }
+    SYSTEM_GET_SECURITY_MANAGER = systemGetSecurityManagerHandle;
+    SECURITY_MANAGER_CHECK_PERMISSION = securityManagerCheckPermission;
+  }
+
   private enum ReadOnlyBehavior {
     ignore,
     transaction,
@@ -1624,10 +1648,7 @@ public class PgConnection implements BaseConnection {
               PSQLState.INVALID_PARAMETER_VALUE);
     }
 
-    SecurityManager securityManager = System.getSecurityManager();
-    if (securityManager != null) {
-      securityManager.checkPermission(SQL_PERMISSION_NETWORK_TIMEOUT);
-    }
+    checkPermission(SQL_PERMISSION_NETWORK_TIMEOUT);
 
     try {
       queryExecutor.setNetworkTimeout(milliseconds);
@@ -1637,6 +1658,19 @@ public class PgConnection implements BaseConnection {
     }
   }
 
+  private void checkPermission(SQLPermission sqlPermissionNetworkTimeout) {
+    if (SYSTEM_GET_SECURITY_MANAGER != null && SECURITY_MANAGER_CHECK_PERMISSION != null) {
+      try {
+        Object securityManager = SYSTEM_GET_SECURITY_MANAGER.invoke();
+        if (securityManager != null) {
+          SECURITY_MANAGER_CHECK_PERMISSION.invoke(securityManager, sqlPermissionNetworkTimeout);
+        }
+      } catch (Throwable e) {
+        throw new RuntimeException(e);
+      }
+    }
+  }
+
   public int getNetworkTimeout() throws SQLException {
     checkClosed();
 


=====================================
src/main/java/org/postgresql/jdbc/PgPreparedStatement.java
=====================================
@@ -99,7 +99,7 @@ class PgPreparedStatement extends PgStatement implements PreparedStatement {
     int maxSupportedParameters = maximumNumberOfParameters();
     if (parameterCount > maxSupportedParameters) {
       throw new PSQLException(
-          GT.tr("PreparedStatement can have at most {0} parameters. Please consider using arrays, or splitting the query in several ones, or using COPY. Given query has {0} parameters",
+          GT.tr("PreparedStatement can have at most {0} parameters. Please consider using arrays, or splitting the query in several ones, or using COPY. Given query has {1} parameters",
               maxSupportedParameters,
               parameterCount),
           PSQLState.INVALID_PARAMETER_VALUE);


=====================================
src/main/java/org/postgresql/jdbc/PgResultSet.java
=====================================
@@ -1418,7 +1418,7 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS
       if (i > 1) {
         selectSQL.append(", ");
       }
-      selectSQL.append(pgmd.getBaseColumnName(i));
+      Utils.escapeIdentifier(selectSQL, pgmd.getBaseColumnName(i));
     }
     selectSQL.append(" from ").append(onlyTable).append(tableName).append(" where ");
 
@@ -1428,7 +1428,8 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS
     for (int i = 0; i < numKeys; i++) {
 
       PrimaryKey primaryKey = primaryKeys.get(i);
-      selectSQL.append(primaryKey.name).append(" = ?");
+      Utils.escapeIdentifier(selectSQL, primaryKey.name);
+      selectSQL.append(" = ?");
 
       if (i < numKeys - 1) {
         selectSQL.append(" and ");


=====================================
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.4.0";
+  public static final String DRIVER_VERSION = "42.4.1";
   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 = 4;
-  public static final int PATCH_VERSION = 0;
+  public static final int PATCH_VERSION = 1;
 
   // JDBC specification
   public static final String JDBC_VERSION = "4.2";


=====================================
src/main/java/org/postgresql/util/StreamWrapper.java
=====================================
@@ -117,6 +117,7 @@ public class StreamWrapper {
             }
           }
 
+          @SuppressWarnings({"deprecation", "removal"})
           protected void finalize() throws IOException {
             // forcibly close it because super.finalize() may keep the FD open, which may prevent
             // file deletion


=====================================
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.4.0
+Implementation-Version: 42.4.1
 Specification-Vendor: Oracle Corporation
 Specification-Title: JDBC
 Implementation-Vendor-Id: org.postgresql


=====================================
src/test/java/org/postgresql/test/XaTests.java
=====================================
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2022, PostgreSQL Global Development Group
+ * See the LICENSE file in the project root for more information.
+ */
+
+package org.postgresql.test;
+
+/**
+ * Declares interface to specify XA tests.
+ */
+public interface XaTests {
+}


=====================================
src/test/java/org/postgresql/test/jdbc2/BaseTest4.java
=====================================
@@ -93,12 +93,18 @@ public class BaseTest4 {
 
   public void assumeByteaSupported() {
     Assume.assumeTrue("bytea is not supported in simple protocol execution mode",
-        preferQueryMode.compareTo(PreferQueryMode.EXTENDED) >= 0);
+        preferQueryMode != PreferQueryMode.SIMPLE);
+  }
+
+  public static void assumeCallableStatementsSupported(Connection con) throws SQLException {
+    PreferQueryMode preferQueryMode = con.unwrap(PGConnection.class).getPreferQueryMode();
+    Assume.assumeTrue("callable statements are not fully supported in simple protocol execution mode",
+        preferQueryMode != PreferQueryMode.SIMPLE);
   }
 
   public void assumeCallableStatementsSupported() {
     Assume.assumeTrue("callable statements are not fully supported in simple protocol execution mode",
-        preferQueryMode.compareTo(PreferQueryMode.EXTENDED) >= 0);
+        preferQueryMode != PreferQueryMode.SIMPLE);
   }
 
   public void assumeBinaryModeRegular() {


=====================================
src/test/java/org/postgresql/test/jdbc2/CallableStmtTest.java
=====================================
@@ -13,10 +13,12 @@ import static org.junit.Assert.fail;
 
 import org.postgresql.test.TestUtil;
 
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 import java.sql.Array;
 import java.sql.CallableStatement;
+import java.sql.Connection;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.SQLWarning;
@@ -29,6 +31,12 @@ import java.sql.Types;
  * @author Paul Bethe
  */
 public class CallableStmtTest extends BaseTest4 {
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    try (Connection con = TestUtil.openDB();) {
+      assumeCallableStatementsSupported(con);
+    }
+  }
 
   @Override
   public void setUp() throws Exception {
@@ -99,7 +107,6 @@ public class CallableStmtTest extends BaseTest4 {
 
   @Test
   public void testGetUpdateCount() throws SQLException {
-    assumeCallableStatementsSupported();
     CallableStatement call = con.prepareCall(func + pkgName + "getDouble (?) }");
     call.setDouble(2, 3.04);
     call.registerOutParameter(1, Types.DOUBLE);
@@ -128,7 +135,6 @@ public class CallableStmtTest extends BaseTest4 {
 
   @Test
   public void testGetDouble() throws Throwable {
-    assumeCallableStatementsSupported();
     CallableStatement call = con.prepareCall(func + pkgName + "getDouble (?) }");
     call.setDouble(2, 3.04);
     call.registerOutParameter(1, Types.DOUBLE);
@@ -147,7 +153,6 @@ public class CallableStmtTest extends BaseTest4 {
 
   @Test
   public void testGetInt() throws Throwable {
-    assumeCallableStatementsSupported();
     CallableStatement call = con.prepareCall(func + pkgName + "getInt (?) }");
     call.setInt(2, 4);
     call.registerOutParameter(1, Types.INTEGER);
@@ -157,7 +162,6 @@ public class CallableStmtTest extends BaseTest4 {
 
   @Test
   public void testGetShort() throws Throwable {
-    assumeCallableStatementsSupported();
     CallableStatement call = con.prepareCall(func + pkgName + "getShort (?) }");
     call.setShort(2, (short) 4);
     call.registerOutParameter(1, Types.SMALLINT);
@@ -167,7 +171,6 @@ public class CallableStmtTest extends BaseTest4 {
 
   @Test
   public void testGetNumeric() throws Throwable {
-    assumeCallableStatementsSupported();
     CallableStatement call = con.prepareCall(func + pkgName + "getNumeric (?) }");
     call.setBigDecimal(2, new java.math.BigDecimal(4));
     call.registerOutParameter(1, Types.NUMERIC);
@@ -177,7 +180,6 @@ public class CallableStmtTest extends BaseTest4 {
 
   @Test
   public void testGetNumericWithoutArg() throws Throwable {
-    assumeCallableStatementsSupported();
     CallableStatement call = con.prepareCall(func + pkgName + "getNumericWithoutArg () }");
     call.registerOutParameter(1, Types.NUMERIC);
     call.execute();
@@ -186,7 +188,6 @@ public class CallableStmtTest extends BaseTest4 {
 
   @Test
   public void testGetString() throws Throwable {
-    assumeCallableStatementsSupported();
     CallableStatement call = con.prepareCall(func + pkgName + "getString (?) }");
     call.setString(2, "foo");
     call.registerOutParameter(1, Types.VARCHAR);
@@ -197,7 +198,6 @@ public class CallableStmtTest extends BaseTest4 {
 
   @Test
   public void testGetArray() throws SQLException {
-    assumeCallableStatementsSupported();
     CallableStatement call = con.prepareCall(func + pkgName + "getarray()}");
     call.registerOutParameter(1, Types.ARRAY);
     call.execute();
@@ -212,7 +212,6 @@ public class CallableStmtTest extends BaseTest4 {
 
   @Test
   public void testRaiseNotice() throws SQLException {
-    assumeCallableStatementsSupported();
     Statement statement = con.createStatement();
     statement.execute("SET SESSION client_min_messages = 'NOTICE'");
     CallableStatement call = con.prepareCall(func + pkgName + "raisenotice()}");


=====================================
src/test/java/org/postgresql/test/jdbc2/ConnectTimeoutTest.java
=====================================
@@ -56,7 +56,7 @@ public class ConnectTimeoutTest {
        * We treat this as a skipped test, as the test didn't really "succeed"
        * in testing the original behaviour, but it didn't fail either.
        */
-      Assume.assumeTrue("Host fast-failed connection to unreachable address "
+      Assume.assumeFalse("Host fast-failed connection to unreachable address "
                         + UNREACHABLE_HOST + " after " + interval + " ms, "
                         + " before timeout should have triggered.",
                         e.getCause() instanceof NoRouteToHostException


=====================================
src/test/java/org/postgresql/test/jdbc2/DriverTest.java
=====================================
@@ -5,23 +5,23 @@
 
 package org.postgresql.test.jdbc2;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 import org.postgresql.Driver;
 import org.postgresql.PGEnvironment;
 import org.postgresql.PGProperty;
 import org.postgresql.test.TestUtil;
+import org.postgresql.util.StubEnvironmentAndProperties;
 import org.postgresql.util.URLCoder;
 
-import org.junit.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.Test;
 import uk.org.webcompere.systemstubs.environment.EnvironmentVariables;
-import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension;
 import uk.org.webcompere.systemstubs.properties.SystemProperties;
 import uk.org.webcompere.systemstubs.resource.Resources;
 
@@ -42,7 +42,7 @@ import java.util.Properties;
  * Tests the dynamically created class org.postgresql.Driver
  *
  */
- at ExtendWith(SystemStubsExtension.class)
+ at StubEnvironmentAndProperties
 public class DriverTest {
 
   @Test
@@ -56,11 +56,11 @@ public class DriverTest {
    * According to the javadoc of java.sql.Driver.connect(...), calling abort when the {@code executor} is {@code null}
    * results in SQLException
    */
-  @Test(expected = SQLException.class)
+  @Test
   public void urlIsNull() throws SQLException {
     Driver driver = new Driver();
 
-    driver.connect(null, new Properties());
+    assertThrows(SQLException.class, () -> driver.connect(null, new Properties()));
   }
 
   /*
@@ -136,14 +136,14 @@ public class DriverTest {
 
   private void verifyUrl(Driver drv, String url, String hosts, String ports, String dbName)
       throws Exception {
-    assertTrue(url, drv.acceptsURL(url));
+    assertTrue(drv.acceptsURL(url), url);
     Method parseMethod =
         drv.getClass().getDeclaredMethod("parseURL", String.class, Properties.class);
     parseMethod.setAccessible(true);
     Properties p = (Properties) parseMethod.invoke(drv, url, null);
-    assertEquals(url, dbName, p.getProperty(PGProperty.PG_DBNAME.getName()));
-    assertEquals(url, hosts, p.getProperty(PGProperty.PG_HOST.getName()));
-    assertEquals(url, ports, p.getProperty(PGProperty.PG_PORT.getName()));
+    assertEquals(dbName, p.getProperty(PGProperty.PG_DBNAME.getName()), url);
+    assertEquals(hosts, p.getProperty(PGProperty.PG_HOST.getName()), url);
+    assertEquals(ports, p.getProperty(PGProperty.PG_PORT.getName()), url);
   }
 
   /**
@@ -515,7 +515,7 @@ public class DriverTest {
       try {
         assertNotNull(con);
         System.err.println();
-        assertFalse("The System.err should not be closed.", System.err.checkError());
+        assertFalse(System.err.checkError(), "The System.err should not be closed.");
       } finally {
         con.close();
       }


=====================================
src/test/java/org/postgresql/test/jdbc2/RefCursorFetchTest.java
=====================================
@@ -78,6 +78,7 @@ public class RefCursorFetchTest extends BaseTest4 {
   public static void beforeClass() throws Exception {
     TestUtil.assumeHaveMinimumServerVersion(ServerVersion.v9_0);
     try (Connection con = TestUtil.openDB();) {
+      assumeCallableStatementsSupported(con);
       TestUtil.createTable(con, "test_blob", "content bytea");
       TestUtil.execute(con, "");
       TestUtil.execute(con, "--create function to read data\n"
@@ -106,7 +107,6 @@ public class RefCursorFetchTest extends BaseTest4 {
   @Override
   public void setUp() throws Exception {
     super.setUp();
-    assumeCallableStatementsSupported();
     con.setAutoCommit(autoCommit == AutoCommit.YES);
   }
 


=====================================
src/test/java/org/postgresql/test/jdbc2/RefCursorTest.java
=====================================
@@ -12,11 +12,13 @@ import static org.junit.Assert.assertTrue;
 
 import org.postgresql.test.TestUtil;
 
+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.ResultSetMetaData;
 import java.sql.SQLException;
@@ -49,6 +51,13 @@ public class RefCursorTest extends BaseTest4 {
     });
   }
 
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    try (Connection con = TestUtil.openDB();) {
+      assumeCallableStatementsSupported(con);
+    }
+  }
+
   @Override
   public void setUp() throws Exception {
     // this is the same as the ResultSet setup.
@@ -87,7 +96,6 @@ public class RefCursorTest extends BaseTest4 {
 
   @Test
   public void testResult() throws SQLException {
-    assumeCallableStatementsSupported();
     CallableStatement call = con.prepareCall("{ ? = call testspg__getRefcursor () }");
     call.registerOutParameter(1, cursorType);
     call.execute();
@@ -119,7 +127,6 @@ public class RefCursorTest extends BaseTest4 {
 
   @Test
   public void testEmptyResult() throws SQLException {
-    assumeCallableStatementsSupported();
     CallableStatement call = con.prepareCall("{ ? = call testspg__getEmptyRefcursor () }");
     call.registerOutParameter(1, cursorType);
     call.execute();
@@ -133,8 +140,6 @@ public class RefCursorTest extends BaseTest4 {
 
   @Test
   public void testMetaData() throws SQLException {
-    assumeCallableStatementsSupported();
-
     CallableStatement call = con.prepareCall("{ ? = call testspg__getRefcursor () }");
     call.registerOutParameter(1, cursorType);
     call.execute();
@@ -152,7 +157,6 @@ public class RefCursorTest extends BaseTest4 {
 
   @Test
   public void testResultType() throws SQLException {
-    assumeCallableStatementsSupported();
     CallableStatement call = con.prepareCall("{ ? = call testspg__getRefcursor () }",
         ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
     call.registerOutParameter(1, cursorType);


=====================================
src/test/java/org/postgresql/test/jdbc2/ResultSetRefreshTest.java
=====================================
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2022, PostgreSQL Global Development Group
+ * See the LICENSE file in the project root for more information.
+ */
+
+package org.postgresql.test.jdbc2;
+
+import static org.junit.Assert.assertTrue;
+
+import org.postgresql.test.TestUtil;
+
+import org.junit.Test;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+public class ResultSetRefreshTest extends BaseTest4 {
+  @Test
+  public void testWithDataColumnThatRequiresEscaping() throws Exception {
+    TestUtil.dropTable(con, "refresh_row_bad_ident");
+    TestUtil.execute(con, "CREATE TABLE refresh_row_bad_ident (id int PRIMARY KEY, \"1 FROM refresh_row_bad_ident; SELECT 2; SELECT *\" int)");
+    TestUtil.execute(con, "INSERT INTO refresh_row_bad_ident (id) VALUES (1), (2), (3)");
+
+    Statement stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
+    ResultSet rs = stmt.executeQuery("SELECT * FROM refresh_row_bad_ident");
+    assertTrue(rs.next());
+    try {
+      rs.refreshRow();
+    } catch (SQLException ex) {
+      throw new RuntimeException("ResultSet.refreshRow() did not handle escaping data column identifiers", ex);
+    }
+    rs.close();
+    stmt.close();
+  }
+
+  @Test
+  public void testWithKeyColumnThatRequiresEscaping() throws Exception {
+    TestUtil.dropTable(con, "refresh_row_bad_ident");
+    TestUtil.execute(con, "CREATE TABLE refresh_row_bad_ident (\"my key\" int PRIMARY KEY)");
+    TestUtil.execute(con, "INSERT INTO refresh_row_bad_ident VALUES (1), (2), (3)");
+
+    Statement stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
+    ResultSet rs = stmt.executeQuery("SELECT * FROM refresh_row_bad_ident");
+    assertTrue(rs.next());
+    try {
+      rs.refreshRow();
+    } catch (SQLException ex) {
+      throw new RuntimeException("ResultSet.refreshRow() did not handle escaping key column identifiers", ex);
+    }
+    rs.close();
+    stmt.close();
+  }
+}


=====================================
src/test/java/org/postgresql/test/jdbc3/Jdbc3CallableStatementTest.java
=====================================
@@ -16,10 +16,12 @@ import org.postgresql.test.TestUtil;
 import org.postgresql.test.jdbc2.BaseTest4;
 import org.postgresql.util.PSQLState;
 
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 import java.math.BigDecimal;
 import java.sql.CallableStatement;
+import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
@@ -30,6 +32,12 @@ import java.sql.Types;
  * @author davec
  */
 public class Jdbc3CallableStatementTest extends BaseTest4 {
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    try (Connection con = TestUtil.openDB();) {
+      assumeCallableStatementsSupported(con);
+    }
+  }
 
   @Override
   public void setUp() throws Exception {
@@ -129,7 +137,6 @@ public class Jdbc3CallableStatementTest extends BaseTest4 {
 
   @Test
   public void testSomeInOut() throws Throwable {
-    assumeCallableStatementsSupported();
     CallableStatement call = con.prepareCall("{ call test_somein_someout(?,?,?) }");
 
     call.registerOutParameter(2, Types.VARCHAR);
@@ -141,7 +148,6 @@ public class Jdbc3CallableStatementTest extends BaseTest4 {
 
   @Test
   public void testNotEnoughParameters() throws Throwable {
-    assumeCallableStatementsSupported();
     CallableStatement cs = con.prepareCall("{call myiofunc(?,?)}");
     cs.setInt(1, 2);
     cs.registerOutParameter(2, Types.INTEGER);
@@ -189,8 +195,6 @@ public class Jdbc3CallableStatementTest extends BaseTest4 {
 
   @Test
   public void testNumeric() throws Throwable {
-    assumeCallableStatementsSupported();
-
     CallableStatement call = con.prepareCall("{ call Numeric_Proc(?,?,?) }");
 
     call.registerOutParameter(1, Types.NUMERIC, 15);
@@ -216,7 +220,6 @@ public class Jdbc3CallableStatementTest extends BaseTest4 {
 
   @Test
   public void testGetObjectDecimal() throws Throwable {
-    assumeCallableStatementsSupported();
     try {
       Statement stmt = con.createStatement();
       stmt.execute(
@@ -420,7 +423,6 @@ public class Jdbc3CallableStatementTest extends BaseTest4 {
 
   @Test
   public void testGetObjectLongVarchar() throws Throwable {
-    assumeCallableStatementsSupported();
     try {
       Statement stmt = con.createStatement();
       stmt.execute("create temp table longvarchar_tab ( t text, null_val text )");
@@ -699,7 +701,6 @@ public class Jdbc3CallableStatementTest extends BaseTest4 {
 
   @Test
   public void testGetObjectFloat() throws Throwable {
-    assumeCallableStatementsSupported();
     try {
       Statement stmt = con.createStatement();
       stmt.execute(createDecimalTab);
@@ -736,7 +737,6 @@ public class Jdbc3CallableStatementTest extends BaseTest4 {
 
   @Test
   public void testGetDouble01() throws Throwable {
-    assumeCallableStatementsSupported();
     try {
       Statement stmt = con.createStatement();
       stmt.execute("create temp table d_tab ( max_val float, min_val float, null_val float )");
@@ -777,7 +777,6 @@ public class Jdbc3CallableStatementTest extends BaseTest4 {
 
   @Test
   public void testGetDoubleAsReal() throws Throwable {
-    assumeCallableStatementsSupported();
     try {
       Statement stmt = con.createStatement();
       stmt.execute("create temp table d_tab ( max_val float, min_val float, null_val float )");
@@ -818,7 +817,6 @@ public class Jdbc3CallableStatementTest extends BaseTest4 {
 
   @Test
   public void testGetShort01() throws Throwable {
-    assumeCallableStatementsSupported();
     try {
       Statement stmt = con.createStatement();
       stmt.execute("create temp table short_tab ( max_val int2, min_val int2, null_val int2 )");
@@ -859,7 +857,6 @@ public class Jdbc3CallableStatementTest extends BaseTest4 {
 
   @Test
   public void testGetInt01() throws Throwable {
-    assumeCallableStatementsSupported();
     try {
       Statement stmt = con.createStatement();
       stmt.execute("create temp table i_tab ( max_val int, min_val int, null_val int )");
@@ -900,7 +897,6 @@ public class Jdbc3CallableStatementTest extends BaseTest4 {
 
   @Test
   public void testGetLong01() throws Throwable {
-    assumeCallableStatementsSupported();
     try {
       Statement stmt = con.createStatement();
       stmt.execute("create temp table l_tab ( max_val int8, min_val int8, null_val int8 )");
@@ -941,7 +937,6 @@ public class Jdbc3CallableStatementTest extends BaseTest4 {
 
   @Test
   public void testGetBoolean01() throws Throwable {
-    assumeCallableStatementsSupported();
     try {
       Statement stmt = con.createStatement();
       stmt.execute(createBitTab);
@@ -992,7 +987,6 @@ public class Jdbc3CallableStatementTest extends BaseTest4 {
 
   @Test
   public void testGetByte01() throws Throwable {
-    assumeCallableStatementsSupported();
     try {
       Statement stmt = con.createStatement();
       stmt.execute("create temp table byte_tab ( max_val int2, min_val int2, null_val int2 )");
@@ -1033,7 +1027,6 @@ public class Jdbc3CallableStatementTest extends BaseTest4 {
 
   @Test
   public void testMultipleOutExecutions() throws SQLException {
-    assumeCallableStatementsSupported();
     CallableStatement cs = con.prepareCall("{call myiofunc(?, ?)}");
     for (int i = 0; i < 10; i++) {
       cs.registerOutParameter(1, Types.INTEGER);
@@ -1048,7 +1041,6 @@ public class Jdbc3CallableStatementTest extends BaseTest4 {
 
   @Test
   public void testSum() throws SQLException {
-    assumeCallableStatementsSupported();
     CallableStatement cs = con.prepareCall("{?= call mysum(?, ?)}");
     cs.registerOutParameter(1, Types.INTEGER);
     cs.setInt(2, 2);
@@ -1059,7 +1051,6 @@ public class Jdbc3CallableStatementTest extends BaseTest4 {
 
   @Test
   public void testFunctionNoParametersWithParentheses() throws SQLException {
-    assumeCallableStatementsSupported();
     CallableStatement cs = con.prepareCall("{?= call mynoparams()}");
     cs.registerOutParameter(1, Types.INTEGER);
     cs.execute();
@@ -1069,7 +1060,6 @@ public class Jdbc3CallableStatementTest extends BaseTest4 {
 
   @Test
   public void testFunctionNoParametersWithoutParentheses() throws SQLException {
-    assumeCallableStatementsSupported();
     CallableStatement cs = con.prepareCall("{?= call mynoparams}");
     cs.registerOutParameter(1, Types.INTEGER);
     cs.execute();
@@ -1079,7 +1069,6 @@ public class Jdbc3CallableStatementTest extends BaseTest4 {
 
   @Test
   public void testProcedureNoParametersWithParentheses() throws SQLException {
-    assumeCallableStatementsSupported();
     CallableStatement cs = con.prepareCall("{ call mynoparamsproc()}");
     cs.execute();
     TestUtil.closeQuietly(cs);
@@ -1087,7 +1076,6 @@ public class Jdbc3CallableStatementTest extends BaseTest4 {
 
   @Test
   public void testProcedureNoParametersWithoutParentheses() throws SQLException {
-    assumeCallableStatementsSupported();
     CallableStatement cs = con.prepareCall("{ call mynoparamsproc}");
     cs.execute();
     TestUtil.closeQuietly(cs);
@@ -1096,7 +1084,6 @@ public class Jdbc3CallableStatementTest extends BaseTest4 {
   @Test
   public void testProcedureInOnlyNativeCall() throws SQLException {
     assumeMinimumServerVersion(ServerVersion.v11);
-    assumeCallableStatementsSupported();
     CallableStatement cs = con.prepareCall("call inonlyprocedure(?)");
     cs.setInt(1, 5);
     cs.execute();
@@ -1106,7 +1093,6 @@ public class Jdbc3CallableStatementTest extends BaseTest4 {
   @Test
   public void testProcedureInOutNativeCall() throws SQLException {
     assumeMinimumServerVersion(ServerVersion.v11);
-    assumeCallableStatementsSupported();
     // inoutprocedure(a INOUT int) returns a*2 via the INOUT parameter
     CallableStatement cs = con.prepareCall("call inoutprocedure(?)");
     cs.setInt(1, 5);


=====================================
src/test/java/org/postgresql/test/jdbc3/ProcedureTransactionTest.java
=====================================
@@ -16,15 +16,23 @@ import org.postgresql.test.TestUtil;
 import org.postgresql.test.jdbc2.BaseTest4;
 import org.postgresql.util.PSQLState;
 
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 import java.sql.CallableStatement;
+import java.sql.Connection;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.Properties;
 
 public class ProcedureTransactionTest extends BaseTest4 {
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    try (Connection con = TestUtil.openDB();) {
+      assumeCallableStatementsSupported(con);
+    }
+  }
 
   @Override
   protected void updateProperties(Properties props) {
@@ -63,7 +71,6 @@ public class ProcedureTransactionTest extends BaseTest4 {
   @Test
   public void testProcWithNoTxnControl() throws SQLException {
     assumeMinimumServerVersion(ServerVersion.v11);
-    assumeCallableStatementsSupported();
     CallableStatement cs = con.prepareCall("call mynotxnproc(?)");
     int val = 1;
     cs.setInt(1, val);
@@ -84,7 +91,6 @@ public class ProcedureTransactionTest extends BaseTest4 {
   @Test
   public void testProcWithCommitInside() throws SQLException {
     assumeMinimumServerVersion(ServerVersion.v11);
-    assumeCallableStatementsSupported();
     CallableStatement cs = con.prepareCall("call mycommitproc(?)");
     int val = 2;
     cs.setInt(1, val);
@@ -105,7 +111,6 @@ public class ProcedureTransactionTest extends BaseTest4 {
   @Test
   public void testProcWithRollbackInside() throws SQLException {
     assumeMinimumServerVersion(ServerVersion.v11);
-    assumeCallableStatementsSupported();
     CallableStatement cs = con.prepareCall("call myrollbackproc(?)");
     int val = 3;
     cs.setInt(1, val);
@@ -148,7 +153,6 @@ public class ProcedureTransactionTest extends BaseTest4 {
 
   private void testProcAutoCommit() throws SQLException {
     assumeMinimumServerVersion(ServerVersion.v11);
-    assumeCallableStatementsSupported();
     CallableStatement cs = con.prepareCall("call mycommitproc(?)");
     int val = 4;
     cs.setInt(1, val);


=====================================
src/test/java/org/postgresql/test/xa/XADataSourceTest.java
=====================================
@@ -12,13 +12,16 @@ import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
 
 import org.postgresql.test.TestUtil;
+import org.postgresql.test.XaTests;
 import org.postgresql.test.jdbc2.optional.BaseDataSourceTest;
 import org.postgresql.xa.PGXADataSource;
 
 // import org.checkerframework.checker.nullness.qual.Nullable;
 import org.junit.After;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 
 import java.sql.Connection;
 import java.sql.ResultSet;
@@ -33,6 +36,7 @@ import javax.transaction.xa.XAException;
 import javax.transaction.xa.XAResource;
 import javax.transaction.xa.Xid;
 
+ at Category(XaTests.class)
 public class XADataSourceTest {
 
   private XADataSource xaDs;
@@ -49,10 +53,16 @@ public class XADataSourceTest {
     BaseDataSourceTest.setupDataSource((PGXADataSource) xaDs);
   }
 
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    try (Connection con = TestUtil.openDB();) {
+      assumeTrue("max_prepared_transactions should be non-zero for XA tests", isPreparedTransactionEnabled(con));
+    }
+  }
+
   @Before
   public void setUp() throws Exception {
     dbConn = TestUtil.openDB();
-    assumeTrue(isPreparedTransactionEnabled(dbConn));
 
     // Check if we're operating as a superuser; some tests require it.
     Statement st = dbConn.createStatement();


=====================================
src/test/java/org/postgresql/util/OSUtilTest.java
=====================================
@@ -8,15 +8,13 @@ package org.postgresql.util;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
 import uk.org.webcompere.systemstubs.environment.EnvironmentVariables;
-import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension;
 import uk.org.webcompere.systemstubs.properties.SystemProperties;
 import uk.org.webcompere.systemstubs.resource.Resources;
 
 import java.io.File;
 
- at ExtendWith(SystemStubsExtension.class)
+ at StubEnvironmentAndProperties
 class OSUtilTest {
 
   @Test


=====================================
src/test/java/org/postgresql/util/PGPropertyPasswordParserTest.java
=====================================
@@ -26,6 +26,7 @@ import java.net.URL;
  *
  * @author Marek Läll
  */
+ at StubEnvironmentAndProperties
 class PGPropertyPasswordParserTest {
 
   // "org.postgresql.pgpassfile" : missing


=====================================
src/test/java/org/postgresql/util/PGPropertyServiceParserTest.java
=====================================
@@ -13,9 +13,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 import org.postgresql.PGEnvironment;
 
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
 import uk.org.webcompere.systemstubs.environment.EnvironmentVariables;
-import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension;
 import uk.org.webcompere.systemstubs.properties.SystemProperties;
 import uk.org.webcompere.systemstubs.resource.Resources;
 
@@ -30,7 +28,7 @@ import java.util.Properties;
  *
  * @author Marek Läll
  */
- at ExtendWith(SystemStubsExtension.class)
+ at StubEnvironmentAndProperties
 class PGPropertyServiceParserTest {
 
   // "org.postgresql.pgservicefile" : missing


=====================================
src/test/java/org/postgresql/util/StubEnvironmentAndProperties.java
=====================================
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2022, PostgreSQL Global Development Group
+ * See the LICENSE file in the project root for more information.
+ */
+
+package org.postgresql.util;
+
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.parallel.Isolated;
+import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation is used to mark a test method as a test that should be run with stubbing system
+ * calls like {@code System#getProperty} and {@code System#getenv}.
+ * <p>The tests should be run in isolation to prevent concurrent modification of properties and
+ * the environment.</p>
+ * <p>Note: environment mocking works from a single thread only until
+ * <a href="https://github.com/webcompere/system-stubs/pull/46">Fix multi-threaded
+ * environment variable mocking</a>, and <a href="https://github.com/mockito/mockito/issues/2142">Mocked
+ * static methods are not available in other threads</a> are resolved</p>
+ */
+ at Isolated
+ at ExtendWith(SystemStubsExtension.class)
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.METHOD, ElementType.TYPE})
+public @interface StubEnvironmentAndProperties {
+}



View it on GitLab: https://salsa.debian.org/java-team/libpostgresql-jdbc-java/-/compare/c17d4ecc6cc0c414567dcc181ac44eaddd1d71ca...c03c688ea0dacca13f3ef030f715524b5a72d125

-- 
View it on GitLab: https://salsa.debian.org/java-team/libpostgresql-jdbc-java/-/compare/c17d4ecc6cc0c414567dcc181ac44eaddd1d71ca...c03c688ea0dacca13f3ef030f715524b5a72d125
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/20220808/097b7310/attachment.htm>


More information about the pkg-java-commits mailing list