From b97070a5b60f51543d95efcb163be23c61c40082 Mon Sep 17 00:00:00 2001 From: Nigro Simone Date: Sun, 13 Sep 2026 12:30:04 +0200 Subject: [PATCH 1/3] fix(pg): run a named statement with an empty text more than once --- packages/pg/lib/query.js | 7 ++++++- .../test/integration/client/empty-query-tests.js | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/packages/pg/lib/query.js b/packages/pg/lib/query.js index 6b9214199..7d88b9d36 100644 --- a/packages/pg/lib/query.js +++ b/packages/pg/lib/query.js @@ -183,7 +183,12 @@ class Query extends EventEmitter { } hasBeenParsed(connection) { - return this.name && (connection.parsedStatements[this.name] || connection.submittedNamedStatements[this.name]) + // by presence, not truth: a named statement with an empty text is parsed all the same + return ( + this.name && + (connection.parsedStatements[this.name] !== undefined || + connection.submittedNamedStatements[this.name] !== undefined) + ) } handlePortalSuspended(connection) { diff --git a/packages/pg/test/integration/client/empty-query-tests.js b/packages/pg/test/integration/client/empty-query-tests.js index 61d46512e..069422635 100644 --- a/packages/pg/test/integration/client/empty-query-tests.js +++ b/packages/pg/test/integration/client/empty-query-tests.js @@ -19,3 +19,17 @@ suite.test('callback supported', function (done) { client.end(done) }) }) + +// the name was recorded as parsed with its empty text, and then read as not parsed at all, +// so the second run prepared it again and the server refused the duplicate +suite.test('a named empty statement can run more than once', async function () { + const client = helper.client() + try { + for (let i = 0; i < 2; i++) { + const result = await client.query({ text: '', name: 'empty' }) + assert.empty(result.rows) + } + } finally { + await client.end() + } +}) From aa2961cc844705e97aa015dbf7ee9a2f7886439c Mon Sep 17 00:00:00 2001 From: Nigro Simone Date: Sun, 13 Sep 2026 12:44:03 +0200 Subject: [PATCH 2/3] fix(pg): run a named statement with an empty text more than once on the native client too --- packages/pg/lib/native/query.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/pg/lib/native/query.js b/packages/pg/lib/native/query.js index 8cb561979..bae7a17c9 100644 --- a/packages/pg/lib/native/query.js +++ b/packages/pg/lib/native/query.js @@ -136,8 +136,9 @@ NativeQuery.prototype.submit = function (client) { const values = (this.values || []).map(utils.prepareValue) // check if the client has already executed this named query - // if so...just execute it again - skip the planning phase - if (client.namedQueries[this.name]) { + // if so...just execute it again - skip the planning phase. By presence, not truth: a + // named statement with an empty text is prepared all the same + if (client.namedQueries[this.name] !== undefined) { if (this.text && client.namedQueries[this.name] !== this.text) { const err = new Error(`Prepared statements must be unique - '${this.name}' was used for a different statement`) return after(err) From f574848d23c54d371154e4bb124ea98ada8016d8 Mon Sep 17 00:00:00 2001 From: Nigro Simone Date: Sun, 13 Sep 2026 12:55:33 +0200 Subject: [PATCH 3/3] ci: re-run after a pg-native crash in the many connections test