Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion packages/pg-cursor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,10 @@ class Cursor extends EventEmitter {
})
}

if (!this.connection || this.state === 'done') {
// After an error the portal is already gone: the server discards it at the
// Sync handleError sends, or the connection itself is dead. There is nothing
// left to close, and no readyForQuery will follow a Close sent now.
if (!this.connection || this.state === 'done' || this.state === 'error') {
setImmediate(cb)
return promise
}
Expand Down
29 changes: 29 additions & 0 deletions packages/pg-cursor/test/close.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,35 @@ describe('close', function () {
})
})

it('can close a cursor after a query error', async function () {
const cursor = this.client.query(new Cursor('SELECT 1/0'))
// Close only once the error's readyForQuery has been handled, as a caller
// closing in a finally block after the rejection usually does.
const drained = new Promise((resolve) => this.client.once('drain', resolve))
await assert.rejects(cursor.read(10), /division by zero/)
await drained
await cursor.close()
const result = await this.client.query('SELECT 1 AS value')
assert.deepStrictEqual(result.rows, [{ value: 1 }])
})

it('can close a cursor after its connection is lost', async function () {
const client = this.client
client.on('error', () => {})
const cursor = client.query(new Cursor(text))
await cursor.read(10)
const ended = new Promise((resolve) => client.once('end', resolve))
const other = new pg.Client()
await other.connect()
try {
await other.query('SELECT pg_terminate_backend($1)', [client.processID])
} finally {
await other.end()
}
await ended
await cursor.close()
})

it('is a no-op to "close" the cursor before submitting it', function (done) {
const cursor = new Cursor(text)
cursor.close(done)
Expand Down
Loading