Fix several memory leaks in the Postgres wrapper. (#20940)
This commit is contained in:
parent
f644f04654
commit
5a848a0707
2 changed files with 27 additions and 16 deletions
|
|
@ -201,7 +201,8 @@ proc prepare*(db: DbConn; stmtName: string, query: SqlQuery;
|
||||||
dbError("parameter substitution expects \"$1\"")
|
dbError("parameter substitution expects \"$1\"")
|
||||||
var res = pqprepare(db, stmtName, query.cstring, int32(nParams), nil)
|
var res = pqprepare(db, stmtName, query.cstring, int32(nParams), nil)
|
||||||
if pqResultStatus(res) != PGRES_COMMAND_OK: dbError(db)
|
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) =
|
proc setRow(res: PPGresult, r: var Row, line, cols: int32) =
|
||||||
for col in 0'i32..cols-1:
|
for col in 0'i32..cols-1:
|
||||||
|
|
@ -468,12 +469,12 @@ proc getRow*(db: DbConn, query: SqlQuery,
|
||||||
## retrieves a single row. If the query doesn't return any rows, this proc
|
## retrieves a single row. If the query doesn't return any rows, this proc
|
||||||
## will return a Row with empty strings for each column.
|
## will return a Row with empty strings for each column.
|
||||||
let res = setupQuery(db, query, args)
|
let res = setupQuery(db, query, args)
|
||||||
getRow(res)
|
result = getRow(res)
|
||||||
|
|
||||||
proc getRow*(db: DbConn, stmtName: SqlPrepared,
|
proc getRow*(db: DbConn, stmtName: SqlPrepared,
|
||||||
args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} =
|
args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} =
|
||||||
let res = setupQuery(db, stmtName, args)
|
let res = setupQuery(db, stmtName, args)
|
||||||
getRow(res)
|
result = getRow(res)
|
||||||
|
|
||||||
proc getAllRows(res: PPGresult): seq[Row] =
|
proc getAllRows(res: PPGresult): seq[Row] =
|
||||||
let N = pqntuples(res)
|
let N = pqntuples(res)
|
||||||
|
|
@ -490,14 +491,14 @@ proc getAllRows*(db: DbConn, query: SqlQuery,
|
||||||
tags: [ReadDbEffect].} =
|
tags: [ReadDbEffect].} =
|
||||||
## executes the query and returns the whole result dataset.
|
## executes the query and returns the whole result dataset.
|
||||||
let res = setupQuery(db, query, args)
|
let res = setupQuery(db, query, args)
|
||||||
getAllRows(res)
|
result = getAllRows(res)
|
||||||
|
|
||||||
proc getAllRows*(db: DbConn, stmtName: SqlPrepared,
|
proc getAllRows*(db: DbConn, stmtName: SqlPrepared,
|
||||||
args: varargs[string, `$`]): seq[Row] {.tags:
|
args: varargs[string, `$`]): seq[Row] {.tags:
|
||||||
[ReadDbEffect].} =
|
[ReadDbEffect].} =
|
||||||
## executes the prepared query and returns the whole result dataset.
|
## executes the prepared query and returns the whole result dataset.
|
||||||
let res = setupQuery(db, stmtName, args)
|
let res = setupQuery(db, stmtName, args)
|
||||||
getAllRows(res)
|
result = getAllRows(res)
|
||||||
|
|
||||||
iterator rows*(db: DbConn, query: SqlQuery,
|
iterator rows*(db: DbConn, query: SqlQuery,
|
||||||
args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} =
|
args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} =
|
||||||
|
|
@ -523,7 +524,8 @@ proc getValue*(db: DbConn, query: SqlQuery,
|
||||||
## result dataset. Returns "" if the dataset contains no rows or the database
|
## result dataset. Returns "" if the dataset contains no rows or the database
|
||||||
## value is NULL.
|
## value is NULL.
|
||||||
let res = setupQuery(db, query, args)
|
let res = setupQuery(db, query, args)
|
||||||
getValue(res)
|
result = getValue(res)
|
||||||
|
pqclear(res)
|
||||||
|
|
||||||
proc getValue*(db: DbConn, stmtName: SqlPrepared,
|
proc getValue*(db: DbConn, stmtName: SqlPrepared,
|
||||||
args: varargs[string, `$`]): string {.
|
args: varargs[string, `$`]): string {.
|
||||||
|
|
@ -532,7 +534,8 @@ proc getValue*(db: DbConn, stmtName: SqlPrepared,
|
||||||
## result dataset. Returns "" if the dataset contains no rows or the database
|
## result dataset. Returns "" if the dataset contains no rows or the database
|
||||||
## value is NULL.
|
## value is NULL.
|
||||||
let res = setupQuery(db, stmtName, args)
|
let res = setupQuery(db, stmtName, args)
|
||||||
getValue(res)
|
result = getValue(res)
|
||||||
|
pqclear(res)
|
||||||
|
|
||||||
proc tryInsertID*(db: DbConn, query: SqlQuery,
|
proc tryInsertID*(db: DbConn, query: SqlQuery,
|
||||||
args: varargs[string, `$`]): int64 {.
|
args: varargs[string, `$`]): int64 {.
|
||||||
|
|
@ -541,12 +544,14 @@ proc tryInsertID*(db: DbConn, query: SqlQuery,
|
||||||
## generated ID for the row or -1 in case of an error. For Postgre this adds
|
## 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
|
## `RETURNING id` to the query, so it only works if your primary key is
|
||||||
## named `id`.
|
## named `id`.
|
||||||
var x = pqgetvalue(setupQuery(db, SqlQuery(string(query) & " RETURNING id"),
|
let res = setupQuery(db, SqlQuery(string(query) & " RETURNING id"),
|
||||||
args), 0, 0)
|
args)
|
||||||
|
var x = pqgetvalue(res, 0, 0)
|
||||||
if not isNil(x):
|
if not isNil(x):
|
||||||
result = parseBiggestInt($x)
|
result = parseBiggestInt($x)
|
||||||
else:
|
else:
|
||||||
result = -1
|
result = -1
|
||||||
|
pqclear(res)
|
||||||
|
|
||||||
proc insertID*(db: DbConn, query: SqlQuery,
|
proc insertID*(db: DbConn, query: SqlQuery,
|
||||||
args: varargs[string, `$`]): int64 {.
|
args: varargs[string, `$`]): int64 {.
|
||||||
|
|
@ -563,12 +568,14 @@ proc tryInsert*(db: DbConn, query: SqlQuery,pkName: string,
|
||||||
{.tags: [WriteDbEffect], since: (1, 3).}=
|
{.tags: [WriteDbEffect], since: (1, 3).}=
|
||||||
## executes the query (typically "INSERT") and returns the
|
## executes the query (typically "INSERT") and returns the
|
||||||
## generated ID for the row or -1 in case of an error.
|
## generated ID for the row or -1 in case of an error.
|
||||||
var x = pqgetvalue(setupQuery(db, SqlQuery(string(query) & " RETURNING " & pkName),
|
let res = setupQuery(db, SqlQuery(string(query) & " RETURNING " & pkName),
|
||||||
args), 0, 0)
|
args)
|
||||||
|
var x = pqgetvalue(res, 0, 0)
|
||||||
if not isNil(x):
|
if not isNil(x):
|
||||||
result = parseBiggestInt($x)
|
result = parseBiggestInt($x)
|
||||||
else:
|
else:
|
||||||
result = -1
|
result = -1
|
||||||
|
pqclear(res)
|
||||||
|
|
||||||
proc insert*(db: DbConn, query: SqlQuery, pkName: string,
|
proc insert*(db: DbConn, query: SqlQuery, pkName: string,
|
||||||
args: varargs[string, `$`]): int64
|
args: varargs[string, `$`]): int64
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import db_postgres, strutils
|
||||||
|
|
||||||
|
|
||||||
let db = open("localhost", "dom", "", "test")
|
let db = open("localhost", "dom", "", "test")
|
||||||
|
|
||||||
db.exec(sql"DROP TABLE IF EXISTS myTable")
|
db.exec(sql"DROP TABLE IF EXISTS myTable")
|
||||||
db.exec(sql("""CREATE TABLE myTable (
|
db.exec(sql("""CREATE TABLE myTable (
|
||||||
id integer PRIMARY KEY,
|
id integer PRIMARY KEY,
|
||||||
|
|
@ -49,9 +50,12 @@ try:
|
||||||
doAssert false, "Exception expected"
|
doAssert false, "Exception expected"
|
||||||
except DbError:
|
except DbError:
|
||||||
let msg = getCurrentExceptionMsg().normalize
|
let msg = getCurrentExceptionMsg().normalize
|
||||||
doAssert "expects" in msg
|
|
||||||
doAssert "?" in msg
|
info "DbError",
|
||||||
doAssert "parameter substitution" in msg
|
msg = $msg
|
||||||
|
|
||||||
|
doAssert "no parameter" in msg
|
||||||
|
doAssert "$1" in msg
|
||||||
|
|
||||||
doAssert db.getValue(sql("select filename from files where id = ?"), 1) == "hello.tmp"
|
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 entry = "あっそ"
|
||||||
var definition = "(int) (See ああそうそう) oh, really (uninterested)/oh yeah?/hmmmmm"
|
var definition = "(int) (See ああそうそう) oh, really (uninterested)/oh yeah?/hmmmmm"
|
||||||
discard db.getRow(
|
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
|
doAssert db.getValue(sql"SELECT definition FROM DICTIONARY WHERE entry = ?", entry) == definition
|
||||||
entry = "Format string entry"
|
entry = "Format string entry"
|
||||||
definition = "Format string definition"
|
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
|
doAssert db.getValue(sql"SELECT definition FROM DICTIONARY WHERE entry = ?", entry) == definition
|
||||||
|
|
||||||
echo("All tests succeeded!")
|
echo("All tests succeeded!")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue