Skip to content
Merged
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: 5 additions & 0 deletions async_postgres/pg_client/cursor.nim
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ proc openCursorImpl(

proc fetchNextImpl(cursor: Cursor): Future[seq[Row]] {.async.} =
let conn = cursor.conn
if conn.state == csClosed:
raise newException(PgConnectionError, "Connection is closed")
let rd = newRowData(int16(cursor.fields.len), cursor.colFormats, cursor.colTypeOids)
rd.fields = cursor.fields
var rowCount: int32 = 0
Expand Down Expand Up @@ -201,6 +203,9 @@ proc fetchNext*(cursor: Cursor): Future[seq[Row]] {.async.} =
## Fetch the next chunk of rows from the cursor.
## Returns an empty seq when the cursor is exhausted.
## On timeout, the connection is marked csClosed (protocol out of sync).
let conn = cursor.conn
if conn.state == csClosed:
raise newException(PgConnectionError, "Connection is closed")
if cursor.bufferedCount > 0:
result = newSeq[Row](cursor.bufferedCount)
for i in 0 ..< cursor.bufferedCount:
Expand Down
15 changes: 15 additions & 0 deletions tests/test_abandonment_e2e.nim
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,21 @@ suite "E2E: Cursor lifecycle invariants":

waitFor t()

test "fetchNext after conn.close() raises PgConnectionError, not SIGSEGV":
proc t() {.async.} =
let conn = await connect(plainConfig())
let cursor =
await conn.openCursor("SELECT i FROM generate_series(1, 100) i", chunkSize = 10)
await conn.close()
var raised = false
try:
discard await cursor.fetchNext()
except PgConnectionError:
raised = true
doAssert raised, "fetchNext after close must raise PgConnectionError"

waitFor t()

test "openCursor with invalid SQL raises and leaves connection ready":
# Recovery path: ErrorResponse during openCursor drains Sync back to
# ReadyForQuery so the connection is reusable immediately.
Expand Down