diff --git a/async_postgres/pg_client.nim b/async_postgres/pg_client.nim index 37244d1..23218aa 100644 --- a/async_postgres/pg_client.nim +++ b/async_postgres/pg_client.nim @@ -381,6 +381,7 @@ template queryRecvLoop( cachedColOids: seq[int32], qr: var QueryResult, timeout: Duration = ZeroDuration, + reuseBuffer: bool = true, ) = var queryError: ref PgQueryError @@ -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: @@ -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: @@ -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 @@ -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 @@ -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: diff --git a/tests/test_e2e.nim b/tests/test_e2e.nim index 4a2fe6e..d8397b6 100644 --- a/tests/test_e2e.nim +++ b/tests/test_e2e.nim @@ -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))