#4203 fix: [postgres] implement binary array deserialization to unblock JDBC setArray - #4207
Conversation
…ck JDBC setArray PostgresType.deserializeBinary() threw "Binary deserialization for arrays not yet implemented" for all array types (ARRAY_INT, ARRAY_LONG, ARRAY_TEXT, ...). The exception in bindCommand() wrote an error response but exited before reading the Bind message's result-format section. The main loop then consumed those leftover bytes as message-type characters, misaligning the protocol and causing both client and server to block on socket reads. Implement PostgreSQL binary array deserialization: ndim, hasnull, elemOid, per-dim (size, lb), then per-element (elemLen, data). Element OID dispatch covers bool, int2/4/8, float4/8, text/varchar/bpchar/json. Adds 5 unit tests in PostgresTypeTest (text[], long[], int[], empty, null element) and 2 setArray integration tests in PostgresProtocolIT that must not hang.
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 6 |
🟢 Coverage 83.05% diff coverage · -7.59% coverage variation
Metric Results Coverage variation ✅ -7.59% coverage variation Diff coverage ✅ 83.05% diff coverage Coverage variation details
Coverable lines Covered lines Coverage Common ancestor commit (a5e1378) 126737 93948 74.13% Head commit (3167773) 158473 (+31736) 105452 (+11504) 66.54% (-7.59%) Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch:
<coverage of head commit> - <coverage of common ancestor commit>Diff coverage details
Coverable lines Covered lines Diff coverage Pull request (#4207) 59 49 83.05% Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified:
<covered lines added or modified>/<coverable lines added or modified> * 100%
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
Code ReviewSummary: This PR fixes a real deadlock bug introduced when Security / Robustness1. Unbounded ArrayList pre-allocation (moderate - potential DoS) In int totalElements = 1;
for (int d = 0; d < ndim; d++) {
totalElements *= buffer.getInt(); // from wire
buffer.getInt();
}
final ArrayList<Object> result = new ArrayList<>(totalElements);A malicious client can send // Defer: don't pre-size from wire data
final ArrayList<Object> result = new ArrayList<>();Or add a reasonable sanity cap (e.g., the remaining bytes in the buffer divided by minimum element size). 2. Integer overflow in multi-dimensional element count totalElements *= buffer.getInt();For a 2D array with two large dimensions (e.g., 50001 x 50001), // Safer:
final long dimSize = buffer.getInt();
totalElements = Math.toIntExact(totalElements * dimSize); // throws ArithmeticException on overflowMinor Issues3. Boolean deserialization inconsistency The scalar path uses 4. Magic OID numbers in The switch arms use raw OID literals (16, 20, 21, 23, 700, 701). The existing 5. Return type widens to
Test CoverageThe unit tests in
The integration test assertions are essentially no-ops: assertThat(count).isGreaterThanOrEqualTo(0); // must not hang
assertThatCode(() -> { rs.next(); }).doesNotThrowAnyException();
// or simply - the test passing without timeout IS the assertionPositive Highlights
Overall: The fix is correct and the implementation is solid. The unbounded allocation (item 1) and integer overflow (item 2) are the only concerns worth addressing before merge - both could cause server instability in adversarial or edge-case scenarios. |
There was a problem hiding this comment.
Code Review
This pull request implements binary deserialization for PostgreSQL arrays, resolving issues where the protocol would hang due to unimplemented array support. The changes include new logic for parsing array dimensions and elements, supported by comprehensive integration and unit tests. Feedback focuses on improving robustness by validating array dimensions against integer overflow and buffer size to prevent potential memory issues, as well as optimizing performance by reducing intermediate allocations during element processing.
| int totalElements = 1; | ||
| for (int d = 0; d < ndim; d++) { | ||
| totalElements *= buffer.getInt(); // dim size | ||
| buffer.getInt(); // lower bound (unused) | ||
| } | ||
|
|
||
| final ArrayList<Object> result = new ArrayList<>(totalElements); |
There was a problem hiding this comment.
The calculation of totalElements is susceptible to integer overflow and lacks validation of dimension sizes. If totalElements overflows or is maliciously large, it can cause an OutOfMemoryError or IllegalArgumentException during ArrayList allocation. To prevent the protocol synchronization issues (deadlocks) this PR aims to fix, it is crucial to validate that dimensions are non-negative and that the total element count is reasonable relative to the remaining buffer size (e.g., each element requires at least 4 bytes for its length header).
long totalElementsLong = 1;
for (int d = 0; d < ndim; d++) {
final int dimSize = buffer.getInt();
if (dimSize < 0)
throw new PostgresProtocolException("Negative array dimension size");
totalElementsLong *= dimSize;
buffer.getInt(); // lower bound (unused)
}
if (totalElementsLong < 0 || totalElementsLong > Integer.MAX_VALUE || totalElementsLong > buffer.remaining() / 4)
throw new PostgresProtocolException("Invalid array dimensions");
final int totalElements = (int) totalElementsLong;
final ArrayList<Object> result = new ArrayList<>(totalElements);There was a problem hiding this comment.
Addressed in 88013eb. totalElements is now a long, each dim size is checked for negative values, the running product is rejected if it exceeds Integer.MAX_VALUE, and the final count is capped at buffer.remaining() / 4 (each element needs at least a 4-byte length prefix). ndim is also clamped to PostgreSQL's MAXDIM=6. Added regression tests deserializeBinaryArrayRejectsNegativeDimension, deserializeBinaryArrayRejectsTooManyDimensions, deserializeBinaryArrayRejectsOversizedElementCount, deserializeBinaryArrayRejectsOverflowAcrossDimensions.
| final byte[] elemBytes = new byte[elemLen]; | ||
| buffer.get(elemBytes); | ||
| result.add(deserializeBinaryElement(elemOid, elemBytes)); |
There was a problem hiding this comment.
Allocating a new byte[] and wrapping it in a ByteBuffer for every element is inefficient, especially for large arrays of primitives. Consider refactoring deserializeBinaryElement in the future to read directly from the parent buffer to avoid these intermediate allocations and reduce garbage collection pressure.
There was a problem hiding this comment.
Noted. The per-element byte[] + wrap pattern is a deliberate trade-off in this PR to keep the protocol fix minimal and easy to audit. Reading scalar elements directly off the parent buffer is a worthwhile follow-up optimization once the variable-length text path is also threaded through; tracking separately.
…formed/malicious input Review feedback from gemini-code-assist and claude bot on PR #4207: - Validate ndim is in [0, 6] (PostgreSQL MAXDIM) and each dim size is non-negative. - Use long arithmetic for totalElements and reject Integer.MAX_VALUE overflow so bad inputs cannot wrap into a short loop count and silently misalign the buffer. - Cap element count at remaining-bytes/4 to block adversarial pre-allocation that could OOM the server. - Replace magic OID literals in deserializeBinaryElement with PostgresType.<NAME>.code references so the element-type dispatch is self-documenting. - Add unit tests for bool[], int2[], float4[], float8[], 2D int[][], and the three validation paths (negative dim, ndim>MAXDIM, oversized element count, multi-dim overflow). - Strengthen the setArray integration tests: drain the result set then run a follow-up COUNT(*) on the same connection to prove the wire protocol stays aligned after the binary-array Bind.
|
Pushed 88013eb addressing review feedback: Security / robustness (claude #1, #2 + gemini high-pri)
Minor issues
Test coverage
Gemini medium-pri (per-element byte[] allocation)
Test results: |
Code Review: #4203 fix - Binary array deserialization for PostgreSQL wire protocolOverviewThis PR correctly identifies and fixes a two-part bug:
The fix is correct, well-tested, and includes solid security validations. Some minor issues worth addressing. Positives
IssuesStructural: error path in
|
…l aligned Round-2 review feedback: - bindCommand() now tracks read progress (totalParamValues, paramsConsumed, resultFormatSectionRead). On exception, the catch block best-effort drains any unread parameter values and the result-format section before writing the error response. This keeps the channel aligned for the next pipelined message even when deserialization throws for malformed or malicious payloads. - Move MAX_ARRAY_DIMENSIONS to the class-level constant block. - Change deserializeBinaryArray return type to List<Object> instead of ArrayList. - Add comment on the int2 (SMALLINT) element-OID branch explaining the asymmetry with the array-level OID enum. - Add comment to the 2D-array test documenting intentional flattening into a single List for IN-parameter binding.
|
Pushed 3167773 addressing round-2 review: Structural - bindCommand error path drain (most valuable item)
Style/robustness
Pushback on switch-vs-if-else (round-2 item 2)
Pushback on jsonb TODO (round-2 item 6)
Test results: |
Code ReviewSummary: This PR fixes a real deadlock: Bug:
|
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #4207 +/- ##
=======================================
Coverage 64.98% 64.99%
=======================================
Files 1643 1643
Lines 126737 126795 +58
Branches 27127 27146 +19
=======================================
+ Hits 82364 82414 +50
- Misses 32818 32835 +17
+ Partials 11555 11546 -9 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…ck JDBC setArray (#4207) * #4203 fix: [postgres] implement binary array deserialization to unblock JDBC setArray PostgresType.deserializeBinary() threw "Binary deserialization for arrays not yet implemented" for all array types (ARRAY_INT, ARRAY_LONG, ARRAY_TEXT, ...). The exception in bindCommand() wrote an error response but exited before reading the Bind message's result-format section. The main loop then consumed those leftover bytes as message-type characters, misaligning the protocol and causing both client and server to block on socket reads. Implement PostgreSQL binary array deserialization: ndim, hasnull, elemOid, per-dim (size, lb), then per-element (elemLen, data). Element OID dispatch covers bool, int2/4/8, float4/8, text/varchar/bpchar/json. Adds 5 unit tests in PostgresTypeTest (text[], long[], int[], empty, null element) and 2 setArray integration tests in PostgresProtocolIT that must not hang. * #4203 fix: [postgres] harden binary array deserialization against malformed/malicious input Review feedback from gemini-code-assist and claude bot on PR #4207: - Validate ndim is in [0, 6] (PostgreSQL MAXDIM) and each dim size is non-negative. - Use long arithmetic for totalElements and reject Integer.MAX_VALUE overflow so bad inputs cannot wrap into a short loop count and silently misalign the buffer. - Cap element count at remaining-bytes/4 to block adversarial pre-allocation that could OOM the server. - Replace magic OID literals in deserializeBinaryElement with PostgresType.<NAME>.code references so the element-type dispatch is self-documenting. - Add unit tests for bool[], int2[], float4[], float8[], 2D int[][], and the three validation paths (negative dim, ndim>MAXDIM, oversized element count, multi-dim overflow). - Strengthen the setArray integration tests: drain the result set then run a follow-up COUNT(*) on the same connection to prove the wire protocol stays aligned after the binary-array Bind. * #4203 fix: [postgres] drain Bind message tail on error to keep channel aligned Round-2 review feedback: - bindCommand() now tracks read progress (totalParamValues, paramsConsumed, resultFormatSectionRead). On exception, the catch block best-effort drains any unread parameter values and the result-format section before writing the error response. This keeps the channel aligned for the next pipelined message even when deserialization throws for malformed or malicious payloads. - Move MAX_ARRAY_DIMENSIONS to the class-level constant block. - Change deserializeBinaryArray return type to List<Object> instead of ArrayList. - Add comment on the int2 (SMALLINT) element-OID branch explaining the asymmetry with the array-level OID enum. - Add comment to the 2D-array test documenting intentional flattening into a single List for IN-parameter binding. (cherry picked from commit 9c6363a)
…n to unblock JDBC setArray (ArcadeData#4207) * ArcadeData#4203 fix: [postgres] implement binary array deserialization to unblock JDBC setArray PostgresType.deserializeBinary() threw "Binary deserialization for arrays not yet implemented" for all array types (ARRAY_INT, ARRAY_LONG, ARRAY_TEXT, ...). The exception in bindCommand() wrote an error response but exited before reading the Bind message's result-format section. The main loop then consumed those leftover bytes as message-type characters, misaligning the protocol and causing both client and server to block on socket reads. Implement PostgreSQL binary array deserialization: ndim, hasnull, elemOid, per-dim (size, lb), then per-element (elemLen, data). Element OID dispatch covers bool, int2/4/8, float4/8, text/varchar/bpchar/json. Adds 5 unit tests in PostgresTypeTest (text[], long[], int[], empty, null element) and 2 setArray integration tests in PostgresProtocolIT that must not hang. * ArcadeData#4203 fix: [postgres] harden binary array deserialization against malformed/malicious input Review feedback from gemini-code-assist and claude bot on PR ArcadeData#4207: - Validate ndim is in [0, 6] (PostgreSQL MAXDIM) and each dim size is non-negative. - Use long arithmetic for totalElements and reject Integer.MAX_VALUE overflow so bad inputs cannot wrap into a short loop count and silently misalign the buffer. - Cap element count at remaining-bytes/4 to block adversarial pre-allocation that could OOM the server. - Replace magic OID literals in deserializeBinaryElement with PostgresType.<NAME>.code references so the element-type dispatch is self-documenting. - Add unit tests for bool[], int2[], float4[], float8[], 2D int[][], and the three validation paths (negative dim, ndim>MAXDIM, oversized element count, multi-dim overflow). - Strengthen the setArray integration tests: drain the result set then run a follow-up COUNT(*) on the same connection to prove the wire protocol stays aligned after the binary-array Bind. * ArcadeData#4203 fix: [postgres] drain Bind message tail on error to keep channel aligned Round-2 review feedback: - bindCommand() now tracks read progress (totalParamValues, paramsConsumed, resultFormatSectionRead). On exception, the catch block best-effort drains any unread parameter values and the result-format section before writing the error response. This keeps the channel aligned for the next pipelined message even when deserialization throws for malformed or malicious payloads. - Move MAX_ARRAY_DIMENSIONS to the class-level constant block. - Change deserializeBinaryArray return type to List<Object> instead of ArrayList. - Add comment on the int2 (SMALLINT) element-OID branch explaining the asymmetry with the array-level OID enum. - Add comment to the 2D-array test documenting intentional flattening into a single List for IN-parameter binding.
…skip ci] Bumps [org.postgresql:postgresql](https://github.com/pgjdbc/pgjdbc) from 42.7.12 to 42.7.13. Release notes *Sourced from [org.postgresql:postgresql's releases](https://github.com/pgjdbc/pgjdbc/releases).* > v42.7.13 > -------- > > Changes > ------- > > * docs: add 42.7.13 release changelog [`@davecramer`](https://github.com/davecramer) ([#4270](https://redirect.github.com/pgjdbc/pgjdbc/issues/4270)) > * Adjust EditorConfig für Makefile [`@BaumiCoder`](https://github.com/BaumiCoder) ([#4279](https://redirect.github.com/pgjdbc/pgjdbc/issues/4279)) > * fix(scram): fail closed on channel-binding downgrade (no scram bump) [`@vlsi`](https://github.com/vlsi) ([#4272](https://redirect.github.com/pgjdbc/pgjdbc/issues/4272)) > * Bump pgjdbc version from 42.7.12 to 42.7.13 [`@davecramer`](https://github.com/davecramer) ([#4269](https://redirect.github.com/pgjdbc/pgjdbc/issues/4269)) > * chore: remove test-anorm-sbt module and its disabled CI wiring [`@vlsi`](https://github.com/vlsi) ([#4261](https://redirect.github.com/pgjdbc/pgjdbc/issues/4261)) > * refactor(test-gss): convert to Java/JUnit 5 submodule of the main build [`@vlsi`](https://github.com/vlsi) ([#4166](https://redirect.github.com/pgjdbc/pgjdbc/issues/4166)) > * ci: derive PG test versions from a Renovate-managed maxPgVersion [`@vlsi`](https://github.com/vlsi) ([#4218](https://redirect.github.com/pgjdbc/pgjdbc/issues/4218)) > * feat(insert): cap reWriteBatchedInserts by the protocol limit, not 128 [`@vlsi`](https://github.com/vlsi) ([#4207](https://redirect.github.com/pgjdbc/pgjdbc/issues/4207)) > * refactor(metadata): derive getPrimaryKeys from pg\_constraint.conkey [`@vlsi`](https://github.com/vlsi) ([#4202](https://redirect.github.com/pgjdbc/pgjdbc/issues/4202)) > * fix(protocol): defer flushes until response processing [`@vlsi`](https://github.com/vlsi) ([#4196](https://redirect.github.com/pgjdbc/pgjdbc/issues/4196)) > * fix(build): resolve the Temurin 8 test toolchain by vendor [`@vlsi`](https://github.com/vlsi) ([#4257](https://redirect.github.com/pgjdbc/pgjdbc/issues/4257)) > * build: include multi-release source sets in the JaCoCo coverage report [`@vlsi`](https://github.com/vlsi) ([#4256](https://redirect.github.com/pgjdbc/pgjdbc/issues/4256)) > * fix(ci): read java\_vendor before overwriting java\_distribution [`@vlsi`](https://github.com/vlsi) ([#4255](https://redirect.github.com/pgjdbc/pgjdbc/issues/4255)) > * ci: generate the whole matrix in one batch, coverage job included [`@vlsi`](https://github.com/vlsi) ([#4253](https://redirect.github.com/pgjdbc/pgjdbc/issues/4253)) > * ci: pass CODECOV\_TOKEN so protected-branch coverage uploads succeed [`@vlsi`](https://github.com/vlsi) ([#4254](https://redirect.github.com/pgjdbc/pgjdbc/issues/4254)) > * ci: collect coverage on one pinned job [`@vlsi`](https://github.com/vlsi) ([#4245](https://redirect.github.com/pgjdbc/pgjdbc/issues/4245)) > * ci: apply -DqueryTimeout from the matrix query\_timeout axis [`@vlsi`](https://github.com/vlsi) ([#4246](https://redirect.github.com/pgjdbc/pgjdbc/issues/4246)) > * ci: make Codecov project and patch statuses informational [`@vlsi`](https://github.com/vlsi) ([#4244](https://redirect.github.com/pgjdbc/pgjdbc/issues/4244)) > * fix(build): restore JaCoCo XML report so Codecov receives coverage [`@vlsi`](https://github.com/vlsi) ([#4240](https://redirect.github.com/pgjdbc/pgjdbc/issues/4240)) > * test(replication): shrink big-transaction inserts to avoid CI timeouts [`@vlsi`](https://github.com/vlsi) ([#4243](https://redirect.github.com/pgjdbc/pgjdbc/issues/4243)) > * update maintainers [`@davecramer`](https://github.com/davecramer) ([#4222](https://redirect.github.com/pgjdbc/pgjdbc/issues/4222)) > * test: add hermetic test for localSocketAddress [`@vlsi`](https://github.com/vlsi) ([#4224](https://redirect.github.com/pgjdbc/pgjdbc/issues/4224)) > * docs(translation): clean up leftover German header in ja.po [`@vlsi`](https://github.com/vlsi) ([#4206](https://redirect.github.com/pgjdbc/pgjdbc/issues/4206)) > * Update ja.po [`@davecramer`](https://github.com/davecramer) ([#2004](https://redirect.github.com/pgjdbc/pgjdbc/issues/2004)) > * test: add PostgreSQL 18 to the CI test matrix [`@vlsi`](https://github.com/vlsi) ([#4198](https://redirect.github.com/pgjdbc/pgjdbc/issues/4198)) > * test: silence expected SSPI warning stack trace in SSPIClientWaffleTest [`@vlsi`](https://github.com/vlsi) ([#4197](https://redirect.github.com/pgjdbc/pgjdbc/issues/4197)) > * fix(ssl): build PKIX trust anchors without a KeyStore so FIPS-mode JVMs can load sslrootcert [`@vlsi`](https://github.com/vlsi) ([#4193](https://redirect.github.com/pgjdbc/pgjdbc/issues/4193)) > * test: fix flaky sentLocationEqualToLastReceiveLSN replication test [`@vlsi`](https://github.com/vlsi) ([#4175](https://redirect.github.com/pgjdbc/pgjdbc/issues/4175)) > * build: promote MethodCanBeStatic to error level [`@vlsi`](https://github.com/vlsi) ([#4172](https://redirect.github.com/pgjdbc/pgjdbc/issues/4172)) > * Fix PGInterval.setSeconds to reject out of range and NaN values [`@sehrope`](https://github.com/sehrope) ([#4194](https://redirect.github.com/pgjdbc/pgjdbc/issues/4194)) > * Replace connectThreadFactory with connectExecutor [`@sehrope`](https://github.com/sehrope) ([#4165](https://redirect.github.com/pgjdbc/pgjdbc/issues/4165)) > * Fix deleting temp file when spooling large stream to disk in StreamWrapper [`@sehrope`](https://github.com/sehrope) ([#4190](https://redirect.github.com/pgjdbc/pgjdbc/issues/4190)) > * chore: Add top level /scratch to gitignore [`@sehrope`](https://github.com/sehrope) ([#4164](https://redirect.github.com/pgjdbc/pgjdbc/issues/4164)) > * refactor: favour composition over inheritance for Driver.ConnectTask [`@vlsi`](https://github.com/vlsi) ([#4160](https://redirect.github.com/pgjdbc/pgjdbc/issues/4160)) > * Fix NumberParser.getFastLong(...) handling of overlong values [`@sehrope`](https://github.com/sehrope) ([#4163](https://redirect.github.com/pgjdbc/pgjdbc/issues/4163)) > * build: produce a multi-release jar from reduced-pom.xml on Java 11+ [`@vlsi`](https://github.com/vlsi) ([#4157](https://redirect.github.com/pgjdbc/pgjdbc/issues/4157)) > * Add connectThreadFactory and refactor Driver to use FutureTask for loginTimeout connection attempts [`@sehrope`](https://github.com/sehrope) ([#4120](https://redirect.github.com/pgjdbc/pgjdbc/issues/4120)) > * test: verify custom properties reach socket factory [`@vlsi`](https://github.com/vlsi) ([#4125](https://redirect.github.com/pgjdbc/pgjdbc/issues/4125)) > * test: fix LazyCleanerTest timeouts for the lingering Java 8 cleanup thread [`@vlsi`](https://github.com/vlsi) ([#4122](https://redirect.github.com/pgjdbc/pgjdbc/issues/4122)) > * test: stabilise StatementTest.fastCloses on Windows [`@vlsi`](https://github.com/vlsi) ([#4121](https://redirect.github.com/pgjdbc/pgjdbc/issues/4121)) > * fix: append default non-proxy hosts when socksNonProxyHosts is set [`@davecramer`](https://github.com/davecramer) ([#4045](https://redirect.github.com/pgjdbc/pgjdbc/issues/4045)) > * test: budget terminating Sync in BatchDeadlockTest small-RETURNING branch [`@vlsi`](https://github.com/vlsi) ([#4116](https://redirect.github.com/pgjdbc/pgjdbc/issues/4116)) > * test: make message assertions locale-independent [`@vlsi`](https://github.com/vlsi) ([#4113](https://redirect.github.com/pgjdbc/pgjdbc/issues/4113)) > * build: drop xgettext default keywords; regenerate translations [`@vlsi`](https://github.com/vlsi) ([#4100](https://redirect.github.com/pgjdbc/pgjdbc/issues/4100)) > * ci: opt-in scheduled workflows via ENABLE\_SCHEDULED\_JOBS repo variable [`@vlsi`](https://github.com/vlsi) ([#4085](https://redirect.github.com/pgjdbc/pgjdbc/issues/4085)) > * Avoid direct java.lang.management dependency in maxResultBuffer parser [`@mblakley-casana`](https://github.com/mblakley-casana) ([#4069](https://redirect.github.com/pgjdbc/pgjdbc/issues/4069)) > * fix: restore pre-describe for generated-key batches [`@bilalshehata`](https://github.com/bilalshehata) ([#4014](https://redirect.github.com/pgjdbc/pgjdbc/issues/4014)) ... (truncated) Changelog *Sourced from [org.postgresql:postgresql's changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md).* > [42.7.13] (2026-07-06) > ---------------------- > > ### Added > > * feat: invalidate the prepared-statement cache when the server reports a `search_path` change via GUC\_REPORT (PostgreSQL 18+), so cached plans are no longer used against the wrong schema [PR [#4259](https://redirect.github.com/pgjdbc/pgjdbc/issues/4259)]([pgjdbc/pgjdbc#4259](https://redirect.github.com/pgjdbc/pgjdbc/pull/4259)) > * feat: `reWriteBatchedInserts` now merges up to 32768 rows into one multi-values `INSERT` (bounded by the 65535 bind-parameter limit on the extended protocol) instead of capping at 128, which speeds up batches of few-column rows. The new `reWriteBatchedInsertsSize` connection property lowers that cap when set; the default of `0` uses that maximum. [PR [#4207](https://redirect.github.com/pgjdbc/pgjdbc/issues/4207)]([pgjdbc/pgjdbc#4207](https://redirect.github.com/pgjdbc/pgjdbc/pull/4207)) > * feat: invalidate the prepared-statement cache after CREATE/DROP/ALTER so callers no longer trip on "cached plan must not change result type" without opting into `autosave=ALWAYS`. Controlled by the new `flushCacheOnDdl` connection property (default `true`); set to `false` for the prior behaviour. [PR [#4067](https://redirect.github.com/pgjdbc/pgjdbc/issues/4067)]([pgjdbc/pgjdbc#4067](https://redirect.github.com/pgjdbc/pgjdbc/pull/4067)) > * feat: add `connectExecutor` connection property to customize the `Executor` used to run the worker task that performs the connection attempt when `loginTimeout` is in effect. The value is the fully qualified name of a class implementing `java.util.concurrent.Executor`. With a null value, the default, the driver retains the prior behavior of running the connection attempt on a daemon thread named `"PostgreSQL JDBC driver connection thread"`. The executor must run the task on a thread other than the caller's. Running the attempt on a named thread lets applications that monitor driver-created threads identify it. [PR [#4165](https://redirect.github.com/pgjdbc/pgjdbc/issues/4165)]([pgjdbc/pgjdbc#4165](https://redirect.github.com/pgjdbc/pgjdbc/pull/4165)) > * feat: add `classLoaderStrategy` connection property to control which classloaders the driver searches when loading a class named by a connection property, for example `socketFactory`. The default `driver-first` now falls back to the thread context classloader when the driver's classloader cannot resolve the class, which fixes class loading in non-flat class paths such as Quarkus and OSGi. Set `driver` to keep the previous driver-classloader-only behaviour, or `context-first` to prefer the thread context classloader [Issue [#2112](https://redirect.github.com/pgjdbc/pgjdbc/issues/2112)]([pgjdbc/pgjdbc#2112](https://redirect.github.com/pgjdbc/pgjdbc/issues/2112)) [PR [#4167](https://redirect.github.com/pgjdbc/pgjdbc/issues/4167)]([pgjdbc/pgjdbc#4167](https://redirect.github.com/pgjdbc/pgjdbc/pull/4167)) > * feat: add OID constants for geometric arrays, `RECORD`, and `refcursor` [PR [#4220](https://redirect.github.com/pgjdbc/pgjdbc/issues/4220)]([pgjdbc/pgjdbc#4220](https://redirect.github.com/pgjdbc/pgjdbc/pull/4220)) > * feat: `LargeObject` `BlobInputStream` now skips by seeking instead of reading, and the driver exposes the server version so it can select the 64-bit large-object API where available [PR [#4204](https://redirect.github.com/pgjdbc/pgjdbc/issues/4204)]([pgjdbc/pgjdbc#4204](https://redirect.github.com/pgjdbc/pgjdbc/pull/4204)) > > ### Changed > > * refactor: the worker that runs the connection attempt under `loginTimeout` is now a `FutureTask` (`ConnectTask`) instead of the hand-rolled `ConnectThread`. When the caller hits the timeout, the task is now cancelled with `cancel(true)`, which interrupts the worker thread rather than letting it run to completion. This makes the connection attempt interruptible, so `loginTimeout` can stop a slow connection attempt instead of leaking a thread. As before, a connection that the worker still manages to establish after the caller gives up is closed by the worker so that it does not leak. There are no public API changes and this should only lead to faster background resource cleanup for connections that time out. [PR [#4120](https://redirect.github.com/pgjdbc/pgjdbc/issues/4120)]([pgjdbc/pgjdbc#4120](https://redirect.github.com/pgjdbc/pgjdbc/pull/4120)) > * chore: `PGXAConnection.ConnectionHandler` now rejects `setAutoCommit(false)` and `setSavepoint(...)` during an active XA branch, in addition to the long-rejected `setAutoCommit(true)` / `commit()` / `rollback()`. The `setSavepoint` rejection was already meant to be in place but the guard misspelled the method name as `setSavePoint`, so savepoints silently went through. Both changes bring the proxy in line with JTA 1.2 §3.4. [PR [#4114](https://redirect.github.com/pgjdbc/pgjdbc/issues/4114)]([pgjdbc/pgjdbc#4114](https://redirect.github.com/pgjdbc/pgjdbc/pull/4114)) > * chore: `commitPrepared` / `rollback`-of-prepared now return `XAER_RMFAIL` instead of `XAER_RMERR` when the underlying connection is left in a non-idle `TransactionState`. Transaction managers (Geronimo, Narayana, Atomikos) treat `XAER_RMFAIL` as retryable on a fresh `XAResource`; the prepared transaction is no longer abandoned. [PR [#4114](https://redirect.github.com/pgjdbc/pgjdbc/issues/4114)]([pgjdbc/pgjdbc#4114](https://redirect.github.com/pgjdbc/pgjdbc/pull/4114)) > * refactor: derive `getPrimaryKeys` from `pg_constraint.conkey` [PR [#4202](https://redirect.github.com/pgjdbc/pgjdbc/issues/4202)]([pgjdbc/pgjdbc#4202](https://redirect.github.com/pgjdbc/pgjdbc/pull/4202)) > > ### Fixed > > * fix: the published GitHub release now ships the released `postgresql-<version>.jar` and its detached PGP signature, taken from the same signed build that is uploaded to Maven Central, instead of a leftover SNAPSHOT jar [Issue [#3812](https://redirect.github.com/pgjdbc/pgjdbc/issues/3812)]([pgjdbc/pgjdbc#3812](https://redirect.github.com/pgjdbc/pgjdbc/issues/3812)) [PR [#3814](https://redirect.github.com/pgjdbc/pgjdbc/issues/3814)]([pgjdbc/pgjdbc#3814](https://redirect.github.com/pgjdbc/pgjdbc/pull/3814)) > * fix: simplify the `Statement#cancel` state machine by dropping the redundant `CANCELLED` state. `killTimerTask` now waits for the state to return to `IDLE` directly, which removes a spin-forever case when more than one thread observes the cancel completing [PR [#1827](https://redirect.github.com/pgjdbc/pgjdbc/issues/1827)]([pgjdbc/pgjdbc#1827](https://redirect.github.com/pgjdbc/pgjdbc/pull/1827)). > * perf: defer simple-query flushes until the driver reads the response, allowing `BEGIN` and the following query to share a network flush [Issue [#3894](https://redirect.github.com/pgjdbc/pgjdbc/issues/3894)]([pgjdbc/pgjdbc#3894](https://redirect.github.com/pgjdbc/pgjdbc/issues/3894)) [PR [#4196](https://redirect.github.com/pgjdbc/pgjdbc/issues/4196)]([pgjdbc/pgjdbc#4196](https://redirect.github.com/pgjdbc/pgjdbc/pull/4196)) > * fix: `reWriteBatchedInserts` no longer throws `IllegalArgumentException` when batching a parameterless `INSERT` (for example `INSERT INTO t VALUES (1, 2)`) of 256 rows or more [PR [#4207](https://redirect.github.com/pgjdbc/pgjdbc/issues/4207)]([pgjdbc/pgjdbc#4207](https://redirect.github.com/pgjdbc/pgjdbc/pull/4207)) > * fix: a comment before `CALL` in a `CallableStatement` no longer hides the native call, so OUT parameter registration works for `/* comment */ call proc(?, ?)` and similar. `Parser.modifyJdbcCall` now skips leading whitespace and SQL comments (both `--` and `/* */`) before the call, tolerates a trailing comment after a `{ ... }` escape, and no longer adds a spurious comma when moving an OUT parameter into a call whose arguments are only a comment [Issue [#2538](https://redirect.github.com/pgjdbc/pgjdbc/issues/2538)]([pgjdbc/pgjdbc#2538](https://redirect.github.com/pgjdbc/pgjdbc/issues/2538)) [PR [#4209](https://redirect.github.com/pgjdbc/pgjdbc/issues/4209)]([pgjdbc/pgjdbc#4209](https://redirect.github.com/pgjdbc/pgjdbc/pull/4209)) > * fix: `PreparedStatement.toString()` no longer throws for a `bytea` value supplied as text via `PGobject`. Hex-format values (`\x...`) are validated and rendered as a `bytea` literal, and escape-format values are quoted and cast like any other literal [Issue [#3757](https://redirect.github.com/pgjdbc/pgjdbc/issues/3757)]([pgjdbc/pgjdbc#3757](https://redirect.github.com/pgjdbc/pgjdbc/issues/3757)) [PR [#4201](https://redirect.github.com/pgjdbc/pgjdbc/issues/4201)]([pgjdbc/pgjdbc#4201](https://redirect.github.com/pgjdbc/pgjdbc/pull/4201)) > * fix: the driver no longer nulls the `contextClassLoader` of shared `ForkJoinPool.commonPool()` worker threads, which previously left unrelated tasks on those threads running with a `null` classloader [Issue [#4155](https://redirect.github.com/pgjdbc/pgjdbc/issues/4155)]([pgjdbc/pgjdbc#4155](https://redirect.github.com/pgjdbc/pgjdbc/issues/4155)) [PR [#4156](https://redirect.github.com/pgjdbc/pgjdbc/issues/4156)]([pgjdbc/pgjdbc#4156](https://redirect.github.com/pgjdbc/pgjdbc/pull/4156)) > * fix: `PgResultSet#getCharacterStream` wraps `String` in a `StringReader` [PR [#4063](https://redirect.github.com/pgjdbc/pgjdbc/issues/4063)]([pgjdbc/pgjdbc#4063](https://redirect.github.com/pgjdbc/pgjdbc/pull/4063)) > * fix: `PGXAConnection` no longer saves and restores the underlying connection's JDBC `autoCommit` flag. All XA-protocol SQL (`BEGIN`, `PREPARE TRANSACTION`, `COMMIT`, `ROLLBACK`, `COMMIT PREPARED`, `ROLLBACK PREPARED`, the `recover()` SELECT) is sent through `QUERY_SUPPRESS_BEGIN`, so the caller's `autoCommit` value is invariant across every `XAResource` call. Fixes the "2nd phase commit must be issued using an idle connection" failure during recovery on managed datasources that pool connections with `autoCommit=false` (TomEE, WildFly, WebSphere Liberty) [PR [#4114](https://redirect.github.com/pgjdbc/pgjdbc/issues/4114)]([pgjdbc/pgjdbc#4114](https://redirect.github.com/pgjdbc/pgjdbc/pull/4114)) > * fix: `PGXAConnection.prepare()` now mutates XA state only after `PREPARE TRANSACTION` succeeds. A failed `PREPARE` previously left the driver thinking the branch was already prepared, so the follow-up `rollback(xid)` tried `ROLLBACK PREPARED` against a non-existent gid and returned `XAER_RMERR`. Transaction managers (Narayana) escalated this to `HeuristicMixedException`. With the fix, `rollback(xid)` takes the active-branch path and issues a plain `ROLLBACK`, which the server accepts cleanly. Fixes [Issue [#3153](https://redirect.github.com/pgjdbc/pgjdbc/issues/3153)]([pgjdbc/pgjdbc#3153](https://redirect.github.com/pgjdbc/pgjdbc/issues/3153)), [Issue [#3123](https://redirect.github.com/pgjdbc/pgjdbc/issues/3123)]([pgjdbc/pgjdbc#3123](https://redirect.github.com/pgjdbc/pgjdbc/issues/3123)). [PR [#4114](https://redirect.github.com/pgjdbc/pgjdbc/issues/4114)]([pgjdbc/pgjdbc#4114](https://redirect.github.com/pgjdbc/pgjdbc/pull/4114)) > * fix: an updatable result set over an unqualified table name is now classified using only the table visible through `search_path`. When two schemas held a table with the same name and the same primary or unique index name but a different set of key columns, the driver took the union of both schemas' columns, so the result set could be wrongly rejected as not updatable [PR [#4214](https://redirect.github.com/pgjdbc/pgjdbc/issues/4214)]([pgjdbc/pgjdbc#4214](https://redirect.github.com/pgjdbc/pgjdbc/pull/4214)). Supersedes [PR [#3400](https://redirect.github.com/pgjdbc/pgjdbc/issues/3400)]([pgjdbc/pgjdbc#3400](https://redirect.github.com/pgjdbc/pgjdbc/pull/3400)). > * fix: `LargeObject.close()` now flushes a buffered output stream before marking the object closed, so closing a large object without an explicit `flush()` no longer drops buffered writes. The flush runs while the object is still open (it calls back into `LargeObject.write()`), and `lo_close` always runs afterward; a failure from `lo_close` no longer masks an earlier flush error, and the transaction is not committed when the flush failed [Issue [#4247](https://redirect.github.com/pgjdbc/pgjdbc/issues/4247)]([pgjdbc/pgjdbc#4247](https://redirect.github.com/pgjdbc/pgjdbc/issues/4247)) [PR [#4248](https://redirect.github.com/pgjdbc/pgjdbc/issues/4248)]([pgjdbc/pgjdbc#4248](https://redirect.github.com/pgjdbc/pgjdbc/pull/4248)). > * fix: reject empty `timestamp`, `timestamptz`, and `date` text with a clear `SQLException` (SQLState `22007`) instead of an `ArrayIndexOutOfBoundsException` [PR [#4278](https://redirect.github.com/pgjdbc/pgjdbc/issues/4278)]([pgjdbc/pgjdbc#4278](https://redirect.github.com/pgjdbc/pgjdbc/pull/4278)) > * fix: return null `CHAR_OCTET_LENGTH` for non-character columns [PR [#4231](https://redirect.github.com/pgjdbc/pgjdbc/issues/4231)]([pgjdbc/pgjdbc#4231](https://redirect.github.com/pgjdbc/pgjdbc/pull/4231)) > * fix: honor scale in `ResultSet.getBigDecimal(int, int)` [PR [#4211](https://redirect.github.com/pgjdbc/pgjdbc/issues/4211)]([pgjdbc/pgjdbc#4211](https://redirect.github.com/pgjdbc/pgjdbc/pull/4211)) > * fix: support `java.time` values in an updatable `ResultSet` `updateRow()` / `insertRow()` [PR [#3848](https://redirect.github.com/pgjdbc/pgjdbc/issues/3848)]([pgjdbc/pgjdbc#3848](https://redirect.github.com/pgjdbc/pgjdbc/pull/3848)) > * fix: improve batching when the `RETURNING` clause contains `varchar` or `numeric` types [PR [#4014](https://redirect.github.com/pgjdbc/pgjdbc/issues/4014)]([pgjdbc/pgjdbc#4014](https://redirect.github.com/pgjdbc/pgjdbc/pull/4014)) > * fix: correct `estimatedReceiveBufferBytes` accounting after a forced `Sync` [PR [#4014](https://redirect.github.com/pgjdbc/pgjdbc/issues/4014)]([pgjdbc/pgjdbc#4014](https://redirect.github.com/pgjdbc/pgjdbc/pull/4014)) > * fix: avoid creating a transient `ResultSet` for describe-statement purposes, and restore the pre-describe path for generated-key batches [PR [#4014](https://redirect.github.com/pgjdbc/pgjdbc/issues/4014)]([pgjdbc/pgjdbc#4014](https://redirect.github.com/pgjdbc/pgjdbc/pull/4014)) > * fix: add an explicit failure message when a multi-statement command executes in a batch [PR [#4014](https://redirect.github.com/pgjdbc/pgjdbc/issues/4014)]([pgjdbc/pgjdbc#4014](https://redirect.github.com/pgjdbc/pgjdbc/pull/4014)) > * fix: detect `search_path` changes case-insensitively [PR [#4216](https://redirect.github.com/pgjdbc/pgjdbc/issues/4216)]([pgjdbc/pgjdbc#4216](https://redirect.github.com/pgjdbc/pgjdbc/pull/4216)) > * fix: auto-detect the SSL key format instead of relying on the `.key` extension [PR [#3946](https://redirect.github.com/pgjdbc/pgjdbc/issues/3946)]([pgjdbc/pgjdbc#3946](https://redirect.github.com/pgjdbc/pgjdbc/pull/3946)) > * fix: build PKIX trust anchors without a `KeyStore` so FIPS JVMs work [PR [#4193](https://redirect.github.com/pgjdbc/pgjdbc/issues/4193)]([pgjdbc/pgjdbc#4193](https://redirect.github.com/pgjdbc/pgjdbc/pull/4193)) > * fix: use `gssResponseTimeout` rather than `sslResponseTimeout` for GSS connections [PR [#4076](https://redirect.github.com/pgjdbc/pgjdbc/issues/4076)]([pgjdbc/pgjdbc#4076](https://redirect.github.com/pgjdbc/pgjdbc/pull/4076)) > * fix: skip the autosave savepoint for `SET LOCAL` / `SET SESSION TRANSACTION` [PR [#4203](https://redirect.github.com/pgjdbc/pgjdbc/issues/4203)]([pgjdbc/pgjdbc#4203](https://redirect.github.com/pgjdbc/pgjdbc/pull/4203)) > * fix: do not throw `AssertionError` from `BatchResultHandler` on a closed connection [PR [#4187](https://redirect.github.com/pgjdbc/pgjdbc/issues/4187)]([pgjdbc/pgjdbc#4187](https://redirect.github.com/pgjdbc/pgjdbc/pull/4187)) > * fix: reject `SQL_TSI_FRAC_SECOND` with an explicit, explained error [PR [#4229](https://redirect.github.com/pgjdbc/pgjdbc/issues/4229)]([pgjdbc/pgjdbc#4229](https://redirect.github.com/pgjdbc/pgjdbc/pull/4229)) > * fix: reject a null URL in `Driver.acceptsURL` with a clear `NullPointerException` [PR [#4205](https://redirect.github.com/pgjdbc/pgjdbc/issues/4205)]([pgjdbc/pgjdbc#4205](https://redirect.github.com/pgjdbc/pgjdbc/pull/4205)) > * fix: reject overlong inputs in `NumberParser.getFastLong` instead of silently wrapping [PR [#4163](https://redirect.github.com/pgjdbc/pgjdbc/issues/4163)]([pgjdbc/pgjdbc#4163](https://redirect.github.com/pgjdbc/pgjdbc/pull/4163)) > * fix: reject out-of-range and NaN values in `PGInterval.setSeconds` [PR [#4194](https://redirect.github.com/pgjdbc/pgjdbc/issues/4194)]([pgjdbc/pgjdbc#4194](https://redirect.github.com/pgjdbc/pgjdbc/pull/4194)) > * fix: close the socket when `PgConnection` setup fails after connect [PR [#4161](https://redirect.github.com/pgjdbc/pgjdbc/issues/4161)]([pgjdbc/pgjdbc#4161](https://redirect.github.com/pgjdbc/pgjdbc/pull/4161)) > * fix: keep the `LazyCleanerImpl` cleanup task alive across a transient empty queue [PR [#4038](https://redirect.github.com/pgjdbc/pgjdbc/issues/4038)]([pgjdbc/pgjdbc#4038](https://redirect.github.com/pgjdbc/pgjdbc/pull/4038)) ... (truncated) Commits * [`3297557`](pgjdbc/pgjdbc@3297557) docs: add 42.7.13 release changelog ([#4270](https://redirect.github.com/pgjdbc/pgjdbc/issues/4270)) * [`d93d370`](pgjdbc/pgjdbc@d93d370) style: apply Autostyle to docs/ and .github/ * [`2e05ff9`](pgjdbc/pgjdbc@2e05ff9) build: check docs/ and .github/ formatting with Autostyle * [`b4a6087`](pgjdbc/pgjdbc@b4a6087) Adjust EditorConfig für Makefiles * [`725cebb`](pgjdbc/pgjdbc@725cebb) fix(jdbc): reject empty timestamp/timestamptz text with a clear error * [`23a1b0d`](pgjdbc/pgjdbc@23a1b0d) fix(scram): fail closed on channel-binding downgrade (no scram bump) * [`0b4077a`](pgjdbc/pgjdbc@0b4077a) Bump pgjdbc version from 42.7.12 to 42.7.13 ([#4269](https://redirect.github.com/pgjdbc/pgjdbc/issues/4269)) * [`394800a`](pgjdbc/pgjdbc@394800a) fix: flush LargeObject output stream before marking closed ([#4248](https://redirect.github.com/pgjdbc/pgjdbc/issues/4248)) * [`83780f1`](pgjdbc/pgjdbc@83780f1) Maintain consistency with the use of the word maintainer vs comitter ([#4234](https://redirect.github.com/pgjdbc/pgjdbc/issues/4234)) * [`d42cad5`](pgjdbc/pgjdbc@d42cad5) fix(jdbc): classify updatable result set by search\_path visibility * Additional commits viewable in [compare view](pgjdbc/pgjdbc@REL42.7.12...REL42.7.13) [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- Dependabot commands and options You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Fixes #4203.
Summary
PostgresType.deserializeBinary()threw"Binary deserialization for arrays not yet implemented"for all array types. The exception inPostgresNetworkExecutor.bindCommand()wrote an error response but returned before reading the Bind message's result-format section, leaving the channel misaligned. The main message loop then consumed those leftover bytes as message-type characters, deadlocking client and server on socket reads.PostgresType.deserializeBinaryArray:ndim+hasnull+elemOid+ per-dimension (size,lb) + per-element (elemLen,data). Element OID dispatch coversbool,int2/4/8,float4/8, and text-like types (default).PreparedStatement.setArray(...)now completes cleanly instead of hanging.Test plan
PostgresTypeTest: 151/151 pass - includes 5 new binary array unit tests (text[],int8[],int4[], empty array, array with null element) and an updated former "not yet implemented" test.PostgresProtocolIT: 72/72 pass - includes newpreparedStatementSetArrayTextDoesNotHangandpreparedStatementSetArrayLongDoesNotHangintegration tests exercising the exactconn.createArrayOf(...)+pst.setArray(...)path from the issue.PostgresWJdbcIT: 29/29 pass - no regressions in the broader JDBC suite.