summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2016-01-18 14:54:50 +0100
committerAraq <rumpf_a@web.de>2016-01-18 14:54:50 +0100
commita114b3251906e14d0c6dce536f82a83a958c5806 (patch)
tree9c627c554ff3175db944e1847a3db18b0fc07149
parent7ee1847137963431d2980bb9e030dbce6c2a8506 (diff)
parent6ca9e5cbcc940ad86045884840770415d1759f56 (diff)
downloadNim-a114b3251906e14d0c6dce536f82a83a958c5806.tar.gz
Merge branch 'devel' of https://github.com/nim-lang/Nim into devel
-rw-r--r--lib/impure/db_mysql.nim44
-rw-r--r--lib/impure/db_odbc.nim48
-rw-r--r--lib/impure/db_postgres.nim18
-rw-r--r--lib/impure/db_sqlite.nim43
-rw-r--r--lib/pure/collections/tables.nim14
-rw-r--r--tests/untestable/tpostgres.nim69
6 files changed, 227 insertions, 9 deletions
diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim
index 170fee8b8..1b7f1de61 100644
--- a/lib/impure/db_mysql.nim
+++ b/lib/impure/db_mysql.nim
@@ -10,7 +10,49 @@
 ## A higher level `mySQL`:idx: database wrapper. The same interface is
 ## 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
 ##
diff --git a/lib/impure/db_odbc.nim b/lib/impure/db_odbc.nim
index 6af69d842..4f0b0469d 100644
--- a/lib/impure/db_odbc.nim
+++ b/lib/impure/db_odbc.nim
@@ -11,12 +11,54 @@
 ##
 ## This is the same interface that is implemented for other databases.
 ##
-## This has NOT yet been (extensively) tested agains ODBC drivers for
-## Teradata, Oracle, Sybase, MSSqlvSvr, et. al.  databases
+## This has NOT yet been (extensively) tested against ODBC drivers for
+## Teradata, Oracle, Sybase, MSSqlvSvr, et. al.  databases.
 ##
 ## 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
 ##
diff --git a/lib/impure/db_postgres.nim b/lib/impure/db_postgres.nim
index 9bdbae4c2..60bd1f081 100644
--- a/lib/impure/db_postgres.nim
+++ b/lib/impure/db_postgres.nim
@@ -10,6 +10,9 @@
 ## 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
 ## ----------------------
 ##
@@ -27,7 +30,7 @@
 ##
 ## 2. ``SqlPrepared`` using ``$1, $2, $3, ...``
 ##
-##  .. code-block:: Nim
+## .. code-block:: Nim
 ##   prepare(db, "myExampleInsert",
 ##           sql"""INSERT INTO myTable
 ##                 (colA, colB, colC)
@@ -162,8 +165,10 @@ proc setupQuery(db: DbConn, stmtName: SqlPrepared,
 
 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" """)
+    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)
@@ -282,6 +287,15 @@ proc getValue*(db: DbConn, query: SqlQuery,
   var x = pqgetvalue(setupQuery(db, query, args), 0, 0)
   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,
                   args: varargs[string, `$`]): int64 {.
                   tags: [WriteDbEffect].}=
diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim
index c0d221a0d..1633d48f7 100644
--- a/lib/impure/db_sqlite.nim
+++ b/lib/impure/db_sqlite.nim
@@ -10,7 +10,48 @@
 ## A higher level `SQLite`:idx: database wrapper. This interface
 ## 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
 ##
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index 329b2a1cb..2ed0d2034 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -887,7 +887,7 @@ proc mget*[A](t: CountTableRef[A], key: A): var int {.deprecated.} =
   result = t[][key]
 
 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 =
   ## returns true iff `key` is in the table `t`.
@@ -1028,3 +1028,15 @@ when isMainModule:
   assert(merged["foo"] == 5)
   assert(merged["bar"] == 3)
   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)
diff --git a/tests/untestable/tpostgres.nim b/tests/untestable/tpostgres.nim
index 81fe8bf51..dcbdaad39 100644
--- a/tests/untestable/tpostgres.nim
+++ b/tests/untestable/tpostgres.nim
@@ -1,4 +1,5 @@
-import db_postgres
+import db_postgres, strutils
+
 
 let db = open("localhost", "dom", "", "test")
 db.exec(sql"DROP TABLE IF EXISTS myTable")
@@ -12,4 +13,70 @@ doAssert db.getValue(sql"SELECT name FROM myTable") == name
 # Check issue #3513
 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()