From 39cb4e28329c8063edea82f23c8825d9ad8f2335 Mon Sep 17 00:00:00 2001 From: Nitjsefnie Date: Sat, 26 Sep 2026 12:33:26 +0200 Subject: [PATCH] Store fetched array types before running the first query 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 #789 Co-Authored-By: Claude Opus 5.5 --- cf/src/connection.js | 6 ++++-- cjs/src/connection.js | 6 ++++-- cjs/tests/index.js | 7 +++++++ deno/src/connection.js | 6 ++++-- deno/tests/index.js | 7 +++++++ src/connection.js | 6 ++++-- tests/index.js | 7 +++++++ 7 files changed, 37 insertions(+), 8 deletions(-) diff --git a/cf/src/connection.js b/cf/src/connection.js index 8e79170..7ff5b78 100644 --- a/cf/src/connection.js +++ b/cf/src/connection.js @@ -769,7 +769,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose async function fetchArrayTypes() { needsTypes = false - const types = await new Query([` + const query = new Query([` select b.oid, b.typarray from pg_catalog.pg_type a left join pg_catalog.pg_type b on b.oid = a.typelem @@ -777,7 +777,9 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose group by b.oid, b.typarray order by b.oid `], [], execute) - types.forEach(({ oid, typarray }) => addArrayType(oid, typarray)) + const resolve = query.resolve + query.resolve = types => (types.forEach(({ oid, typarray }) => addArrayType(oid, typarray)), resolve(types)) + await query } function addArrayType(oid, typarray) { diff --git a/cjs/src/connection.js b/cjs/src/connection.js index 07f6716..00870cd 100644 --- a/cjs/src/connection.js +++ b/cjs/src/connection.js @@ -767,7 +767,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose async function fetchArrayTypes() { needsTypes = false - const types = await new Query([` + const query = new Query([` select b.oid, b.typarray from pg_catalog.pg_type a left join pg_catalog.pg_type b on b.oid = a.typelem @@ -775,7 +775,9 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose group by b.oid, b.typarray order by b.oid `], [], execute) - types.forEach(({ oid, typarray }) => addArrayType(oid, typarray)) + const resolve = query.resolve + query.resolve = types => (types.forEach(({ oid, typarray }) => addArrayType(oid, typarray)), resolve(types)) + await query } function addArrayType(oid, typarray) { diff --git a/cjs/tests/index.js b/cjs/tests/index.js index 85d1aa4..725c435 100644 --- a/cjs/tests/index.js +++ b/cjs/tests/index.js @@ -154,6 +154,13 @@ t('Escape in arrays', async() => ['Hello "you",c:\\windows', (await sql`select ${ sql.array(['Hello "you"', 'c:\\windows']) } as x`)[0].x.join(',')] ) +t('Array in first query of new client', async() => { + const sql = postgres(options) + const x = (await sql`select ${ sql.array([1, 2]) }::int[] as x`)[0].x + await sql.end() + return ['1,2', x.join()] +}) + t('Escapes', async() => { return ['hej"hej', Object.keys((await sql`select 1 as ${ sql('hej"hej') }`)[0])[0]] }) diff --git a/deno/src/connection.js b/deno/src/connection.js index 796725d..a23701b 100644 --- a/deno/src/connection.js +++ b/deno/src/connection.js @@ -770,7 +770,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose async function fetchArrayTypes() { needsTypes = false - const types = await new Query([` + const query = new Query([` select b.oid, b.typarray from pg_catalog.pg_type a left join pg_catalog.pg_type b on b.oid = a.typelem @@ -778,7 +778,9 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose group by b.oid, b.typarray order by b.oid `], [], execute) - types.forEach(({ oid, typarray }) => addArrayType(oid, typarray)) + const resolve = query.resolve + query.resolve = types => (types.forEach(({ oid, typarray }) => addArrayType(oid, typarray)), resolve(types)) + await query } function addArrayType(oid, typarray) { diff --git a/deno/tests/index.js b/deno/tests/index.js index cc2a251..a3d4ed2 100644 --- a/deno/tests/index.js +++ b/deno/tests/index.js @@ -156,6 +156,13 @@ t('Escape in arrays', async() => ['Hello "you",c:\\windows', (await sql`select ${ sql.array(['Hello "you"', 'c:\\windows']) } as x`)[0].x.join(',')] ) +t('Array in first query of new client', async() => { + const sql = postgres(options) + const x = (await sql`select ${ sql.array([1, 2]) }::int[] as x`)[0].x + await sql.end() + return ['1,2', x.join()] +}) + t('Escapes', async() => { return ['hej"hej', Object.keys((await sql`select 1 as ${ sql('hej"hej') }`)[0])[0]] }) diff --git a/src/connection.js b/src/connection.js index 10ab1bb..3e79bd0 100644 --- a/src/connection.js +++ b/src/connection.js @@ -767,7 +767,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose async function fetchArrayTypes() { needsTypes = false - const types = await new Query([` + const query = new Query([` select b.oid, b.typarray from pg_catalog.pg_type a left join pg_catalog.pg_type b on b.oid = a.typelem @@ -775,7 +775,9 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose group by b.oid, b.typarray order by b.oid `], [], execute) - types.forEach(({ oid, typarray }) => addArrayType(oid, typarray)) + const resolve = query.resolve + query.resolve = types => (types.forEach(({ oid, typarray }) => addArrayType(oid, typarray)), resolve(types)) + await query } function addArrayType(oid, typarray) { diff --git a/tests/index.js b/tests/index.js index 845c6ce..855d101 100644 --- a/tests/index.js +++ b/tests/index.js @@ -154,6 +154,13 @@ t('Escape in arrays', async() => ['Hello "you",c:\\windows', (await sql`select ${ sql.array(['Hello "you"', 'c:\\windows']) } as x`)[0].x.join(',')] ) +t('Array in first query of new client', async() => { + const sql = postgres(options) + const x = (await sql`select ${ sql.array([1, 2]) }::int[] as x`)[0].x + await sql.end() + return ['1,2', x.join()] +}) + t('Escapes', async() => { return ['hej"hej', Object.keys((await sql`select 1 as ${ sql('hej"hej') }`)[0])[0]] })