@@ -43,18 +43,33 @@ if (!connectionString) {
4343}
4444
4545/**
46- * `fetch_types: false` skips postgres.js's `pg_catalog.pg_type` roundtrip, which
47- * it otherwise runs on every new connection before that connection's first query.
48- * It builds array parsers only — scalar types (including `jsonb` and pgvector)
49- * are unaffected — and Drizzle already parses this schema's `text[]` columns
50- * itself, so the fetch is pure connection-setup latency.
46+ * `fetch_types: false` skips postgres.js's `pg_catalog.pg_type` roundtrip, which it
47+ * otherwise runs on every new connection before that connection's first query.
5148 *
52- * The one behavior this changes: a raw `db.execute` that projects an array-typed
53- * column yields the wire form `'{a,b}'` rather than `['a','b']`, since nothing maps
54- * the result. Verified by differential test that Drizzle-typed selects and
55- * `.returning()` are unaffected — `PgArray.mapFromDriverValue` parses the wire form
56- * itself, and writes never reach the array serializer because Drizzle serializes
57- * arrays before binding.
49+ * That roundtrip populates the array type map, which postgres.js uses in BOTH
50+ * directions, for every array type — not just `text[]`. Disabling it has two
51+ * consequences on every client built from these options (the primary, the replica,
52+ * and every `dbFor()` sub-pool):
53+ *
54+ * 1. Reads: a raw `db.execute` projecting an array column yields the wire form
55+ * `'{a,b}'`, not `['a','b']`. Drizzle-typed selects and `.returning()` are
56+ * unaffected — `PgArray.mapFromDriverValue` parses the wire form itself.
57+ * 2. Writes: a JS array bound as a SINGLE parameter fails at execution with
58+ * `22P02 Array value must start with "{"` — there is no serializer to build the
59+ * literal, and neither `prepare: false` nor `sql.array()` avoids it. Drizzle-typed
60+ * column writes ARE safe (`PgArray.mapToDriverValue` stringifies first), as are
61+ * `inArray`/`${jsArray}` in a drizzle `sql` template (both expand to scalar binds).
62+ * Raw binds are NOT: never write `sql.param(someArray)`. Pass an expanded list
63+ * (`IN ${ids}`) or an explicit `ARRAY[${sql.join(...)}]::text[]` of scalars.
64+ *
65+ * Scalar types — including `jsonb`, pgvector, enums and ranges — are unaffected.
66+ *
67+ * Note postgres.js's OWN `sql` tag has the opposite semantics: it binds `${array}`
68+ * as one array parameter. `packages/db/scripts/migrate.ts` deliberately omits
69+ * `fetch_types` for that reason; see the note there before sharing these options.
70+ *
71+ * Pinned by apps/sim/lib/execution/payloads/prune-metadata-sql.test.ts, which renders
72+ * the real statements and asserts no bind parameter is an array.
5873 */
5974const poolOptions = {
6075 prepare : false ,
0 commit comments