; This small library is based on https://github.com/Wiladams/LJIT2SQLite ; It is meant to be an _extremely_ thin wrapper around the SQLite API. (local sqlffi (require :diet-sqlite.sqlite3_ffi)) (local ffi (require :ffi)) (local util (require :lib.util)) (local {: SQLITE_OK : SQLITE_INTEGER : SQLITE_FLOAT : SQLITE_NULL : SQLITE_BLOB : SQLITE_TEXT : SQLITE_TRANSIENT} (require :diet-sqlite.codes)) (local sql {:step sqlffi.sqlite3_step :reset sqlffi.sqlite3_reset}) (fn sql.open [dbname] (let [lpdb (ffi.new "sqlite3*[1]") rc (sqlffi.sqlite3_open dbname lpdb) db (. lpdb 0)] (when (not= db nil) (ffi.gc db sqlffi.sqlite3_close_v2)) (values rc (. lpdb 0)))) (fn sql.close [db] (ffi.gc db nil) (sqlffi.sqlite3_close_v2 db)) (fn sql.prepare [db sql ?flags] (let [ppStmt (ffi.new "sqlite3_stmt *[1]") rc (sqlffi.sqlite3_prepare_v3 db sql -1 (or ?flags 0) ppStmt nil) stmt (. ppStmt 0)] (when (not= stmt nil) (ffi.gc stmt sqlffi.sqlite3_finalize)) (values rc stmt))) ; this exists just to have a unique object identity you can shove into a table (set sql.null {}) (fn sql.bind [stmt i ?val] (match (type i) :table (each [ival val (ipairs i)] (sql.assert (sql.bind stmt ival val))) :number (match (type ?val) :string (sqlffi.sqlite3_bind_text stmt i ?val (length ?val) SQLITE_TRANSIENT) :number (sqlffi.sqlite3_bind_double stmt i ?val) :nil (sqlffi.sqlite3_bind_null stmt i) (where :table (= ?val sql.null)) (sqlffi.sqlite3_bind_null stmt i) _ (error (.. "Don't know how to bind value " (fv ?val)))))) (fn sql.column [stmt icol] (let [i (- icol 1)] ; column indexes are 0-based (match (sqlffi.sqlite3_column_type stmt i) SQLITE_INTEGER (sqlffi.sqlite3_column_double stmt i) SQLITE_FLOAT (sqlffi.sqlite3_column_double stmt i) SQLITE_NULL nil SQLITE_TEXT (ffi.string (sqlffi.sqlite3_column_text stmt i)) SQLITE_BLOB (error "no blob support right now") ?unknown (error (.. "unrecognized type " ?unknown))))) (fn sql.columns [stmt] (icollect [i (util.countiter (sqlffi.sqlite3_column_count stmt))] (or (sql.column stmt i) sql.null))) (fn sql.assert-rc [rc-expect rc ...] (if (= rc-expect rc) ... (error (.. "Expected " rc-expect ", got " rc)))) (fn sql.assert [...] (sql.assert-rc SQLITE_OK ...)) sql