diff --git a/packages/pg/lib/client.js b/packages/pg/lib/client.js index 2b13c1de7..e97f88839 100644 --- a/packages/pg/lib/client.js +++ b/packages/pg/lib/client.js @@ -438,6 +438,12 @@ class Client extends EventEmitter { if (activeQuery.name) { delete this.connection.submittedNamedStatements[activeQuery.name] } + // a FATAL error ends the session; the backend closes the socket and + // the client must not be handed out from a pool again. Set the flag + // before reporting so error handlers that release() see the dead client + if (msg.severity === 'FATAL' || msg.severityNonLocalized === 'FATAL') { + this._queryable = false + } activeQuery.handleError(msg, this.connection) } diff --git a/packages/pg/test/unit/client/fatal-session-tests.js b/packages/pg/test/unit/client/fatal-session-tests.js new file mode 100644 index 000000000..42c2834d4 --- /dev/null +++ b/packages/pg/test/unit/client/fatal-session-tests.js @@ -0,0 +1,43 @@ +'use strict' +const helper = require('./test-helper') +const Query = require('../../../lib/query') +const assert = require('assert') + +const suite = new helper.Suite() + +suite.test('marks client not queryable when an active query gets a FATAL error', function (done) { + const client = helper.client() + assert.equal(client._queryable, true) + client.connection.emit('readyForQuery') + + client.query( + new Query({ + text: 'select pg_sleep(30)', + callback: function (err) { + assert.equal(err.severity, 'FATAL') + assert.equal(client._queryable, false) + done() + }, + }) + ) + + client.connection.emit('errorMessage', { severity: 'FATAL', code: '57P01' }) +}) + +suite.test('keeps client queryable for a non-FATAL error', function (done) { + const client = helper.client() + client.connection.emit('readyForQuery') + + client.query( + new Query({ + text: 'select 1', + callback: function (err) { + assert.equal(err.severity, 'ERROR') + assert.equal(client._queryable, true) + done() + }, + }) + ) + + client.connection.emit('errorMessage', { severity: 'ERROR', code: '42601' }) +})