Merge branch 'devel' of https://github.com/nim-lang/Nim into devel
This commit is contained in:
commit
a114b32519
6 changed files with 227 additions and 9 deletions
|
|
@ -10,7 +10,49 @@
|
||||||
## A higher level `mySQL`:idx: database wrapper. The same interface is
|
## A higher level `mySQL`:idx: database wrapper. The same interface is
|
||||||
## implemented for other databases too.
|
## implemented for other databases too.
|
||||||
##
|
##
|
||||||
## Example:
|
## See also: `db_odbc <db_odbc.html>`_, `db_sqlite <db_sqlite.html>`_,
|
||||||
|
## `db_postgres <db_postgres.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:
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## sql"INSERT INTO myTable (colA, colB, colC) VALUES (?, ?, ?)"
|
||||||
|
##
|
||||||
|
##
|
||||||
|
## Examples
|
||||||
|
## --------
|
||||||
|
##
|
||||||
|
## Opening a connection to a database
|
||||||
|
## ==================================
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## import db_mysql
|
||||||
|
## let db = open("localhost", "user", "password", "dbname")
|
||||||
|
## db.close()
|
||||||
|
##
|
||||||
|
## Creating a table
|
||||||
|
## ================
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## db.exec(sql"DROP TABLE IF EXISTS myTable")
|
||||||
|
## db.exec(sql("""CREATE TABLE myTable (
|
||||||
|
## id integer,
|
||||||
|
## name varchar(50) not null)"""))
|
||||||
|
##
|
||||||
|
## Inserting data
|
||||||
|
## ==============
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## db.exec(sql"INSERT INTO myTable (id, name) VALUES (0, ?)",
|
||||||
|
## "Dominik")
|
||||||
|
##
|
||||||
|
## Larger example
|
||||||
|
## ==============
|
||||||
##
|
##
|
||||||
## .. code-block:: Nim
|
## .. code-block:: Nim
|
||||||
##
|
##
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,54 @@
|
||||||
##
|
##
|
||||||
## This is the same interface that is implemented for other databases.
|
## This is the same interface that is implemented for other databases.
|
||||||
##
|
##
|
||||||
## This has NOT yet been (extensively) tested agains ODBC drivers for
|
## This has NOT yet been (extensively) tested against ODBC drivers for
|
||||||
## Teradata, Oracle, Sybase, MSSqlvSvr, et. al. databases
|
## Teradata, Oracle, Sybase, MSSqlvSvr, et. al. databases.
|
||||||
##
|
##
|
||||||
## Currently all queries are ANSI calls, not Unicode.
|
## Currently all queries are ANSI calls, not Unicode.
|
||||||
##
|
##
|
||||||
## Example:
|
## See also: `db_postgres <db_postgres.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:
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## sql"INSERT INTO myTable (colA, colB, colC) VALUES (?, ?, ?)"
|
||||||
|
##
|
||||||
|
##
|
||||||
|
## Examples
|
||||||
|
## --------
|
||||||
|
##
|
||||||
|
## Opening a connection to a database
|
||||||
|
## ==================================
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## import db_odbc
|
||||||
|
## let db = open("localhost", "user", "password", "dbname")
|
||||||
|
## db.close()
|
||||||
|
##
|
||||||
|
## Creating a table
|
||||||
|
## ================
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## db.exec(sql"DROP TABLE IF EXISTS myTable")
|
||||||
|
## db.exec(sql("""CREATE TABLE myTable (
|
||||||
|
## id integer,
|
||||||
|
## name varchar(50) not null)"""))
|
||||||
|
##
|
||||||
|
## Inserting data
|
||||||
|
## ==============
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## db.exec(sql"INSERT INTO myTable (id, name) VALUES (0, ?)",
|
||||||
|
## "Andreas")
|
||||||
|
##
|
||||||
|
## Large example
|
||||||
|
## =============
|
||||||
##
|
##
|
||||||
## .. code-block:: Nim
|
## .. code-block:: Nim
|
||||||
##
|
##
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,9 @@
|
||||||
## A higher level `PostgreSQL`:idx: database wrapper. This interface
|
## A higher level `PostgreSQL`:idx: database wrapper. This interface
|
||||||
## is implemented for other databases also.
|
## 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
|
## Parameter substitution
|
||||||
## ----------------------
|
## ----------------------
|
||||||
##
|
##
|
||||||
|
|
@ -162,8 +165,10 @@ proc setupQuery(db: DbConn, stmtName: SqlPrepared,
|
||||||
|
|
||||||
proc prepare*(db: DbConn; stmtName: string, query: SqlQuery;
|
proc prepare*(db: DbConn; stmtName: string, query: SqlQuery;
|
||||||
nParams: int): SqlPrepared =
|
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"):
|
if nParams > 0 and not string(query).contains("$1"):
|
||||||
dbError("""parameter substitution expects "$1" """)
|
dbError("parameter substitution expects \"$1\"")
|
||||||
var res = pqprepare(db, stmtName, query.string, int32(nParams), nil)
|
var res = pqprepare(db, stmtName, query.string, int32(nParams), nil)
|
||||||
if pqResultStatus(res) != PGRES_COMMAND_OK: dbError(db)
|
if pqResultStatus(res) != PGRES_COMMAND_OK: dbError(db)
|
||||||
return SqlPrepared(stmtName)
|
return SqlPrepared(stmtName)
|
||||||
|
|
@ -282,6 +287,15 @@ proc getValue*(db: DbConn, query: SqlQuery,
|
||||||
var x = pqgetvalue(setupQuery(db, query, args), 0, 0)
|
var x = pqgetvalue(setupQuery(db, query, args), 0, 0)
|
||||||
result = if isNil(x): "" else: $x
|
result = if isNil(x): "" else: $x
|
||||||
|
|
||||||
|
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.
|
||||||
|
var x = pqgetvalue(setupQuery(db, stmtName, args), 0, 0)
|
||||||
|
result = if isNil(x): "" else: $x
|
||||||
|
|
||||||
proc tryInsertID*(db: DbConn, query: SqlQuery,
|
proc tryInsertID*(db: DbConn, query: SqlQuery,
|
||||||
args: varargs[string, `$`]): int64 {.
|
args: varargs[string, `$`]): int64 {.
|
||||||
tags: [WriteDbEffect].}=
|
tags: [WriteDbEffect].}=
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,48 @@
|
||||||
## A higher level `SQLite`:idx: database wrapper. This interface
|
## A higher level `SQLite`:idx: database wrapper. This interface
|
||||||
## is implemented for other databases too.
|
## is implemented for other databases too.
|
||||||
##
|
##
|
||||||
## Example:
|
## See also: `db_odbc <db_odbc.html>`_, `db_postgres <db_postgres.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:
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## sql"INSERT INTO myTable (colA, colB, colC) VALUES (?, ?, ?)"
|
||||||
|
##
|
||||||
|
## Examples
|
||||||
|
## --------
|
||||||
|
##
|
||||||
|
## Opening a connection to a database
|
||||||
|
## ==================================
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## import db_sqlite
|
||||||
|
## let db = open("localhost", "user", "password", "dbname")
|
||||||
|
## db.close()
|
||||||
|
##
|
||||||
|
## Creating a table
|
||||||
|
## ================
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## db.exec(sql"DROP TABLE IF EXISTS myTable")
|
||||||
|
## db.exec(sql("""CREATE TABLE myTable (
|
||||||
|
## id integer,
|
||||||
|
## name varchar(50) not null)"""))
|
||||||
|
##
|
||||||
|
## Inserting data
|
||||||
|
## ==============
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## db.exec(sql"INSERT INTO myTable (id, name) VALUES (0, ?)",
|
||||||
|
## "Jack")
|
||||||
|
##
|
||||||
|
## Larger example
|
||||||
|
## ==============
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
##
|
##
|
||||||
|
|
|
||||||
|
|
@ -887,7 +887,7 @@ proc mget*[A](t: CountTableRef[A], key: A): var int {.deprecated.} =
|
||||||
result = t[][key]
|
result = t[][key]
|
||||||
|
|
||||||
proc getOrDefault*[A](t: CountTableRef[A], key: A): int =
|
proc getOrDefault*[A](t: CountTableRef[A], key: A): int =
|
||||||
getOrDefaultImpl(t, key)
|
result = t[].getOrDefault(key)
|
||||||
|
|
||||||
proc hasKey*[A](t: CountTableRef[A], key: A): bool =
|
proc hasKey*[A](t: CountTableRef[A], key: A): bool =
|
||||||
## returns true iff `key` is in the table `t`.
|
## returns true iff `key` is in the table `t`.
|
||||||
|
|
@ -1028,3 +1028,15 @@ when isMainModule:
|
||||||
assert(merged["foo"] == 5)
|
assert(merged["foo"] == 5)
|
||||||
assert(merged["bar"] == 3)
|
assert(merged["bar"] == 3)
|
||||||
assert(merged["baz"] == 14)
|
assert(merged["baz"] == 14)
|
||||||
|
|
||||||
|
block:
|
||||||
|
const testKey = "TESTKEY"
|
||||||
|
let t: CountTableRef[string] = newCountTable[string]()
|
||||||
|
|
||||||
|
# Before, does not compile with error message:
|
||||||
|
#test_counttable.nim(7, 43) template/generic instantiation from here
|
||||||
|
#lib/pure/collections/tables.nim(117, 21) template/generic instantiation from here
|
||||||
|
#lib/pure/collections/tableimpl.nim(32, 27) Error: undeclared field: 'hcode
|
||||||
|
doAssert 0 == t.getOrDefault(testKey)
|
||||||
|
t.inc(testKey,3)
|
||||||
|
doAssert 3 == t.getOrDefault(testKey)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import db_postgres
|
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")
|
||||||
|
|
@ -12,4 +13,70 @@ doAssert db.getValue(sql"SELECT name FROM myTable") == name
|
||||||
# Check issue #3513
|
# Check issue #3513
|
||||||
doAssert db.getValue(sql"SELECT name FROM myTable") == name
|
doAssert db.getValue(sql"SELECT name FROM myTable") == name
|
||||||
|
|
||||||
|
|
||||||
|
# issue #3560
|
||||||
|
proc addToDb(conn: DbConn, fileId: int, fileName: string): int64 =
|
||||||
|
result = conn.insertId(sql("INSERT into files (id, filename) VALUES (?, ?)"), fileId, fileName)
|
||||||
|
|
||||||
|
db.exec(sql"DROP TABLE IF EXISTS files")
|
||||||
|
db.exec(sql"DROP TABLE IF EXISTS fileobjects")
|
||||||
|
db.exec(sql("""CREATE TABLE FILEOBJECTS(
|
||||||
|
ID SERIAL PRIMARY KEY,
|
||||||
|
FILE_SIZE INT,
|
||||||
|
MD5 CHAR(32) NOT NULL UNIQUE
|
||||||
|
);"""))
|
||||||
|
|
||||||
|
db.exec(sql("""CREATE TABLE FILES(
|
||||||
|
ID SERIAL PRIMARY KEY,
|
||||||
|
OBJECT_ID INT,
|
||||||
|
FILENAME TEXT NOT NULL,
|
||||||
|
URI TEXT,
|
||||||
|
SCHEME CHAR(10),
|
||||||
|
PUBLIC BOOLEAN DEFAULT FALSE,
|
||||||
|
CONSTRAINT fk1_fileobjs FOREIGN KEY (object_id)
|
||||||
|
REFERENCES fileobjects (id) MATCH SIMPLE
|
||||||
|
ON DELETE CASCADE
|
||||||
|
);"""))
|
||||||
|
|
||||||
|
let f1 = db.addToDb(1, "hello.tmp")
|
||||||
|
doAssert f1 == 1
|
||||||
|
let f2 = db.addToDb(2, "hello2.tmp")
|
||||||
|
doAssert f2 == 2
|
||||||
|
|
||||||
|
# PreparedStmt vs. normal query
|
||||||
|
try:
|
||||||
|
echo db.getValue(sql("select * from files where id = $1"), 1)
|
||||||
|
doAssert false, "Exception expected"
|
||||||
|
except DbError:
|
||||||
|
let msg = getCurrentExceptionMsg().normalize
|
||||||
|
doAssert "expects" in msg
|
||||||
|
doAssert "?" in msg
|
||||||
|
doAssert "parameter substitution" in msg
|
||||||
|
|
||||||
|
doAssert db.getValue(sql("select filename from files where id = ?"), 1) == "hello.tmp"
|
||||||
|
|
||||||
|
var first = prepare(db, "one", sql"select filename from files where id = $1", 1)
|
||||||
|
doAssert db.getValue(first, 1) == "hello.tmp"
|
||||||
|
|
||||||
|
try:
|
||||||
|
var second = prepare(db, "two", sql"select filename from files where id = ?", 1)
|
||||||
|
doAssert false, "Exception expected"
|
||||||
|
except:
|
||||||
|
let msg = getCurrentExceptionMsg().normalize
|
||||||
|
doAssert "expects" in msg
|
||||||
|
doAssert "$1" in msg
|
||||||
|
doAssert "parameter substitution" in msg
|
||||||
|
|
||||||
|
# issue #3569
|
||||||
|
db.exec(SqlQuery("DROP TABLE IF EXISTS tags"))
|
||||||
|
db.exec(SqlQuery("CREATE TABLE tags(id serial UNIQUE, name varchar(255))"))
|
||||||
|
|
||||||
|
for i in 1..10:
|
||||||
|
var name = "t" & $i
|
||||||
|
echo(name)
|
||||||
|
discard db.getRow(
|
||||||
|
SqlQuery("INSERT INTO tags(name) VALUES(\'$1\') RETURNING id" % [name]))
|
||||||
|
|
||||||
|
echo("All tests succeeded!")
|
||||||
|
|
||||||
db.close()
|
db.close()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue