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
72 changes: 49 additions & 23 deletions async_postgres/pg_client.nim
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ template queryRecvLoop(
cachedColOids: seq[int32],
qr: var QueryResult,
timeout: Duration = ZeroDuration,
reuseBuffer: bool = true,
) =
var queryError: ref PgQueryError

Expand All @@ -390,14 +391,19 @@ template queryRecvLoop(
for i in 0 ..< qr.fields.len:
qr.fields[i].formatCode = cachedColFmts[i]
if qr.fields.len > 0:
if conn.rowDataBuf != nil:
conn.rowDataBuf = conn.rowDataBuf.reuseRowData(
int16(qr.fields.len), cachedColFmts, cachedColOids
)
if reuseBuffer:
if conn.rowDataBuf != nil:
conn.rowDataBuf = conn.rowDataBuf.reuseRowData(
int16(qr.fields.len), cachedColFmts, cachedColOids
)
else:
conn.rowDataBuf =
newRowData(int16(qr.fields.len), cachedColFmts, cachedColOids)
conn.rowDataBuf.fields = qr.fields
qr.data = conn.rowDataBuf
else:
conn.rowDataBuf = newRowData(int16(qr.fields.len), cachedColFmts, cachedColOids)
conn.rowDataBuf.fields = qr.fields
qr.data = conn.rowDataBuf
qr.data = newRowData(int16(qr.fields.len), cachedColFmts, cachedColOids)
qr.data.fields = qr.fields

block recvLoop:
while true:
Expand Down Expand Up @@ -427,12 +433,17 @@ template queryRecvLoop(
cf[i] = resultFormats[i]
else:
qr.fields = msg.fields
if conn.rowDataBuf != nil:
conn.rowDataBuf = conn.rowDataBuf.reuseRowData(int16(qr.fields.len), cf, co)
if reuseBuffer:
if conn.rowDataBuf != nil:
conn.rowDataBuf =
conn.rowDataBuf.reuseRowData(int16(qr.fields.len), cf, co)
else:
conn.rowDataBuf = newRowData(int16(qr.fields.len), cf, co)
conn.rowDataBuf.fields = qr.fields
qr.data = conn.rowDataBuf
else:
conn.rowDataBuf = newRowData(int16(qr.fields.len), cf, co)
conn.rowDataBuf.fields = qr.fields
qr.data = conn.rowDataBuf
qr.data = newRowData(int16(qr.fields.len), cf, co)
qr.data.fields = qr.fields
of bmkNoData:
discard
of bmkCommandComplete:
Expand Down Expand Up @@ -519,8 +530,18 @@ proc queryImpl(

var qr = QueryResult()
queryRecvLoop(
conn, sql, effectiveResultFormats, cacheHit, cacheMiss, stmtName, cachedFields,
cachedColFmts, cachedColOids, qr, timeout,
conn,
sql,
effectiveResultFormats,
cacheHit,
cacheMiss,
stmtName,
cachedFields,
cachedColFmts,
cachedColOids,
qr,
timeout,
reuseBuffer = false,
)
return qr

Expand Down Expand Up @@ -580,8 +601,18 @@ proc queryImpl(

var qr = QueryResult()
queryRecvLoop(
conn, sql, effectiveResultFormats, cacheHit, cacheMiss, stmtName, cachedFields,
cachedColFmts, cachedColOids, qr, timeout,
conn,
sql,
effectiveResultFormats,
cacheHit,
cacheMiss,
stmtName,
cachedFields,
cachedColFmts,
cachedColOids,
qr,
timeout,
reuseBuffer = false,
)
return qr

Expand Down Expand Up @@ -1116,13 +1147,8 @@ proc executeImpl(
for i in 0 ..< qr.fields.len:
colFmts[i] = qr.fields[i].formatCode
colOids[i] = qr.fields[i].typeOid
if conn.rowDataBuf != nil:
conn.rowDataBuf =
conn.rowDataBuf.reuseRowData(int16(qr.fields.len), colFmts, colOids)
else:
conn.rowDataBuf = newRowData(int16(qr.fields.len), colFmts, colOids)
conn.rowDataBuf.fields = qr.fields
qr.data = conn.rowDataBuf
qr.data = newRowData(int16(qr.fields.len), colFmts, colOids)
qr.data.fields = qr.fields
var queryError: ref PgQueryError

block recvLoop:
Expand Down
15 changes: 15 additions & 0 deletions tests/test_e2e.nim
Original file line number Diff line number Diff line change
Expand Up @@ -4749,6 +4749,21 @@ suite "E2E: Convenience Query Methods":

waitFor t()

test "query Row survives subsequent queries (lifetime bug)":
proc t() {.async.} =
let conn = await connect(plainConfig())
let qr1 = await conn.query("SELECT 'x'")
let qr2 = await conn.query("SELECT 'y'")
doAssert qr1.rowCount == 1
doAssert qr2.rowCount == 1
let row1 = Row(data: qr1.data, rowIdx: 0)
let row2 = Row(data: qr2.data, rowIdx: 0)
doAssert row1.getStr(0) == "x", "qr1 data was invalidated by qr2"
doAssert row2.getStr(0) == "y"
await conn.close()

waitFor t()

test "pool queryOne":
proc t() {.async.} =
let pool = await newPool(initPoolConfig(plainConfig(), minSize = 1, maxSize = 2))
Expand Down
Loading