diff --git a/packages/pg/lib/query.js b/packages/pg/lib/query.js index 3b93cb5ba..6d8838eda 100644 --- a/packages/pg/lib/query.js +++ b/packages/pg/lib/query.js @@ -239,7 +239,10 @@ class Query extends EventEmitter { connection.close({ type: 'S', name: this.name }) connection.sync() - this.handleError(err, connection) + // defer the error until readyForQuery so the query settles exactly + // once; reporting it here would let handleReadyForQuery settle the + // same query again as a success when the server answers our sync + this._canceledDueToError = err return } diff --git a/packages/pg/test/unit/client/throw-in-bind-tests.js b/packages/pg/test/unit/client/throw-in-bind-tests.js index 8b460b9e4..1c5c6e624 100644 --- a/packages/pg/test/unit/client/throw-in-bind-tests.js +++ b/packages/pg/test/unit/client/throw-in-bind-tests.js @@ -52,6 +52,8 @@ suite.test('calls callback with error when bind throws', function (done) { }, }) ) + // the server answers the sync sent after the failed bind + con.emit('readyForQuery') }) suite.test('emits error event when bind throws (no callback)', function (done) { @@ -67,6 +69,7 @@ suite.test('emits error event when bind throws (no callback)', function (done) { done() }) client.query(query) + con.emit('readyForQuery') }) suite.test('send close when bind throws', function (done) { @@ -83,4 +86,24 @@ suite.test('send close when bind throws', function (done) { }, }) ) + con.emit('readyForQuery') +}) + +suite.test('settles the query exactly once when bind throws', function (done) { + const { client, con } = setupClient() + con.emit('readyForQuery') + let calls = 0 + client.query( + new Query({ + text: 'select $1', + values: ['x'], + callback: function () { + calls++ + }, + }) + ) + // the server answers the sync sent after the failed bind + con.emit('readyForQuery') + assert.equal(calls, 1, 'callback should be called exactly once') + done() })