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
1 change: 1 addition & 0 deletions src/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose

function errored(err) {
stream && (stream.destroy(err), stream = null)
final && (final(err), final = null)
query && queryError(query, err)
initial && (queryError(initial, err), initial = null)
}
Expand Down
31 changes: 31 additions & 0 deletions tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2038,6 +2038,37 @@ t('Copy from abort', async() => {
]
})

t('Copy from settles instead of hanging when the server rejects the data', { timeout: 2 }, async() => {
await sql`create table test (x int, y int)`

let error
try {
await sql.begin(async sql => {
const writable = await sql`COPY test FROM STDIN`.writable()
await new Promise((resolve, reject) => {
writable.on('error', reject)
writable.on('finish', resolve)
// 3 columns in the row, 2 in the table -> server errors mid copy,
// after the writable's final() has already fired (.end() below)
writable.end('1\t2\t3\n')
})
})
} catch (err) {
error = err
}

const idleInTransaction = await sql`
select count(*)::int as count from pg_stat_activity
where state = 'idle in transaction (aborted)'
`

return [
true,
!!error && error.message.includes('extra data') && idleInTransaction[0].count === 0,
await sql`drop table test`
]
})

t('multiple queries before connect', async() => {
const sql = postgres({ ...options, max: 2 })
const xs = await Promise.all([
Expand Down