Skip to content

Fix schemas and Bind formats for SQL cursor FETCH - #1

Merged
tonyalaribe merged 3 commits into
timefusion-upgrade-55from
fix/fetch-result-schema
Oct 21, 2026
Merged

tonyalaribe merged 3 commits into
timefusion-upgrade-55from
fix/fetch-result-schema

Conversation

@tonyalaribe

@tonyalaribe tonyalaribe commented Oct 21, 2026 •

Copy link
Copy Markdown

Extended FETCH describes no columns for SQL-declared cursors, then returns a populated DataRow. Newer PostgreSQL clients reject the field-count mismatch. The cursor also encodes rows as text at DECLARE time, preventing Bind from selecting binary output.

Retain the cursor input as a streaming Arrow source and encode each FETCH with the requested format. The portal's retained scan owns that source; the per-session schema registry contains weak references. Limited FETCH keeps the remainder of its current batch, and unlimited FETCH streams through the existing encoder. Parse describes the actual result schema. Reusing a prepared FETCH after a cursor changes result type returns SQLSTATE 0A000 instead of malformed rows.

The new formatted hook delegates to the existing hook by default, preserving existing custom hooks. No dependency, persisted format, or codec implementation changes.

Consumer validation in TimeFusion with tokio-postgres 0.7.18:

  • Original full run fails with DataRow field count mismatch.
  • The strengthened real-TCP regression decodes bigint and array values, switches between binary and simple/text FETCH, checks FETCH 0 and exhaustion, checks cancellation and connection reuse, and rejects changed cached result schemas.
  • Removing the registered source table leaves the open cursor readable. CLOSE releases its gated input, verified through a weak reference.
  • Forcing text encoding makes the value-decoding guard fail. Restoring the correction passes all 109 selected protocol/streaming tests.
  • cargo lint passes in the consumer. Full release signoff follows the immutable source pin; it is not claimed by these targeted results.

PostgreSQL defines Bind as the format selector for extended FETCH: https://www.postgresql.org/docs/16/sql-declare.html

Local evidence: /tmp/timefusion-advisory-refresh-2026-10-21/cursor-{protocol-final,format-red,lifetime,lint}.log. The maintained consumer regression is in src/server/mod.rs, wire_streams_cancels_and_reuses_connection. The draft remains open until integrated validation is complete.

Fork fixture follow-up (1388ea3): consume each returned row stream before issuing the next FETCH. The maintained unit guards now assert exact first/remaining/exhausted counts instead of response type alone. No assertion or client validation is removed. Standalone fork nextest runs pass all 31 default-feature tests and all 34 pgvector tests. These runs use the fork registry graph; the separate consumer checks exercise TimeFusion's pinned DataFusion and vendored pgwire graph.

The consumer now pins immutable Git revision 1388ea37ec8eeefd13b07771f8d0052f164ae7f1. Its integrated release gate passes on frozen TimeFusion commit d8e3f68e: 2,802 native tests, 16 doctests, PGWire smoke, all 85 active e2e tests, formatting, and cargo lint. Seventeen native tests and two e2e tests retain their existing skips. The production Linux image also passes its real PGWire smoke and is published by source fingerprint. No production rollout is claimed.

All 14 current-head fork CI jobs pass, including the clean Linux build and base, pgvector, and postgis integrations. Final consumer evidence: /tmp/timefusion-advisory-refresh-2026-10-21/final-full-signoff.log and final-frozen-inputs.json.

@tonyalaribe
tonyalaribe marked this pull request as ready for review October 21, 2026 14:03
@tonyalaribe
tonyalaribe merged commit 3fa84a1 into timefusion-upgrade-55 Oct 21, 2026
14 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.

1 participant