[Git][java-team/libpostgresql-jdbc-java][master] 3 commits: New upstream version 42.7.10
Christoph Berg (@myon)
gitlab at salsa.debian.org
Wed Feb 11 19:39:16 GMT 2026
Christoph Berg pushed to branch master at Debian Java Maintainers / libpostgresql-jdbc-java
Commits:
71e3655f by Christoph Berg at 2026-02-11T20:38:09+01:00
New upstream version 42.7.10
- - - - -
2d0c8ff4 by Christoph Berg at 2026-02-11T20:38:12+01:00
Update upstream source from tag 'upstream/42.7.10'
Update to upstream version '42.7.10'
with Debian dir da60d3c039ea0b5ce61bd7708e2d329822bccacf
- - - - -
5449b3c8 by Christoph Berg at 2026-02-11T20:39:00+01:00
New upstream version 42.7.10.
- - - - -
29 changed files:
- debian/changelog
- pom.xml
- src/main/java/org/postgresql/PGProperty.java
- src/main/java/org/postgresql/PGStatement.java
- src/main/java/org/postgresql/core/ServerVersion.java
- src/main/java/org/postgresql/core/v3/ConnectionFactoryImpl.java
- src/main/java/org/postgresql/core/v3/QueryExecutorImpl.java
- src/main/java/org/postgresql/jdbc/PgResultSet.java
- src/main/java/org/postgresql/jdbc/TimestampUtils.java
- src/main/java/org/postgresql/util/DriverInfo.java
- src/main/java/org/postgresql/util/PGInterval.java
- src/main/resources/META-INF/MANIFEST.MF
- src/test/java/org/postgresql/jdbc/LargeObjectManagerTest.java
- + src/test/java/org/postgresql/test/annotations/DisabledIfServerVersionGreater.java
- src/test/java/org/postgresql/test/impl/ServerVersionCondition.java
- + src/test/java/org/postgresql/test/impl/ServerVersionGreaterCondition.java
- + src/test/java/org/postgresql/test/jdbc2/CleanupSavepointsWithFastpathTest.java
- src/test/java/org/postgresql/test/jdbc2/DateTest.java
- src/test/java/org/postgresql/test/jdbc2/GetXXXTest.java
- src/test/java/org/postgresql/test/jdbc2/IntervalTest.java
- src/test/java/org/postgresql/test/jdbc2/PGTimeTest.java
- src/test/java/org/postgresql/test/jdbc2/PGTimestampTest.java
- src/test/java/org/postgresql/test/jdbc2/PreparedStatementTest.java
- src/test/java/org/postgresql/test/jdbc2/TimeTest.java
- src/test/java/org/postgresql/test/jdbc2/TimestampTest.java
- src/test/java/org/postgresql/test/jdbc2/TimezoneCachingTest.java
- src/test/java/org/postgresql/test/jdbc2/TimezoneTest.java
- src/test/java/org/postgresql/test/jdbc4/jdbc41/GetObjectTest.java
- src/test/java/org/postgresql/test/jdbc42/TimestampUtilsTest.java
Changes:
=====================================
debian/changelog
=====================================
@@ -1,3 +1,9 @@
+libpgjava (42.7.10-1) unstable; urgency=medium
+
+ * New upstream version 42.7.10.
+
+ -- Christoph Berg <myon at debian.org> Wed, 11 Feb 2026 20:38:12 +0100
+
libpgjava (42.7.9-1) unstable; urgency=medium
* New upstream version 42.7.9.
=====================================
pom.xml
=====================================
@@ -8,7 +8,7 @@
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
- <version>42.7.9</version>
+ <version>42.7.10</version>
<packaging>jar</packaging>
<name>PostgreSQL JDBC Driver - JDBC 4.2</name>
<description>Java JDBC 4.2 (JRE 8+) driver for PostgreSQL database</description>
=====================================
src/main/java/org/postgresql/PGProperty.java
=====================================
@@ -752,7 +752,6 @@ public enum PGProperty {
null,
"The password for the client's ssl key (ignored if sslpasswordcallback is set)"),
-
/**
* The classname instantiating {@link javax.security.auth.callback.CallbackHandler} to use.
*/
=====================================
src/main/java/org/postgresql/PGStatement.java
=====================================
@@ -20,9 +20,8 @@ public interface PGStatement {
// -infinity / infinity representation in Java
long DATE_POSITIVE_INFINITY = 9223372036825200000L;
long DATE_NEGATIVE_INFINITY = -9223372036832400000L;
- // Days (2^31) in ms that can be stored minus the difference between the postgres and java epoch
- long DATE_POSITIVE_SMALLER_INFINITY = 185541640502400000L;
- long DATE_NEGATIVE_SMALLER_INFINITY = -185541640502400000L;
+ long DATE_POSITIVE_SMALLER_INFINITY = 185543533774800000L;
+ long DATE_NEGATIVE_SMALLER_INFINITY = -185543533774800000L;
/**
* Returns the Last inserted/updated oid.
=====================================
src/main/java/org/postgresql/core/ServerVersion.java
=====================================
@@ -38,7 +38,9 @@ public enum ServerVersion implements Version {
v15("15"),
v16("16"),
v17("17"),
- v18("18")
+ v18("18"),
+ v19("19"),
+ v20("20")
;
private final int version;
=====================================
src/main/java/org/postgresql/core/v3/ConnectionFactoryImpl.java
=====================================
@@ -220,11 +220,11 @@ public class ConnectionFactoryImpl extends ConnectionFactory {
if (protocolVersion != null) {
int decimal = protocolVersion.indexOf('.');
if (decimal == -1) {
- protocolMinor = Integer.parseInt(protocolVersion);
+ protocolMajor = Integer.parseInt(protocolVersion);
protocolMinor = 0;
} else {
- protocolMinor = Integer.parseInt(protocolVersion.substring(decimal + 1));
protocolMajor = Integer.parseInt(protocolVersion.substring(0,decimal));
+ protocolMinor = Integer.parseInt(protocolVersion.substring(decimal + 1));
}
}
@@ -754,7 +754,7 @@ public class ConnectionFactoryImpl extends ConnectionFactory {
// do not connect and throw an error
String errorMessage = "Protocol error, received invalid options: ";
for (int i = 0; i < numOptionsNotRecognized; i++) {
- errorMessage += i > 0 ? "" : "," + pgStream.receiveString();
+ errorMessage += (i > 0 ? "," : "") + pgStream.receiveString();
}
LOGGER.log(Level.FINEST, errorMessage);
throw new PSQLException(errorMessage, PSQLState.PROTOCOL_VIOLATION);
=====================================
src/main/java/org/postgresql/core/v3/QueryExecutorImpl.java
=====================================
@@ -478,13 +478,13 @@ public class QueryExecutorImpl extends QueryExecutorBase {
}
private boolean shouldCreateAutomaticSavepoint(Query query, int flags) {
- if (!isTransactionActive(flags)) {
+ if (getAutoSave() == AutoSave.NEVER) {
return false;
}
- if (isSpecialQuery(query)) {
+ if (!isTransactionActive(flags)) {
return false;
}
- if (getAutoSave() == AutoSave.NEVER) {
+ if (isSpecialQuery(query)) {
return false;
}
return getAutoSave() == AutoSave.ALWAYS || queryMightFail(query);
@@ -496,8 +496,25 @@ public class QueryExecutorImpl extends QueryExecutorBase {
}
private boolean isSpecialQuery(Query query) {
- return query == restoreToAutoSave
- || "COMMIT".equalsIgnoreCase(query.getNativeSql());
+ if (query == restoreToAutoSave) {
+ return true;
+ }
+ String sql = query.getNativeSql();
+ // SET TRANSACTION ISOLATION LEVEL and SET SESSION CHARACTERISTICS cannot be called in subtransaction
+ // SAVEPOINT commands cannot use autosave because:
+ // - SAVEPOINT: releasing the autosave would destroy the user's savepoint (created after autosave)
+ // - RELEASE SAVEPOINT: same issue, plus the released savepoint might no longer exist
+ // - ROLLBACK TO SAVEPOINT: destroys savepoints created after the target, including autosave
+ return "COMMIT".equalsIgnoreCase(sql)
+ || startsWithIgnoreCase(sql, "SET TRANSACTION")
+ || startsWithIgnoreCase(sql, "SET SESSION CHARACTERISTICS")
+ || startsWithIgnoreCase(sql, "SAVEPOINT")
+ || startsWithIgnoreCase(sql, "RELEASE")
+ || startsWithIgnoreCase(sql, "ROLLBACK TO SAVEPOINT");
+ }
+
+ private static boolean startsWithIgnoreCase(String str, String prefix) {
+ return str.regionMatches(true, 0, prefix, 0, prefix.length());
}
// If query has no resulting fields, it cannot fail with 'cached plan must not change result type'
@@ -740,6 +757,12 @@ public class QueryExecutorImpl extends QueryExecutorBase {
doSubprotocolBegin();
}
try {
+ // Process any pending responses from simple queries (e.g., RELEASE SAVEPOINT
+ // from cleanupSavepoints). These responses would otherwise be misinterpreted
+ // by receiveFastpathResult(). See https://github.com/pgjdbc/pgjdbc/issues/3910
+ if (!pendingExecuteQueue.isEmpty()) {
+ processResults(new ResultHandlerBase(), 0);
+ }
sendFastpathCall(fnid, (SimpleParameterList) parameters);
return receiveFastpathResult();
} catch (IOException ioe) {
@@ -1045,6 +1068,12 @@ public class QueryExecutorImpl extends QueryExecutorBase {
byte[] buf = sql.getBytes(StandardCharsets.UTF_8);
try {
+ // Process any pending responses from simple queries (e.g., RELEASE SAVEPOINT
+ // from cleanupSavepoints). These responses would otherwise be misinterpreted
+ // by processCopyResults(). See https://github.com/pgjdbc/pgjdbc/issues/3910
+ if (!pendingExecuteQueue.isEmpty()) {
+ processResults(new ResultHandlerBase(), 0);
+ }
LOGGER.log(Level.FINEST, " FE=> Query(CopyStart)");
pgStream.sendChar(PgMessageType.QUERY_REQUEST);
=====================================
src/main/java/org/postgresql/jdbc/PgResultSet.java
=====================================
@@ -5,7 +5,6 @@
package org.postgresql.jdbc;
-import static org.postgresql.jdbc.TimestampUtils.createProlepticGregorianCalendar;
import static org.postgresql.util.internal.Nullness.castNonNull;
import org.postgresql.Driver;
@@ -3977,7 +3976,7 @@ public class PgResultSet implements ResultSet, PGRefCursorResultSet {
if (timestampValue == null) {
return null;
}
- Calendar calendar = createProlepticGregorianCalendar(getDefaultCalendar().getTimeZone());
+ Calendar calendar = Calendar.getInstance(getDefaultCalendar().getTimeZone());
calendar.setTimeInMillis(timestampValue.getTime());
return type.cast(calendar);
} else {
=====================================
src/main/java/org/postgresql/jdbc/TimestampUtils.java
=====================================
@@ -135,8 +135,8 @@ public class TimestampUtils {
private final StringBuilder sbuf = new StringBuilder();
// This calendar is used when user provides calendar in setX(, Calendar) method.
- // It ensures calendar is proleptic Gregorian.
- private final Calendar calendarWithUserTz = createProlepticGregorianCalendar(TimeZone.getDefault());
+ // It ensures calendar is Gregorian.
+ private final Calendar calendarWithUserTz = new GregorianCalendar();
private /* @Nullable */ Calendar calCache;
private /* @Nullable */ ZoneOffset calCacheZone;
@@ -159,11 +159,11 @@ public class TimestampUtils {
}
// normally we would use:
- // calCache = createProlepticGregorianCalendar(TimeZone.getTimeZone(offset));
+ // calCache = new GregorianCalendar(TimeZone.getTimeZone(offset));
// But this seems to cause issues for some crazy offsets as returned by server for BC dates!
final String tzid = offset.getTotalSeconds() == 0 ? "UTC" : "GMT".concat(offset.getId());
final TimeZone syntheticTZ = new SimpleTimeZone(offset.getTotalSeconds() * 1000, tzid);
- calCache = createProlepticGregorianCalendar(syntheticTZ);
+ calCache = new GregorianCalendar(syntheticTZ);
calCacheZone = offset;
return calCache;
}
@@ -766,7 +766,7 @@ public class TimestampUtils {
return new Date(PGStatement.DATE_NEGATIVE_INFINITY);
}
if ( cal == null ) {
- cal = createProlepticGregorianCalendar(TimeZone.getDefault());
+ cal = Calendar.getInstance();
}
ParsedTimestamp pt;
@@ -1782,7 +1782,8 @@ public class TimestampUtils {
}
/**
- * Converts the given postgresql seconds to java seconds. See {@link #toPgSecs}
+ * Converts the given postgresql seconds to java seconds. Reverse engineered by inserting varying
+ * dates to postgresql and tuning the formula until the java dates matched. See {@link #toPgSecs}
* for the reverse operation.
*
* @param secs Postgresql seconds.
@@ -1790,9 +1791,19 @@ public class TimestampUtils {
*/
@SuppressWarnings("JavaDurationGetSecondsToToSeconds")
private static long toJavaSecs(long secs) {
- // postgres epoch to java epoch
+ // postgres epoc to java epoc
secs += PG_EPOCH_DIFF.getSeconds();
+ // Julian/Gregorian calendar cutoff point
+ if (secs < -12219292800L) { // October 4, 1582 -> October 15, 1582
+ secs += 86400 * 10;
+ if (secs < -14825808000L) { // 1500-02-28 -> 1500-03-01
+ int extraLeaps = (int) ((secs + 14825808000L) / 3155760000L);
+ extraLeaps--;
+ extraLeaps -= extraLeaps / 4;
+ secs += extraLeaps * 86400L;
+ }
+ }
return secs;
}
@@ -1805,9 +1816,20 @@ public class TimestampUtils {
*/
@SuppressWarnings("JavaDurationGetSecondsToToSeconds")
private static long toPgSecs(long secs) {
- // java epoch to postgres epoch
+ // java epoc to postgres epoc
secs -= PG_EPOCH_DIFF.getSeconds();
+ // Julian/Gregorian calendar cutoff point
+ if (secs < -13165977600L) { // October 15, 1582 -> October 4, 1582
+ secs -= 86400 * 10;
+ if (secs < -15773356800L) { // 1500-03-01 -> 1500-02-28
+ int years = (int) ((secs + 15773356800L) / -3155823050L);
+ years++;
+ years -= years / 4;
+ secs += years * 86400L;
+ }
+ }
+
return secs;
}
@@ -1854,23 +1876,6 @@ public class TimestampUtils {
return TimeZone.getTimeZone(timeZone);
}
- /**
- * Create a proleptic Gregorian calendar with the given time zone. This differs from a newly
- * created (Gregorian)Calendar instance that is typically a hybrid of the Julian and Gregorian
- * calendar
- *
- * @param tz the time zone to use
- * @return The proleptic Gregorian Calendar instance
- */
- @SuppressWarnings("JavaUtilDate") // Using new Date(long) is not problematic on its own
- public static Calendar createProlepticGregorianCalendar(TimeZone tz) {
- GregorianCalendar prolepticGregorianCalendar = new GregorianCalendar(tz);
- // Make the calendar pure (proleptic) Gregorian
- prolepticGregorianCalendar.setGregorianChange(new java.util.Date(Long.MIN_VALUE));
-
- return prolepticGregorianCalendar;
- }
-
private static long floorDiv(long x, long y) {
long r = x / y;
// if the signs are different and modulo not zero, round down
=====================================
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.7.9";
+ public static final String DRIVER_VERSION = "42.7.10";
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 = 7;
- public static final int PATCH_VERSION = 9;
+ public static final int PATCH_VERSION = 10;
// JDBC specification
public static final String JDBC_VERSION = "4.2";
=====================================
src/main/java/org/postgresql/util/PGInterval.java
=====================================
@@ -5,8 +5,6 @@
package org.postgresql.util;
-import static org.postgresql.jdbc.TimestampUtils.createProlepticGregorianCalendar;
-
// import org.checkerframework.checker.nullness.qual.Nullable;
import java.io.Serializable;
@@ -15,7 +13,6 @@ import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.StringTokenizer;
-import java.util.TimeZone;
/**
* This implements a class that handles the PostgreSQL interval type.
@@ -471,7 +468,7 @@ public class PGInterval extends PGobject implements Serializable, Cloneable {
if (isNull) {
return;
}
- final Calendar cal = createProlepticGregorianCalendar(TimeZone.getDefault());
+ final Calendar cal = Calendar.getInstance();
cal.setTime(date);
add(cal);
date.setTime(cal.getTime().getTime());
=====================================
src/main/resources/META-INF/MANIFEST.MF
=====================================
@@ -1,7 +1,7 @@
Manifest-Version: 1.0
Bundle-License: BSD-2-Clause
Implementation-Title: PostgreSQL JDBC Driver
-Implementation-Version: 42.7.9
+Implementation-Version: 42.7.10
Specification-Vendor: Oracle Corporation
Specification-Version: 4.2
Specification-Title: JDBC
=====================================
src/test/java/org/postgresql/jdbc/LargeObjectManagerTest.java
=====================================
@@ -38,11 +38,20 @@ class LargeObjectManagerTest {
* It is possible for PostgreSQL to send a ParameterStatus message after an ErrorResponse
* Receiving such a message should not lead to an invalid connection state
* See https://github.com/pgjdbc/pgjdbc/issues/2237
+ *
+ * Note: This test is skipped when autosave is enabled because with autosave, a savepoint
+ * is created before the SET statement. When a subsequent error occurs, PostgreSQL doesn't
+ * send ParameterStatus to reset the parameter because it expects the client might
+ * ROLLBACK TO SAVEPOINT to recover. This is expected autosave behavior - protecting
+ * previous successful statements from being rolled back.
*/
@Test
void openWithErrorAndSubsequentParameterStatusMessageShouldLeaveConnectionInUsableStateAndUpdateParameterStatus() throws Exception {
try (PgConnection con = (PgConnection) TestUtil.openDB()) {
assumeTrue(TestUtil.haveMinimumServerVersion(con, ServerVersion.v9_0));
+ assumeTrue(con.getAutosave() == AutoSave.NEVER,
+ "Test requires autosave=never because autosave creates savepoints that prevent "
+ + "PostgreSQL from sending ParameterStatus on error");
con.setAutoCommit(false);
String originalApplicationName = con.getParameterStatus("application_name");
try (Statement statement = con.createStatement()) {
=====================================
src/test/java/org/postgresql/test/annotations/DisabledIfServerVersionGreater.java
=====================================
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2026, PostgreSQL Global Development Group
+ * See the LICENSE file in the project root for more information.
+ */
+
+package org.postgresql.test.annotations;
+
+import org.postgresql.test.impl.ServerVersionGreaterCondition;
+
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Disables test if the current server version is greater than specified version.
+ * @see org.junit.jupiter.api.Disabled
+ */
+ at Target({ElementType.TYPE, ElementType.METHOD})
+ at Retention(RetentionPolicy.RUNTIME)
+ at ExtendWith(ServerVersionGreaterCondition.class)
+public @interface DisabledIfServerVersionGreater {
+ /**
+ * @return not null sever version in form x.y.z like 9.4, 9.5.3, etc.
+ * @see org.postgresql.core.ServerVersion
+ */
+ String value();
+}
=====================================
src/test/java/org/postgresql/test/impl/ServerVersionCondition.java
=====================================
@@ -29,7 +29,7 @@ public class ServerVersionCondition implements ExecutionCondition {
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
return context.getElement()
.flatMap(element ->
- AnnotationUtils.findAnnotation(element, DisabledIfServerVersionBelow.class)
+ AnnotationUtils.findAnnotation(element, DisabledIfServerVersionBelow.class)
.map(annotation -> ServerVersionCondition.toResult(element, annotation))
).orElse(ENABLED);
}
=====================================
src/test/java/org/postgresql/test/impl/ServerVersionGreaterCondition.java
=====================================
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2026, PostgreSQL Global Development Group
+ * See the LICENSE file in the project root for more information.
+ */
+
+package org.postgresql.test.impl;
+
+import org.postgresql.core.ServerVersion;
+import org.postgresql.core.Version;
+import org.postgresql.test.TestUtil;
+import org.postgresql.test.annotations.DisabledIfServerVersionGreater;
+
+import org.junit.jupiter.api.extension.ConditionEvaluationResult;
+import org.junit.jupiter.api.extension.ExecutionCondition;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.platform.commons.support.AnnotationSupport;
+
+import java.lang.reflect.AnnotatedElement;
+import java.sql.Connection;
+
+public class ServerVersionGreaterCondition implements ExecutionCondition {
+ private static final ConditionEvaluationResult ENABLED = ConditionEvaluationResult.enabled(
+ "@DisabledIfServerVersionGreater is not present");
+
+ @Override
+ public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
+ return context.getElement()
+ .flatMap(element ->
+ AnnotationSupport.findAnnotation(element, DisabledIfServerVersionGreater.class)
+ .map(annotation -> ServerVersionGreaterCondition.toResult(element, annotation))
+ ).orElse(ENABLED);
+ }
+
+ private static ConditionEvaluationResult toResult(AnnotatedElement element,
+ DisabledIfServerVersionGreater annotation) {
+ Version maxVersion = ServerVersion.from(annotation.value());
+ if (maxVersion.getVersionNum() <= 0) {
+ throw new IllegalArgumentException(
+ "Server version " + annotation.value() + " not valid for "
+ + element);
+ }
+
+ try (Connection con = TestUtil.openDB()) {
+ String dbVersionNumber = con.getMetaData().getDatabaseProductVersion();
+ Version actualVersion = ServerVersion.from(dbVersionNumber);
+ if (actualVersion.getVersionNum() >= maxVersion.getVersionNum()) {
+ return ConditionEvaluationResult.disabled(
+ "Test requires version <= " + maxVersion
+ + ", but the server version is " + actualVersion);
+ }
+ return ConditionEvaluationResult.enabled(
+ "Test requires version <= " + maxVersion
+ + ", and the server version is " + actualVersion);
+ } catch (Exception e) {
+ throw new IllegalStateException("Not available open connection", e);
+ }
+ }
+}
=====================================
src/test/java/org/postgresql/test/jdbc2/CleanupSavepointsWithFastpathTest.java
=====================================
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2024, PostgreSQL Global Development Group
+ * See the LICENSE file in the project root for more information.
+ */
+
+package org.postgresql.test.jdbc2;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.params.provider.Arguments.arguments;
+
+import org.postgresql.PGConnection;
+import org.postgresql.PGProperty;
+import org.postgresql.largeobject.LargeObject;
+import org.postgresql.largeobject.LargeObjectManager;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedClass;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.nio.charset.StandardCharsets;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Properties;
+
+/**
+ * Tests for GitHub issue #3910: cleanupSavepoints=true causes "Unknown Response Type C."
+ * error when used with Large Object operations (fastpath).
+ *
+ * <p>The bug occurs because {@code releaseSavePoint()} in {@code QueryExecutorImpl} sends
+ * the RELEASE SAVEPOINT command but doesn't wait for the response. The CommandComplete ('C')
+ * response is left in the buffer. When a fastpath operation (used by Large Objects) executes
+ * next, {@code receiveFastpathResult()} receives this unexpected 'C' message and throws
+ * "Unknown Response Type C."</p>
+ *
+ * @see <a href="https://github.com/pgjdbc/pgjdbc/issues/3910">Issue #3910</a>
+ */
+ at ParameterizedClass
+ at MethodSource("data")
+class CleanupSavepointsWithFastpathTest extends BaseTest4 {
+ CleanupSavepointsWithFastpathTest(BinaryMode binaryMode) {
+ setBinaryMode(binaryMode);
+ }
+
+ static Iterable<Arguments> data() {
+ Collection<Arguments> ids = new ArrayList<>();
+ for (BinaryMode binaryMode : BinaryMode.values()) {
+ ids.add(arguments(binaryMode));
+ }
+ return ids;
+ }
+
+ @Override
+ protected void updateProperties(Properties props) {
+ super.updateProperties(props);
+ PGProperty.AUTOSAVE.set(props, "always");
+ PGProperty.CLEANUP_SAVEPOINTS.set(props, true);
+ }
+
+ /**
+ * Tests that Large Object operations work correctly when cleanupSavepoints=true
+ * and autosave=always are both enabled.
+ *
+ * <p>This reproduces the bug from issue #3910 where the combination of these
+ * settings causes fastpath operations to fail with "Unknown Response Type C."</p>
+ */
+ @Test
+ void testLargeObjectWithCleanupSavepoints() throws Exception {
+ con.setAutoCommit(false);
+
+ // Execute a query to trigger autosave mechanism
+ // This will set a savepoint before the query and release it after (due to cleanupSavepoints)
+ try (Statement stmt = con.createStatement()) {
+ stmt.execute("SELECT 1");
+ }
+
+ // Now try Large Object operations - these use fastpath protocol
+ // The bug: the RELEASE SAVEPOINT response ('C') is still in the buffer
+ // and receiveFastpathResult() will read it instead of the expected response
+ LargeObjectManager lom = con.unwrap(PGConnection.class).getLargeObjectAPI();
+
+ // This should NOT throw "Unknown Response Type C."
+ long oid = lom.createLO();
+ try {
+ try (LargeObject lo = lom.open(oid)) {
+ byte[] data = "Test data for issue #3910".getBytes(StandardCharsets.UTF_8);
+ lo.write(data);
+ lo.seek(0);
+ byte[] readBack = lo.read(data.length);
+ assertArrayEquals(data, readBack,
+ "Large object data should be readable after write");
+ }
+ } finally {
+ lom.delete(oid);
+ }
+ }
+
+ /**
+ * Tests that a sequence of queries followed by Large Object operations works correctly.
+ * This tests multiple rounds of savepoint creation/cleanup followed by fastpath.
+ */
+ @Test
+ void testMultipleQueriesThenLargeObject() throws Exception {
+ con.setAutoCommit(false);
+
+ // Execute multiple queries - each will trigger savepoint creation and cleanup
+ try (Statement stmt = con.createStatement()) {
+ for (int i = 0; i < 5; i++) {
+ stmt.execute("SELECT " + i);
+ }
+ }
+
+ // Now try Large Object operations
+ LargeObjectManager lom = con.unwrap(PGConnection.class).getLargeObjectAPI();
+ long oid = lom.createLO();
+ try {
+ try (LargeObject lo = lom.open(oid)) {
+ lo.write(new byte[]{1, 2, 3, 4, 5});
+ }
+ } finally {
+ lom.delete(oid);
+ }
+ }
+
+ /**
+ * Tests interleaving of regular queries and Large Object operations.
+ */
+ @Test
+ void testInterleavedQueriesAndLargeObjects() throws Exception {
+ con.setAutoCommit(false);
+
+ LargeObjectManager lom = con.unwrap(PGConnection.class).getLargeObjectAPI();
+
+ for (int i = 0; i < 3; i++) {
+ // Execute a query (triggers savepoint cleanup)
+ try (Statement stmt = con.createStatement();
+ ResultSet rs = stmt.executeQuery("SELECT " + i)) {
+ rs.next();
+ }
+
+ // Then do Large Object operation (uses fastpath)
+ long oid = lom.createLO();
+ try {
+ try (LargeObject lo = lom.open(oid)) {
+ lo.write(("Iteration " + i).getBytes(StandardCharsets.UTF_8));
+ }
+ } finally {
+ lom.delete(oid);
+ }
+ }
+ }
+
+ /**
+ * Tests PreparedStatement execution followed by Large Object operations.
+ * PreparedStatements may use different code paths for savepoint handling.
+ */
+ @Test
+ void testPreparedStatementThenLargeObject() throws Exception {
+ con.setAutoCommit(false);
+
+ // Use PreparedStatement to trigger server-side prepare
+ try (PreparedStatement ps = con.prepareStatement("SELECT ?")) {
+ ps.setInt(1, 42);
+ try (ResultSet rs = ps.executeQuery()) {
+ rs.next();
+ }
+ // Execute again to trigger cached statement path
+ ps.setInt(1, 43);
+ try (ResultSet rs = ps.executeQuery()) {
+ rs.next();
+ }
+ }
+
+ // Large Object operation should still work
+ LargeObjectManager lom = con.unwrap(PGConnection.class).getLargeObjectAPI();
+ long oid = lom.createLO();
+ try {
+ try (LargeObject lo = lom.open(oid)) {
+ lo.write(new byte[100]);
+ }
+ } finally {
+ lom.delete(oid);
+ }
+ }
+
+ /**
+ * Verifies that Large Objects work without cleanupSavepoints (baseline test).
+ * This confirms the issue is specifically with cleanupSavepoints=true.
+ */
+ @Test
+ void testLargeObjectWithoutCleanupSavepoints() throws Exception {
+ con.setAutoCommit(false);
+
+ try (Statement stmt = con.createStatement()) {
+ stmt.execute("SELECT 1");
+ }
+
+ LargeObjectManager lom = con.unwrap(PGConnection.class).getLargeObjectAPI();
+ long oid = lom.createLO();
+ try {
+ try (LargeObject lo = lom.open(oid)) {
+ byte[] data = "Baseline test".getBytes(StandardCharsets.UTF_8);
+ lo.write(data);
+ lo.seek(0);
+ byte[] readBack = lo.read(data.length);
+ assertArrayEquals(data, readBack);
+ }
+ } finally {
+ lom.delete(oid);
+ }
+ }
+}
=====================================
src/test/java/org/postgresql/test/jdbc2/DateTest.java
=====================================
@@ -10,7 +10,6 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
-import static org.postgresql.jdbc.TimestampUtils.createProlepticGregorianCalendar;
import org.postgresql.test.TestUtil;
@@ -24,7 +23,6 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
@@ -320,13 +318,7 @@ public class DateTest extends BaseTest4 {
st.close();
}
- private static java.sql.Date makeDate(int year, int month, int day) {
- Calendar cal = createProlepticGregorianCalendar(TimeZone.getDefault());
- cal.clear();
- // Note that Calendar.MONTH is zero based
- cal.set(year, month - 1, day);
-
- return new java.sql.Date(cal.getTimeInMillis());
+ private static java.sql.Date makeDate(int y, int m, int d) {
+ return new java.sql.Date(y - 1900, m - 1, d);
}
-
}
=====================================
src/test/java/org/postgresql/test/jdbc2/GetXXXTest.java
=====================================
@@ -8,7 +8,6 @@ package org.postgresql.test.jdbc2;
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 static org.postgresql.jdbc.TimestampUtils.createProlepticGregorianCalendar;
import org.postgresql.test.TestUtil;
import org.postgresql.util.PGInterval;
@@ -25,7 +24,6 @@ import java.sql.Statement;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.HashMap;
-import java.util.TimeZone;
/*
* Test for getObject
@@ -39,7 +37,7 @@ class GetXXXTest {
TestUtil.createTempTable(con, "test_interval",
"initial timestamp with time zone, final timestamp with time zone");
PreparedStatement pstmt = con.prepareStatement("insert into test_interval values (?,?)");
- Calendar cal = createProlepticGregorianCalendar(TimeZone.getDefault());
+ Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, -1);
pstmt.setTimestamp(1, new Timestamp(cal.getTime().getTime()));
=====================================
src/test/java/org/postgresql/test/jdbc2/IntervalTest.java
=====================================
@@ -9,7 +9,6 @@ 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.assertTrue;
-import static org.postgresql.jdbc.TimestampUtils.createProlepticGregorianCalendar;
import org.postgresql.test.TestUtil;
import org.postgresql.util.PGInterval;
@@ -28,8 +27,8 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.util.Calendar;
import java.util.Date;
+import java.util.GregorianCalendar;
import java.util.Locale;
-import java.util.TimeZone;
import java.util.concurrent.ThreadLocalRandom;
@Isolated("Uses Locale.setDefault")
@@ -149,7 +148,7 @@ class IntervalTest {
@Test
void addRounding() {
PGInterval pgi = new PGInterval(0, 0, 0, 0, 0, 0.6006);
- Calendar cal = createProlepticGregorianCalendar(TimeZone.getDefault());
+ Calendar cal = Calendar.getInstance();
long origTime = cal.getTime().getTime();
pgi.add(cal);
long newTime = cal.getTime().getTime();
@@ -209,7 +208,7 @@ class IntervalTest {
}
private static Calendar getStartCalendar() {
- Calendar cal = createProlepticGregorianCalendar(TimeZone.getDefault());
+ Calendar cal = new GregorianCalendar();
cal.set(Calendar.YEAR, 2005);
cal.set(Calendar.MONTH, 4);
cal.set(Calendar.DAY_OF_MONTH, 29);
@@ -287,25 +286,6 @@ class IntervalTest {
assertEquals(date2, date);
}
- @Test
- void dateYear1000() throws Exception {
- final Calendar calYear1000 = createProlepticGregorianCalendar(TimeZone.getDefault());
- calYear1000.clear();
- calYear1000.set(1000, Calendar.JANUARY, 1);
-
- final Calendar calYear2000 = createProlepticGregorianCalendar(TimeZone.getDefault());
- calYear2000.clear();
- calYear2000.set(2000, Calendar.JANUARY, 1);
-
- final Date date = calYear1000.getTime();
- final Date dateYear2000 = calYear2000.getTime();
-
- PGInterval pgi = new PGInterval("@ +1000 years");
- pgi.add(date);
-
- assertEquals(dateYear2000, date);
- }
-
@Test
void postgresDate() throws Exception {
Date date = getStartCalendar().getTime();
@@ -492,13 +472,7 @@ class IntervalTest {
assertEquals(1, pgi.getMicroSeconds());
}
- private static java.sql.Date makeDate(int year, int month, int day) {
- Calendar cal = createProlepticGregorianCalendar(TimeZone.getDefault());
- cal.clear();
- // Note that Calendar.MONTH is zero based
- cal.set(year, month - 1, day);
-
- return new java.sql.Date(cal.getTimeInMillis());
+ private static java.sql.Date makeDate(int y, int m, int d) {
+ return new java.sql.Date(y - 1900, m - 1, d);
}
-
}
=====================================
src/test/java/org/postgresql/test/jdbc2/PGTimeTest.java
=====================================
@@ -9,7 +9,6 @@ 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 static org.junit.jupiter.api.Assumptions.assumeTrue;
-import static org.postgresql.jdbc.TimestampUtils.createProlepticGregorianCalendar;
import org.postgresql.test.TestUtil;
import org.postgresql.util.PGInterval;
@@ -58,21 +57,21 @@ public class PGTimeTest extends BaseTest4 {
public void testTimeWithInterval() throws SQLException {
assumeTrue(TestUtil.haveIntegerDateTimes(con));
- Calendar cal = createProlepticGregorianCalendar(TimeZone.getDefault());
+ Calendar cal = Calendar.getInstance();
cal.set(1970, Calendar.JANUARY, 1);
final long now = cal.getTimeInMillis();
verifyTimeWithInterval(new PGTime(now), new PGInterval(0, 0, 0, 1, 2, 3.14), true);
verifyTimeWithInterval(new PGTime(now), new PGInterval(0, 0, 0, 1, 2, 3.14), false);
- verifyTimeWithInterval(new PGTime(now, createProlepticGregorianCalendar(TimeZone.getTimeZone("GMT"))),
+ verifyTimeWithInterval(new PGTime(now, Calendar.getInstance(TimeZone.getTimeZone("GMT"))),
new PGInterval(0, 0, 0, 1, 2, 3.14), true);
- verifyTimeWithInterval(new PGTime(now, createProlepticGregorianCalendar(TimeZone.getTimeZone("GMT"))),
+ verifyTimeWithInterval(new PGTime(now, Calendar.getInstance(TimeZone.getTimeZone("GMT"))),
new PGInterval(0, 0, 0, 1, 2, 3.14), false);
- verifyTimeWithInterval(new PGTime(now, createProlepticGregorianCalendar(TimeZone.getTimeZone("GMT+01:00"))),
+ verifyTimeWithInterval(new PGTime(now, Calendar.getInstance(TimeZone.getTimeZone("GMT+01:00"))),
new PGInterval(0, 0, 0, 1, 2, 3.456), true);
- verifyTimeWithInterval(new PGTime(now, createProlepticGregorianCalendar(TimeZone.getTimeZone("GMT+01:00"))),
+ verifyTimeWithInterval(new PGTime(now, Calendar.getInstance(TimeZone.getTimeZone("GMT+01:00"))),
new PGInterval(0, 0, 0, 1, 2, 3.456), false);
}
@@ -136,20 +135,20 @@ public class PGTimeTest extends BaseTest4 {
*/
@Test
public void testTimeInsertAndSelect() throws SQLException {
- Calendar cal = createProlepticGregorianCalendar(TimeZone.getDefault());
+ Calendar cal = Calendar.getInstance();
cal.set(1970, Calendar.JANUARY, 1);
final long now = cal.getTimeInMillis();
verifyInsertAndSelect(new PGTime(now), true);
verifyInsertAndSelect(new PGTime(now), false);
- verifyInsertAndSelect(new PGTime(now, createProlepticGregorianCalendar(TimeZone.getTimeZone("GMT"))), true);
- verifyInsertAndSelect(new PGTime(now, createProlepticGregorianCalendar(TimeZone.getTimeZone("GMT"))),
+ verifyInsertAndSelect(new PGTime(now, Calendar.getInstance(TimeZone.getTimeZone("GMT"))), true);
+ verifyInsertAndSelect(new PGTime(now, Calendar.getInstance(TimeZone.getTimeZone("GMT"))),
false);
- verifyInsertAndSelect(new PGTime(now, createProlepticGregorianCalendar(TimeZone.getTimeZone("GMT+01:00"))),
+ verifyInsertAndSelect(new PGTime(now, Calendar.getInstance(TimeZone.getTimeZone("GMT+01:00"))),
true);
- verifyInsertAndSelect(new PGTime(now, createProlepticGregorianCalendar(TimeZone.getTimeZone("GMT+01:00"))),
+ verifyInsertAndSelect(new PGTime(now, Calendar.getInstance(TimeZone.getTimeZone("GMT+01:00"))),
false);
}
@@ -244,5 +243,4 @@ public class PGTimeTest extends BaseTest4 {
}
return sdf;
}
-
}
=====================================
src/test/java/org/postgresql/test/jdbc2/PGTimestampTest.java
=====================================
@@ -9,7 +9,6 @@ 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 static org.junit.jupiter.api.Assumptions.assumeTrue;
-import static org.postgresql.jdbc.TimestampUtils.createProlepticGregorianCalendar;
import org.postgresql.test.TestUtil;
import org.postgresql.util.PGInterval;
@@ -26,6 +25,7 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
+import java.util.Calendar;
import java.util.TimeZone;
/**
@@ -66,13 +66,13 @@ class PGTimestampTest {
verifyTimestampWithInterval(timestamp, interval, false);
timestamp = new PGTimestamp(System.currentTimeMillis(),
- createProlepticGregorianCalendar(TimeZone.getTimeZone("GMT")));
+ Calendar.getInstance(TimeZone.getTimeZone("GMT")));
interval = new PGInterval(0, 0, 0, 1, 2, 3.14);
verifyTimestampWithInterval(timestamp, interval, true);
verifyTimestampWithInterval(timestamp, interval, false);
timestamp = new PGTimestamp(System.currentTimeMillis(),
- createProlepticGregorianCalendar(TimeZone.getTimeZone("GMT+01:00")));
+ Calendar.getInstance(TimeZone.getTimeZone("GMT+01:00")));
interval = new PGInterval(-3, -2, -1, 1, 2, 3.14);
verifyTimestampWithInterval(timestamp, interval, true);
verifyTimestampWithInterval(timestamp, interval, false);
@@ -139,15 +139,15 @@ class PGTimestampTest {
verifyInsertAndSelect(new PGTimestamp(now), true);
verifyInsertAndSelect(new PGTimestamp(now), false);
- verifyInsertAndSelect(new PGTimestamp(now, createProlepticGregorianCalendar(TimeZone.getTimeZone("GMT"))),
+ verifyInsertAndSelect(new PGTimestamp(now, Calendar.getInstance(TimeZone.getTimeZone("GMT"))),
true);
- verifyInsertAndSelect(new PGTimestamp(now, createProlepticGregorianCalendar(TimeZone.getTimeZone("GMT"))),
+ verifyInsertAndSelect(new PGTimestamp(now, Calendar.getInstance(TimeZone.getTimeZone("GMT"))),
false);
verifyInsertAndSelect(
- new PGTimestamp(now, createProlepticGregorianCalendar(TimeZone.getTimeZone("GMT+01:00"))), true);
+ new PGTimestamp(now, Calendar.getInstance(TimeZone.getTimeZone("GMT+01:00"))), true);
verifyInsertAndSelect(
- new PGTimestamp(now, createProlepticGregorianCalendar(TimeZone.getTimeZone("GMT+01:00"))), false);
+ new PGTimestamp(now, Calendar.getInstance(TimeZone.getTimeZone("GMT+01:00"))), false);
}
/**
@@ -242,5 +242,4 @@ class PGTimestampTest {
}
return sdf;
}
-
}
=====================================
src/test/java/org/postgresql/test/jdbc2/PreparedStatementTest.java
=====================================
@@ -23,6 +23,7 @@ import org.postgresql.jdbc.PgConnection;
import org.postgresql.jdbc.PgStatement;
import org.postgresql.jdbc.PreferQueryMode;
import org.postgresql.test.TestUtil;
+import org.postgresql.test.annotations.DisabledIfServerVersionGreater;
import org.postgresql.test.util.BrokenInputStream;
import org.postgresql.util.GT;
import org.postgresql.util.PSQLState;
@@ -466,8 +467,12 @@ public class PreparedStatementTest extends BaseTest4 {
}
+ @DisabledIfServerVersionGreater("19")
@Test
public void testSingleQuotes() throws SQLException {
+ // This test is only relevant for PostgreSQL 18 and below
+ // as of 4576208 in postgres non-standard strings now throw an error.
+
String[] testStrings = new String[]{
"bare ? question mark",
"quoted \\' single quote",
=====================================
src/test/java/org/postgresql/test/jdbc2/TimeTest.java
=====================================
@@ -9,7 +9,6 @@ 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.assertTrue;
-import static org.postgresql.jdbc.TimestampUtils.createProlepticGregorianCalendar;
import org.postgresql.test.TestUtil;
@@ -61,9 +60,11 @@ class TimeTest {
void getTimeZone() throws Exception {
final Time midnight = new Time(0, 0, 0);
Statement stmt = con.createStatement();
- Calendar cal = createProlepticGregorianCalendar(TimeZone.getTimeZone("GMT"));
+ Calendar cal = Calendar.getInstance();
- int localOffset = TimeZone.getDefault().getOffset(midnight.getTime());
+ cal.setTimeZone(TimeZone.getTimeZone("GMT"));
+
+ int localOffset = Calendar.getInstance().getTimeZone().getOffset(midnight.getTime());
// set the time to midnight to make this easy
assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL("testtime", "'00:00:00','00:00:00'")));
@@ -250,7 +251,7 @@ class TimeTest {
t = rs.getTime(1);
assertNotNull(t);
Time tmpTime = Time.valueOf("5:1:2");
- int localOffset = TimeZone.getDefault().getOffset(tmpTime.getTime());
+ int localOffset = Calendar.getInstance().getTimeZone().getOffset(tmpTime.getTime());
int timeOffset = 3 * 60 * 60 * 1000;
tmpTime.setTime(tmpTime.getTime() + timeOffset + localOffset);
assertEquals(makeTime(tmpTime.getHours(), tmpTime.getMinutes(), tmpTime.getSeconds()), t);
@@ -259,7 +260,7 @@ class TimeTest {
t = rs.getTime(1);
assertNotNull(t);
tmpTime = Time.valueOf("23:59:59");
- localOffset = TimeZone.getDefault().getOffset(tmpTime.getTime());
+ localOffset = Calendar.getInstance().getTimeZone().getOffset(tmpTime.getTime());
timeOffset = -11 * 60 * 60 * 1000;
tmpTime.setTime(tmpTime.getTime() + timeOffset + localOffset);
assertEquals(makeTime(tmpTime.getHours(), tmpTime.getMinutes(), tmpTime.getSeconds()), t);
@@ -273,5 +274,4 @@ class TimeTest {
private static Time makeTime(int h, int m, int s) {
return Time.valueOf(TestUtil.fix(h, 2) + ":" + TestUtil.fix(m, 2) + ":" + TestUtil.fix(s, 2));
}
-
}
=====================================
src/test/java/org/postgresql/test/jdbc2/TimestampTest.java
=====================================
@@ -10,7 +10,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
-import static org.postgresql.jdbc.TimestampUtils.createProlepticGregorianCalendar;
import org.postgresql.PGStatement;
import org.postgresql.core.BaseConnection;
@@ -31,11 +30,10 @@ import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.text.SimpleDateFormat;
-import java.time.OffsetDateTime;
-import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
+import java.util.GregorianCalendar;
import java.util.TimeZone;
/*
@@ -84,7 +82,7 @@ public class TimestampTest extends BaseTest4 {
*/
@Test
public void testCalendarModification() throws SQLException {
- Calendar cal = createProlepticGregorianCalendar(TimeZone.getDefault());
+ Calendar cal = Calendar.getInstance();
Calendar origCal = (Calendar) cal.clone();
PreparedStatement ps = con.prepareStatement("INSERT INTO " + TSWOTZ_TABLE + " VALUES (?)");
@@ -133,9 +131,10 @@ public class TimestampTest extends BaseTest4 {
}
private void runInfinityTests(String table, long value) throws SQLException {
+ GregorianCalendar cal = new GregorianCalendar();
// Pick some random timezone that is hopefully different than ours
// and exists in this JVM.
- Calendar cal = createProlepticGregorianCalendar(TimeZone.getTimeZone("Europe/Warsaw"));
+ cal.setTimeZone(TimeZone.getTimeZone("Europe/Warsaw"));
String strValue;
if (value == PGStatement.DATE_POSITIVE_INFINITY) {
@@ -218,39 +217,10 @@ public class TimestampTest extends BaseTest4 {
stmt.close();
}
- /*
- * Tests the timestamp methods in ResultSet on timestamp with time zone we insert a known string
- * value fpr the year 1000 (don't use setTimestamp) then see that we get back the same value from
- * getTimestamp
- */
- @Test
- public void testGetTimestampYear1000WTZ() throws SQLException {
- assumeTrue(TestUtil.haveIntegerDateTimes(con));
-
- Statement stmt = con.createStatement();
-
- assertEquals(1, stmt.executeUpdate(TestUtil.insertSQL(TSWTZ_TABLE, "'" + TS_YEAR1000_WTZ_PGFORMAT + "'")));
-
- ResultSet rs = stmt.executeQuery("select ts from " + TSWTZ_TABLE);
- assertNotNull(rs);
-
- assertTrue(rs.next());
- Timestamp t = rs.getTimestamp(1);
- assertNotNull(t);
- // Be aware that Timestamp.toString() formats with the Julian calendar for such old dates
- assertEquals(TS_YEAR1000_WTZ, t);
-
- rs.close();
-
- assertEquals(1, stmt.executeUpdate("DELETE FROM " + TSWTZ_TABLE));
-
- stmt.close();
- }
-
/*
* Tests the timestamp methods in PreparedStatement on timestamp with time zone we insert a value
* using setTimestamp then see that we get back the same value from getTimestamp (which we know
- * works as it was tested independently of setTimestamp)
+ * works as it was tested independently of setTimestamp
*/
@Test
public void testSetTimestampWTZ() throws SQLException {
@@ -319,34 +289,6 @@ public class TimestampTest extends BaseTest4 {
stmt.close();
}
- /*
- * Tests the timestamp methods in PreparedStatement on timestamp with time zone we insert the
- * year 1000 value using setTimestamp then see that we get back the same value from getTimestamp
- * (which we know works as it was tested independently of setTimestamp)
- */
- @Test
- public void testSetTimestampYear1000WTZ() throws SQLException {
- assumeTrue(TestUtil.haveIntegerDateTimes(con));
-
- Statement stmt = con.createStatement();
- PreparedStatement pstmt = con.prepareStatement(TestUtil.insertSQL(TSWTZ_TABLE, "?"));
-
- pstmt.setTimestamp(1, TS_YEAR1000_WTZ);
- assertEquals(1, pstmt.executeUpdate());
-
- ResultSet rs = stmt.executeQuery("select ts from " + TSWTZ_TABLE);
- assertNotNull(rs);
- assertTrue(rs.next());
- assertEquals(ODT_YEAR1000, rs.getObject(1, OffsetDateTime.class));
-
- rs.close();
-
- assertEquals(1, stmt.executeUpdate("DELETE FROM " + TSWTZ_TABLE));
-
- pstmt.close();
- stmt.close();
- }
-
/*
* Tests the timestamp methods in ResultSet on timestamp without time zone we insert a known
* string value (don't use setTimestamp) then see that we get back the same value from
@@ -667,8 +609,6 @@ public class TimestampTest extends BaseTest4 {
ts = ts + tz;
dateFormat = new SimpleDateFormat("y-M-d H:m:s z");
}
- dateFormat.setCalendar(createProlepticGregorianCalendar(TimeZone.getDefault()));
-
java.util.Date date = dateFormat.parse(ts);
result = new Timestamp(date.getTime());
result.setNanos(f);
@@ -694,12 +634,6 @@ public class TimestampTest extends BaseTest4 {
getTimestamp(2000, 7, 7, 15, 0, 0, 123456000, "GMT");
private static final String TS4WTZ_PGFORMAT = "2000-07-07 15:00:00.123456+00";
- private static final Timestamp TS_YEAR1000_WTZ =
- getTimestamp(1000, 1, 1, 0, 0, 0, 0, "UTC");
- private static final String TS_YEAR1000_WTZ_PGFORMAT = "1000-01-01 00:00:00.0+00";
- private static final OffsetDateTime ODT_YEAR1000 =
- OffsetDateTime.of(1000, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC);
-
private static final Timestamp TS1WOTZ =
getTimestamp(1950, 2, 7, 15, 0, 0, 100000000, null);
private static final String TS1WOTZ_PGFORMAT = "1950-02-07 15:00:00.1";
=====================================
src/test/java/org/postgresql/test/jdbc2/TimezoneCachingTest.java
=====================================
@@ -8,7 +8,6 @@ package org.postgresql.test.jdbc2;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assumptions.assumeFalse;
-import static org.postgresql.jdbc.TimestampUtils.createProlepticGregorianCalendar;
import org.postgresql.core.BaseConnection;
import org.postgresql.jdbc.TimestampUtils;
@@ -26,6 +25,7 @@ import java.sql.Statement;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Calendar;
+import java.util.GregorianCalendar;
import java.util.TimeZone;
public class TimezoneCachingTest extends BaseTest4 {
@@ -105,8 +105,8 @@ public class TimezoneCachingTest extends BaseTest4 {
TimeZone tz2 = TimeZone.getTimeZone("GMT-2:00");
TimeZone tz3 = TimeZone.getTimeZone("UTC+2");
TimeZone tz4 = TimeZone.getTimeZone("UTC+3");
- Calendar c3 = createProlepticGregorianCalendar(tz3);
- Calendar c4 = createProlepticGregorianCalendar(tz4);
+ Calendar c3 = new GregorianCalendar(tz3);
+ Calendar c4 = new GregorianCalendar(tz4);
try {
stmt = con.createStatement();
TimeZone.setDefault(tz1);
@@ -254,8 +254,8 @@ public class TimezoneCachingTest extends BaseTest4 {
TimeZone tz2 = TimeZone.getTimeZone("GMT-2:00"); // 10 hour difference
Timestamp ts1 = new Timestamp(2016 - 1900, 0, 31, 3, 0, 0, 0);
Timestamp ts2 = new Timestamp(2016 - 1900, 0, 31, 13, 0, 0, 0); // 10 hour difference
- Calendar c1 = createProlepticGregorianCalendar(tz1);
- Calendar c2 = createProlepticGregorianCalendar(tz2);
+ Calendar c1 = new GregorianCalendar(tz1);
+ Calendar c2 = new GregorianCalendar(tz2);
try {
TimeZone.setDefault(tz1);
pstmt = con.prepareStatement("INSERT INTO testtz VALUES (?,?)");
=====================================
src/test/java/org/postgresql/test/jdbc2/TimezoneTest.java
=====================================
@@ -8,7 +8,6 @@ package org.postgresql.test.jdbc2;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.postgresql.jdbc.TimestampUtils.createProlepticGregorianCalendar;
import org.postgresql.PGProperty;
import org.postgresql.test.TestUtil;
@@ -77,10 +76,10 @@ public class TimezoneTest {
TimeZone tzGMT05 = TimeZone.getTimeZone("GMT-05"); // -0500 always
TimeZone tzGMT13 = TimeZone.getTimeZone("GMT+13"); // +1000 always
- cUTC = createProlepticGregorianCalendar(tzUTC);
- cGMT03 = createProlepticGregorianCalendar(tzGMT03);
- cGMT05 = createProlepticGregorianCalendar(tzGMT05);
- cGMT13 = createProlepticGregorianCalendar(tzGMT13);
+ cUTC = Calendar.getInstance(tzUTC);
+ cGMT03 = Calendar.getInstance(tzGMT03);
+ cGMT05 = Calendar.getInstance(tzGMT05);
+ cGMT13 = Calendar.getInstance(tzGMT13);
}
@BeforeEach
@@ -860,10 +859,9 @@ public class TimezoneTest {
PreparedStatement pstmt =
con.prepareStatement("SELECT ts, d FROM testtimezone order by seq /*" + timeZone + "*/");
- Calendar expectedTimestamp = createProlepticGregorianCalendar(TimeZone.getDefault());
+ Calendar expectedTimestamp = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat(testDateFormat);
- sdf.setCalendar(expectedTimestamp);
for (int i = 0; i < PREPARE_THRESHOLD; i++) {
ResultSet rs = pstmt.executeQuery();
@@ -973,5 +971,4 @@ public class TimezoneTest {
}
return millis;
}
-
}
=====================================
src/test/java/org/postgresql/test/jdbc4/jdbc41/GetObjectTest.java
=====================================
@@ -9,7 +9,6 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.postgresql.jdbc.TimestampUtils.createProlepticGregorianCalendar;
import org.postgresql.core.BaseConnection;
import org.postgresql.core.ServerVersion;
@@ -48,6 +47,7 @@ import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Calendar;
+import java.util.GregorianCalendar;
import java.util.TimeZone;
import java.util.UUID;
@@ -198,9 +198,14 @@ class GetObjectTest {
ResultSet rs = stmt.executeQuery(TestUtil.selectSQL("table1", "timestamp_without_time_zone_column"));
try {
assertTrue(rs.next());
- Calendar calendar = createProlepticGregorianCalendar(TimeZone.getDefault());
+ Calendar calendar = GregorianCalendar.getInstance();
calendar.clear();
- calendar.set(2004, Calendar.OCTOBER, 19, 10, 23, 54);
+ calendar.set(Calendar.YEAR, 2004);
+ calendar.set(Calendar.MONTH, Calendar.OCTOBER);
+ calendar.set(Calendar.DAY_OF_MONTH, 19);
+ calendar.set(Calendar.HOUR_OF_DAY, 10);
+ calendar.set(Calendar.MINUTE, 23);
+ calendar.set(Calendar.SECOND, 54);
Timestamp expectedNoZone = new Timestamp(calendar.getTimeInMillis());
assertEquals(expectedNoZone, rs.getObject("timestamp_without_time_zone_column", Timestamp.class));
assertEquals(expectedNoZone, rs.getObject(1, Timestamp.class));
@@ -219,9 +224,14 @@ class GetObjectTest {
+ ", null::timestamp as null_timestamp");
try {
assertTrue(rs.next());
- Calendar calendar = createProlepticGregorianCalendar(TimeZone.getDefault());
+ Calendar calendar = GregorianCalendar.getInstance();
calendar.clear();
- calendar.set(2004, Calendar.OCTOBER, 19, 10, 23, 54);
+ calendar.set(Calendar.YEAR, 2004);
+ calendar.set(Calendar.MONTH, Calendar.OCTOBER);
+ calendar.set(Calendar.DAY_OF_MONTH, 19);
+ calendar.set(Calendar.HOUR_OF_DAY, 10);
+ calendar.set(Calendar.MINUTE, 23);
+ calendar.set(Calendar.SECOND, 54);
java.util.Date expected = new java.util.Date(calendar.getTimeInMillis());
assertEquals(expected, rs.getObject("timestamp_without_time_zone_column", java.util.Date.class));
assertEquals(expected, rs.getObject(1, java.util.Date.class));
@@ -251,9 +261,14 @@ class GetObjectTest {
try {
assertTrue(rs.next());
- Calendar calendar = createProlepticGregorianCalendar(timeZone);
+ Calendar calendar = GregorianCalendar.getInstance(timeZone);
calendar.clear();
- calendar.set(2004, Calendar.OCTOBER, 19, 10, 23, 54);
+ calendar.set(Calendar.YEAR, 2004);
+ calendar.set(Calendar.MONTH, Calendar.OCTOBER);
+ calendar.set(Calendar.DAY_OF_MONTH, 19);
+ calendar.set(Calendar.HOUR_OF_DAY, 10);
+ calendar.set(Calendar.MINUTE, 23);
+ calendar.set(Calendar.SECOND, 54);
Timestamp expectedWithZone = new Timestamp(calendar.getTimeInMillis());
assertEquals(expectedWithZone, rs.getObject("timestamp_with_time_zone_column", Timestamp.class));
assertEquals(expectedWithZone, rs.getObject(1, Timestamp.class));
@@ -277,9 +292,14 @@ class GetObjectTest {
+ ", TIMESTAMP '2004-10-19 10:23:54+02'::timestamp as timestamp_with_time_zone_column, null::timestamp as null_timestamp");
try {
assertTrue(rs.next());
- Calendar calendar = createProlepticGregorianCalendar(TimeZone.getDefault());
+ Calendar calendar = GregorianCalendar.getInstance();
calendar.clear();
- calendar.set(2004, Calendar.OCTOBER, 19, 10, 23, 54);
+ calendar.set(Calendar.YEAR, 2004);
+ calendar.set(Calendar.MONTH, Calendar.OCTOBER);
+ calendar.set(Calendar.DAY_OF_MONTH, 19);
+ calendar.set(Calendar.HOUR_OF_DAY, 10);
+ calendar.set(Calendar.MINUTE, 23);
+ calendar.set(Calendar.SECOND, 54);
long expected = calendar.getTimeInMillis();
assertEquals(expected, rs.getObject("timestamp_without_time_zone_column", Calendar.class).getTimeInMillis());
assertEquals(expected, rs.getObject(1, Calendar.class).getTimeInMillis());
@@ -294,29 +314,6 @@ class GetObjectTest {
}
}
- /**
- * Test the behavior getObject for timestamp columns using the year 1000.
- */
- @Test
- void getCalendarYear1000() throws SQLException {
- Statement stmt = conn.createStatement();
-
- ResultSet rs = stmt.executeQuery("select TIMESTAMP '1000-10-19 10:23:54'::timestamp as timestamp_without_time_zone_column"
- + ", TIMESTAMP '1000-10-19 10:23:54+02'::timestamp as timestamp_with_time_zone_column, null::timestamp as null_timestamp");
- try {
- assertTrue(rs.next());
- Calendar expectedCal = createProlepticGregorianCalendar(TimeZone.getDefault());
- expectedCal.clear();
- expectedCal.set(1000, Calendar.OCTOBER, 19, 10, 23, 54);
-
- assertEquals(expectedCal.getTimeInMillis(), rs.getObject("timestamp_without_time_zone_column", Calendar.class).getTimeInMillis());
- expectedCal.setTimeZone(TimeZone.getTimeZone("GMT+2:00"));
- assertEquals(expectedCal.getTimeInMillis(), rs.getObject("timestamp_with_time_zone_column", Calendar.class).getTimeInMillis());
- } finally {
- rs.close();
- }
- }
-
/**
* Test the behavior getObject for date columns.
*/
@@ -328,9 +325,11 @@ class GetObjectTest {
ResultSet rs = stmt.executeQuery(TestUtil.selectSQL("table1", "date_column"));
try {
assertTrue(rs.next());
- Calendar calendar = createProlepticGregorianCalendar(TimeZone.getDefault());
+ Calendar calendar = GregorianCalendar.getInstance();
calendar.clear();
- calendar.set(1999, Calendar.JANUARY, 8);
+ calendar.set(Calendar.YEAR, 1999);
+ calendar.set(Calendar.MONTH, Calendar.JANUARY);
+ calendar.set(Calendar.DAY_OF_MONTH, 8);
Date expectedNoZone = new Date(calendar.getTimeInMillis());
assertEquals(expectedNoZone, rs.getObject("date_column", Date.class));
assertEquals(expectedNoZone, rs.getObject(1, Date.class));
@@ -380,9 +379,14 @@ class GetObjectTest {
ResultSet rs = stmt.executeQuery(TestUtil.selectSQL("table1", "time_without_time_zone_column"));
try {
assertTrue(rs.next());
- Calendar calendar = createProlepticGregorianCalendar(TimeZone.getDefault());
+ Calendar calendar = GregorianCalendar.getInstance();
calendar.clear();
- calendar.set(1970, Calendar.JANUARY, 1, 4, 5, 6);
+ calendar.set(Calendar.YEAR, 1970);
+ calendar.set(Calendar.MONTH, Calendar.JANUARY);
+ calendar.set(Calendar.DAY_OF_MONTH, 1);
+ calendar.set(Calendar.HOUR, 4);
+ calendar.set(Calendar.MINUTE, 5);
+ calendar.set(Calendar.SECOND, 6);
Time expectedNoZone = new Time(calendar.getTimeInMillis());
assertEquals(expectedNoZone, rs.getObject("time_without_time_zone_column", Time.class));
assertEquals(expectedNoZone, rs.getObject(1, Time.class));
=====================================
src/test/java/org/postgresql/test/jdbc42/TimestampUtilsTest.java
=====================================
@@ -6,7 +6,6 @@
package org.postgresql.test.jdbc42;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import org.postgresql.jdbc.TimestampUtils;
import org.postgresql.util.ByteConverter;
@@ -15,14 +14,8 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.sql.SQLException;
-import java.time.LocalDate;
import java.time.LocalTime;
import java.time.OffsetTime;
-import java.time.ZoneOffset;
-import java.time.temporal.ChronoUnit;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
import java.util.TimeZone;
class TimestampUtilsTest {
@@ -178,142 +171,4 @@ class TimestampUtilsTest {
timestampUtils.toOffsetTime(inputTime),
"timestampUtils.toOffsetTime(" + inputTime + ")");
}
-
- @Test
- void getSharedCalendar() {
- Calendar calendar = timestampUtils.getSharedCalendar(null);
- // The default time zone should be applied
- assertEquals(TimeZone.getDefault(), calendar.getTimeZone());
- assertInstanceOf(GregorianCalendar.class, calendar);
- GregorianCalendar gregorianCalendar = (GregorianCalendar) calendar;
- // The returned calendar should be pure (proleptic) Gregorian
- assertEquals(new Date(Long.MIN_VALUE), gregorianCalendar.getGregorianChange());
- }
-
- @Test
- void createProlepticGregorianCalendar() {
- Calendar calendar = TimestampUtils.createProlepticGregorianCalendar(TimeZone.getTimeZone(ZoneOffset.UTC));
- // The supplied time zone should be applied
- assertEquals(TimeZone.getTimeZone(ZoneOffset.UTC), calendar.getTimeZone());
- assertInstanceOf(GregorianCalendar.class, calendar);
- GregorianCalendar gregorianCalendar = (GregorianCalendar) calendar;
- // The returned calendar should be pure (proleptic) Gregorian
- assertEquals(new Date(Long.MIN_VALUE), gregorianCalendar.getGregorianChange());
- // Perform a date calculation close to the default switch from Julian to Gregorian dates
- gregorianCalendar.clear();
- gregorianCalendar.set(1582, Calendar.OCTOBER, 5);
- gregorianCalendar.add(Calendar.DAY_OF_MONTH, 15);
- assertEquals(1582, gregorianCalendar.get(Calendar.YEAR));
- assertEquals(Calendar.OCTOBER, gregorianCalendar.get(Calendar.MONTH));
- // Would be 30 if the calendar had the default Julian to Gregorian change date
- assertEquals(20, gregorianCalendar.get(Calendar.DAY_OF_MONTH));
- }
-
- @Test
- void toDate() throws SQLException {
- Calendar expectedCal = TimestampUtils.createProlepticGregorianCalendar(TimeZone.getDefault());
- expectedCal.clear();
- expectedCal.set(2025, Calendar.NOVEMBER, 25);
-
- assertEquals(expectedCal.getTime(), timestampUtils.toDate(TimestampUtils.createProlepticGregorianCalendar(TimeZone.getDefault()), "2025-11-25"));
- assertEquals(expectedCal.getTime(), timestampUtils.toDate(null, "2025-11-25 00:00:00"));
- }
-
- @Test
- void toDateYear1000() throws SQLException {
- Calendar expectedCal = TimestampUtils.createProlepticGregorianCalendar(TimeZone.getDefault());
- expectedCal.clear();
- expectedCal.set(1000, Calendar.JANUARY, 1);
- // Be aware that Date.toString() formats with the Julian calendar for such old dates
- assertEquals(expectedCal.getTime(), timestampUtils.toDate(TimestampUtils.createProlepticGregorianCalendar(TimeZone.getDefault()), "1000-01-01"));
- assertEquals(expectedCal.getTime(), timestampUtils.toDate(null, "1000-01-01 00:00:00"));
- }
-
- @Test
- void toDateBin() throws SQLException {
- final int days = 10;
- final byte[] bytes = new byte[4];
- ByteConverter.int4(bytes, 0, days);
-
- Calendar expectedCal = TimestampUtils.createProlepticGregorianCalendar(TimeZone.getDefault());
- expectedCal.clear();
- // Postgres epoch (but in default time zone) + days
- expectedCal.set(2000, Calendar.JANUARY, 1 + days);
-
- assertEquals(expectedCal.getTime(), timestampUtils.toDateBin(null, bytes));
- }
-
- @Test
- void toDateBinYear1000() throws SQLException {
- // java.time is based on ISO-8601, that means the proleptic Gregorian calendar is used
- final int days = Math.toIntExact(ChronoUnit.DAYS.between(LocalDate.of(2000, 1, 1), LocalDate.of(1000, 1, 1)));
- final byte[] bytes = new byte[4];
- ByteConverter.int4(bytes, 0, days);
-
- Calendar expectedCal = TimestampUtils.createProlepticGregorianCalendar(TimeZone.getDefault());
- expectedCal.clear();
- expectedCal.set(1000, Calendar.JANUARY, 1);
-
- // Be aware that Date.toString() formats with the Julian calendar for such old dates
- assertEquals(expectedCal.getTime(), timestampUtils.toDateBin(null, bytes));
- }
-
- @Test
- void toTimestamp() throws SQLException {
- Calendar expectedCal = TimestampUtils.createProlepticGregorianCalendar(TimeZone.getDefault());
- expectedCal.clear();
- expectedCal.set(2025, Calendar.NOVEMBER, 25, 16, 34, 45);
-
- assertEquals(expectedCal.getTime().getTime(), timestampUtils.toTimestamp(TimestampUtils.createProlepticGregorianCalendar(TimeZone.getDefault()), "2025-11-25 16:34:45").getTime());
- assertEquals(expectedCal.getTime().getTime(), timestampUtils.toTimestamp(null, "2025-11-25 16:34:45").getTime());
- }
-
- @Test
- void toTimestampYear1000() throws SQLException {
- Calendar expectedCal = TimestampUtils.createProlepticGregorianCalendar(TimeZone.getDefault());
- expectedCal.clear();
- expectedCal.set(1000, Calendar.NOVEMBER, 25, 16, 34, 45);
-
- assertEquals(expectedCal.getTime().getTime(), timestampUtils.toTimestamp(TimestampUtils.createProlepticGregorianCalendar(TimeZone.getDefault()), "1000-11-25 16:34:45").getTime());
- assertEquals(expectedCal.getTime().getTime(), timestampUtils.toTimestamp(null, "1000-11-25 16:34:45").getTime());
- }
-
- @Test
- void toTimestampBin() throws SQLException {
- final int days = 10;
- final int hours = 14;
- final int minutes = 16;
- final long daysInMicros = days * 24L * 60L * 60L * 1000_000L;
- final long hoursInMicros = hours * 60L * 60L * 1000_000L;
- final long minutesInMicros = minutes * 60L * 1000_000L;
- final byte[] bytes = new byte[8];
- ByteConverter.int8(bytes, 0, daysInMicros + hoursInMicros + minutesInMicros);
-
- Calendar expectedCal = TimestampUtils.createProlepticGregorianCalendar(TimeZone.getDefault());
- expectedCal.clear();
- // Postgres epoch (but in default time zone) + days
- expectedCal.set(2000, Calendar.JANUARY, 1 + days, hours, minutes);
-
- assertEquals(expectedCal.getTime().getTime(), timestampUtils.toTimestampBin(null, bytes, false).getTime());
- }
-
- @Test
- void toTimestampBinYear1000() throws SQLException {
- // java.time is based on ISO-8601, that means the proleptic Gregorian calendar is used
- final int days = Math.toIntExact(ChronoUnit.DAYS.between(LocalDate.of(2000, 1, 1), LocalDate.of(1000, 1, 1)));
- final int hours = 14;
- final int minutes = 16;
- final long daysInMicros = days * 24L * 60L * 60L * 1000_000L;
- final long hoursInMicros = hours * 60L * 60L * 1000_000L;
- final long minutesInMicros = minutes * 60L * 1000_000L;
- final byte[] bytes = new byte[8];
- ByteConverter.int8(bytes, 0, daysInMicros + hoursInMicros + minutesInMicros);
-
- Calendar expectedCal = TimestampUtils.createProlepticGregorianCalendar(TimeZone.getDefault());
- expectedCal.clear();
- expectedCal.set(1000, Calendar.JANUARY, 1, hours, minutes);
-
- assertEquals(expectedCal.getTime().getTime(), timestampUtils.toTimestampBin(null, bytes, false).getTime());
- }
-
}
View it on GitLab: https://salsa.debian.org/java-team/libpostgresql-jdbc-java/-/compare/a1416d479698a409230e409fe53819df0640a4e8...5449b3c82ed97ab39adf51dd374eb6e05f099f84
--
View it on GitLab: https://salsa.debian.org/java-team/libpostgresql-jdbc-java/-/compare/a1416d479698a409230e409fe53819df0640a4e8...5449b3c82ed97ab39adf51dd374eb6e05f099f84
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/20260211/64ad008d/attachment.htm>
More information about the pkg-java-commits
mailing list