Skip to content

Store fetched array types before running the first query - #1230

Open
Nitjsefnie wants to merge 1 commit into
porsager:masterfrom
Nitjsefnie-OSC:fix-first-query-array-types
Open

Nitjsefnie wants to merge 1 commit into
porsager:masterfrom
Nitjsefnie-OSC:fix-first-query-array-types

Conversation

@Nitjsefnie

Copy link
Copy Markdown

Summary

A new connection built its first query before the array types it had just fetched were stored, so an sql.array() parameter in that query was bound as its element type. This fills typeArrayMap inside the types query's resolve, which is the fetchState() idiom, so the map is populated before ReadyForQuery goes on to execute(initial).

Related Issues and Pull Requests

Fixes #789
Relates to #1081

Changes

  • src/connection.js fetchArrayTypes(): wraps the types query's resolve so that addArrayType runs synchronously when ReadyForQuery resolves it. Before, it ran in the await continuation, which is queued as a microtask after execute(initial) has already built the opening query against an empty map. Startup sequencing and the rejection path are unchanged: a failing types query still rejects fetchArrayTypes()'s promise exactly as before. Fixes #789: Wait for DB type initialization before querying #1081 fixes the same bug by deferring execute(initial) behind a promise on every connection start instead.
  • tests/index.js: new test "Array in first query of new client". It creates a fresh client, whose typeArrayMap is empty, and sends sql.array([1, 2])::int[] as its first query. The existing array tests use the shared, already-warmed client, which is why they pass on the unfixed code.
  • cjs/, cf/, deno/: regenerated with npm run build, keeping only the hunks for this change. A fresh build at master also rewrites output that 411429e and 9afd16d never regenerated: the parameters[i] = x line in each connection.js, and the retry-serialization tests in cjs/tests and deno/tests. That output is left out of this PR.

Testing

  • The new test fails on unmodified src/ with 22P02 malformed array literal: "1,2" and passes with the fix.
  • A variant that fills the map in a queued microtask instead of synchronously also fails the test.
  • A variant of the test that uses the shared client passes on the unfixed code, which confirms the fresh client is what makes the test sensitive.
  • The full npm test (esm, cjs, deno) passes on Node 24 against PostgreSQL 17, configured like CI (pg_hba.conf, ssl, wal_level = logical, max_prepared_transactions). Only one cell of the CI matrix was run.
  • Pools with max > 1 fail the same way on unfixed code: with three concurrent cold queries on max: 10, exactly one fails in every run, and which one varies. With the fix, all three succeed in five runs out of five. There is no separate pooled test, because every connection goes through the same fetchArrayTypes() that the new test covers.

Footer

Generated by Claude Opus 5.5 (brief, implementation, review)

fetchArrayTypes() awaited the types query and only then filled
typeArrayMap. The types query's ReadyForQuery resolves it and, in the
same synchronous call, goes on to execute(initial), so a new
connection's first query was built while the map was still empty and
an sql.array() parameter was bound as its element type, e.g.
"malformed array literal" with an array cast. Fill the map inside the
query's resolve, like fetchState() does, so it is populated before the
initial query is built.

Fixes porsager#789

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

zakarlyya commented Sep 29, 2026 •

Copy link
Copy Markdown

We hit this 1–2k times a day on 3.4.4 (malformed array literal from sql.array in the first query on a new connection).

Would be great to see this merged @porsager Related: #789, #1081.

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.

Wrong inferred array types when invoking sql.array() for the first time.

2 participants