diff --git a/diet-sqlite/codes.lua b/diet-sqlite/codes.lua new file mode 100644 index 0000000..e0221c9 --- /dev/null +++ b/diet-sqlite/codes.lua @@ -0,0 +1,281 @@ +--This file is generated by running the +--gencodes.lua +--script. If you want to alter this file, it is best +--to make the changes in that script and run it again. +local ffi = require "ffi" + +return { +SQLITE_TRANSIENT = ffi.cast('void(*)(void*)', -1); +SQLITE_STATIC = ffi.cast('void(*)(void*)', 0); + +-- error codes +SQLITE_EMPTY = 16; +SQLITE_CANTOPEN = 14; +SQLITE_FULL = 13; +SQLITE_BUSY = 5; +SQLITE_FORMAT = 24; +SQLITE_READONLY = 8; +SQLITE_LOCKED = 6; +SQLITE_INTERNAL = 2; +SQLITE_ROW = 100; +SQLITE_PERM = 3; +SQLITE_CORRUPT = 11; +SQLITE_ABORT = 4; +SQLITE_SCHEMA = 17; +SQLITE_DONE = 101; +SQLITE_MISMATCH = 20; +SQLITE_OK = 0; +SQLITE_TOOBIG = 18; +SQLITE_AUTH = 23; +SQLITE_NOLFS = 22; +SQLITE_PROTOCOL = 15; +SQLITE_IOERR = 10; +SQLITE_CONSTRAINT = 19; +SQLITE_NOTADB = 26; +SQLITE_MISUSE = 21; +SQLITE_RANGE = 25; +SQLITE_NOMEM = 7; +SQLITE_ERROR = 1; +SQLITE_INTERRUPT = 9; +SQLITE_NOTFOUND = 12; +-- Codes +SQLITE_IOERR_BLOCKED = 2826; +SQLITE_LIMIT_EXPR_DEPTH = 3; +SQLITE_IOERR_SHMMAP = 5386; +SQLITE_ACCESS_READ = 2; +SQLITE_IOCAP_SAFE_APPEND = 512; +SQLITE_READONLY_CANTLOCK = 520; +SQLITE_CREATE_INDEX = 1; +SQLITE_STATUS_SCRATCH_SIZE = 8; +SQLITE_OPEN_MAIN_JOURNAL = 2048; +SQLITE_CREATE_VIEW = 8; +SQLITE_SET_LOCKPROXYFILE = 3; +SQLITE_CANTOPEN_NOTEMPDIR = 270; +SQLITE_NULL = 5; +SQLITE_IOCAP_ATOMIC1K = 4; +SQLITE_STATUS_PAGECACHE_OVERFLOW = 2; +SQLITE_SHM_SHARED = 4; +SQLITE_ANALYZE = 28; +SQLITE_FCNTL_WIN32_AV_RETRY = 9; +SQLITE_LOCKED_SHAREDCACHE = 262; +SQLITE_OPEN_TRANSIENT_DB = 1024; +SQLITE_TESTCTRL_ALWAYS = 13; +SQLITE_DBCONFIG_LOOKASIDE = 1001; +SQLITE_CREATE_TEMP_TRIGGER = 5; +SQLITE_IOERR_TRUNCATE = 1546; +SQLITE_IOERR_DELETE = 2570; +SQLITE_GET_LOCKPROXYFILE = 2; +SQLITE_FCNTL_SIZE_HINT = 5; +SQLITE_STATUS_SCRATCH_OVERFLOW = 4; +SQLITE_OPEN_MAIN_DB = 256; +SQLITE_STATUS_PARSER_STACK = 6; +SQLITE_OPEN_PRIVATECACHE = 262144; +SQLITE_FUNCTION = 31; +SQLITE_LIMIT_LIKE_PATTERN_LENGTH = 8; +SQLITE_IOERR_SEEK = 5642; +SQLITE_FCNTL_CHUNK_SIZE = 6; +SQLITE_DROP_TEMP_VIEW = 15; +SQLITE_DBSTATUS_LOOKASIDE_USED = 0; +SQLITE_IOCAP_POWERSAFE_OVERWRITE = 4096; +SQLITE_CONFIG_URI = 17; +SQLITE_IOERR_READ = 266; +SQLITE_ABORT = 4; +SQLITE_DBSTATUS_MAX = 9; +SQLITE_OPEN_FULLMUTEX = 65536; +SQLITE_IOCAP_ATOMIC64K = 256; +SQLITE_CREATE_TEMP_VIEW = 6; +SQLITE_ATTACH = 24; +SQLITE_CREATE_TRIGGER = 7; +SQLITE_MUTEX_FAST = 0; +SQLITE_REPLACE = 5; +SQLITE_TESTCTRL_PENDING_BYTE = 11; +SQLITE_DELETE = 9; +SQLITE_IOERR_DIR_FSYNC = 1290; +SQLITE_FCNTL_PRAGMA = 14; +SQLITE_FAIL = 3; +SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE = 5; +SQLITE_STMTSTATUS_SORT = 2; +SQLITE_IOERR_LOCK = 3850; +SQLITE_VTAB_CONSTRAINT_SUPPORT = 1; +SQLITE_CHECKPOINT_RESTART = 2; +SQLITE_OPEN_READONLY = 1; +SQLITE_CONFIG_MUTEX = 10; +SQLITE_IOCAP_ATOMIC512 = 2; +SQLITE_FCNTL_VFSNAME = 12; +SQLITE_DBSTATUS_CACHE_HIT = 7; +SQLITE_IOERR_NOMEM = 3082; +SQLITE_CHECKPOINT_PASSIVE = 0; +SQLITE_IOERR_CHECKRESERVEDLOCK = 3594; +SQLITE_IOERR_RDLOCK = 2314; +SQLITE_STMTSTATUS_AUTOINDEX = 3; +SQLITE_ROLLBACK = 1; +SQLITE_UTF16BE = 3; +SQLITE_INDEX_CONSTRAINT_GE = 32; +SQLITE_IOERR_SHMOPEN = 4618; +SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN = 2048; +SQLITE_DBSTATUS_CACHE_WRITE = 9; +SQLITE_IOCAP_ATOMIC4K = 16; +SQLITE_LIMIT_VARIABLE_NUMBER = 9; +SQLITE_DBSTATUS_CACHE_MISS = 8; +SQLITE_CHECKPOINT_FULL = 1; +SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL = 6; +SQLITE_DBSTATUS_LOOKASIDE_HIT = 4; +SQLITE_STATUS_PAGECACHE_SIZE = 7; +SQLITE_SYNC_NORMAL = 2; +SQLITE_DBSTATUS_SCHEMA_USED = 2; +SQLITE_CONFIG_SINGLETHREAD = 1; +SQLITE_LIMIT_SQL_LENGTH = 1; +SQLITE_FCNTL_FILE_POINTER = 7; +SQLITE_CREATE_TEMP_INDEX = 3; +SQLITE_READ = 20; +SQLITE_STATUS_MALLOC_COUNT = 9; +SQLITE_DBSTATUS_STMT_USED = 3; +SQLITE_SHM_EXCLUSIVE = 8; +SQLITE_INDEX_CONSTRAINT_LE = 8; +SQLITE_BUSY_RECOVERY = 261; +SQLITE_DROP_VIEW = 17; +SQLITE_TESTCTRL_PRNG_SAVE = 5; +SQLITE_OPEN_MASTER_JOURNAL = 16384; +SQLITE_PRAGMA = 19; +SQLITE_CONFIG_MALLOC = 4; +SQLITE_UTF16 = 4; +SQLITE_STATUS_MEMORY_USED = 0; +SQLITE_TESTCTRL_LAST = 19; +SQLITE_CONFIG_SERIALIZED = 3; +SQLITE_FCNTL_LOCKSTATE = 1; +SQLITE_OPEN_TEMP_DB = 512; +SQLITE_TESTCTRL_EXPLAIN_STMT = 19; +SQLITE_MUTEX_STATIC_PMEM = 7; +SQLITE_OPEN_SUBJOURNAL = 8192; +SQLITE_TESTCTRL_BITVEC_TEST = 8; +SQLITE_DROP_TRIGGER = 16; +SQLITE_ALTER_TABLE = 26; +SQLITE_IOERR_UNLOCK = 2058; +SQLITE_CONFIG_GETMALLOC = 5; +SQLITE_SHM_LOCK = 2; +SQLITE_DROP_TEMP_TABLE = 13; +SQLITE_FLOAT = 2; +SQLITE_OPEN_CREATE = 4; +SQLITE_TESTCTRL_RESERVE = 14; +SQLITE_TESTCTRL_ASSERT = 12; +SQLITE_FCNTL_OVERWRITE = 11; +SQLITE_STATUS_MALLOC_SIZE = 5; +SQLITE_OPEN_SHAREDCACHE = 131072; +SQLITE_OPEN_URI = 64; +SQLITE_TESTCTRL_SCRATCHMALLOC = 17; +SQLITE_DROP_TABLE = 11; +SQLITE_TESTCTRL_PRNG_RESET = 7; +SQLITE_CREATE_TEMP_TABLE = 4; +SQLITE_TESTCTRL_PRNG_RESTORE = 6; +SQLITE_STATUS_SCRATCH_USED = 3; +SQLITE_LIMIT_TRIGGER_DEPTH = 10; +SQLITE_MUTEX_STATIC_LRU2 = 7; +SQLITE_TESTCTRL_FIRST = 5; +SQLITE_OPEN_AUTOPROXY = 32; +SQLITE_SYNC_FULL = 3; +SQLITE_TESTCTRL_LOCALTIME_FAULT = 18; +SQLITE_TESTCTRL_FAULT_INSTALL = 9; +SQLITE_MUTEX_STATIC_PRNG = 5; +SQLITE_MUTEX_STATIC_OPEN = 4; +SQLITE_MUTEX_STATIC_MEM2 = 4; +SQLITE_TRANSACTION = 22; +SQLITE_MUTEX_STATIC_MEM = 3; +SQLITE_IOERR_DIR_CLOSE = 4362; +SQLITE_MUTEX_STATIC_MASTER = 2; +SQLITE_MUTEX_RECURSIVE = 1; +SQLITE_CREATE_VTABLE = 29; +SQLITE_CONFIG_SCRATCH = 6; +SQLITE_STMTSTATUS_FULLSCAN_STEP = 1; +SQLITE_INDEX_CONSTRAINT_LT = 16; +SQLITE_MUTEX_STATIC_LRU = 6; +SQLITE_DBCONFIG_ENABLE_TRIGGER = 1003; +SQLITE_CONFIG_MEMSTATUS = 9; +SQLITE_BLOB = 4; +SQLITE_UTF16_ALIGNED = 8; +SQLITE_DETACH = 25; +SQLITE_STATUS_PAGECACHE_USED = 1; +SQLITE_FCNTL_PERSIST_WAL = 10; +SQLITE_IOERR_SHORT_READ = 522; +SQLITE_UTF16LE = 2; +SQLITE_UTF8 = 1; +SQLITE_TEXT = 3; +SQLITE_INDEX_CONSTRAINT_EQ = 2; +SQLITE_IOERR_SHMSIZE = 4874; +SQLITE_INSERT = 18; +SQLITE_LOCK_RESERVED = 2; +SQLITE_LIMIT_ATTACHED = 7; +SQLITE_LIMIT_COLUMN = 2; +SQLITE_IOERR_FSTAT = 1802; +SQLITE_CONFIG_LOOKASIDE = 13; +SQLITE_CONFIG_GETPCACHE2 = 19; +SQLITE_READONLY_RECOVERY = 264; +SQLITE_CONFIG_GETMUTEX = 11; +SQLITE_IOCAP_ATOMIC16K = 64; +SQLITE_LIMIT_FUNCTION_ARG = 6; +SQLITE_REINDEX = 27; +SQLITE_OPEN_READWRITE = 2; +SQLITE_COPY = 0; +SQLITE_SAVEPOINT = 32; +SQLITE_DROP_VTABLE = 30; +SQLITE_IOERR_CLOSE = 4106; +SQLITE_INDEX_CONSTRAINT_MATCH = 64; +SQLITE_ANY = 5; +SQLITE_UPDATE = 23; +SQLITE_SELECT = 21; +SQLITE_DROP_INDEX = 10; +SQLITE_INDEX_CONSTRAINT_GT = 4; +SQLITE_IOCAP_SEQUENTIAL = 1024; +SQLITE_CONFIG_PAGECACHE = 7; +SQLITE_TESTCTRL_OPTIMIZATIONS = 15; +SQLITE_IOERR_ACCESS = 3338; +SQLITE_IOCAP_ATOMIC = 1; +SQLITE_TESTCTRL_ISKEYWORD = 16; +SQLITE_IOCAP_ATOMIC32K = 128; +SQLITE_DROP_TEMP_TRIGGER = 14; +SQLITE_OPEN_WAL = 524288; +SQLITE_OPEN_EXCLUSIVE = 16; +SQLITE_CORRUPT_VTAB = 267; +SQLITE_OPEN_TEMP_JOURNAL = 4096; +SQLITE_CANTOPEN_ISDIR = 526; +SQLITE_OPEN_DELETEONCLOSE = 8; +SQLITE_CONFIG_HEAP = 8; +SQLITE_INTEGER = 1; +SQLITE_ACCESS_EXISTS = 0; +SQLITE_FCNTL_POWERSAFE_OVERWRITE = 13; +SQLITE_LIMIT_VDBE_OP = 5; +SQLITE_IOERR_FSYNC = 1034; +SQLITE_LOCK_SHARED = 1; +SQLITE_IOCAP_ATOMIC2K = 8; +SQLITE_LOCK_EXCLUSIVE = 4; +SQLITE_DBSTATUS_CACHE_USED = 1; +SQLITE_LOCK_PENDING = 3; +SQLITE_SYNC_DATAONLY = 16; +SQLITE_DENY = 1; +SQLITE_DROP_TEMP_INDEX = 12; +SQLITE_LAST_ERRNO = 4; +SQLITE_FCNTL_SYNC_OMITTED = 8; +SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS = 10; +SQLITE_CONFIG_LOG = 16; +SQLITE_OPEN_NOMUTEX = 32768; +SQLITE_DBCONFIG_ENABLE_FKEY = 1002; +SQLITE_IGNORE = 2; +SQLITE_IOERR_WRITE = 778; +SQLITE_IOERR_SHMLOCK = 5130; +SQLITE_CONFIG_MULTITHREAD = 2; +SQLITE_ABORT_ROLLBACK = 516; +SQLITE_SHM_NLOCK = 8; +SQLITE_CONFIG_PCACHE = 14; +SQLITE_LIMIT_COMPOUND_SELECT = 4; +SQLITE_ACCESS_READWRITE = 1; +SQLITE_CONFIG_PCACHE2 = 18; +SQLITE_IOCAP_ATOMIC8K = 32; +SQLITE_LOCK_NONE = 0; +SQLITE_CREATE_TABLE = 2; +SQLITE_LIMIT_LENGTH = 0; +SQLITE_CONFIG_GETPCACHE = 15; +SQLITE_SHM_UNLOCK = 1; +SQLITE_PREPARE_PERSISTENT = 0x01; +SQLITE_PREPARE_NORMALIZE = 0x02; +SQLITE_PREPARE_NO_VTAB = 0x04; +} + diff --git a/diet-sqlite/init.fnl b/diet-sqlite/init.fnl new file mode 100644 index 0000000..f9113d5 --- /dev/null +++ b/diet-sqlite/init.fnl @@ -0,0 +1,61 @@ +; 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} (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 diff --git a/diet-sqlite/sqlite3_ffi.lua b/diet-sqlite/sqlite3_ffi.lua new file mode 100644 index 0000000..896030e --- /dev/null +++ b/diet-sqlite/sqlite3_ffi.lua @@ -0,0 +1,870 @@ +--[[ +** 2001 September 15 + ** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +--]] + + +local ffi = require "ffi" + +--[[ + Created from this version: + + #define SQLITE_VERSION "3.7.12.1" + #define SQLITE_VERSION_NUMBER 3007012 + #define SQLITE_SOURCE_ID "2012-05-22 02:45:53 6d326d44fd1d626aae0e8456e5fa2049f1ce0789" +--]] + + +ffi.cdef[[ + +const char sqlite3_version[]; +const char *sqlite3_libversion(void); +const char *sqlite3_sourceid(void); +int sqlite3_libversion_number(void); + + + +int sqlite3_threadsafe(void); + + +typedef struct sqlite3 sqlite3; + + +typedef int64_t sqlite3_int64; +typedef uint64_t sqlite3_uint64; + + + + int sqlite3_close(sqlite3 *); + int sqlite3_close_v2(sqlite3 *); + + + int sqlite3_exec( + sqlite3*, /* An open database */ + const char *sql, /* SQL to be evaluated */ + int (*callback)(void*,int,char**,char**), /* Callback function */ + void *, /* 1st argument to callback */ + char **errmsg /* Error msg written here */ +); + + +typedef struct sqlite3_file sqlite3_file; +struct sqlite3_file { + const struct sqlite3_io_methods *pMethods; +}; + + +typedef struct sqlite3_io_methods sqlite3_io_methods; +struct sqlite3_io_methods { + int iVersion; + int (*xClose)(sqlite3_file*); + int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); + int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst); + int (*xTruncate)(sqlite3_file*, sqlite3_int64 size); + int (*xSync)(sqlite3_file*, int flags); + int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize); + int (*xLock)(sqlite3_file*, int); + int (*xUnlock)(sqlite3_file*, int); + int (*xCheckReservedLock)(sqlite3_file*, int *pResOut); + int (*xFileControl)(sqlite3_file*, int op, void *pArg); + int (*xSectorSize)(sqlite3_file*); + int (*xDeviceCharacteristics)(sqlite3_file*); + int (*xShmMap)(sqlite3_file*, int iPg, int pgsz, int, void volatile**); + int (*xShmLock)(sqlite3_file*, int offset, int n, int flags); + void (*xShmBarrier)(sqlite3_file*); + int (*xShmUnmap)(sqlite3_file*, int deleteFlag); +}; + + + + + + + + +typedef struct sqlite3_mutex sqlite3_mutex; + + +typedef struct sqlite3_vfs sqlite3_vfs; +typedef void (*sqlite3_syscall_ptr)(void); +struct sqlite3_vfs { + int iVersion; + int szOsFile; + int mxPathname; + sqlite3_vfs *pNext; + const char *zName; + void *pAppData; + int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*, + int flags, int *pOutFlags); + int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir); + int (*xAccess)(sqlite3_vfs*, const char *zName, int flags, int *pResOut); + int (*xFullPathname)(sqlite3_vfs*, const char *zName, int nOut, char *zOut); + void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename); + void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg); + void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(void); + void (*xDlClose)(sqlite3_vfs*, void*); + int (*xRandomness)(sqlite3_vfs*, int nByte, char *zOut); + int (*xSleep)(sqlite3_vfs*, int microseconds); + int (*xCurrentTime)(sqlite3_vfs*, double*); + int (*xGetLastError)(sqlite3_vfs*, int, char *); + + int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*); + + int (*xSetSystemCall)(sqlite3_vfs*, const char *zName, sqlite3_syscall_ptr); + sqlite3_syscall_ptr (*xGetSystemCall)(sqlite3_vfs*, const char *zName); + const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName); + +}; + + + + + + + int sqlite3_initialize(void); + int sqlite3_shutdown(void); + int sqlite3_os_init(void); + int sqlite3_os_end(void); + + + int sqlite3_config(int, ...); + + + int sqlite3_db_config(sqlite3*, int op, ...); + + +typedef struct sqlite3_mem_methods sqlite3_mem_methods; +struct sqlite3_mem_methods { + void *(*xMalloc)(int); /* Memory allocation function */ + void (*xFree)(void*); /* Free a prior allocation */ + void *(*xRealloc)(void*,int); /* Resize an allocation */ + int (*xSize)(void*); /* Return the size of an allocation */ + int (*xRoundup)(int); /* Round up request size to allocation size */ + int (*xInit)(void*); /* Initialize the memory allocator */ + void (*xShutdown)(void*); /* Deinitialize the memory allocator */ + void *pAppData; /* Argument to xInit() and xShutdown() */ +}; + + + + + + + + int sqlite3_extended_result_codes(sqlite3*, int onoff); + + + sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); + + + int sqlite3_changes(sqlite3*); + + + int sqlite3_total_changes(sqlite3*); + + + void sqlite3_interrupt(sqlite3*); + + + int sqlite3_complete(const char *sql); + int sqlite3_complete16(const void *sql); + + + int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); + + + int sqlite3_busy_timeout(sqlite3*, int ms); + +/* +// Legacy, don't want to use this in new code + int sqlite3_get_table( + sqlite3 *db, // An open database + const char *zSql, // SQL to be evaluated + char ***pazResult, // Results of the query + int *pnRow, // Number of result rows written here + int *pnColumn, // Number of result columns written here + char **pzErrmsg // Error msg written here +); + void sqlite3_free_table(char **result); +*/ + + char *sqlite3_mprintf(const char*,...); + char *sqlite3_vmprintf(const char*, va_list); + char *sqlite3_snprintf(int,char*,const char*, ...); + char *sqlite3_vsnprintf(int,char*,const char*, va_list); + + + void *sqlite3_malloc(int); + void *sqlite3_realloc(void*, int); + void sqlite3_free(void*); + + + sqlite3_int64 sqlite3_memory_used(void); + sqlite3_int64 sqlite3_memory_highwater(int resetFlag); + + + void sqlite3_randomness(int N, void *P); + + +int sqlite3_set_authorizer(sqlite3*, + int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), + void *pUserData +); + + + + void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*); + void *sqlite3_profile(sqlite3*, + void(*xProfile)(void*,const char*,sqlite3_uint64), void*); + + + void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); + + int sqlite3_open( + const char *filename, /* Database filename (UTF-8) */ + sqlite3 **ppDb /* OUT: SQLite db handle */ +); +int sqlite3_open16( + const void *filename, /* Database filename (UTF-16) */ + sqlite3 **ppDb /* OUT: SQLite db handle */ +); +int sqlite3_open_v2( + const char *filename, /* Database filename (UTF-8) */ + sqlite3 **ppDb, /* OUT: SQLite db handle */ + int flags, /* Flags */ + const char *zVfs /* Name of VFS module to use */ +); + + +const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam); +int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault); +sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64); + + + +int sqlite3_errcode(sqlite3 *db); +int sqlite3_extended_errcode(sqlite3 *db); +const char *sqlite3_errmsg(sqlite3*); +const void *sqlite3_errmsg16(sqlite3*); + + +typedef struct sqlite3_stmt sqlite3_stmt; + + +int sqlite3_limit(sqlite3*, int id, int newVal); + + + + +int sqlite3_prepare( + sqlite3 *db, /* Database handle */ + const char *zSql, /* SQL statement, UTF-8 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const char **pzTail /* OUT: Pointer to unused portion of zSql */ +); + int sqlite3_prepare_v2( + sqlite3 *db, /* Database handle */ + const char *zSql, /* SQL statement, UTF-8 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const char **pzTail /* OUT: Pointer to unused portion of zSql */ +); +int sqlite3_prepare_v3( + sqlite3 *db, /* Database handle */ + const char *zSql, /* SQL statement, UTF-8 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const char **pzTail /* OUT: Pointer to unused portion of zSql */ +); + int sqlite3_prepare16( + sqlite3 *db, /* Database handle */ + const void *zSql, /* SQL statement, UTF-16 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const void **pzTail /* OUT: Pointer to unused portion of zSql */ +); + int sqlite3_prepare16_v2( + sqlite3 *db, /* Database handle */ + const void *zSql, /* SQL statement, UTF-16 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const void **pzTail /* OUT: Pointer to unused portion of zSql */ +); +int sqlite3_prepare16_v3( + sqlite3 *db, /* Database handle */ + const void *zSql, /* SQL statement, UTF-16 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const void **pzTail /* OUT: Pointer to unused portion of zSql */ +); + +const char *sqlite3_sql(sqlite3_stmt *pStmt); +int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); +int sqlite3_stmt_busy(sqlite3_stmt*); + + +typedef struct Mem sqlite3_value; + + +typedef struct sqlite3_context sqlite3_context; + + int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); + int sqlite3_bind_double(sqlite3_stmt*, int, double); + int sqlite3_bind_int(sqlite3_stmt*, int, int); + int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); + int sqlite3_bind_null(sqlite3_stmt*, int); + int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*)); + int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); + int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); + int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); + int sqlite3_bind_parameter_count(sqlite3_stmt*); + const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int); + int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName); + int sqlite3_clear_bindings(sqlite3_stmt*); + int sqlite3_column_count(sqlite3_stmt *pStmt); + const char *sqlite3_column_name(sqlite3_stmt*, int N); + const void *sqlite3_column_name16(sqlite3_stmt*, int N); + const char *sqlite3_column_database_name(sqlite3_stmt*,int); + const void *sqlite3_column_database_name16(sqlite3_stmt*,int); + const char *sqlite3_column_table_name(sqlite3_stmt*,int); + const void *sqlite3_column_table_name16(sqlite3_stmt*,int); + const char *sqlite3_column_origin_name(sqlite3_stmt*,int); + const void *sqlite3_column_origin_name16(sqlite3_stmt*,int); + const char *sqlite3_column_decltype(sqlite3_stmt*,int); + const void *sqlite3_column_decltype16(sqlite3_stmt*,int); + int sqlite3_step(sqlite3_stmt*); + int sqlite3_data_count(sqlite3_stmt *pStmt); + const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); + int sqlite3_column_bytes(sqlite3_stmt*, int iCol); + int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); + double sqlite3_column_double(sqlite3_stmt*, int iCol); + int sqlite3_column_int(sqlite3_stmt*, int iCol); + sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); + const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); + const void *sqlite3_column_text16(sqlite3_stmt*, int iCol); + int sqlite3_column_type(sqlite3_stmt*, int iCol); + sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol); + int sqlite3_finalize(sqlite3_stmt *pStmt); + int sqlite3_reset(sqlite3_stmt *pStmt); + + + int sqlite3_create_function( + sqlite3 *db, + const char *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*) +); + int sqlite3_create_function16( + sqlite3 *db, + const void *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*) +); + int sqlite3_create_function_v2( + sqlite3 *db, + + const char *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void(*xDestroy)(void*) +); + + + + + + + const void *sqlite3_value_blob(sqlite3_value*); + int sqlite3_value_bytes(sqlite3_value*); + int sqlite3_value_bytes16(sqlite3_value*); + double sqlite3_value_double(sqlite3_value*); + int sqlite3_value_int(sqlite3_value*); + sqlite3_int64 sqlite3_value_int64(sqlite3_value*); + const unsigned char *sqlite3_value_text(sqlite3_value*); + const void *sqlite3_value_text16(sqlite3_value*); + const void *sqlite3_value_text16le(sqlite3_value*); + const void *sqlite3_value_text16be(sqlite3_value*); + int sqlite3_value_type(sqlite3_value*); + int sqlite3_value_numeric_type(sqlite3_value*); + + + void *sqlite3_aggregate_context(sqlite3_context*, int nBytes); + + + void *sqlite3_user_data(sqlite3_context*); + + + sqlite3 *sqlite3_context_db_handle(sqlite3_context*); + + + void *sqlite3_get_auxdata(sqlite3_context*, int N); + void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*)); + + + + + + void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*)); + void sqlite3_result_double(sqlite3_context*, double); + void sqlite3_result_error(sqlite3_context*, const char*, int); + void sqlite3_result_error16(sqlite3_context*, const void*, int); + void sqlite3_result_error_toobig(sqlite3_context*); + void sqlite3_result_error_nomem(sqlite3_context*); + void sqlite3_result_error_code(sqlite3_context*, int); + void sqlite3_result_int(sqlite3_context*, int); + void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); + void sqlite3_result_null(sqlite3_context*); + void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); + void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); + void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); + void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); + void sqlite3_result_value(sqlite3_context*, sqlite3_value*); + void sqlite3_result_zeroblob(sqlite3_context*, int n); + + + int sqlite3_create_collation( + sqlite3*, + const char *zName, + int eTextRep, + void *pArg, + int(*xCompare)(void*,int,const void*,int,const void*) +); + int sqlite3_create_collation_v2( + sqlite3*, + const char *zName, + int eTextRep, + void *pArg, + int(*xCompare)(void*,int,const void*,int,const void*), + void(*xDestroy)(void*) +); + int sqlite3_create_collation16( + sqlite3*, + const void *zName, + int eTextRep, + void *pArg, + int(*xCompare)(void*,int,const void*,int,const void*) +); + + + int sqlite3_collation_needed( + sqlite3*, + void*, + void(*)(void*,sqlite3*,int eTextRep,const char*) +); + int sqlite3_collation_needed16( + sqlite3*, + void*, + void(*)(void*,sqlite3*,int eTextRep,const void*) +); + + + + + int sqlite3_sleep(int); + + + char *sqlite3_temp_directory; + + + int sqlite3_get_autocommit(sqlite3*); + + + sqlite3 *sqlite3_db_handle(sqlite3_stmt*); + + + const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName); + + int sqlite3_db_readonly(sqlite3 *db, const char *zDbName); + + + sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt); + + + void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*); + void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); + + + void *sqlite3_update_hook( + sqlite3*, + void(*)(void *,int ,char const *,char const *,sqlite3_int64), + void* +); + + + int sqlite3_enable_shared_cache(int); + + + int sqlite3_release_memory(int); + + + int sqlite3_db_release_memory(sqlite3*); + + + sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N); + + + int sqlite3_table_column_metadata( + sqlite3 *db, /* Connection handle */ + const char *zDbName, /* Database name or NULL */ + const char *zTableName, /* Table name */ + const char *zColumnName, /* Column name */ + char const **pzDataType, /* OUTPUT: Declared data type */ + char const **pzCollSeq, /* OUTPUT: Collation sequence name */ + int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */ + int *pPrimaryKey, /* OUTPUT: True if column part of PK */ + int *pAutoinc /* OUTPUT: True if column is auto-increment */ +); + + + int sqlite3_load_extension( + sqlite3 *db, /* Load the extension into this database connection */ + const char *zFile, /* Name of the shared library containing extension */ + const char *zProc, /* Entry point. Derived from zFile if 0 */ + char **pzErrMsg /* Put error message here if not 0 */ +); + + + int sqlite3_enable_load_extension(sqlite3 *db, int onoff); + + + int sqlite3_auto_extension(void (*xEntryPoint)(void)); + + + void sqlite3_reset_auto_extension(void); + + + + +typedef struct sqlite3_vtab sqlite3_vtab; +typedef struct sqlite3_index_info sqlite3_index_info; +typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor; +typedef struct sqlite3_module sqlite3_module; + + +struct sqlite3_module { + int iVersion; + int (*xCreate)(sqlite3*, void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVTab, char**); + int (*xConnect)(sqlite3*, void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVTab, char**); + int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*); + int (*xDisconnect)(sqlite3_vtab *pVTab); + int (*xDestroy)(sqlite3_vtab *pVTab); + int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor); + int (*xClose)(sqlite3_vtab_cursor*); + int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr, + int argc, sqlite3_value **argv); + int (*xNext)(sqlite3_vtab_cursor*); + int (*xEof)(sqlite3_vtab_cursor*); + int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int); + int (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64 *pRowid); + int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *); + int (*xBegin)(sqlite3_vtab *pVTab); + int (*xSync)(sqlite3_vtab *pVTab); + int (*xCommit)(sqlite3_vtab *pVTab); + int (*xRollback)(sqlite3_vtab *pVTab); + int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName, + void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), + void **ppArg); + int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); + /* The methods above are in version 1 of the sqlite_module object. Those + ** below are for version 2 and greater. */ + int (*xSavepoint)(sqlite3_vtab *pVTab, int); + int (*xRelease)(sqlite3_vtab *pVTab, int); + int (*xRollbackTo)(sqlite3_vtab *pVTab, int); +}; + + +struct sqlite3_index_info { + /* Inputs */ + int nConstraint; /* Number of entries in aConstraint */ + struct sqlite3_index_constraint { + int iColumn; /* Column on left-hand side of constraint */ + unsigned char op; /* Constraint operator */ + unsigned char usable; /* True if this constraint is usable */ + int iTermOffset; /* Used internally - xBestIndex should ignore */ + } *aConstraint; /* Table of WHERE clause constraints */ + int nOrderBy; /* Number of terms in the ORDER BY clause */ + struct sqlite3_index_orderby { + int iColumn; /* Column number */ + unsigned char desc; /* True for DESC. False for ASC. */ + } *aOrderBy; /* The ORDER BY clause */ + /* Outputs */ + struct sqlite3_index_constraint_usage { + int argvIndex; /* if >0, constraint is part of argv to xFilter */ + unsigned char omit; /* Do not code a test for this constraint */ + } *aConstraintUsage; + int idxNum; /* Number used to identify the index */ + char *idxStr; /* String, possibly obtained from sqlite3_malloc */ + int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */ + int orderByConsumed; /* True if output is already ordered */ + double estimatedCost; /* Estimated cost of using this index */ +}; + + + + + + int sqlite3_create_module( + sqlite3 *db, /* SQLite connection to register module with */ + const char *zName, /* Name of the module */ + const sqlite3_module *p, /* Methods for the module */ + void *pClientData /* Client data for xCreate/xConnect */ +); + int sqlite3_create_module_v2( + sqlite3 *db, /* SQLite connection to register module with */ + const char *zName, /* Name of the module */ + const sqlite3_module *p, /* Methods for the module */ + void *pClientData, /* Client data for xCreate/xConnect */ + void(*xDestroy)(void*) /* Module destructor function */ +); + + +struct sqlite3_vtab { + const sqlite3_module *pModule; /* The module for this virtual table */ + int nRef; /* NO LONGER USED */ + char *zErrMsg; /* Error message from sqlite3_mprintf() */ + /* Virtual table implementations will typically add additional fields */ +}; + + +struct sqlite3_vtab_cursor { + sqlite3_vtab *pVtab; /* Virtual table of this cursor */ + /* Virtual table implementations will typically add additional fields */ +}; + + + int sqlite3_declare_vtab(sqlite3*, const char *zSQL); + + + int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg); + + + + +typedef struct sqlite3_blob sqlite3_blob; + + + int sqlite3_blob_open( + sqlite3*, + const char *zDb, + const char *zTable, + const char *zColumn, + sqlite3_int64 iRow, + int flags, + sqlite3_blob **ppBlob +); + + + int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64); + + + int sqlite3_blob_close(sqlite3_blob *); + + + int sqlite3_blob_bytes(sqlite3_blob *); + + + int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset); + + + int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset); + + + sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName); + int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt); + int sqlite3_vfs_unregister(sqlite3_vfs*); + + + sqlite3_mutex *sqlite3_mutex_alloc(int); + void sqlite3_mutex_free(sqlite3_mutex*); + void sqlite3_mutex_enter(sqlite3_mutex*); + int sqlite3_mutex_try(sqlite3_mutex*); + void sqlite3_mutex_leave(sqlite3_mutex*); + + +typedef struct sqlite3_mutex_methods sqlite3_mutex_methods; +struct sqlite3_mutex_methods { + int (*xMutexInit)(void); + int (*xMutexEnd)(void); + sqlite3_mutex *(*xMutexAlloc)(int); + void (*xMutexFree)(sqlite3_mutex *); + void (*xMutexEnter)(sqlite3_mutex *); + int (*xMutexTry)(sqlite3_mutex *); + void (*xMutexLeave)(sqlite3_mutex *); + int (*xMutexHeld)(sqlite3_mutex *); + int (*xMutexNotheld)(sqlite3_mutex *); +}; + + + + + + sqlite3_mutex *sqlite3_db_mutex(sqlite3*); + + int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*); + + + int sqlite3_test_control(int op, ...); + + + + int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); + + + int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); + + + + + + int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); + + + + + +typedef struct sqlite3_pcache sqlite3_pcache; + + +typedef struct sqlite3_pcache_page sqlite3_pcache_page; +struct sqlite3_pcache_page { + void *pBuf; /* The content of the page */ + void *pExtra; /* Extra information associated with the page */ +}; + + +typedef struct sqlite3_pcache_methods2 sqlite3_pcache_methods2; +struct sqlite3_pcache_methods2 { + int iVersion; + void *pArg; + int (*xInit)(void*); + void (*xShutdown)(void*); + sqlite3_pcache *(*xCreate)(int szPage, int szExtra, int bPurgeable); + void (*xCachesize)(sqlite3_pcache*, int nCachesize); + int (*xPagecount)(sqlite3_pcache*); + sqlite3_pcache_page *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag); + void (*xUnpin)(sqlite3_pcache*, sqlite3_pcache_page*, int discard); + void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*, + unsigned oldKey, unsigned newKey); + void (*xTruncate)(sqlite3_pcache*, unsigned iLimit); + void (*xDestroy)(sqlite3_pcache*); + void (*xShrink)(sqlite3_pcache*); +}; + + + + +typedef struct sqlite3_backup sqlite3_backup; + + + sqlite3_backup *sqlite3_backup_init( + sqlite3 *pDest, /* Destination database handle */ + const char *zDestName, /* Destination database name */ + sqlite3 *pSource, /* Source database handle */ + const char *zSourceName /* Source database name */ +); + int sqlite3_backup_step(sqlite3_backup *p, int nPage); + int sqlite3_backup_finish(sqlite3_backup *p); + int sqlite3_backup_remaining(sqlite3_backup *p); + int sqlite3_backup_pagecount(sqlite3_backup *p); + + + int sqlite3_unlock_notify( + sqlite3 *pBlocked, /* Waiting connection */ + void (*xNotify)(void **apArg, int nArg), /* Callback function to invoke */ + void *pNotifyArg /* Argument to pass to xNotify */ +); + + + + int sqlite3_stricmp(const char *, const char *); + int sqlite3_strnicmp(const char *, const char *, int); + + + void sqlite3_log(int iErrCode, const char *zFormat, ...); + + + void *sqlite3_wal_hook( + sqlite3*, + int(*)(void *,sqlite3*,const char*,int), + void* +); + + + int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); + + + int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); + + + int sqlite3_wal_checkpoint_v2( + sqlite3 *db, /* Database handle */ + const char *zDb, /* Name of attached database (or NULL) */ + int eMode, /* SQLITE_CHECKPOINT_* value */ + int *pnLog, /* OUT: Size of WAL log in frames */ + int *pnCkpt /* OUT: Total number of frames checkpointed */ +); + + + int sqlite3_vtab_config(sqlite3*, int op, ...); + + int sqlite3_vtab_on_conflict(sqlite3 *); + + + + + + +// RTree Geometry Queries +typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry; + + + int sqlite3_rtree_geometry_callback( + sqlite3 *db, + const char *zGeom, + int (*xGeom)(sqlite3_rtree_geometry*, int n, double *a, int *pRes), + void *pContext +); + + +struct sqlite3_rtree_geometry { + void *pContext; + int nParam; + double *aParam; + void *pUser; + void (*xDelUser)(void *); +}; +]] + +local Lib = ffi.load(ffi.os == "Windows" and "bin/sqlite3" or "sqlite3") + +-- initialize the library +Lib.sqlite3_initialize(); + +return Lib; + diff --git a/waltz/sqlog.fnl b/sqlog/compiler.fnl similarity index 91% rename from waltz/sqlog.fnl rename to sqlog/compiler.fnl index 8778936..a16a9c2 100644 --- a/waltz/sqlog.fnl +++ b/sqlog/compiler.fnl @@ -14,7 +14,7 @@ (local lume (require :lib.lume)) (local util (require :lib.util)) -(local Sqlog (Object:extend)) +(local Compiler (Object:extend)) ; Generating SQL from Datalog should not be too complex, but it pays to start with the simplest ; case and build up from there. @@ -66,28 +66,32 @@ ; (!- [p 1 x] [q x]) -> DELETE FROM p WHERE p._rowid_ IN (SELECT p._rowid_ FROM p JOIN q WHERE p.c1 = 1 AND p.c2 = q.c1) ; update: -; (!~ [q (+ x 1)] [q x]) -> UPDATE q SET c1 = q.c1 + 1 -; (!~ [p (+ x 1) _] [p x 3]) -> UPDATE p SET c1 = p.c1 + 1 WHERE p.c2 = 3 +; (!= [q (+ x 1)] [q x]) -> UPDATE q SET c1 = q.c1 + 1 +; (!= [p (+ x 1) _] [p x 3]) -> UPDATE p SET c1 = p.c1 + 1 WHERE p.c2 = 3 ; invalid update: -; (!~ [p (+ x 1) _] [q x]) -> UPDATE p SET c1 = q.c1 + 1 FROM q -- this is valid sql, but it's madness - enforce the first query clause matches table +; (!= [p (+ x 1) _] [q x]) -> UPDATE p SET c1 = q.c1 + 1 FROM q -- this is valid sql, but it's madness - enforce the first query clause matches table -(fn Sqlog.new [self] +(fn cat [list sep ?f] + (table.concat (icollect [i v (ipairs list)] ((or ?f #$1) v i)) sep)) + +(fn Compiler.new [self] (set self.tables {}) (set self.rules {})) -(fn Sqlog.deftable [self name ...] +(fn Compiler.deftable [self name ...] "Defines the column names of a table and their expected ordering" (when (. name self.rules) (error "tables and rules must not overlap")) - (tset self.tables name [...])) + (tset self.tables name [...]) + {:query (.. "CREATE TABLE " name "(" (cat [...] ", ") ")") :constants [] :selection []}) -(fn Sqlog.defrule [self head ...] +(fn Compiler.defrule [self head ...] (match head [:literal name] (let [rulelist (or (. self.rules name) [])] (table.insert rulelist [head ...]) (tset self.rules name rulelist)) _ (error "Expected literal for head, got " (fv head)))) -(fn Sqlog.defrules [self ...] +(fn Compiler.defrules [self ...] (for [i 1 (select :# ...)] (self:defrule (table.unpack (select i ...))))) (fn append-if-missing [list value] @@ -96,7 +100,7 @@ (fn add-clause [analysis clause] (table.insert analysis.clauses clause)) -(fn Sqlog.reference-name [self analysis name] +(fn Compiler.reference-name [self analysis name] (if (or (. self.rules name) (. self.tables name)) (do (table.insert analysis.tables name) (when (. self.rules name) @@ -104,7 +108,7 @@ (length analysis.tables)) (error (.. "Unknown table / rule " name)))) -(fn Sqlog.reference-variable [self analysis varname expr] +(fn Compiler.reference-variable [self analysis varname expr] (when (not= varname :_) (match (. analysis.variable-mapping varname) mapping (add-clause analysis [:= mapping expr]) @@ -112,7 +116,7 @@ (table.insert analysis.variables varname))))) (local comparitors (collect [_ op (ipairs [:< :> :<= :>= := :and :or])] op true)) -(fn Sqlog.analyze-literal [self analysis literal] +(fn Compiler.analyze-literal [self analysis literal] (match literal [:literal name params] (let [itable (self:reference-name analysis name)] (each [icolumn value (ipairs params)] @@ -134,7 +138,7 @@ :referenced-rules (or (?. ?parent :referenced-rules) [])}) (local infix-ops (collect [_ op (ipairs [:+ :- :* :/ :< :> :<= :>= := :|| :and :or])] op true)) -(fn Sqlog.gen-expr [self analysis expr] +(fn Compiler.gen-expr [self analysis expr] (match expr [:const val] (do (table.insert analysis.constants val) "?") [:column itable icolumn] (.. "_t" itable "." @@ -148,10 +152,7 @@ (where [op lhs rhs] (. infix-ops op)) (.. "(" (self:gen-expr analysis lhs) " " op " " (self:gen-expr analysis rhs) ")") _ (error (.. "Unrecognized expression " (fv expr))))) -(fn cat [list sep ?f] - (table.concat (icollect [i v (ipairs list)] ((or ?f #$1) v i)) sep)) - -(fn Sqlog.gen-rule-clause [self analysis-parent [head & literals]] +(fn Compiler.gen-rule-clause [self analysis-parent [head & literals]] (let [analysis (new-analysis analysis-parent)] (each [_ literal (ipairs literals)] (self:analyze-literal analysis literal)) (match head @@ -160,7 +161,7 @@ _ (error (.. "Expected literal, got " (fv head)))) (self:gen-select analysis))) -(fn Sqlog.gen-rule [self analysis name] +(fn Compiler.gen-rule [self analysis name] (let [rule (. self.rules name) column-count (match rule [[[:literal _ clauses]]] (length clauses) @@ -168,7 +169,7 @@ (.. name "(" (table.concat (icollect [i (util.countiter column-count)] (.. "c" i)) ", ") ") AS NOT MATERIALIZED (" (cat rule " UNION " #(self:gen-rule-clause analysis $1)) ")"))) -(fn Sqlog.gen-with-rules [self analysis] +(fn Compiler.gen-with-rules [self analysis] (let [rulequeries []] ; ipairs will iterate over all referenced-rules even if gen-rule causes more to be appended (each [_ name (ipairs analysis.referenced-rules)] @@ -177,7 +178,7 @@ (.. "WITH RECURSIVE " (cat rulequeries ", ") " ") ""))) -(fn Sqlog.gen-select [self analysis] +(fn Compiler.gen-select [self analysis] (.. "SELECT " (if (> (length analysis.selection) 0) (cat analysis.selection ", " #(self:gen-expr analysis $1)) @@ -189,7 +190,7 @@ (.. " WHERE " (cat analysis.clauses " AND " #(self:gen-expr analysis $1))) ""))) -(fn Sqlog.gen-update [self analysis] +(fn Compiler.gen-update [self analysis] (.. "UPDATE " (. analysis.tables 1) " AS _t1 SET " (cat analysis.selection ", " #(self:gen-expr analysis $1)) (if (>= (length analysis.tables) 2) @@ -199,14 +200,14 @@ (.. " WHERE " (cat analysis.clauses " AND " #(self:gen-expr analysis $1))) ""))) -(fn Sqlog.query [self ...] +(fn Compiler.query [self ...] (let [analysis (new-analysis)] (each [_ literal (ipairs [...])] (self:analyze-literal analysis literal)) (set analysis.selection (icollect [_ varname (ipairs analysis.variables)] [:as (. analysis.variable-mapping varname) varname])) (set analysis.query (.. (self:gen-with-rules analysis) (self:gen-select analysis))) analysis)) -(fn Sqlog.insert [self head ...] +(fn Compiler.insert [self head ...] (match head [:literal name params] (let [analysis (new-analysis) @@ -222,7 +223,7 @@ analysis) _ (error (.. "Expected literal, got " (fv head))))) -(fn Sqlog.delete [self head ...] +(fn Compiler.delete [self head ...] (match head [:literal name params] (let [analysis (new-analysis)] @@ -232,7 +233,7 @@ analysis) _ (error (.. "Expected literal, got " (fv head))))) -(fn Sqlog.update [self newhead head ...] +(fn Compiler.update [self newhead head ...] (match [newhead head] [[:literal name params] [:literal name]] (let [analysis (new-analysis) @@ -245,5 +246,5 @@ (set analysis.query (.. (self:gen-with-rules analysis) (self:gen-update analysis))) analysis))) -Sqlog +Compiler diff --git a/sqlog/init.fnl b/sqlog/init.fnl new file mode 100644 index 0000000..3424b0c --- /dev/null +++ b/sqlog/init.fnl @@ -0,0 +1,58 @@ +(local Compiler (require :sqlog.compiler)) +(local sqlite (require :diet-sqlite)) +(local Object (require :core.object)) +(local {: SQLITE_ROW} (require :diet-sqlite.codes)) + +(local Sqlog (Object:extend)) + +(fn Sqlog.new [self] + (set self.compiler (Compiler))) + +(fn Sqlog.connect [self dbname] + (set self.db (sqlite.assert (sqlite.open dbname)))) + +(fn Sqlog.deftable [self name ...] (self:execute (self.compiler:deftable name ...))) +(fn Sqlog.defrule [self head ...] (self.compiler:defrule head ...)) +(fn Sqlog.defrules [self ...] (self.compiler:defrules ...)) + +(fn Sqlog.compile-sql [self analysis] + (when (= analysis.stmt nil) + (let [stmt (sqlite.assert (sqlite.prepare self.db analysis.query))] + (sqlite.bind stmt analysis.constants) + (set analysis.stmt stmt))) + analysis) + +(fn Sqlog.execute [self analysis ?collect-results] + (self:compile-sql analysis) + (sqlite.reset analysis.stmt) + (if ?collect-results + (let [result []] + (while (= SQLITE_ROW (sqlite.step analysis.stmt)) + (table.insert result (collect [icol expr (ipairs analysis.selection)] + (match expr + [:as _ name] name + _ icol) + (sqlite.column analysis.stmt icol)))) + result) + (sqlite.step analysis.stmt))) + +(fn Sqlog.compile-action [self action] + (self:compile-sql + (match action + [:!+ & insert] (self.compiler:insert (table.unpack insert)) + [:literal] (self.compiler:insert action) + [:!- & delete] (self.compiler:delete (table.unpack delete)) + [:!= & update] (self.compiler:update (table.unpack update))))) + +(fn Sqlog.compile-query [self ...] (self:compile-sql (self.compiler:query ...))) + +(fn Sqlog.specify [self action ...] + (when (not= action nil) + (match action + [:* & rule] (self:defrule (table.unpack rule)) + _ (self:execute (self:compile-action action))) + (self:specify ...))) + +(fn Sqlog.query [self ...] (self:execute (self:compile-query ...) true)) + +Sqlog diff --git a/waltz/macros.fnl b/sqlog/macros.fnl similarity index 92% rename from waltz/macros.fnl rename to sqlog/macros.fnl index 2a72493..25ef066 100644 --- a/waltz/macros.fnl +++ b/sqlog/macros.fnl @@ -24,6 +24,7 @@ (fn insert [s ...] `(: ,s :insert ,(clauses ...))) (fn delete [s ...] `(: ,s :delete ,(clauses ...))) (fn update [s ...] `(: ,s :update ,(clauses ...))) +(fn specify [s ...] `(: ,s :specify ,(clauses ...))) -{: clause : clauses :$ clauses : defrule : defrules : query : insert : delete : update} +{: clause : clauses :$ clauses : defrule : defrules : query : insert : delete : update : specify} diff --git a/sqlog/sqltest.fnl b/sqlog/sqltest.fnl new file mode 100644 index 0000000..3e87c70 --- /dev/null +++ b/sqlog/sqltest.fnl @@ -0,0 +1,18 @@ +(local Sqlog (require :sqlog)) +(import-macros {: $ : query : specify} :sqlog.macros) + +(local s (Sqlog)) +(s:connect ":memory:") +(s:deftable :parent :parent :child) +(specify s + (* [generation name (|| name " jr") 2] [parent name (|| name " jr")]) + (* [generation name (|| name " iii") 3] [ancestor name (|| name " iii")]) + (* [ancestor x y 1] [parent x y]) + (* [ancestor x y (+ gen 1)] [parent x z] [ancestor z y gen]) + [parent :bob "bob jr"] + [parent "bob jr" "bob iii"] + [parent :bob :fred] + [parent :fred :jim] + [parent :fred :betty]) +(pp (query s [generation :bob descendant gen])) + diff --git a/waltz/sqltest.fnl b/waltz/sqltest.fnl deleted file mode 100644 index 5d16974..0000000 --- a/waltz/sqltest.fnl +++ /dev/null @@ -1,13 +0,0 @@ -(local Sqlog (require :waltz.sqlog)) -(import-macros {: $ : query : insert : delete : update : defrules} :waltz.macros) - -(local s (Sqlog)) -(s:deftable :parent :parent :child) -(s:deftable :p :x :y) -(s:deftable :q :z) -(defrules s - ([generation name (|| name " jr") 2] [parent name (|| name " jr")]) - ([generation name (|| name " iii") 3] [ancestor name (|| name " iii")]) - ([ancestor x y 1] [parent x y]) - ([ancestor x y (+ gen 1)] [parent x z] [ancestor z y gen])) -(pp (update s [p _ (+ y 1)] [p x y] [q x]))