integrate sqlite, reorganize code

* diet-sqlite - a cleaned-up, slightly updated, and de-ooped version of
  https://github.com/Wiladams/LJIT2SQLite
* rename waltz -> sqlog
* separate compiler from driver
* introduce uniform syntax for actions
This commit is contained in:
Jeremy Penner 2022-03-29 13:24:34 -04:00
parent 837ee0299a
commit fd3fcbd978
8 changed files with 1317 additions and 40 deletions

281
diet-sqlite/codes.lua Normal file
View file

@ -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;
}

61
diet-sqlite/init.fnl Normal file
View file

@ -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

870
diet-sqlite/sqlite3_ffi.lua Normal file
View file

@ -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;

View file

@ -14,7 +14,7 @@
(local lume (require :lib.lume)) (local lume (require :lib.lume))
(local util (require :lib.util)) (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 ; Generating SQL from Datalog should not be too complex, but it pays to start with the simplest
; case and build up from there. ; 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) ; (!- [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: ; update:
; (!~ [q (+ x 1)] [q x]) -> UPDATE q SET c1 = q.c1 + 1 ; (!= [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 ; (!= [p (+ x 1) _] [p x 3]) -> UPDATE p SET c1 = p.c1 + 1 WHERE p.c2 = 3
; invalid update: ; 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.tables {})
(set self.rules {})) (set self.rules {}))
(fn Sqlog.deftable [self name ...] (fn Compiler.deftable [self name ...]
"Defines the column names of a table and their expected ordering" "Defines the column names of a table and their expected ordering"
(when (. name self.rules) (error "tables and rules must not overlap")) (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 (match head
[:literal name] (let [rulelist (or (. self.rules name) [])] [:literal name] (let [rulelist (or (. self.rules name) [])]
(table.insert rulelist [head ...]) (table.insert rulelist [head ...])
(tset self.rules name rulelist)) (tset self.rules name rulelist))
_ (error "Expected literal for head, got " (fv head)))) _ (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 ...))))) (for [i 1 (select :# ...)] (self:defrule (table.unpack (select i ...)))))
(fn append-if-missing [list value] (fn append-if-missing [list value]
@ -96,7 +100,7 @@
(fn add-clause [analysis clause] (table.insert analysis.clauses clause)) (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)) (if (or (. self.rules name) (. self.tables name))
(do (table.insert analysis.tables name) (do (table.insert analysis.tables name)
(when (. self.rules name) (when (. self.rules name)
@ -104,7 +108,7 @@
(length analysis.tables)) (length analysis.tables))
(error (.. "Unknown table / rule " name)))) (error (.. "Unknown table / rule " name))))
(fn Sqlog.reference-variable [self analysis varname expr] (fn Compiler.reference-variable [self analysis varname expr]
(when (not= varname :_) (when (not= varname :_)
(match (. analysis.variable-mapping varname) (match (. analysis.variable-mapping varname)
mapping (add-clause analysis [:= mapping expr]) mapping (add-clause analysis [:= mapping expr])
@ -112,7 +116,7 @@
(table.insert analysis.variables varname))))) (table.insert analysis.variables varname)))))
(local comparitors (collect [_ op (ipairs [:< :> :<= :>= := :and :or])] op true)) (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 (match literal
[:literal name params] (let [itable (self:reference-name analysis name)] [:literal name params] (let [itable (self:reference-name analysis name)]
(each [icolumn value (ipairs params)] (each [icolumn value (ipairs params)]
@ -134,7 +138,7 @@
:referenced-rules (or (?. ?parent :referenced-rules) [])}) :referenced-rules (or (?. ?parent :referenced-rules) [])})
(local infix-ops (collect [_ op (ipairs [:+ :- :* :/ :< :> :<= :>= := :|| :and :or])] op true)) (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 (match expr
[:const val] (do (table.insert analysis.constants val) "?") [:const val] (do (table.insert analysis.constants val) "?")
[:column itable icolumn] (.. "_t" itable "." [: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) ")") (where [op lhs rhs] (. infix-ops op)) (.. "(" (self:gen-expr analysis lhs) " " op " " (self:gen-expr analysis rhs) ")")
_ (error (.. "Unrecognized expression " (fv expr))))) _ (error (.. "Unrecognized expression " (fv expr)))))
(fn cat [list sep ?f] (fn Compiler.gen-rule-clause [self analysis-parent [head & literals]]
(table.concat (icollect [i v (ipairs list)] ((or ?f #$1) v i)) sep))
(fn Sqlog.gen-rule-clause [self analysis-parent [head & literals]]
(let [analysis (new-analysis analysis-parent)] (let [analysis (new-analysis analysis-parent)]
(each [_ literal (ipairs literals)] (self:analyze-literal analysis literal)) (each [_ literal (ipairs literals)] (self:analyze-literal analysis literal))
(match head (match head
@ -160,7 +161,7 @@
_ (error (.. "Expected literal, got " (fv head)))) _ (error (.. "Expected literal, got " (fv head))))
(self:gen-select analysis))) (self:gen-select analysis)))
(fn Sqlog.gen-rule [self analysis name] (fn Compiler.gen-rule [self analysis name]
(let [rule (. self.rules name) (let [rule (. self.rules name)
column-count (match rule column-count (match rule
[[[:literal _ clauses]]] (length clauses) [[[:literal _ clauses]]] (length clauses)
@ -168,7 +169,7 @@
(.. name "(" (table.concat (icollect [i (util.countiter column-count)] (.. "c" i)) ", ") ") AS NOT MATERIALIZED (" (.. name "(" (table.concat (icollect [i (util.countiter column-count)] (.. "c" i)) ", ") ") AS NOT MATERIALIZED ("
(cat rule " UNION " #(self:gen-rule-clause analysis $1)) ")"))) (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 []] (let [rulequeries []]
; ipairs will iterate over all referenced-rules even if gen-rule causes more to be appended ; ipairs will iterate over all referenced-rules even if gen-rule causes more to be appended
(each [_ name (ipairs analysis.referenced-rules)] (each [_ name (ipairs analysis.referenced-rules)]
@ -177,7 +178,7 @@
(.. "WITH RECURSIVE " (cat rulequeries ", ") " ") (.. "WITH RECURSIVE " (cat rulequeries ", ") " ")
""))) "")))
(fn Sqlog.gen-select [self analysis] (fn Compiler.gen-select [self analysis]
(.. "SELECT " (.. "SELECT "
(if (> (length analysis.selection) 0) (if (> (length analysis.selection) 0)
(cat analysis.selection ", " #(self:gen-expr analysis $1)) (cat analysis.selection ", " #(self:gen-expr analysis $1))
@ -189,7 +190,7 @@
(.. " WHERE " (cat analysis.clauses " AND " #(self:gen-expr analysis $1))) (.. " 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 " (.. "UPDATE " (. analysis.tables 1) " AS _t1 SET "
(cat analysis.selection ", " #(self:gen-expr analysis $1)) (cat analysis.selection ", " #(self:gen-expr analysis $1))
(if (>= (length analysis.tables) 2) (if (>= (length analysis.tables) 2)
@ -199,14 +200,14 @@
(.. " WHERE " (cat analysis.clauses " AND " #(self:gen-expr analysis $1))) (.. " WHERE " (cat analysis.clauses " AND " #(self:gen-expr analysis $1)))
""))) "")))
(fn Sqlog.query [self ...] (fn Compiler.query [self ...]
(let [analysis (new-analysis)] (let [analysis (new-analysis)]
(each [_ literal (ipairs [...])] (self:analyze-literal analysis literal)) (each [_ literal (ipairs [...])] (self:analyze-literal analysis literal))
(set analysis.selection (icollect [_ varname (ipairs analysis.variables)] [:as (. analysis.variable-mapping varname) varname])) (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))) (set analysis.query (.. (self:gen-with-rules analysis) (self:gen-select analysis)))
analysis)) analysis))
(fn Sqlog.insert [self head ...] (fn Compiler.insert [self head ...]
(match head (match head
[:literal name params] [:literal name params]
(let [analysis (new-analysis) (let [analysis (new-analysis)
@ -222,7 +223,7 @@
analysis) analysis)
_ (error (.. "Expected literal, got " (fv head))))) _ (error (.. "Expected literal, got " (fv head)))))
(fn Sqlog.delete [self head ...] (fn Compiler.delete [self head ...]
(match head (match head
[:literal name params] [:literal name params]
(let [analysis (new-analysis)] (let [analysis (new-analysis)]
@ -232,7 +233,7 @@
analysis) analysis)
_ (error (.. "Expected literal, got " (fv head))))) _ (error (.. "Expected literal, got " (fv head)))))
(fn Sqlog.update [self newhead head ...] (fn Compiler.update [self newhead head ...]
(match [newhead head] (match [newhead head]
[[:literal name params] [:literal name]] [[:literal name params] [:literal name]]
(let [analysis (new-analysis) (let [analysis (new-analysis)
@ -245,5 +246,5 @@
(set analysis.query (.. (self:gen-with-rules analysis) (self:gen-update analysis))) (set analysis.query (.. (self:gen-with-rules analysis) (self:gen-update analysis)))
analysis))) analysis)))
Sqlog Compiler

58
sqlog/init.fnl Normal file
View file

@ -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

View file

@ -24,6 +24,7 @@
(fn insert [s ...] `(: ,s :insert ,(clauses ...))) (fn insert [s ...] `(: ,s :insert ,(clauses ...)))
(fn delete [s ...] `(: ,s :delete ,(clauses ...))) (fn delete [s ...] `(: ,s :delete ,(clauses ...)))
(fn update [s ...] `(: ,s :update ,(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}

18
sqlog/sqltest.fnl Normal file
View file

@ -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]))

View file

@ -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]))