summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--lib/impure/db_mysql.nim27
-rw-r--r--lib/impure/db_postgres.nim21
-rw-r--r--lib/impure/db_sqlite.nim24
3 files changed, 71 insertions, 1 deletions
diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim
index 619c2a656..7c2901efd 100644
--- a/lib/impure/db_mysql.nim
+++ b/lib/impure/db_mysql.nim
@@ -16,6 +16,9 @@ type
   DbConn* = PMySQL    ## encapsulates a database connection
   Row* = seq[string]   ## a row of a dataset. NULL database values will be
                        ## transformed always to the empty string.
+  InstantRow* = tuple[row: cstringArray, len: int]  ## a handle that can be
+                                                    ## used to get a row's
+                                                    ## column text on demand
   EDb* = object of IOError ## exception that is raised if a database error occurs
 
   SqlQuery* = distinct string ## an SQL query string
@@ -127,6 +130,30 @@ iterator fastRows*(db: DbConn, query: SqlQuery,
       yield result
     properFreeResult(sqlres, row)
 
+iterator instantRows*(db: DbConn, query: SqlQuery,
+                      args: varargs[string, `$`]): InstantRow
+                      {.tags: [FReadDb].} =
+  ## same as fastRows but returns a handle that can be used to get column text
+  ## on demand using []. Returned handle is valid only within interator body.
+  rawExec(db, query, args)
+  var sqlres = mysql.useResult(db)
+  if sqlres != nil:
+    let L = int(mysql.numFields(sqlres))
+    var row: cstringArray
+    while true:
+      row = mysql.fetchRow(sqlres)
+      if row == nil: break
+      yield (row: row, len: L)
+    properFreeResult(sqlres, row)
+
+proc `[]`*(row: InstantRow, col: int): string {.inline.} =
+  ## returns text for given column of the row
+  $row.row[col]
+
+proc len*(row: InstantRow): int {.inline.} =
+  ## returns number of columns in the row
+  row.len
+
 proc getRow*(db: DbConn, query: SqlQuery,
              args: varargs[string, `$`]): Row {.tags: [FReadDB].} =
   ## retrieves a single row. If the query doesn't return any rows, this proc
diff --git a/lib/impure/db_postgres.nim b/lib/impure/db_postgres.nim
index 774cb1510..c88e660f4 100644
--- a/lib/impure/db_postgres.nim
+++ b/lib/impure/db_postgres.nim
@@ -16,6 +16,9 @@ type
   DbConn* = PPGconn   ## encapsulates a database connection
   Row* = seq[string]  ## a row of a dataset. NULL database values will be
                        ## transformed always to the empty string.
+  InstantRow* = tuple[res: PPGresult, line: int32]  ## a handle that can be
+                                                    ## used to get a row's
+                                                    ## column text on demand
   EDb* = object of IOError ## exception that is raised if a database error occurs
   
   SqlQuery* = distinct string ## an SQL query string
@@ -159,6 +162,24 @@ iterator fastRows*(db: DbConn, stmtName: SqlPrepared,
     yield result
   pqClear(res)
 
+iterator instantRows*(db: DbConn, query: SqlQuery,
+                      args: varargs[string, `$`]): InstantRow
+                      {.tags: [FReadDb].} =
+  ## same as fastRows but returns a handle that can be used to get column text
+  ## on demand using []. Returned handle is valid only within interator body.
+  var res = setupQuery(db, query, args)
+  for i in 0..pqNtuples(res)-1:
+    yield (res: res, line: i)
+  pqClear(res)
+
+proc `[]`*(row: InstantRow, col: int32): string {.inline.} =
+  ## returns text for given column of the row
+  $pqgetvalue(row.res, row.line, col)
+
+proc len*(row: InstantRow): int32 {.inline.} =
+  ## returns number of columns in the row
+  pqNfields(row.res)
+
 proc getRow*(db: DbConn, query: SqlQuery,
              args: varargs[string, `$`]): Row {.tags: [FReadDB].} =
   ## retrieves a single row. If the query doesn't return any rows, this proc
diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim
index 47e7c1900..1a037becc 100644
--- a/lib/impure/db_sqlite.nim
+++ b/lib/impure/db_sqlite.nim
@@ -16,6 +16,8 @@ type
   DbConn* = PSqlite3  ## encapsulates a database connection
   Row* = seq[string]  ## a row of a dataset. NULL database values will be
                        ## transformed always to the empty string.
+  InstantRow* = Pstmt  ## a handle that can be used to get a row's column
+                       ## text on demand
   EDb* = object of IOError ## exception that is raised if a database error occurs
   
   SqlQuery* = distinct string ## an SQL query string
@@ -109,6 +111,24 @@ iterator fastRows*(db: DbConn, query: SqlQuery,
     yield result
   if finalize(stmt) != SQLITE_OK: dbError(db)
 
+iterator instantRows*(db: DbConn, query: SqlQuery,
+                      args: varargs[string, `$`]): InstantRow
+                      {.tags: [FReadDb].} =
+  ## same as fastRows but returns a handle that can be used to get column text
+  ## on demand using []. Returned handle is valid only within interator body.
+  var stmt = setupQuery(db, query, args)
+  while step(stmt) == SQLITE_ROW:
+    yield stmt
+  if finalize(stmt) != SQLITE_OK: dbError(db)
+
+proc `[]`*(row: InstantRow, col: int32): string {.inline.} =
+  ## returns text for given column of the row
+  $column_text(row, col)
+
+proc len*(row: InstantRow): int32 {.inline.} =
+  ## returns number of columns in the row
+  column_count(row)
+
 proc getRow*(db: DbConn, query: SqlQuery,
              args: varargs[string, `$`]): Row {.tags: [FReadDb].} =
   ## retrieves a single row. If the query doesn't return any rows, this proc
@@ -216,5 +236,7 @@ when not defined(testing) and isMainModule:
   #db.query("insert into tbl1 values('goodbye', 20)")
   for r in db.rows(sql"select * from tbl1", []):
     echo(r[0], r[1])
-  
+  for r in db.instantRows(sql"select * from tbl1", []):
+    echo(r[0], r[1])
+
   db_sqlite.close(db)