diff options
author | ringabout <43030857+ringabout@users.noreply.github.com> | 2022-12-06 22:37:16 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-06 22:37:16 +0800 |
commit | 9ba07edb2ec7fcdd628cfa7155c4853160ebd5c3 (patch) | |
tree | 4ae00008d9604bf997350f72f89cea60338c91b6 /lib/impure/db_postgres.nim | |
parent | 4ca2dcb404aa1b92900e838790d5df554fc0cb9a (diff) | |
download | Nim-9ba07edb2ec7fcdd628cfa7155c4853160ebd5c3.tar.gz |
build the documentation of official packages (#20986)
* remove db stuffs * remove punycode * remove * fixes script * add cloner * patches * disable * patch * fixes external packages * disable two packages * preview documentation build * try again * fixes URL * fixes a bug * simplify * fixes documentaion * fixes * Apply suggestions from code review
Diffstat (limited to 'lib/impure/db_postgres.nim')
-rw-r--r-- | lib/impure/db_postgres.nim | 647 |
1 files changed, 0 insertions, 647 deletions
diff --git a/lib/impure/db_postgres.nim b/lib/impure/db_postgres.nim deleted file mode 100644 index 43ab94dbc..000000000 --- a/lib/impure/db_postgres.nim +++ /dev/null @@ -1,647 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2015 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## A higher level `PostgreSQL`:idx: database wrapper. This interface -## is implemented for other databases also. -## -## See also: `db_odbc <db_odbc.html>`_, `db_sqlite <db_sqlite.html>`_, -## `db_mysql <db_mysql.html>`_. -## -## Parameter substitution -## ====================== -## -## All `db_*` modules support the same form of parameter substitution. -## That is, using the `?` (question mark) to signify the place where a -## value should be placed. For example: -## -## ```Nim -## sql"INSERT INTO myTable (colA, colB, colC) VALUES (?, ?, ?)" -## ``` -## -## **Note**: There are two approaches to parameter substitution support by -## this module. -## -## 1. `SqlQuery` using `?, ?, ?, ...` (same as all the `db_*` modules) -## -## 2. `SqlPrepared` using `$1, $2, $3, ...` -## -## ```Nim -## prepare(db, "myExampleInsert", -## sql"""INSERT INTO myTable -## (colA, colB, colC) -## VALUES ($1, $2, $3)""", -## 3) -## ``` -## -## -## Unix Socket -## =========== -## -## Using Unix sockets instead of TCP connection can -## `improve performance up to 30% ~ 175% for some operations <https://momjian.us/main/blogs/pgblog/2012.html#June_6_2012>`_. -## -## To use Unix sockets with `db_postgres`, change the server address to the socket file path: -## -## ```Nim -## import std/db_postgres ## Change "localhost" or "127.0.0.1" to the socket file path -## let db = db_postgres.open("/run/postgresql", "user", "password", "database") -## echo db.getAllRows(sql"SELECT version();") -## db.close() -## ``` -## -## The socket file path is operating system specific and distribution specific, -## additional configuration may or may not be needed on your `postgresql.conf`. -## The Postgres server must be on the same computer and only works for Unix-like operating systems. -## -## -## Examples -## ======== -## -## Opening a connection to a database -## ---------------------------------- -## -## ```Nim -## import std/db_postgres -## let db = open("localhost", "user", "password", "dbname") -## db.close() -## ``` -## -## Creating a table -## ---------------- -## -## ```Nim -## db.exec(sql"DROP TABLE IF EXISTS myTable") -## db.exec(sql("""CREATE TABLE myTable ( -## id integer, -## name varchar(50) not null)""")) -## ``` -## -## Inserting data -## -------------- -## -## ```Nim -## db.exec(sql"INSERT INTO myTable (id, name) VALUES (0, ?)", -## "Dominik") -## ``` -import strutils, postgres - -import db_common -export db_common - -import std/private/[since, dbutils] - -type - DbConn* = PPGconn ## encapsulates a database connection - Row* = seq[string] ## a row of a dataset. NULL database values will be - ## converted to nil. - InstantRow* = object ## a handle that can be - res: PPGresult ## used to get a row's - SqlPrepared* = distinct string ## a identifier for the prepared queries - -proc dbError*(db: DbConn) {.noreturn.} = - ## raises a DbError exception. - var e: ref DbError - new(e) - e.msg = $pqErrorMessage(db) - raise e - -proc dbQuote*(s: string): string = - ## DB quotes the string. - result = "'" - for c in items(s): - case c - of '\'': add(result, "''") - of '\0': add(result, "\\0") - else: add(result, c) - add(result, '\'') - -proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string = - dbFormatImpl(formatstr, dbQuote, args) - -proc tryExec*(db: DbConn, query: SqlQuery, - args: varargs[string, `$`]): bool {.tags: [ReadDbEffect, WriteDbEffect].} = - ## tries to execute the query and returns true if successful, false otherwise. - var res = pqexecParams(db, dbFormat(query, args).cstring, 0, nil, nil, - nil, nil, 0) - result = pqresultStatus(res) == PGRES_COMMAND_OK - pqclear(res) - -proc tryExec*(db: DbConn, stmtName: SqlPrepared, - args: varargs[string, `$`]): bool {.tags: [ - ReadDbEffect, WriteDbEffect].} = - ## tries to execute the query and returns true if successful, false otherwise. - var arr = allocCStringArray(args) - var res = pqexecPrepared(db, stmtName.cstring, int32(args.len), arr, - nil, nil, 0) - deallocCStringArray(arr) - result = pqresultStatus(res) == PGRES_COMMAND_OK - pqclear(res) - -proc exec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]) {. - tags: [ReadDbEffect, WriteDbEffect].} = - ## executes the query and raises EDB if not successful. - var res = pqexecParams(db, dbFormat(query, args).cstring, 0, nil, nil, - nil, nil, 0) - if pqresultStatus(res) != PGRES_COMMAND_OK: dbError(db) - pqclear(res) - -proc exec*(db: DbConn, stmtName: SqlPrepared, - args: varargs[string]) {.tags: [ReadDbEffect, WriteDbEffect].} = - var arr = allocCStringArray(args) - var res = pqexecPrepared(db, stmtName.cstring, int32(args.len), arr, - nil, nil, 0) - deallocCStringArray(arr) - if pqResultStatus(res) != PGRES_COMMAND_OK: dbError(db) - pqclear(res) - -proc newRow(L: int): Row = - newSeq(result, L) - for i in 0..L-1: result[i] = "" - -proc setupQuery(db: DbConn, query: SqlQuery, - args: varargs[string]): PPGresult = - result = pqexec(db, dbFormat(query, args).cstring) - if pqResultStatus(result) != PGRES_TUPLES_OK: dbError(db) - -proc setupQuery(db: DbConn, stmtName: SqlPrepared, - args: varargs[string]): PPGresult = - var arr = allocCStringArray(args) - result = pqexecPrepared(db, stmtName.cstring, int32(args.len), arr, - nil, nil, 0) - deallocCStringArray(arr) - if pqResultStatus(result) != PGRES_TUPLES_OK: dbError(db) - -proc setupSingeRowQuery(db: DbConn, query: SqlQuery, - args: varargs[string]) = - if pqsendquery(db, dbFormat(query, args).cstring) != 1: - dbError(db) - if pqSetSingleRowMode(db) != 1: - dbError(db) - -proc setupSingeRowQuery(db: DbConn, stmtName: SqlPrepared, - args: varargs[string]) = - var arr = allocCStringArray(args) - if pqsendqueryprepared(db, stmtName.cstring, int32(args.len), arr, nil, nil, 0) != 1: - dbError(db) - if pqSetSingleRowMode(db) != 1: - dbError(db) - deallocCStringArray(arr) - -proc prepare*(db: DbConn; stmtName: string, query: SqlQuery; - nParams: int): SqlPrepared = - ## Creates a new `SqlPrepared` statement. Parameter substitution is done - ## via `$1`, `$2`, `$3`, etc. - if nParams > 0 and not string(query).contains("$1"): - dbError("parameter substitution expects \"$1\"") - var res = pqprepare(db, stmtName, query.cstring, int32(nParams), nil) - if pqResultStatus(res) != PGRES_COMMAND_OK: dbError(db) - result = SqlPrepared(stmtName) - pqclear(res) - -proc setRow(res: PPGresult, r: var Row, line, cols: int32) = - for col in 0'i32..cols-1: - setLen(r[col], 0) - let x = pqgetvalue(res, line, col) - if x.isNil: - r[col] = "" - else: - add(r[col], x) - -template fetchRows(db: DbConn): untyped = - var res: PPGresult = nil - while true: - res = pqgetresult(db) - if res == nil: - break - let status = pqresultStatus(res) - if status == PGRES_TUPLES_OK: - discard - elif status != PGRES_SINGLE_TUPLE: - dbError(db) - else: - let L = pqNfields(res) - var result = newRow(L) - setRow(res, result, 0, L) - yield result - pqclear(res) - -iterator fastRows*(db: DbConn, query: SqlQuery, - args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} = - ## executes the query and iterates over the result dataset. This is very - ## fast, but potentially dangerous: If the for-loop-body executes another - ## query, the results can be undefined. For Postgres it is safe though. - setupSingeRowQuery(db, query, args) - fetchRows(db) - -iterator fastRows*(db: DbConn, stmtName: SqlPrepared, - args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} = - ## executes the query and iterates over the result dataset. This is very - ## fast, but potentially dangerous: If the for-loop-body executes another - ## query, the results can be undefined. For Postgres it is safe though. - setupSingeRowQuery(db, stmtName, args) - fetchRows(db) - -template fetchinstantRows(db: DbConn): untyped = - var res: PPGresult = nil - while true: - res = pqgetresult(db) - if res == nil: - break - let status = pqresultStatus(res) - if status == PGRES_TUPLES_OK: - discard - elif status != PGRES_SINGLE_TUPLE: - dbError(db) - else: - yield InstantRow(res: res) - pqclear(res) - -iterator instantRows*(db: DbConn, query: SqlQuery, - args: varargs[string, `$`]): InstantRow - {.tags: [ReadDbEffect].} = - ## same as fastRows but returns a handle that can be used to get column text - ## on demand using `[]`. Returned handle is valid only within iterator body. - setupSingeRowQuery(db, query, args) - fetchinstantRows(db) - -iterator instantRows*(db: DbConn, stmtName: SqlPrepared, - args: varargs[string, `$`]): InstantRow - {.tags: [ReadDbEffect].} = - ## same as fastRows but returns a handle that can be used to get column text - ## on demand using `[]`. Returned handle is valid only within iterator body. - setupSingeRowQuery(db, stmtName, args) - fetchinstantRows(db) - -proc getColumnType(res: PPGresult, col: int) : DbType = - ## returns DbType for given column in the row - ## defined in pg_type.h file in the postgres source code - ## Wire representation for types: http://www.npgsql.org/dev/types.html - var oid = pqftype(res, int32(col)) - ## The integer returned is the internal OID number of the type - case oid - of 16: return DbType(kind: DbTypeKind.dbBool, name: "bool") - of 17: return DbType(kind: DbTypeKind.dbBlob, name: "bytea") - - of 21: return DbType(kind: DbTypeKind.dbInt, name: "int2", size: 2) - of 23: return DbType(kind: DbTypeKind.dbInt, name: "int4", size: 4) - of 20: return DbType(kind: DbTypeKind.dbInt, name: "int8", size: 8) - of 1560: return DbType(kind: DbTypeKind.dbBit, name: "bit") - of 1562: return DbType(kind: DbTypeKind.dbInt, name: "varbit") - - of 18: return DbType(kind: DbTypeKind.dbFixedChar, name: "char") - of 19: return DbType(kind: DbTypeKind.dbFixedChar, name: "name") - of 1042: return DbType(kind: DbTypeKind.dbFixedChar, name: "bpchar") - - of 25: return DbType(kind: DbTypeKind.dbVarchar, name: "text") - of 1043: return DbType(kind: DbTypeKind.dbVarChar, name: "varchar") - of 2275: return DbType(kind: DbTypeKind.dbVarchar, name: "cstring") - - of 700: return DbType(kind: DbTypeKind.dbFloat, name: "float4") - of 701: return DbType(kind: DbTypeKind.dbFloat, name: "float8") - - of 790: return DbType(kind: DbTypeKind.dbDecimal, name: "money") - of 1700: return DbType(kind: DbTypeKind.dbDecimal, name: "numeric") - - of 704: return DbType(kind: DbTypeKind.dbTimeInterval, name: "tinterval") - of 702: return DbType(kind: DbTypeKind.dbTimestamp, name: "abstime") - of 703: return DbType(kind: DbTypeKind.dbTimeInterval, name: "reltime") - of 1082: return DbType(kind: DbTypeKind.dbDate, name: "date") - of 1083: return DbType(kind: DbTypeKind.dbTime, name: "time") - of 1114: return DbType(kind: DbTypeKind.dbTimestamp, name: "timestamp") - of 1184: return DbType(kind: DbTypeKind.dbTimestamp, name: "timestamptz") - of 1186: return DbType(kind: DbTypeKind.dbTimeInterval, name: "interval") - of 1266: return DbType(kind: DbTypeKind.dbTime, name: "timetz") - - of 114: return DbType(kind: DbTypeKind.dbJson, name: "json") - of 142: return DbType(kind: DbTypeKind.dbXml, name: "xml") - of 3802: return DbType(kind: DbTypeKind.dbJson, name: "jsonb") - - of 600: return DbType(kind: DbTypeKind.dbPoint, name: "point") - of 601: return DbType(kind: DbTypeKind.dbLseg, name: "lseg") - of 602: return DbType(kind: DbTypeKind.dbPath, name: "path") - of 603: return DbType(kind: DbTypeKind.dbBox, name: "box") - of 604: return DbType(kind: DbTypeKind.dbPolygon, name: "polygon") - of 628: return DbType(kind: DbTypeKind.dbLine, name: "line") - of 718: return DbType(kind: DbTypeKind.dbCircle, name: "circle") - - of 650: return DbType(kind: DbTypeKind.dbInet, name: "cidr") - of 829: return DbType(kind: DbTypeKind.dbMacAddress, name: "macaddr") - of 869: return DbType(kind: DbTypeKind.dbInet, name: "inet") - - of 2950: return DbType(kind: DbTypeKind.dbVarchar, name: "uuid") - of 3614: return DbType(kind: DbTypeKind.dbVarchar, name: "tsvector") - of 3615: return DbType(kind: DbTypeKind.dbVarchar, name: "tsquery") - of 2970: return DbType(kind: DbTypeKind.dbVarchar, name: "txid_snapshot") - - of 27: return DbType(kind: DbTypeKind.dbComposite, name: "tid") - of 1790: return DbType(kind: DbTypeKind.dbComposite, name: "refcursor") - of 2249: return DbType(kind: DbTypeKind.dbComposite, name: "record") - of 3904: return DbType(kind: DbTypeKind.dbComposite, name: "int4range") - of 3906: return DbType(kind: DbTypeKind.dbComposite, name: "numrange") - of 3908: return DbType(kind: DbTypeKind.dbComposite, name: "tsrange") - of 3910: return DbType(kind: DbTypeKind.dbComposite, name: "tstzrange") - of 3912: return DbType(kind: DbTypeKind.dbComposite, name: "daterange") - of 3926: return DbType(kind: DbTypeKind.dbComposite, name: "int8range") - - of 22: return DbType(kind: DbTypeKind.dbArray, name: "int2vector") - of 30: return DbType(kind: DbTypeKind.dbArray, name: "oidvector") - of 143: return DbType(kind: DbTypeKind.dbArray, name: "xml[]") - of 199: return DbType(kind: DbTypeKind.dbArray, name: "json[]") - of 629: return DbType(kind: DbTypeKind.dbArray, name: "line[]") - of 651: return DbType(kind: DbTypeKind.dbArray, name: "cidr[]") - of 719: return DbType(kind: DbTypeKind.dbArray, name: "circle[]") - of 791: return DbType(kind: DbTypeKind.dbArray, name: "money[]") - of 1000: return DbType(kind: DbTypeKind.dbArray, name: "bool[]") - of 1001: return DbType(kind: DbTypeKind.dbArray, name: "bytea[]") - of 1002: return DbType(kind: DbTypeKind.dbArray, name: "char[]") - of 1003: return DbType(kind: DbTypeKind.dbArray, name: "name[]") - of 1005: return DbType(kind: DbTypeKind.dbArray, name: "int2[]") - of 1006: return DbType(kind: DbTypeKind.dbArray, name: "int2vector[]") - of 1007: return DbType(kind: DbTypeKind.dbArray, name: "int4[]") - of 1008: return DbType(kind: DbTypeKind.dbArray, name: "regproc[]") - of 1009: return DbType(kind: DbTypeKind.dbArray, name: "text[]") - of 1028: return DbType(kind: DbTypeKind.dbArray, name: "oid[]") - of 1010: return DbType(kind: DbTypeKind.dbArray, name: "tid[]") - of 1011: return DbType(kind: DbTypeKind.dbArray, name: "xid[]") - of 1012: return DbType(kind: DbTypeKind.dbArray, name: "cid[]") - of 1013: return DbType(kind: DbTypeKind.dbArray, name: "oidvector[]") - of 1014: return DbType(kind: DbTypeKind.dbArray, name: "bpchar[]") - of 1015: return DbType(kind: DbTypeKind.dbArray, name: "varchar[]") - of 1016: return DbType(kind: DbTypeKind.dbArray, name: "int8[]") - of 1017: return DbType(kind: DbTypeKind.dbArray, name: "point[]") - of 1018: return DbType(kind: DbTypeKind.dbArray, name: "lseg[]") - of 1019: return DbType(kind: DbTypeKind.dbArray, name: "path[]") - of 1020: return DbType(kind: DbTypeKind.dbArray, name: "box[]") - of 1021: return DbType(kind: DbTypeKind.dbArray, name: "float4[]") - of 1022: return DbType(kind: DbTypeKind.dbArray, name: "float8[]") - of 1023: return DbType(kind: DbTypeKind.dbArray, name: "abstime[]") - of 1024: return DbType(kind: DbTypeKind.dbArray, name: "reltime[]") - of 1025: return DbType(kind: DbTypeKind.dbArray, name: "tinterval[]") - of 1027: return DbType(kind: DbTypeKind.dbArray, name: "polygon[]") - of 1040: return DbType(kind: DbTypeKind.dbArray, name: "macaddr[]") - of 1041: return DbType(kind: DbTypeKind.dbArray, name: "inet[]") - of 1263: return DbType(kind: DbTypeKind.dbArray, name: "cstring[]") - of 1115: return DbType(kind: DbTypeKind.dbArray, name: "timestamp[]") - of 1182: return DbType(kind: DbTypeKind.dbArray, name: "date[]") - of 1183: return DbType(kind: DbTypeKind.dbArray, name: "time[]") - of 1185: return DbType(kind: DbTypeKind.dbArray, name: "timestamptz[]") - of 1187: return DbType(kind: DbTypeKind.dbArray, name: "interval[]") - of 1231: return DbType(kind: DbTypeKind.dbArray, name: "numeric[]") - of 1270: return DbType(kind: DbTypeKind.dbArray, name: "timetz[]") - of 1561: return DbType(kind: DbTypeKind.dbArray, name: "bit[]") - of 1563: return DbType(kind: DbTypeKind.dbArray, name: "varbit[]") - of 2201: return DbType(kind: DbTypeKind.dbArray, name: "refcursor[]") - of 2951: return DbType(kind: DbTypeKind.dbArray, name: "uuid[]") - of 3643: return DbType(kind: DbTypeKind.dbArray, name: "tsvector[]") - of 3645: return DbType(kind: DbTypeKind.dbArray, name: "tsquery[]") - of 3807: return DbType(kind: DbTypeKind.dbArray, name: "jsonb[]") - of 2949: return DbType(kind: DbTypeKind.dbArray, name: "txid_snapshot[]") - of 3905: return DbType(kind: DbTypeKind.dbArray, name: "int4range[]") - of 3907: return DbType(kind: DbTypeKind.dbArray, name: "numrange[]") - of 3909: return DbType(kind: DbTypeKind.dbArray, name: "tsrange[]") - of 3911: return DbType(kind: DbTypeKind.dbArray, name: "tstzrange[]") - of 3913: return DbType(kind: DbTypeKind.dbArray, name: "daterange[]") - of 3927: return DbType(kind: DbTypeKind.dbArray, name: "int8range[]") - of 2287: return DbType(kind: DbTypeKind.dbArray, name: "record[]") - - of 705: return DbType(kind: DbTypeKind.dbUnknown, name: "unknown") - else: return DbType(kind: DbTypeKind.dbUnknown, name: $oid) ## Query the system table pg_type to determine exactly which type is referenced. - -proc setColumnInfo(columns: var DbColumns; res: PPGresult, L: int32) = - setLen(columns, L) - for i in 0'i32..<L: - columns[i].name = $pqfname(res, i) - columns[i].typ = getColumnType(res, i) - columns[i].tableName = $(pqftable(res, i)) ## Returns the OID of the table from which the given column was fetched. - ## Query the system table pg_class to determine exactly which table is referenced. - #columns[i].primaryKey = libpq does not have a function for that - #columns[i].foreignKey = libpq does not have a function for that - -iterator instantRows*(db: DbConn; columns: var DbColumns; query: SqlQuery; - args: varargs[string, `$`]): InstantRow - {.tags: [ReadDbEffect].} = - setupSingeRowQuery(db, query, args) - var res: PPGresult = nil - var colsObtained = false - while true: - res = pqgetresult(db) - if not colsObtained: - setColumnInfo(columns, res, pqnfields(res)) - colsObtained = true - if res == nil: - break - let status = pqresultStatus(res) - if status == PGRES_TUPLES_OK: - discard - elif status != PGRES_SINGLE_TUPLE: - dbError(db) - else: - yield InstantRow(res: res) - pqclear(res) - -proc `[]`*(row: InstantRow; col: int): string {.inline.} = - ## returns text for given column of the row - $pqgetvalue(row.res, int32(0), int32(col)) - -proc unsafeColumnAt*(row: InstantRow, index: int): cstring {.inline.} = - ## Return cstring of given column of the row - pqgetvalue(row.res, int32(0), int32(index)) - -proc len*(row: InstantRow): int {.inline.} = - ## returns number of columns in the row - int(pqNfields(row.res)) - -proc getRow(res: PPGresult): Row = - let L = pqnfields(res) - result = newRow(L) - if pqntuples(res) > 0: - setRow(res, result, 0, L) - pqclear(res) - -proc getRow*(db: DbConn, query: SqlQuery, - args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} = - ## 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) - result = getRow(res) - -proc getRow*(db: DbConn, stmtName: SqlPrepared, - args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} = - let res = setupQuery(db, stmtName, args) - result = getRow(res) - -proc getAllRows(res: PPGresult): seq[Row] = - let N = pqntuples(res) - let L = pqnfields(res) - result = newSeqOfCap[Row](N) - var row = newRow(L) - for i in 0'i32..N-1: - setRow(res, row, i, L) - result.add(row) - pqclear(res) - -proc getAllRows*(db: DbConn, query: SqlQuery, - args: varargs[string, `$`]): seq[Row] {. - tags: [ReadDbEffect].} = - ## executes the query and returns the whole result dataset. - let res = setupQuery(db, query, args) - 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) - result = getAllRows(res) - -iterator rows*(db: DbConn, query: SqlQuery, - args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} = - ## same as `fastRows`, but slower and safe. - for r in items(getAllRows(db, query, args)): yield r - -iterator rows*(db: DbConn, stmtName: SqlPrepared, - args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} = - ## same as `fastRows`, but slower and safe. - for r in items(getAllRows(db, stmtName, args)): yield r - -proc getValue(res: PPGresult): string = - if pqntuples(res) > 0: - var x = pqgetvalue(res, 0, 0) - result = if isNil(x): "" else: $x - else: - result = "" - -proc getValue*(db: DbConn, query: SqlQuery, - args: varargs[string, `$`]): string {. - tags: [ReadDbEffect].} = - ## executes the query and returns the first column of the first row of the - ## result dataset. Returns "" if the dataset contains no rows or the database - ## value is NULL. - let res = setupQuery(db, query, args) - result = getValue(res) - pqclear(res) - -proc getValue*(db: DbConn, stmtName: SqlPrepared, - args: varargs[string, `$`]): string {. - tags: [ReadDbEffect].} = - ## executes the query and returns the first column of the first row of the - ## result dataset. Returns "" if the dataset contains no rows or the database - ## value is NULL. - let res = setupQuery(db, stmtName, args) - result = getValue(res) - pqclear(res) - -proc tryInsertID*(db: DbConn, query: SqlQuery, - args: varargs[string, `$`]): int64 {. - tags: [WriteDbEffect].}= - ## executes the query (typically "INSERT") and returns the - ## 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`. - 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 {. - tags: [WriteDbEffect].} = - ## executes the query (typically "INSERT") and returns the - ## generated ID for the row. For Postgre this adds - ## `RETURNING id` to the query, so it only works if your primary key is - ## named `id`. - result = tryInsertID(db, query, args) - if result < 0: dbError(db) - -proc tryInsert*(db: DbConn, query: SqlQuery,pkName: string, - args: varargs[string, `$`]): int64 - {.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. - 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 - {.tags: [WriteDbEffect], since: (1, 3).} = - ## executes the query (typically "INSERT") and returns the - ## generated ID - result = tryInsert(db, query, pkName, args) - if result < 0: dbError(db) - -proc execAffectedRows*(db: DbConn, query: SqlQuery, - args: varargs[string, `$`]): int64 {.tags: [ - ReadDbEffect, WriteDbEffect].} = - ## executes the query (typically "UPDATE") and returns the - ## number of affected rows. - var q = dbFormat(query, args) - var res = pqExec(db, q.cstring) - if pqresultStatus(res) != PGRES_COMMAND_OK: dbError(db) - result = parseBiggestInt($pqcmdTuples(res)) - pqclear(res) - -proc execAffectedRows*(db: DbConn, stmtName: SqlPrepared, - args: varargs[string, `$`]): int64 {.tags: [ - ReadDbEffect, WriteDbEffect].} = - ## executes the query (typically "UPDATE") and returns the - ## number of affected rows. - var arr = allocCStringArray(args) - var res = pqexecPrepared(db, stmtName.cstring, int32(args.len), arr, - nil, nil, 0) - deallocCStringArray(arr) - if pqresultStatus(res) != PGRES_COMMAND_OK: dbError(db) - result = parseBiggestInt($pqcmdTuples(res)) - pqclear(res) - -proc close*(db: DbConn) {.tags: [DbEffect].} = - ## closes the database connection. - if db != nil: pqfinish(db) - -proc open*(connection, user, password, database: string): DbConn {. - tags: [DbEffect].} = - ## opens a database connection. Raises `EDb` if the connection could not - ## be established. - ## - ## Clients can also use Postgres keyword/value connection strings to - ## connect. - ## - ## Example: - ## ```nim - ## con = open("", "", "", "host=localhost port=5432 dbname=mydb") - ## ``` - ## - ## See http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING - ## for more information. - let - colonPos = connection.find(':') - host = if colonPos < 0: connection - else: substr(connection, 0, colonPos-1) - port = if colonPos < 0: "" - else: substr(connection, colonPos+1) - result = pqsetdbLogin(host.cstring, port.cstring, nil, nil, database, user, password) - if pqStatus(result) != CONNECTION_OK: dbError(result) # result = nil - -proc setEncoding*(connection: DbConn, encoding: string): bool {. - tags: [DbEffect].} = - ## sets the encoding of a database connection, returns true for - ## success, false for failure. - return pqsetClientEncoding(connection, encoding) == 0 - - -# Tests are in ../../tests/untestable/tpostgres. |