db_sqlite.nim 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## A higher level `SQLite`:idx: database wrapper. This interface
  10. ## is implemented for other databases too.
  11. ##
  12. ## Basic usage
  13. ## ===========
  14. ##
  15. ## The basic flow of using this module is:
  16. ##
  17. ## 1. Open database connection
  18. ## 2. Execute SQL query
  19. ## 3. Close database connection
  20. ##
  21. ## Parameter substitution
  22. ## ----------------------
  23. ##
  24. ## All ``db_*`` modules support the same form of parameter substitution.
  25. ## That is, using the ``?`` (question mark) to signify the place where a
  26. ## value should be placed. For example:
  27. ##
  28. ## .. code-block:: Nim
  29. ##
  30. ## sql"INSERT INTO my_table (colA, colB, colC) VALUES (?, ?, ?)"
  31. ##
  32. ## Opening a connection to a database
  33. ## ----------------------------------
  34. ##
  35. ## .. code-block:: Nim
  36. ##
  37. ## import db_sqlite
  38. ##
  39. ## # user, password, database name can be empty.
  40. ## # These params are not used on db_sqlite module.
  41. ## let db = open("mytest.db", "", "", "")
  42. ## db.close()
  43. ##
  44. ## Creating a table
  45. ## ----------------
  46. ##
  47. ## .. code-block:: Nim
  48. ##
  49. ## db.exec(sql"DROP TABLE IF EXISTS my_table")
  50. ## db.exec(sql"""CREATE TABLE my_table (
  51. ## id INTEGER,
  52. ## name VARCHAR(50) NOT NULL
  53. ## )""")
  54. ##
  55. ## Inserting data
  56. ## --------------
  57. ##
  58. ## .. code-block:: Nim
  59. ##
  60. ## db.exec(sql"INSERT INTO my_table (id, name) VALUES (0, ?)",
  61. ## "Jack")
  62. ##
  63. ## Larger example
  64. ## --------------
  65. ##
  66. ## .. code-block:: nim
  67. ##
  68. ## import db_sqlite, math
  69. ##
  70. ## let db = open("mytest.db", "", "", "")
  71. ##
  72. ## db.exec(sql"DROP TABLE IF EXISTS my_table")
  73. ## db.exec(sql"""CREATE TABLE my_table (
  74. ## id INTEGER PRIMARY KEY,
  75. ## name VARCHAR(50) NOT NULL,
  76. ## i INT(11),
  77. ## f DECIMAL(18, 10)
  78. ## )""")
  79. ##
  80. ## db.exec(sql"BEGIN")
  81. ## for i in 1..1000:
  82. ## db.exec(sql"INSERT INTO my_table (name, i, f) VALUES (?, ?, ?)",
  83. ## "Item#" & $i, i, sqrt(i.float))
  84. ## db.exec(sql"COMMIT")
  85. ##
  86. ## for x in db.fastRows(sql"SELECT * FROM my_table"):
  87. ## echo x
  88. ##
  89. ## let id = db.tryInsertId(sql"""INSERT INTO my_table (name, i, f)
  90. ## VALUES (?, ?, ?)""",
  91. ## "Item#1001", 1001, sqrt(1001.0))
  92. ## echo "Inserted item: ", db.getValue(sql"SELECT name FROM my_table WHERE id=?", id)
  93. ##
  94. ## db.close()
  95. ##
  96. ##
  97. ## Note
  98. ## ====
  99. ## This module does not implement any ORM features such as mapping the types from the schema.
  100. ## Instead, a ``seq[string]`` is returned for each row.
  101. ##
  102. ## The reasoning is as follows:
  103. ## 1. it's close to what many DBs offer natively (char**)
  104. ## 2. it hides the number of types that the DB supports
  105. ## (int? int64? decimal up to 10 places? geo coords?)
  106. ## 3. it's convenient when all you do is to forward the data to somewhere else (echo, log, put the data into a new query)
  107. ##
  108. ## See also
  109. ## ========
  110. ##
  111. ## * `db_odbc module <db_odbc.html>`_ for ODBC database wrapper
  112. ## * `db_mysql module <db_mysql.html>`_ for MySQL database wrapper
  113. ## * `db_postgres module <db_postgres.html>`_ for PostgreSQL database wrapper
  114. {.deadCodeElim: on.} # dce option deprecated
  115. import sqlite3
  116. import db_common
  117. export db_common
  118. type
  119. DbConn* = PSqlite3 ## Encapsulates a database connection.
  120. Row* = seq[string] ## A row of a dataset. `NULL` database values will be
  121. ## converted to an empty string.
  122. InstantRow* = PStmt ## A handle that can be used to get a row's column
  123. ## text on demand.
  124. proc dbError*(db: DbConn) {.noreturn.} =
  125. ## Raises a `DbError` exception.
  126. ##
  127. ## **Examples:**
  128. ##
  129. ## .. code-block:: Nim
  130. ##
  131. ## let db = open("mytest.db", "", "", "")
  132. ## if not db.tryExec(sql"SELECT * FROM not_exist_table"):
  133. ## dbError(db)
  134. ## db.close()
  135. var e: ref DbError
  136. new(e)
  137. e.msg = $sqlite3.errmsg(db)
  138. raise e
  139. proc dbQuote*(s: string): string =
  140. ## Escapes the `'` (single quote) char to `''`.
  141. ## Because single quote is used for defining `VARCHAR` in SQL.
  142. runnableExamples:
  143. doAssert dbQuote("'") == "''''"
  144. doAssert dbQuote("A Foobar's pen.") == "'A Foobar''s pen.'"
  145. result = "'"
  146. for c in items(s):
  147. if c == '\'': add(result, "''")
  148. else: add(result, c)
  149. add(result, '\'')
  150. proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string =
  151. result = ""
  152. var a = 0
  153. for c in items(string(formatstr)):
  154. if c == '?':
  155. add(result, dbQuote(args[a]))
  156. inc(a)
  157. else:
  158. add(result, c)
  159. proc tryExec*(db: DbConn, query: SqlQuery,
  160. args: varargs[string, `$`]): bool {.
  161. tags: [ReadDbEffect, WriteDbEffect].} =
  162. ## Tries to execute the query and returns `true` if successful, `false` otherwise.
  163. ##
  164. ## **Examples:**
  165. ##
  166. ## .. code-block:: Nim
  167. ##
  168. ## let db = open("mytest.db", "", "", "")
  169. ## if not db.tryExec(sql"SELECT * FROM my_table"):
  170. ## dbError(db)
  171. ## db.close()
  172. assert(not db.isNil, "Database not connected.")
  173. var q = dbFormat(query, args)
  174. var stmt: sqlite3.PStmt
  175. if prepare_v2(db, q, q.len.cint, stmt, nil) == SQLITE_OK:
  176. let x = step(stmt)
  177. if x in {SQLITE_DONE, SQLITE_ROW}:
  178. result = finalize(stmt) == SQLITE_OK
  179. proc exec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]) {.
  180. tags: [ReadDbEffect, WriteDbEffect].} =
  181. ## Executes the query and raises a `DbError` exception if not successful.
  182. ##
  183. ## **Examples:**
  184. ##
  185. ## .. code-block:: Nim
  186. ##
  187. ## let db = open("mytest.db", "", "", "")
  188. ## try:
  189. ## db.exec(sql"INSERT INTO my_table (id, name) VALUES (?, ?)",
  190. ## 1, "item#1")
  191. ## except:
  192. ## stderr.writeLine(getCurrentExceptionMsg())
  193. ## finally:
  194. ## db.close()
  195. if not tryExec(db, query, args): dbError(db)
  196. proc newRow(L: int): Row =
  197. newSeq(result, L)
  198. for i in 0..L-1: result[i] = ""
  199. proc setupQuery(db: DbConn, query: SqlQuery,
  200. args: varargs[string]): PStmt =
  201. assert(not db.isNil, "Database not connected.")
  202. var q = dbFormat(query, args)
  203. if prepare_v2(db, q, q.len.cint, result, nil) != SQLITE_OK: dbError(db)
  204. proc setRow(stmt: PStmt, r: var Row, cols: cint) =
  205. for col in 0'i32..cols-1:
  206. setLen(r[col], column_bytes(stmt, col)) # set capacity
  207. setLen(r[col], 0)
  208. let x = column_text(stmt, col)
  209. if not isNil(x): add(r[col], x)
  210. iterator fastRows*(db: DbConn, query: SqlQuery,
  211. args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} =
  212. ## Executes the query and iterates over the result dataset.
  213. ##
  214. ## This is very fast, but potentially dangerous. Use this iterator only
  215. ## if you require **ALL** the rows.
  216. ##
  217. ## **Note:** Breaking the `fastRows()` iterator during a loop will cause the
  218. ## next database query to raise a `DbError` exception ``unable to close due
  219. ## to ...``.
  220. ##
  221. ## **Examples:**
  222. ##
  223. ## .. code-block:: Nim
  224. ##
  225. ## let db = open("mytest.db", "", "", "")
  226. ##
  227. ## # Records of my_table:
  228. ## # | id | name |
  229. ## # |----|----------|
  230. ## # | 1 | item#1 |
  231. ## # | 2 | item#2 |
  232. ##
  233. ## for row in db.fastRows(sql"SELECT id, name FROM my_table"):
  234. ## echo row
  235. ##
  236. ## # Output:
  237. ## # @["1", "item#1"]
  238. ## # @["2", "item#2"]
  239. ##
  240. ## db.close()
  241. var stmt = setupQuery(db, query, args)
  242. var L = (column_count(stmt))
  243. var result = newRow(L)
  244. try:
  245. while step(stmt) == SQLITE_ROW:
  246. setRow(stmt, result, L)
  247. yield result
  248. finally:
  249. if finalize(stmt) != SQLITE_OK: dbError(db)
  250. iterator instantRows*(db: DbConn, query: SqlQuery,
  251. args: varargs[string, `$`]): InstantRow
  252. {.tags: [ReadDbEffect].} =
  253. ## Similar to `fastRows iterator <#fastRows.i,DbConn,SqlQuery,varargs[string,]>`_
  254. ## but returns a handle that can be used to get column text
  255. ## on demand using `[]`. Returned handle is valid only within the iterator body.
  256. ##
  257. ## **Examples:**
  258. ##
  259. ## .. code-block:: Nim
  260. ##
  261. ## let db = open("mytest.db", "", "", "")
  262. ##
  263. ## # Records of my_table:
  264. ## # | id | name |
  265. ## # |----|----------|
  266. ## # | 1 | item#1 |
  267. ## # | 2 | item#2 |
  268. ##
  269. ## for row in db.instantRows(sql"SELECT * FROM my_table"):
  270. ## echo "id:" & row[0]
  271. ## echo "name:" & row[1]
  272. ## echo "length:" & $len(row)
  273. ##
  274. ## # Output:
  275. ## # id:1
  276. ## # name:item#1
  277. ## # length:2
  278. ## # id:2
  279. ## # name:item#2
  280. ## # length:2
  281. ##
  282. ## db.close()
  283. var stmt = setupQuery(db, query, args)
  284. try:
  285. while step(stmt) == SQLITE_ROW:
  286. yield stmt
  287. finally:
  288. if finalize(stmt) != SQLITE_OK: dbError(db)
  289. proc toTypeKind(t: var DbType; x: int32) =
  290. case x
  291. of SQLITE_INTEGER:
  292. t.kind = dbInt
  293. t.size = 8
  294. of SQLITE_FLOAT:
  295. t.kind = dbFloat
  296. t.size = 8
  297. of SQLITE_BLOB: t.kind = dbBlob
  298. of SQLITE_NULL: t.kind = dbNull
  299. of SQLITE_TEXT: t.kind = dbVarchar
  300. else: t.kind = dbUnknown
  301. proc setColumns(columns: var DbColumns; x: PStmt) =
  302. let L = column_count(x)
  303. setLen(columns, L)
  304. for i in 0'i32 ..< L:
  305. columns[i].name = $column_name(x, i)
  306. columns[i].typ.name = $column_decltype(x, i)
  307. toTypeKind(columns[i].typ, column_type(x, i))
  308. columns[i].tableName = $column_table_name(x, i)
  309. iterator instantRows*(db: DbConn; columns: var DbColumns; query: SqlQuery,
  310. args: varargs[string, `$`]): InstantRow
  311. {.tags: [ReadDbEffect].} =
  312. ## Similar to `instantRows iterator <#instantRows.i,DbConn,SqlQuery,varargs[string,]>`_,
  313. ## but sets information about columns to `columns`.
  314. ##
  315. ## **Examples:**
  316. ##
  317. ## .. code-block:: Nim
  318. ##
  319. ## let db = open("mytest.db", "", "", "")
  320. ##
  321. ## # Records of my_table:
  322. ## # | id | name |
  323. ## # |----|----------|
  324. ## # | 1 | item#1 |
  325. ## # | 2 | item#2 |
  326. ##
  327. ## var columns: DbColumns
  328. ## for row in db.instantRows(columns, sql"SELECT * FROM my_table"):
  329. ## discard
  330. ## echo columns[0]
  331. ##
  332. ## # Output:
  333. ## # (name: "id", tableName: "my_table", typ: (kind: dbNull,
  334. ## # notNull: false, name: "INTEGER", size: 0, maxReprLen: 0, precision: 0,
  335. ## # scale: 0, min: 0, max: 0, validValues: @[]), primaryKey: false,
  336. ## # foreignKey: false)
  337. ##
  338. ## db.close()
  339. var stmt = setupQuery(db, query, args)
  340. setColumns(columns, stmt)
  341. try:
  342. while step(stmt) == SQLITE_ROW:
  343. yield stmt
  344. finally:
  345. if finalize(stmt) != SQLITE_OK: dbError(db)
  346. proc `[]`*(row: InstantRow, col: int32): string {.inline.} =
  347. ## Returns text for given column of the row.
  348. ##
  349. ## See also:
  350. ## * `instantRows iterator <#instantRows.i,DbConn,SqlQuery,varargs[string,]>`_
  351. ## example code
  352. $column_text(row, col)
  353. proc unsafeColumnAt*(row: InstantRow, index: int32): cstring {.inline.} =
  354. ## Returns cstring for given column of the row.
  355. ##
  356. ## See also:
  357. ## * `instantRows iterator <#instantRows.i,DbConn,SqlQuery,varargs[string,]>`_
  358. ## example code
  359. column_text(row, index)
  360. proc len*(row: InstantRow): int32 {.inline.} =
  361. ## Returns number of columns in a row.
  362. ##
  363. ## See also:
  364. ## * `instantRows iterator <#instantRows.i,DbConn,SqlQuery,varargs[string,]>`_
  365. ## example code
  366. column_count(row)
  367. proc getRow*(db: DbConn, query: SqlQuery,
  368. args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} =
  369. ## Retrieves a single row. If the query doesn't return any rows, this proc
  370. ## will return a `Row` with empty strings for each column.
  371. ##
  372. ## **Examples:**
  373. ##
  374. ## .. code-block:: Nim
  375. ##
  376. ## let db = open("mytest.db", "", "", "")
  377. ##
  378. ## # Records of my_table:
  379. ## # | id | name |
  380. ## # |----|----------|
  381. ## # | 1 | item#1 |
  382. ## # | 2 | item#2 |
  383. ##
  384. ## doAssert db.getRow(sql"SELECT id, name FROM my_table"
  385. ## ) == Row(@["1", "item#1"])
  386. ## doAssert db.getRow(sql"SELECT id, name FROM my_table WHERE id = ?",
  387. ## 2) == Row(@["2", "item#2"])
  388. ##
  389. ## # Returns empty.
  390. ## doAssert db.getRow(sql"INSERT INTO my_table (id, name) VALUES (?, ?)",
  391. ## 3, "item#3") == @[]
  392. ## doAssert db.getRow(sql"DELETE FROM my_table WHERE id = ?", 3) == @[]
  393. ## doAssert db.getRow(sql"UPDATE my_table SET name = 'ITEM#1' WHERE id = ?",
  394. ## 1) == @[]
  395. ## db.close()
  396. var stmt = setupQuery(db, query, args)
  397. var L = (column_count(stmt))
  398. result = newRow(L)
  399. if step(stmt) == SQLITE_ROW:
  400. setRow(stmt, result, L)
  401. if finalize(stmt) != SQLITE_OK: dbError(db)
  402. proc getAllRows*(db: DbConn, query: SqlQuery,
  403. args: varargs[string, `$`]): seq[Row] {.tags: [ReadDbEffect].} =
  404. ## Executes the query and returns the whole result dataset.
  405. ##
  406. ## **Examples:**
  407. ##
  408. ## .. code-block:: Nim
  409. ##
  410. ## let db = open("mytest.db", "", "", "")
  411. ##
  412. ## # Records of my_table:
  413. ## # | id | name |
  414. ## # |----|----------|
  415. ## # | 1 | item#1 |
  416. ## # | 2 | item#2 |
  417. ##
  418. ## doAssert db.getAllRows(sql"SELECT id, name FROM my_table") == @[Row(@["1", "item#1"]), Row(@["2", "item#2"])]
  419. ## db.close()
  420. result = @[]
  421. for r in fastRows(db, query, args):
  422. result.add(r)
  423. iterator rows*(db: DbConn, query: SqlQuery,
  424. args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} =
  425. ## Similar to `fastRows iterator <#fastRows.i,DbConn,SqlQuery,varargs[string,]>`_,
  426. ## but slower and safe.
  427. ##
  428. ## **Examples:**
  429. ##
  430. ## .. code-block:: Nim
  431. ##
  432. ## let db = open("mytest.db", "", "", "")
  433. ##
  434. ## # Records of my_table:
  435. ## # | id | name |
  436. ## # |----|----------|
  437. ## # | 1 | item#1 |
  438. ## # | 2 | item#2 |
  439. ##
  440. ## for row in db.rows(sql"SELECT id, name FROM my_table"):
  441. ## echo row
  442. ##
  443. ## ## Output:
  444. ## ## @["1", "item#1"]
  445. ## ## @["2", "item#2"]
  446. ##
  447. ## db.close()
  448. for r in fastRows(db, query, args): yield r
  449. proc getValue*(db: DbConn, query: SqlQuery,
  450. args: varargs[string, `$`]): string {.tags: [ReadDbEffect].} =
  451. ## Executes the query and returns the first column of the first row of the
  452. ## result dataset. Returns `""` if the dataset contains no rows or the database
  453. ## value is `NULL`.
  454. ##
  455. ## **Examples:**
  456. ##
  457. ## .. code-block:: Nim
  458. ##
  459. ## let db = open("mytest.db", "", "", "")
  460. ##
  461. ## # Records of my_table:
  462. ## # | id | name |
  463. ## # |----|----------|
  464. ## # | 1 | item#1 |
  465. ## # | 2 | item#2 |
  466. ##
  467. ## doAssert db.getValue(sql"SELECT name FROM my_table WHERE id = ?",
  468. ## 2) == "item#2"
  469. ## doAssert db.getValue(sql"SELECT id, name FROM my_table") == "1"
  470. ## doAssert db.getValue(sql"SELECT name, id FROM my_table") == "item#1"
  471. ##
  472. ## db.close()
  473. var stmt = setupQuery(db, query, args)
  474. if step(stmt) == SQLITE_ROW:
  475. let cb = column_bytes(stmt, 0)
  476. if cb == 0:
  477. result = ""
  478. else:
  479. result = newStringOfCap(cb)
  480. add(result, column_text(stmt, 0))
  481. else:
  482. result = ""
  483. if finalize(stmt) != SQLITE_OK: dbError(db)
  484. proc tryInsertID*(db: DbConn, query: SqlQuery,
  485. args: varargs[string, `$`]): int64
  486. {.tags: [WriteDbEffect], raises: [].} =
  487. ## Executes the query (typically "INSERT") and returns the
  488. ## generated ID for the row or -1 in case of an error.
  489. ##
  490. ## **Examples:**
  491. ##
  492. ## .. code-block:: Nim
  493. ##
  494. ## let db = open("mytest.db", "", "", "")
  495. ## db.exec(sql"CREATE TABLE my_table (id INTEGER, name VARCHAR(50) NOT NULL)")
  496. ##
  497. ## doAssert db.tryInsertID(sql"INSERT INTO not_exist_table (id, name) VALUES (?, ?)",
  498. ## 1, "item#1") == -1
  499. ## db.close()
  500. assert(not db.isNil, "Database not connected.")
  501. var q = dbFormat(query, args)
  502. var stmt: sqlite3.PStmt
  503. result = -1
  504. if prepare_v2(db, q, q.len.cint, stmt, nil) == SQLITE_OK:
  505. if step(stmt) == SQLITE_DONE:
  506. result = last_insert_rowid(db)
  507. if finalize(stmt) != SQLITE_OK:
  508. result = -1
  509. proc insertID*(db: DbConn, query: SqlQuery,
  510. args: varargs[string, `$`]): int64 {.tags: [WriteDbEffect].} =
  511. ## Executes the query (typically "INSERT") and returns the
  512. ## generated ID for the row.
  513. ##
  514. ## Raises a `DbError` exception when failed to insert row.
  515. ## For Postgre this adds ``RETURNING id`` to the query, so it only works
  516. ## if your primary key is named ``id``.
  517. ##
  518. ## **Examples:**
  519. ##
  520. ## .. code-block:: Nim
  521. ##
  522. ## let db = open("mytest.db", "", "", "")
  523. ## db.exec(sql"CREATE TABLE my_table (id INTEGER, name VARCHAR(50) NOT NULL)")
  524. ##
  525. ## for i in 0..2:
  526. ## let id = db.insertID(sql"INSERT INTO my_table (id, name) VALUES (?, ?)", i, "item#" & $i)
  527. ## echo "LoopIndex = ", i, ", InsertID = ", id
  528. ##
  529. ## # Output:
  530. ## # LoopIndex = 0, InsertID = 1
  531. ## # LoopIndex = 1, InsertID = 2
  532. ## # LoopIndex = 2, InsertID = 3
  533. ##
  534. ## db.close()
  535. result = tryInsertID(db, query, args)
  536. if result < 0: dbError(db)
  537. proc execAffectedRows*(db: DbConn, query: SqlQuery,
  538. args: varargs[string, `$`]): int64 {.
  539. tags: [ReadDbEffect, WriteDbEffect].} =
  540. ## Executes the query (typically "UPDATE") and returns the
  541. ## number of affected rows.
  542. ##
  543. ## **Examples:**
  544. ##
  545. ## .. code-block:: Nim
  546. ##
  547. ## let db = open("mytest.db", "", "", "")
  548. ##
  549. ## # Records of my_table:
  550. ## # | id | name |
  551. ## # |----|----------|
  552. ## # | 1 | item#1 |
  553. ## # | 2 | item#2 |
  554. ##
  555. ## doAssert db.execAffectedRows(sql"UPDATE my_table SET name = 'TEST'") == 2
  556. ##
  557. ## db.close()
  558. exec(db, query, args)
  559. result = changes(db)
  560. proc close*(db: DbConn) {.tags: [DbEffect].} =
  561. ## Closes the database connection.
  562. ##
  563. ## **Examples:**
  564. ##
  565. ## .. code-block:: Nim
  566. ##
  567. ## let db = open("mytest.db", "", "", "")
  568. ## db.close()
  569. if sqlite3.close(db) != SQLITE_OK: dbError(db)
  570. proc open*(connection, user, password, database: string): DbConn {.
  571. tags: [DbEffect].} =
  572. ## Opens a database connection. Raises a `DbError` exception if the connection
  573. ## could not be established.
  574. ##
  575. ## **Note:** Only the ``connection`` parameter is used for ``sqlite``.
  576. ##
  577. ## **Examples:**
  578. ##
  579. ## .. code-block:: Nim
  580. ##
  581. ## try:
  582. ## let db = open("mytest.db", "", "", "")
  583. ## ## do something...
  584. ## ## db.getAllRows(sql"SELECT * FROM my_table")
  585. ## db.close()
  586. ## except:
  587. ## stderr.writeLine(getCurrentExceptionMsg())
  588. var db: DbConn
  589. if sqlite3.open(connection, db) == SQLITE_OK:
  590. result = db
  591. else:
  592. dbError(db)
  593. proc setEncoding*(connection: DbConn, encoding: string): bool {.
  594. tags: [DbEffect].} =
  595. ## Sets the encoding of a database connection, returns `true` for
  596. ## success, `false` for failure.
  597. ##
  598. ## **Note:** The encoding cannot be changed once it's been set.
  599. ## According to SQLite3 documentation, any attempt to change
  600. ## the encoding after the database is created will be silently
  601. ## ignored.
  602. exec(connection, sql"PRAGMA encoding = ?", [encoding])
  603. result = connection.getValue(sql"PRAGMA encoding") == encoding
  604. when not defined(testing) and isMainModule:
  605. var db = open("db.sql", "", "", "")
  606. exec(db, sql"create table tbl1(one varchar(10), two smallint)", [])
  607. exec(db, sql"insert into tbl1 values('hello!',10)", [])
  608. exec(db, sql"insert into tbl1 values('goodbye', 20)", [])
  609. #db.query("create table tbl1(one varchar(10), two smallint)")
  610. #db.query("insert into tbl1 values('hello!',10)")
  611. #db.query("insert into tbl1 values('goodbye', 20)")
  612. for r in db.rows(sql"select * from tbl1", []):
  613. echo(r[0], r[1])
  614. for r in db.instantRows(sql"select * from tbl1", []):
  615. echo(r[0], r[1])
  616. db_sqlite.close(db)