Fix several memory leaks in the Postgres wrapper. (#20940)

(cherry picked from commit 5a848a0707)
This commit is contained in:
jfilby
2022-11-27 20:28:38 +02:00
committed by narimiran
parent 224319f787
commit d2de2e7be1
2 changed files with 27 additions and 16 deletions

View File

@@ -207,7 +207,8 @@ proc prepare*(db: DbConn; stmtName: string, query: SqlQuery;
dbError("parameter substitution expects \"$1\"")
var res = pqprepare(db, stmtName, query.string, int32(nParams), nil)
if pqResultStatus(res) != PGRES_COMMAND_OK: dbError(db)
return SqlPrepared(stmtName)
result = SqlPrepared(stmtName)
pqclear(res)
proc setRow(res: PPGresult, r: var Row, line, cols: int32) =
for col in 0'i32..cols-1:
@@ -474,12 +475,12 @@ proc getRow*(db: DbConn, query: SqlQuery,
## retrieves a single row. If the query doesn't return any rows, this proc
## will return a Row with empty strings for each column.
let res = setupQuery(db, query, args)
getRow(res)
result = getRow(res)
proc getRow*(db: DbConn, stmtName: SqlPrepared,
args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} =
let res = setupQuery(db, stmtName, args)
getRow(res)
result = getRow(res)
proc getAllRows(res: PPGresult): seq[Row] =
let N = pqntuples(res)
@@ -496,14 +497,14 @@ proc getAllRows*(db: DbConn, query: SqlQuery,
tags: [ReadDbEffect].} =
## executes the query and returns the whole result dataset.
let res = setupQuery(db, query, args)
getAllRows(res)
result = getAllRows(res)
proc getAllRows*(db: DbConn, stmtName: SqlPrepared,
args: varargs[string, `$`]): seq[Row] {.tags:
[ReadDbEffect].} =
## executes the prepared query and returns the whole result dataset.
let res = setupQuery(db, stmtName, args)
getAllRows(res)
result = getAllRows(res)
iterator rows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} =
@@ -529,7 +530,8 @@ proc getValue*(db: DbConn, query: SqlQuery,
## result dataset. Returns "" if the dataset contains no rows or the database
## value is NULL.
let res = setupQuery(db, query, args)
getValue(res)
result = getValue(res)
pqclear(res)
proc getValue*(db: DbConn, stmtName: SqlPrepared,
args: varargs[string, `$`]): string {.
@@ -538,7 +540,8 @@ proc getValue*(db: DbConn, stmtName: SqlPrepared,
## result dataset. Returns "" if the dataset contains no rows or the database
## value is NULL.
let res = setupQuery(db, stmtName, args)
getValue(res)
result = getValue(res)
pqclear(res)
proc tryInsertID*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): int64 {.
@@ -547,12 +550,14 @@ proc tryInsertID*(db: DbConn, query: SqlQuery,
## generated ID for the row or -1 in case of an error. For Postgre this adds
## `RETURNING id` to the query, so it only works if your primary key is
## named `id`.
var x = pqgetvalue(setupQuery(db, SqlQuery(string(query) & " RETURNING id"),
args), 0, 0)
let res = setupQuery(db, SqlQuery(string(query) & " RETURNING id"),
args)
var x = pqgetvalue(res, 0, 0)
if not isNil(x):
result = parseBiggestInt($x)
else:
result = -1
pqclear(res)
proc insertID*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): int64 {.
@@ -569,12 +574,14 @@ proc tryInsert*(db: DbConn, query: SqlQuery,pkName: string,
{.tags: [WriteDbEffect], since: (1, 3).}=
## executes the query (typically "INSERT") and returns the
## generated ID for the row or -1 in case of an error.
var x = pqgetvalue(setupQuery(db, SqlQuery(string(query) & " RETURNING " & pkName),
args), 0, 0)
let res = setupQuery(db, SqlQuery(string(query) & " RETURNING " & pkName),
args)
var x = pqgetvalue(res, 0, 0)
if not isNil(x):
result = parseBiggestInt($x)
else:
result = -1
pqclear(res)
proc insert*(db: DbConn, query: SqlQuery, pkName: string,
args: varargs[string, `$`]): int64

View File

@@ -2,6 +2,7 @@ import db_postgres, strutils
let db = open("localhost", "dom", "", "test")
db.exec(sql"DROP TABLE IF EXISTS myTable")
db.exec(sql("""CREATE TABLE myTable (
id integer PRIMARY KEY,
@@ -49,9 +50,12 @@ try:
doAssert false, "Exception expected"
except DbError:
let msg = getCurrentExceptionMsg().normalize
doAssert "expects" in msg
doAssert "?" in msg
doAssert "parameter substitution" in msg
info "DbError",
msg = $msg
doAssert "no parameter" in msg
doAssert "$1" in msg
doAssert db.getValue(sql("select filename from files where id = ?"), 1) == "hello.tmp"
@@ -315,11 +319,11 @@ db.exec(sql("""CREATE TABLE DICTIONARY(
var entry = "あっそ"
var definition = "(int) (See ああそうそう) oh, really (uninterested)/oh yeah?/hmmmmm"
discard db.getRow(
SqlQuery("INSERT INTO DICTIONARY(entry, definition) VALUES(\'$1\', \'$2\') RETURNING id" % [entry, definition]))
sql("INSERT INTO DICTIONARY(entry, definition) VALUES(?, ?) RETURNING id"), entry, definition)
doAssert db.getValue(sql"SELECT definition FROM DICTIONARY WHERE entry = ?", entry) == definition
entry = "Format string entry"
definition = "Format string definition"
db.exec(sql"INSERT INTO DICTIONARY(entry, definition) VALUES (?, ?)", entry, definition)
db.exec(SqlQuery("INSERT INTO DICTIONARY(entry, definition) VALUES (?, ?)"), entry, definition)
doAssert db.getValue(sql"SELECT definition FROM DICTIONARY WHERE entry = ?", entry) == definition
echo("All tests succeeded!")