Skip to content

Decode binary-format parameters by their declared type in PgProtocolHandler - #754

Merged
brittleboye merged 3 commits into
Convex-Dev:developfrom
trsb-standards:fix-pgwire-binary-parameters
Oct 15, 2026
Merged

brittleboye merged 3 commits into
Convex-Dev:developfrom
trsb-standards:fix-pgwire-binary-parameters

Conversation

@trsb-standards

@trsb-standards trsb-standards commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Prepared statements from the PostgreSQL JDBC driver send numeric parameters in binary format. Binding those bytes with setBytes gives Calcite a byte string where it expects a number, so numeric inserts and updates fail.

Decode binary parameters using the type OID declared in Parse. Signed integers, floating-point values, booleans and text use the corresponding JDBC setters; OIDs are widened as unsigned 32-bit values, preserving values through 4294967295. Invalid fixed-width lengths return SQLSTATE 08P01. Unsupported or unspecified types retain the existing byte-array fallback.

Validation:

  • JDBC regression tests cover integer and floating-point inserts/updates, including repeated execution past the prepare threshold.
  • PgBinaryParameterTest covers unsigned OID boundaries, signed INT4 boundaries and malformed OID lengths before binding.
  • ./mvnw -B -T1C test -pl convex-db -am passed (database suite: 188 tests, 2 existing skips).
  • After merging current develop, ./mvnw -B clean install passed across all modules on JDK 25 on retry. The first attempt failed the unchanged core BlobsParamTest.testSlice identity assertion (Inconsistent Hash on 0x); the isolated test passed, and the full retry passed.

The separate extended-query RowDescription issue remains covered by #755; this PR does not enable the two SELECT tests skipped for that issue.

…andler

The PostgreSQL JDBC driver sends numeric parameters in binary format: setLong
arrives as the 8 bytes of an int8. Bind passed every binary parameter to
setBytes, so Calcite received a byte string where it expected a number and the
statement failed with "ByteString cannot be cast to class java.lang.Number".

Decode a binary parameter by the type OID the client declared in Parse (int2,
int4, int8, oid, float4, float8, bool and the text types). Types without a
decoding, and parameters with no declared type, are bound as bytes as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@trsb-standards

Copy link
Copy Markdown
Contributor Author

The failing build (21) job is AnyValuePropertyTest.dataRoundTrip in convex-core, with the generated argument #[b0]. This change only touches convex-db, and build (25) passed on the same commit.

It reproduces on an untouched develop without the property test's randomness. ByteFlagGen can produce ByteFlag.create(0) or ByteFlag.create(1). Those encode to b0 and b1, so they decode as CVMBool. The two are equal, but their hash codes differ, which is what the test's assertEquals(o.hashCode(), o2.hashCode()) trips over:

ByteFlag.create(0): ByteFlag prints #[b0], hashCode 1641429988 | decoded: CVMBool prints false, hashCode 1477057675 | equals true
ByteFlag.create(1): ByteFlag prints #[b1], hashCode 559160229  | decoded: CVMBool prints true,  hashCode -1477057676 | equals true

So the job fails whenever the generator happens to pick flag 0 or 1. A re-run should clear it here (I cannot trigger one). I can open a separate issue or pull request for the hash code mismatch if that is useful.

@brittleboye
brittleboye merged commit d27e743 into Convex-Dev:develop Oct 15, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants