1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431 |
- /************************************************************************
- * lsqlite3 *
- * Copyright (C) 2002-2016 Tiago Dionizio, Doug Currie *
- * All rights reserved. *
- * Author : Tiago Dionizio <tiago.dionizio@ist.utl.pt> *
- * Author : Doug Currie <doug.currie@alum.mit.edu> *
- * Library : lsqlite3 - an SQLite 3 database binding for Lua 5 *
- * *
- * Permission is hereby granted, free of charge, to any person obtaining *
- * a copy of this software and associated documentation files (the *
- * "Software"), to deal in the Software without restriction, including *
- * without limitation the rights to use, copy, modify, merge, publish, *
- * distribute, sublicense, and/or sell copies of the Software, and to *
- * permit persons to whom the Software is furnished to do so, subject to *
- * the following conditions: *
- * *
- * The above copyright notice and this permission notice shall be *
- * included in all copies or substantial portions of the Software. *
- * *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY *
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, *
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE *
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
- ************************************************************************/
- #define LSQLITE_VERSION "0.9.4"
- #define LSQLITE_OMIT_UPDATE_HOOK 1
- #define SQLITE_OMIT_PROGRESS_CALLBACK 1
- #include <c_stdlib.h>
- #include <c_string.h>
- #include <assert.h>
- #define LUA_LIB
- #include "module.h"
- #include "lua.h"
- #include "lauxlib.h"
- #if LUA_VERSION_NUM > 501
- /*
- ** Lua 5.2
- */
- #define lua_strlen lua_rawlen
- /* luaL_typerror always used with arg at ndx == NULL */
- #define luaL_typerror(L,ndx,str) luaL_error(L,"bad argument %d (%s expected, got nil)",ndx,str)
- /* luaL_register used once, so below expansion is OK for this case */
- #define luaL_register(L,name,reg) lua_newtable(L);luaL_setfuncs(L,reg,0)
- /* luaL_openlib always used with name == NULL */
- #define luaL_openlib(L,name,reg,nup) luaL_setfuncs(L,reg,nup)
- #if LUA_VERSION_NUM > 502
- /*
- ** Lua 5.3
- */
- #define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
- #endif
- #endif
- #include "sqlite3.h"
- /* compile time features */
- #if !defined(SQLITE_OMIT_PROGRESS_CALLBACK)
- #define SQLITE_OMIT_PROGRESS_CALLBACK 0
- #endif
- #if !defined(LSQLITE_OMIT_UPDATE_HOOK)
- #define LSQLITE_OMIT_UPDATE_HOOK 0
- #endif
- #if defined(LSQLITE_OMIT_OPEN_V2)
- #define SQLITE3_OPEN(L,filename,flags) sqlite3_open(L,filename)
- #else
- #define SQLITE3_OPEN(L,filename,flags) sqlite3_open_v2(L,filename,flags,NULL)
- #endif
- typedef struct sdb sdb;
- typedef struct sdb_vm sdb_vm;
- typedef struct sdb_bu sdb_bu;
- typedef struct sdb_func sdb_func;
- /* to use as C user data so i know what function sqlite is calling */
- struct sdb_func {
- /* references to associated lua values */
- int fn_step;
- int fn_finalize;
- int udata;
- sdb *db;
- char aggregate;
- sdb_func *next;
- };
- /* information about database */
- struct sdb {
- /* associated lua state */
- lua_State *L;
- /* sqlite database handle */
- sqlite3 *db;
- /* sql functions stack usage */
- sdb_func *func; /* top SQL function being called */
- /* references */
- int busy_cb; /* busy callback */
- int busy_udata;
- int progress_cb; /* progress handler */
- int progress_udata;
- int trace_cb; /* trace callback */
- int trace_udata;
- #if !defined(LSQLITE_OMIT_UPDATE_HOOK) || !LSQLITE_OMIT_UPDATE_HOOK
- int update_hook_cb; /* update_hook callback */
- int update_hook_udata;
- int commit_hook_cb; /* commit_hook callback */
- int commit_hook_udata;
- int rollback_hook_cb; /* rollback_hook callback */
- int rollback_hook_udata;
- #endif
- };
- static const char *sqlite_meta = ":sqlite3";
- static const char *sqlite_vm_meta = ":sqlite3:vm";
- static const char *sqlite_bu_meta = ":sqlite3:bu";
- static const char *sqlite_ctx_meta = ":sqlite3:ctx";
- static int sqlite_ctx_meta_ref;
- /* Lua 5.3 introduced an integer type, but depending on the implementation, it could be 32
- ** or 64 bits (or something else?). This helper macro tries to do "the right thing."
- */
- #if LUA_VERSION_NUM > 502
- #define PUSH_INT64(L,i64in,fallback) \
- do { \
- sqlite_int64 i64 = i64in; \
- lua_Integer i = (lua_Integer )i64; \
- if (i == i64) lua_pushinteger(L, i);\
- else { \
- lua_Number n = (lua_Number)i64; \
- if (n == i64) lua_pushnumber(L, n); \
- else fallback; \
- } \
- } while (0)
- #else
- #define PUSH_INT64(L,i64in,fallback) \
- do { \
- sqlite_int64 i64 = i64in; \
- lua_Number n = (lua_Number)i64; \
- if (n == i64) lua_pushnumber(L, n); \
- else fallback; \
- } while (0)
- #endif
- /*
- ** =======================================================
- ** Database Virtual Machine Operations
- ** =======================================================
- */
- static void vm_push_column(lua_State *L, sqlite3_stmt *vm, int idx) {
- switch (sqlite3_column_type(vm, idx)) {
- case SQLITE_INTEGER:
- PUSH_INT64(L, sqlite3_column_int64(vm, idx)
- , lua_pushlstring(L, (const char*)sqlite3_column_text(vm, idx)
- , sqlite3_column_bytes(vm, idx)));
- break;
- case SQLITE_FLOAT:
- lua_pushnumber(L, sqlite3_column_double(vm, idx));
- break;
- case SQLITE_TEXT:
- lua_pushlstring(L, (const char*)sqlite3_column_text(vm, idx), sqlite3_column_bytes(vm, idx));
- break;
- case SQLITE_BLOB:
- lua_pushlstring(L, sqlite3_column_blob(vm, idx), sqlite3_column_bytes(vm, idx));
- break;
- case SQLITE_NULL:
- lua_pushnil(L);
- break;
- default:
- lua_pushnil(L);
- break;
- }
- }
- /* virtual machine information */
- struct sdb_vm {
- sdb *db; /* associated database handle */
- sqlite3_stmt *vm; /* virtual machine */
- /* sqlite3_step info */
- int columns; /* number of columns in result */
- char has_values; /* true when step succeeds */
- char temp; /* temporary vm used in db:rows */
- };
- /* called with db,sql text on the lua stack */
- static sdb_vm *newvm(lua_State *L, sdb *db) {
- sdb_vm *svm = (sdb_vm*)lua_newuserdata(L, sizeof(sdb_vm)); /* db sql svm_ud -- */
- luaL_getmetatable(L, sqlite_vm_meta);
- lua_setmetatable(L, -2); /* set metatable */
- svm->db = db;
- svm->columns = 0;
- svm->has_values = 0;
- svm->vm = NULL;
- svm->temp = 0;
- /* add an entry on the database table: svm -> db to keep db live while svm is live */
- lua_pushlightuserdata(L, db); /* db sql svm_ud db_lud -- */
- lua_rawget(L, LUA_REGISTRYINDEX); /* db sql svm_ud reg[db_lud] -- */
- lua_pushlightuserdata(L, svm); /* db sql svm_ud reg[db_lud] svm_lud -- */
- lua_pushvalue(L, -5); /* db sql svm_ud reg[db_lud] svm_lud db -- */
- lua_rawset(L, -3); /* (reg[db_lud])[svm_lud] = db ; set the db for this vm */
- lua_pop(L, 1); /* db sql svm_ud -- */
- return svm;
- }
- static int cleanupvm(lua_State *L, sdb_vm *svm) {
- /* remove entry in database table - no harm if not present in the table */
- lua_pushlightuserdata(L, svm->db);
- lua_rawget(L, LUA_REGISTRYINDEX);
- lua_pushlightuserdata(L, svm);
- lua_pushnil(L);
- lua_rawset(L, -3);
- lua_pop(L, 1);
- svm->columns = 0;
- svm->has_values = 0;
- if (!svm->vm) return 0;
- lua_pushinteger(L, sqlite3_finalize(svm->vm));
- svm->vm = NULL;
- return 1;
- }
- static int stepvm(lua_State *L, sdb_vm *svm) {
- return sqlite3_step(svm->vm);
- }
- static sdb_vm *lsqlite_getvm(lua_State *L, int index) {
- sdb_vm *svm = (sdb_vm*)luaL_checkudata(L, index, sqlite_vm_meta);
- if (svm == NULL) luaL_argerror(L, index, "bad sqlite virtual machine");
- return svm;
- }
- static sdb_vm *lsqlite_checkvm(lua_State *L, int index) {
- sdb_vm *svm = lsqlite_getvm(L, index);
- if (svm->vm == NULL) luaL_argerror(L, index, "attempt to use closed sqlite virtual machine");
- return svm;
- }
- static int dbvm_isopen(lua_State *L) {
- sdb_vm *svm = lsqlite_getvm(L, 1);
- lua_pushboolean(L, svm->vm != NULL ? 1 : 0);
- return 1;
- }
- static int dbvm_tostring(lua_State *L) {
- char buff[39];
- sdb_vm *svm = lsqlite_getvm(L, 1);
- if (svm->vm == NULL)
- strcpy(buff, "closed");
- else
- c_sprintf(buff, "%p", svm);
- lua_pushfstring(L, "sqlite virtual machine (%s)", buff);
- return 1;
- }
- static int dbvm_gc(lua_State *L) {
- sdb_vm *svm = lsqlite_getvm(L, 1);
- if (svm->vm != NULL) /* ignore closed vms */
- cleanupvm(L, svm);
- return 0;
- }
- static int dbvm_step(lua_State *L) {
- int result;
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- result = stepvm(L, svm);
- svm->has_values = result == SQLITE_ROW ? 1 : 0;
- svm->columns = sqlite3_data_count(svm->vm);
- lua_pushinteger(L, result);
- return 1;
- }
- static int dbvm_finalize(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- return cleanupvm(L, svm);
- }
- static int dbvm_reset(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_reset(svm->vm);
- lua_pushinteger(L, sqlite3_errcode(svm->db->db));
- return 1;
- }
- static void dbvm_check_contents(lua_State *L, sdb_vm *svm) {
- if (!svm->has_values) {
- luaL_error(L, "misuse of function");
- }
- }
- static void dbvm_check_index(lua_State *L, sdb_vm *svm, int index) {
- if (index < 0 || index >= svm->columns) {
- luaL_error(L, "index out of range [0..%d]", svm->columns - 1);
- }
- }
- static void dbvm_check_bind_index(lua_State *L, sdb_vm *svm, int index) {
- if (index < 1 || index > sqlite3_bind_parameter_count(svm->vm)) {
- luaL_error(L, "bind index out of range [1..%d]", sqlite3_bind_parameter_count(svm->vm));
- }
- }
- static int dbvm_last_insert_rowid(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- /* conversion warning: int64 -> luaNumber */
- sqlite_int64 rowid = sqlite3_last_insert_rowid(svm->db->db);
- PUSH_INT64(L, rowid, lua_pushfstring(L, "%ll", rowid));
- return 1;
- }
- /*
- ** =======================================================
- ** Virtual Machine - generic info
- ** =======================================================
- */
- static int dbvm_columns(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- lua_pushinteger(L, sqlite3_column_count(svm->vm));
- return 1;
- }
- /*
- ** =======================================================
- ** Virtual Machine - getters
- ** =======================================================
- */
- static int dbvm_get_value(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- int index = luaL_checkint(L, 2);
- dbvm_check_contents(L, svm);
- dbvm_check_index(L, svm, index);
- vm_push_column(L, svm->vm, index);
- return 1;
- }
- static int dbvm_get_name(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- int index = luaL_checknumber(L, 2);
- dbvm_check_index(L, svm, index);
- lua_pushstring(L, sqlite3_column_name(svm->vm, index));
- return 1;
- }
- #if 0
- static int dbvm_get_type(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- int index = luaL_checknumber(L, 2);
- dbvm_check_index(L, svm, index);
- lua_pushstring(L, sqlite3_column_decltype(svm->vm, index));
- return 1;
- }
- #else
- static int dbvm_get_type(lua_State *L) {
- lua_pushliteral(L, "column decltype support disabled at compile time");
- lua_error(L);
- return 0;
- }
- #endif
- static int dbvm_get_values(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm = svm->vm;
- int columns = svm->columns;
- int n;
- dbvm_check_contents(L, svm);
- lua_createtable(L, columns, 0);
- for (n = 0; n < columns;) {
- vm_push_column(L, vm, n++);
- lua_rawseti(L, -2, n);
- }
- return 1;
- }
- static int dbvm_get_names(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm = svm->vm;
- int columns = sqlite3_column_count(vm); /* valid as soon as statement prepared */
- int n;
- lua_createtable(L, columns, 0);
- for (n = 0; n < columns;) {
- lua_pushstring(L, sqlite3_column_name(vm, n++));
- lua_rawseti(L, -2, n);
- }
- return 1;
- }
- #if 0
- static int dbvm_get_types(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm = svm->vm;
- int columns = sqlite3_column_count(vm); /* valid as soon as statement prepared */
- int n;
- lua_createtable(L, columns, 0);
- for (n = 0; n < columns;) {
- lua_pushstring(L, sqlite3_column_decltype(vm, n++));
- lua_rawseti(L, -2, n);
- }
- return 1;
- }
- #else
- static int dbvm_get_types(lua_State *L) {
- lua_pushliteral(L, "column decltype support disabled at compile time");
- lua_error(L);
- return 0;
- }
- #endif
- static int dbvm_get_uvalues(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm = svm->vm;
- int columns = svm->columns;
- int n;
- dbvm_check_contents(L, svm);
- lua_checkstack(L, columns);
- for (n = 0; n < columns; ++n)
- vm_push_column(L, vm, n);
- return columns;
- }
- static int dbvm_get_unames(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm = svm->vm;
- int columns = sqlite3_column_count(vm); /* valid as soon as statement prepared */
- int n;
- lua_checkstack(L, columns);
- for (n = 0; n < columns; ++n)
- lua_pushstring(L, sqlite3_column_name(vm, n));
- return columns;
- }
- #if 0
- static int dbvm_get_utypes(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm = svm->vm;
- int columns = sqlite3_column_count(vm); /* valid as soon as statement prepared */
- int n;
- lua_checkstack(L, columns);
- for (n = 0; n < columns; ++n)
- lua_pushstring(L, sqlite3_column_decltype(vm, n));
- return columns;
- }
- #else
- static int dbvm_get_utypes(lua_State *L) {
- lua_pushliteral(L, "column decltype support disabled at compile time");
- lua_error(L);
- return 0;
- }
- #endif
- static int dbvm_get_named_values(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm = svm->vm;
- int columns = svm->columns;
- int n;
- dbvm_check_contents(L, svm);
- lua_createtable(L, 0, columns);
- for (n = 0; n < columns; ++n) {
- lua_pushstring(L, sqlite3_column_name(vm, n));
- vm_push_column(L, vm, n);
- lua_rawset(L, -3);
- }
- return 1;
- }
- #if 0
- static int dbvm_get_named_types(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm = svm->vm;
- int columns = sqlite3_column_count(vm);
- int n;
- lua_createtable(L, 0, columns);
- for (n = 0; n < columns; ++n) {
- lua_pushstring(L, sqlite3_column_name(vm, n));
- lua_pushstring(L, sqlite3_column_decltype(vm, n));
- lua_rawset(L, -3);
- }
- return 1;
- }
- #else
- static int dbvm_get_named_types(lua_State *L) {
- lua_pushliteral(L, "column decltype support disabled at compile time");
- lua_error(L);
- return 0;
- }
- #endif
- /*
- ** =======================================================
- ** Virtual Machine - Bind
- ** =======================================================
- */
- static int dbvm_bind_index(lua_State *L, sqlite3_stmt *vm, int index, int lindex) {
- switch (lua_type(L, lindex)) {
- case LUA_TSTRING:
- return sqlite3_bind_text(vm, index, lua_tostring(L, lindex), lua_strlen(L, lindex), SQLITE_TRANSIENT);
- case LUA_TNUMBER:
- #if LUA_VERSION_NUM > 502
- if (lua_isinteger(L, lindex))
- return sqlite3_bind_int64(vm, index, lua_tointeger(L, lindex));
- #endif
- return sqlite3_bind_double(vm, index, lua_tonumber(L, lindex));
- case LUA_TBOOLEAN:
- return sqlite3_bind_int(vm, index, lua_toboolean(L, lindex) ? 1 : 0);
- case LUA_TNONE:
- case LUA_TNIL:
- return sqlite3_bind_null(vm, index);
- default:
- luaL_error(L, "index (%d) - invalid data type for bind (%s)", index, lua_typename(L, lua_type(L, lindex)));
- return SQLITE_MISUSE; /*!*/
- }
- }
- static int dbvm_bind_parameter_count(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- lua_pushinteger(L, sqlite3_bind_parameter_count(svm->vm));
- return 1;
- }
- static int dbvm_bind_parameter_name(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- int index = luaL_checknumber(L, 2);
- dbvm_check_bind_index(L, svm, index);
- lua_pushstring(L, sqlite3_bind_parameter_name(svm->vm, index));
- return 1;
- }
- static int dbvm_bind(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm = svm->vm;
- int index = luaL_checkint(L, 2);
- int result;
- dbvm_check_bind_index(L, svm, index);
- result = dbvm_bind_index(L, vm, index, 3);
- lua_pushinteger(L, result);
- return 1;
- }
- static int dbvm_bind_blob(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- int index = luaL_checkint(L, 2);
- const char *value = luaL_checkstring(L, 3);
- int len = lua_strlen(L, 3);
- lua_pushinteger(L, sqlite3_bind_blob(svm->vm, index, value, len, SQLITE_TRANSIENT));
- return 1;
- }
- static int dbvm_bind_values(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm = svm->vm;
- int top = lua_gettop(L);
- int result, n;
- if (top - 1 != sqlite3_bind_parameter_count(vm))
- luaL_error(L,
- "incorrect number of parameters to bind (%d given, %d to bind)",
- top - 1,
- sqlite3_bind_parameter_count(vm)
- );
- for (n = 2; n <= top; ++n) {
- if ((result = dbvm_bind_index(L, vm, n - 1, n)) != SQLITE_OK) {
- lua_pushinteger(L, result);
- return 1;
- }
- }
- lua_pushinteger(L, SQLITE_OK);
- return 1;
- }
- static int dbvm_bind_names(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm = svm->vm;
- int count = sqlite3_bind_parameter_count(vm);
- const char *name;
- int result, n;
- luaL_checktype(L, 2, LUA_TTABLE);
- for (n = 1; n <= count; ++n) {
- name = sqlite3_bind_parameter_name(vm, n);
- if (name && (name[0] == ':' || name[0] == '$')) {
- lua_pushstring(L, ++name);
- lua_gettable(L, 2);
- result = dbvm_bind_index(L, vm, n, -1);
- lua_pop(L, 1);
- }
- else {
- lua_pushinteger(L, n);
- lua_gettable(L, 2);
- result = dbvm_bind_index(L, vm, n, -1);
- lua_pop(L, 1);
- }
- if (result != SQLITE_OK) {
- lua_pushinteger(L, result);
- return 1;
- }
- }
- lua_pushinteger(L, SQLITE_OK);
- return 1;
- }
- /*
- ** =======================================================
- ** Database (internal management)
- ** =======================================================
- */
- /*
- ** When creating database handles, always creates a `closed' database handle
- ** before opening the actual database; so, if there is a memory error, the
- ** database is not left opened.
- **
- ** Creates a new 'table' and leaves it in the stack
- */
- static sdb *newdb (lua_State *L) {
- sdb *db = (sdb*)lua_newuserdata(L, sizeof(sdb));
- db->L = L;
- db->db = NULL; /* database handle is currently `closed' */
- db->func = NULL;
- db->busy_cb =
- db->busy_udata =
- db->progress_cb =
- db->progress_udata =
- db->trace_cb =
- db->trace_udata =
- #if !defined(LSQLITE_OMIT_UPDATE_HOOK) || !LSQLITE_OMIT_UPDATE_HOOK
- db->update_hook_cb =
- db->update_hook_udata =
- db->commit_hook_cb =
- db->commit_hook_udata =
- db->rollback_hook_cb =
- db->rollback_hook_udata =
- #endif
- LUA_NOREF;
- luaL_getmetatable(L, sqlite_meta);
- lua_setmetatable(L, -2); /* set metatable */
- /* to keep track of 'open' virtual machines */
- lua_pushlightuserdata(L, db);
- lua_newtable(L);
- lua_rawset(L, LUA_REGISTRYINDEX);
- return db;
- }
- static int cleanupdb(lua_State *L, sdb *db) {
- sdb_func *func;
- sdb_func *func_next;
- int top;
- int result;
- /* free associated virtual machines */
- lua_pushlightuserdata(L, db);
- lua_rawget(L, LUA_REGISTRYINDEX);
- /* close all used handles */
- top = lua_gettop(L);
- lua_pushnil(L);
- while (lua_next(L, -2)) {
- sdb_vm *svm = lua_touserdata(L, -2); /* key: vm; val: sql text */
- cleanupvm(L, svm);
- lua_settop(L, top);
- lua_pushnil(L);
- }
- lua_pop(L, 1); /* pop vm table */
- /* remove entry in lua registry table */
- lua_pushlightuserdata(L, db);
- lua_pushnil(L);
- lua_rawset(L, LUA_REGISTRYINDEX);
- /* 'free' all references */
- luaL_unref(L, LUA_REGISTRYINDEX, db->busy_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->busy_udata);
- luaL_unref(L, LUA_REGISTRYINDEX, db->progress_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->progress_udata);
- luaL_unref(L, LUA_REGISTRYINDEX, db->trace_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->trace_udata);
- #if !defined(LSQLITE_OMIT_UPDATE_HOOK) || !LSQLITE_OMIT_UPDATE_HOOK
- luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_udata);
- luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_udata);
- luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_udata);
- #endif
- /* close database */
- result = sqlite3_close(db->db);
- db->db = NULL;
- /* free associated memory with created functions */
- func = db->func;
- while (func) {
- func_next = func->next;
- luaL_unref(L, LUA_REGISTRYINDEX, func->fn_step);
- luaL_unref(L, LUA_REGISTRYINDEX, func->fn_finalize);
- luaL_unref(L, LUA_REGISTRYINDEX, func->udata);
- c_free(func);
- func = func_next;
- }
- db->func = NULL;
- return result;
- }
- static sdb *lsqlite_getdb(lua_State *L, int index) {
- sdb *db = (sdb*)luaL_checkudata(L, index, sqlite_meta);
- if (db == NULL) luaL_typerror(L, index, "invalid sqlite database");
- return db;
- }
- static sdb *lsqlite_checkdb(lua_State *L, int index) {
- sdb *db = lsqlite_getdb(L, index);
- if (db->db == NULL) luaL_argerror(L, index, "attempt to use closed sqlite database");
- return db;
- }
- /*
- ** =======================================================
- ** User Defined Functions - Context Methods
- ** =======================================================
- */
- typedef struct {
- sqlite3_context *ctx;
- int ud;
- } lcontext;
- static lcontext *lsqlite_make_context(lua_State *L) {
- lcontext *ctx = (lcontext*)lua_newuserdata(L, sizeof(lcontext));
- lua_rawgeti(L, LUA_REGISTRYINDEX, sqlite_ctx_meta_ref);
- lua_setmetatable(L, -2);
- ctx->ctx = NULL;
- ctx->ud = LUA_NOREF;
- return ctx;
- }
- static lcontext *lsqlite_getcontext(lua_State *L, int index) {
- lcontext *ctx = (lcontext*)luaL_checkudata(L, index, sqlite_ctx_meta);
- if (ctx == NULL) luaL_typerror(L, index, "sqlite context");
- return ctx;
- }
- static lcontext *lsqlite_checkcontext(lua_State *L, int index) {
- lcontext *ctx = lsqlite_getcontext(L, index);
- if (ctx->ctx == NULL) luaL_argerror(L, index, "invalid sqlite context");
- return ctx;
- }
- static int lcontext_tostring(lua_State *L) {
- char buff[39];
- lcontext *ctx = lsqlite_getcontext(L, 1);
- if (ctx->ctx == NULL)
- strcpy(buff, "closed");
- else
- c_sprintf(buff, "%p", ctx->ctx);
- lua_pushfstring(L, "sqlite function context (%s)", buff);
- return 1;
- }
- static void lcontext_check_aggregate(lua_State *L, lcontext *ctx) {
- sdb_func *func = (sdb_func*)sqlite3_user_data(ctx->ctx);
- if (!func->aggregate) {
- luaL_error(L, "attempt to call aggregate method from scalar function");
- }
- }
- static int lcontext_user_data(lua_State *L) {
- lcontext *ctx = lsqlite_checkcontext(L, 1);
- sdb_func *func = (sdb_func*)sqlite3_user_data(ctx->ctx);
- lua_rawgeti(L, LUA_REGISTRYINDEX, func->udata);
- return 1;
- }
- static int lcontext_get_aggregate_context(lua_State *L) {
- lcontext *ctx = lsqlite_checkcontext(L, 1);
- lcontext_check_aggregate(L, ctx);
- lua_rawgeti(L, LUA_REGISTRYINDEX, ctx->ud);
- return 1;
- }
- static int lcontext_set_aggregate_context(lua_State *L) {
- lcontext *ctx = lsqlite_checkcontext(L, 1);
- lcontext_check_aggregate(L, ctx);
- lua_settop(L, 2);
- luaL_unref(L, LUA_REGISTRYINDEX, ctx->ud);
- ctx->ud = luaL_ref(L, LUA_REGISTRYINDEX);
- return 0;
- }
- #if 0
- static int lcontext_aggregate_count(lua_State *L) {
- lcontext *ctx = lsqlite_checkcontext(L, 1);
- lcontext_check_aggregate(L, ctx);
- lua_pushinteger(L, sqlite3_aggregate_count(ctx->ctx));
- return 1;
- }
- #else
- static int lcontext_aggregate_count(lua_State *L) {
- lua_pushliteral(L, "aggregate count support disabled at compile time");
- lua_error(L);
- return 0;
- }
- #endif
- #if 0
- void *sqlite3_get_auxdata(sqlite3_context*, int);
- void sqlite3_set_auxdata(sqlite3_context*, int, void*, void (*)(void*));
- #endif
- static int lcontext_result(lua_State *L) {
- lcontext *ctx = lsqlite_checkcontext(L, 1);
- switch (lua_type(L, 2)) {
- case LUA_TNUMBER:
- #if LUA_VERSION_NUM > 502
- if (lua_isinteger(L, 2))
- sqlite3_result_int64(ctx->ctx, luaL_checkinteger(L, 2));
- else
- #endif
- sqlite3_result_double(ctx->ctx, luaL_checknumber(L, 2));
- break;
- case LUA_TSTRING:
- sqlite3_result_text(ctx->ctx, luaL_checkstring(L, 2), lua_strlen(L, 2), SQLITE_TRANSIENT);
- break;
- case LUA_TNIL:
- case LUA_TNONE:
- sqlite3_result_null(ctx->ctx);
- break;
- default:
- luaL_error(L, "invalid result type %s", lua_typename(L, 2));
- break;
- }
- return 0;
- }
- static int lcontext_result_blob(lua_State *L) {
- lcontext *ctx = lsqlite_checkcontext(L, 1);
- const char *blob = luaL_checkstring(L, 2);
- int size = lua_strlen(L, 2);
- sqlite3_result_blob(ctx->ctx, (const void*)blob, size, SQLITE_TRANSIENT);
- return 0;
- }
- static int lcontext_result_double(lua_State *L) {
- lcontext *ctx = lsqlite_checkcontext(L, 1);
- double d = luaL_checknumber(L, 2);
- sqlite3_result_double(ctx->ctx, d);
- return 0;
- }
- static int lcontext_result_error(lua_State *L) {
- lcontext *ctx = lsqlite_checkcontext(L, 1);
- const char *err = luaL_checkstring(L, 2);
- int size = lua_strlen(L, 2);
- sqlite3_result_error(ctx->ctx, err, size);
- return 0;
- }
- static int lcontext_result_int(lua_State *L) {
- lcontext *ctx = lsqlite_checkcontext(L, 1);
- int i = luaL_checkint(L, 2);
- sqlite3_result_int(ctx->ctx, i);
- return 0;
- }
- static int lcontext_result_null(lua_State *L) {
- lcontext *ctx = lsqlite_checkcontext(L, 1);
- sqlite3_result_null(ctx->ctx);
- return 0;
- }
- static int lcontext_result_text(lua_State *L) {
- lcontext *ctx = lsqlite_checkcontext(L, 1);
- const char *text = luaL_checkstring(L, 2);
- int size = lua_strlen(L, 2);
- sqlite3_result_text(ctx->ctx, text, size, SQLITE_TRANSIENT);
- return 0;
- }
- /*
- ** =======================================================
- ** Database Methods
- ** =======================================================
- */
- static int db_isopen(lua_State *L) {
- sdb *db = lsqlite_getdb(L, 1);
- lua_pushboolean(L, db->db != NULL ? 1 : 0);
- return 1;
- }
- static int db_last_insert_rowid(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- /* conversion warning: int64 -> luaNumber */
- sqlite_int64 rowid = sqlite3_last_insert_rowid(db->db);
- PUSH_INT64(L, rowid, lua_pushfstring(L, "%ll", rowid));
- return 1;
- }
- static int db_changes(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- lua_pushinteger(L, sqlite3_changes(db->db));
- return 1;
- }
- static int db_total_changes(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- lua_pushinteger(L, sqlite3_total_changes(db->db));
- return 1;
- }
- static int db_errcode(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- lua_pushinteger(L, sqlite3_errcode(db->db));
- return 1;
- }
- static int db_errmsg(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- lua_pushstring(L, sqlite3_errmsg(db->db));
- return 1;
- }
- static int db_interrupt(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- sqlite3_interrupt(db->db);
- return 0;
- }
- static int db_db_filename(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- const char *db_name = luaL_checkstring(L, 2);
- // sqlite3_db_filename may return NULL, in that case Lua pushes nil...
- lua_pushstring(L, sqlite3_db_filename(db->db, db_name));
- return 1;
- }
- /*
- ** Registering SQL functions:
- */
- static void db_push_value(lua_State *L, sqlite3_value *value) {
- switch (sqlite3_value_type(value)) {
- case SQLITE_TEXT:
- lua_pushlstring(L, (const char*)sqlite3_value_text(value), sqlite3_value_bytes(value));
- break;
- case SQLITE_INTEGER:
- PUSH_INT64(L, sqlite3_value_int64(value)
- , lua_pushlstring(L, (const char*)sqlite3_value_text(value)
- , sqlite3_value_bytes(value)));
- break;
- case SQLITE_FLOAT:
- lua_pushnumber(L, sqlite3_value_double(value));
- break;
- case SQLITE_BLOB:
- lua_pushlstring(L, sqlite3_value_blob(value), sqlite3_value_bytes(value));
- break;
- case SQLITE_NULL:
- lua_pushnil(L);
- break;
- default:
- /* things done properly (SQLite + Lua SQLite)
- ** this should never happen */
- lua_pushnil(L);
- break;
- }
- }
- /*
- ** callback functions used when calling registered sql functions
- */
- /* scalar function to be called
- ** callback params: context, values... */
- static void db_sql_normal_function(sqlite3_context *context, int argc, sqlite3_value **argv) {
- sdb_func *func = (sdb_func*)sqlite3_user_data(context);
- lua_State *L = func->db->L;
- int n;
- lcontext *ctx;
- int top = lua_gettop(L);
- /* ensure there is enough space in the stack */
- lua_checkstack(L, argc + 3);
- lua_rawgeti(L, LUA_REGISTRYINDEX, func->fn_step); /* function to call */
- if (!func->aggregate) {
- ctx = lsqlite_make_context(L); /* push context - used to set results */
- }
- else {
- /* reuse context userdata value */
- void *p = sqlite3_aggregate_context(context, 1);
- /* i think it is OK to use assume that using a light user data
- ** as an entry on LUA REGISTRY table will be unique */
- lua_pushlightuserdata(L, p);
- lua_rawget(L, LUA_REGISTRYINDEX); /* context table */
- if (lua_isnil(L, -1)) { /* not yet created? */
- lua_pop(L, 1);
- ctx = lsqlite_make_context(L);
- lua_pushlightuserdata(L, p);
- lua_pushvalue(L, -2);
- lua_rawset(L, LUA_REGISTRYINDEX);
- }
- else
- ctx = lsqlite_getcontext(L, -1);
- }
- /* push params */
- for (n = 0; n < argc; ++n) {
- db_push_value(L, argv[n]);
- }
- /* set context */
- ctx->ctx = context;
- if (lua_pcall(L, argc + 1, 0, 0)) {
- const char *errmsg = lua_tostring(L, -1);
- int size = lua_strlen(L, -1);
- sqlite3_result_error(context, errmsg, size);
- }
- /* invalidate context */
- ctx->ctx = NULL;
- if (!func->aggregate) {
- luaL_unref(L, LUA_REGISTRYINDEX, ctx->ud);
- }
- lua_settop(L, top);
- }
- static void db_sql_finalize_function(sqlite3_context *context) {
- sdb_func *func = (sdb_func*)sqlite3_user_data(context);
- lua_State *L = func->db->L;
- void *p = sqlite3_aggregate_context(context, 1); /* minimal mem usage */
- lcontext *ctx;
- int top = lua_gettop(L);
- lua_rawgeti(L, LUA_REGISTRYINDEX, func->fn_finalize); /* function to call */
- /* i think it is OK to use assume that using a light user data
- ** as an entry on LUA REGISTRY table will be unique */
- lua_pushlightuserdata(L, p);
- lua_rawget(L, LUA_REGISTRYINDEX); /* context table */
- if (lua_isnil(L, -1)) { /* not yet created? - shouldn't happen in finalize function */
- lua_pop(L, 1);
- ctx = lsqlite_make_context(L);
- lua_pushlightuserdata(L, p);
- lua_pushvalue(L, -2);
- lua_rawset(L, LUA_REGISTRYINDEX);
- }
- else
- ctx = lsqlite_getcontext(L, -1);
- /* set context */
- ctx->ctx = context;
- if (lua_pcall(L, 1, 0, 0)) {
- sqlite3_result_error(context, lua_tostring(L, -1), -1);
- }
- /* invalidate context */
- ctx->ctx = NULL;
- /* cleanup context */
- luaL_unref(L, LUA_REGISTRYINDEX, ctx->ud);
- /* remove it from registry */
- lua_pushlightuserdata(L, p);
- lua_pushnil(L);
- lua_rawset(L, LUA_REGISTRYINDEX);
- lua_settop(L, top);
- }
- /*
- ** Register a normal function
- ** Params: db, function name, number arguments, [ callback | step, finalize], user data
- ** Returns: true on sucess
- **
- ** Normal function:
- ** Params: context, params
- **
- ** Aggregate function:
- ** Params of step: context, params
- ** Params of finalize: context
- */
- static int db_register_function(lua_State *L, int aggregate) {
- sdb *db = lsqlite_checkdb(L, 1);
- const char *name;
- int args;
- int result;
- sdb_func *func;
- /* safety measure */
- if (aggregate) aggregate = 1;
- name = luaL_checkstring(L, 2);
- args = luaL_checkint(L, 3);
- luaL_checktype(L, 4, LUA_TFUNCTION);
- if (aggregate) luaL_checktype(L, 5, LUA_TFUNCTION);
- /* maybe an alternative way to allocate memory should be used/avoided */
- func = (sdb_func*)c_malloc(sizeof(sdb_func));
- if (func == NULL) {
- luaL_error(L, "out of memory");
- }
- result = sqlite3_create_function(
- db->db, name, args, SQLITE_UTF8, func,
- aggregate ? NULL : db_sql_normal_function,
- aggregate ? db_sql_normal_function : NULL,
- aggregate ? db_sql_finalize_function : NULL
- );
- if (result == SQLITE_OK) {
- /* safety measures for userdata field to be present in the stack */
- lua_settop(L, 5 + aggregate);
- /* save registered function in db function list */
- func->db = db;
- func->aggregate = aggregate;
- func->next = db->func;
- db->func = func;
- /* save the setp/normal function callback */
- lua_pushvalue(L, 4);
- func->fn_step = luaL_ref(L, LUA_REGISTRYINDEX);
- /* save user data */
- lua_pushvalue(L, 5+aggregate);
- func->udata = luaL_ref(L, LUA_REGISTRYINDEX);
- if (aggregate) {
- lua_pushvalue(L, 5);
- func->fn_finalize = luaL_ref(L, LUA_REGISTRYINDEX);
- }
- else
- func->fn_finalize = LUA_NOREF;
- }
- else {
- /* free allocated memory */
- c_free(func);
- }
- lua_pushboolean(L, result == SQLITE_OK ? 1 : 0);
- return 1;
- }
- static int db_create_function(lua_State *L) {
- return db_register_function(L, 0);
- }
- static int db_create_aggregate(lua_State *L) {
- return db_register_function(L, 1);
- }
- /* create_collation; contributed by Thomas Lauer
- */
- typedef struct {
- lua_State *L;
- int ref;
- } scc;
- static int collwrapper(scc *co,int l1,const void *p1,
- int l2,const void *p2) {
- int res=0;
- lua_State *L=co->L;
- lua_rawgeti(L,LUA_REGISTRYINDEX,co->ref);
- lua_pushlstring(L,p1,l1);
- lua_pushlstring(L,p2,l2);
- if (lua_pcall(L,2,1,0)==0) res=(int)lua_tonumber(L,-1);
- lua_pop(L,1);
- return res;
- }
- static void collfree(scc *co) {
- if (co) {
- luaL_unref(co->L,LUA_REGISTRYINDEX,co->ref);
- c_free(co);
- }
- }
- static int db_create_collation(lua_State *L) {
- sdb *db=lsqlite_checkdb(L,1);
- const char *collname=luaL_checkstring(L,2);
- scc *co=NULL;
- int (*collfunc)(scc *,int,const void *,int,const void *)=NULL;
- lua_settop(L,3); /* default args to nil, and exclude extras */
- if (lua_isfunction(L,3)) collfunc=collwrapper;
- else if (!lua_isnil(L,3))
- luaL_error(L,"create_collation: function or nil expected");
- if (collfunc != NULL) {
- co=(scc *)c_malloc(sizeof(scc)); /* userdata is a no-no as it
- will be garbage-collected */
- if (co) {
- co->L=L;
- /* lua_settop(L,3) above means we don't need: lua_pushvalue(L,3); */
- co->ref=luaL_ref(L,LUA_REGISTRYINDEX);
- }
- else luaL_error(L,"create_collation: could not allocate callback");
- }
- sqlite3_create_collation_v2(db->db, collname, SQLITE_UTF8,
- (void *)co,
- (int(*)(void*,int,const void*,int,const void*))collfunc,
- (void(*)(void*))collfree);
- return 0;
- }
- /* Thanks to Wolfgang Oertl...
- */
- #if 0
- static int db_load_extension(lua_State *L) {
- sdb *db=lsqlite_checkdb(L,1);
- const char *extname=luaL_optstring(L,2,NULL);
- const char *entrypoint=luaL_optstring(L,3,NULL);
- int result;
- char *errmsg = NULL;
- if (extname == NULL) {
- result = sqlite3_enable_load_extension(db->db,0); /* disable extension loading */
- }
- else {
- sqlite3_enable_load_extension(db->db,1); /* enable extension loading */
- result = sqlite3_load_extension(db->db,extname,entrypoint,&errmsg);
- }
- if (result == SQLITE_OK) {
- lua_pushboolean(L,1);
- return 1;
- }
- lua_pushboolean(L,0); /* so, assert(load_extension(...)) works */
- lua_pushstring(L,errmsg);
- sqlite3_free(errmsg);
- return 2;
- }
- #else
- static int db_load_extension(lua_State *L) {
- lua_pushliteral(L, "db_load_extension support disabled at compile time");
- lua_error(L);
- return 0;
- }
- #endif
- /*
- ** trace callback:
- ** Params: database, callback function, userdata
- **
- ** callback function:
- ** Params: userdata, sql
- */
- static void db_trace_callback(void *user, const char *sql) {
- sdb *db = (sdb*)user;
- lua_State *L = db->L;
- int top = lua_gettop(L);
- /* setup lua callback call */
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->trace_cb); /* get callback */
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->trace_udata); /* get callback user data */
- lua_pushstring(L, sql); /* traced sql statement */
- /* call lua function */
- lua_pcall(L, 2, 0, 0);
- /* ignore any error generated by this function */
- lua_settop(L, top);
- }
- #if 0
- static int db_trace(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- if (lua_gettop(L) < 2 || lua_isnil(L, 2)) {
- luaL_unref(L, LUA_REGISTRYINDEX, db->trace_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->trace_udata);
- db->trace_cb =
- db->trace_udata = LUA_NOREF;
- /* clear trace handler */
- sqlite3_trace(db->db, NULL, NULL);
- }
- else {
- luaL_checktype(L, 2, LUA_TFUNCTION);
- /* make sure we have an userdata field (even if nil) */
- lua_settop(L, 3);
- luaL_unref(L, LUA_REGISTRYINDEX, db->trace_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->trace_udata);
- db->trace_udata = luaL_ref(L, LUA_REGISTRYINDEX);
- db->trace_cb = luaL_ref(L, LUA_REGISTRYINDEX);
- /* set trace handler */
- sqlite3_trace(db->db, db_trace_callback, db);
- }
- return 0;
- }
- #else
- static int db_trace(lua_State *L) {
- lua_pushliteral(L, "db_trace support disabled at compile time");
- lua_error(L);
- return 0;
- }
- #endif
- #if !defined(LSQLITE_OMIT_UPDATE_HOOK) || !LSQLITE_OMIT_UPDATE_HOOK
- /*
- ** update_hook callback:
- ** Params: database, callback function, userdata
- **
- ** callback function:
- ** Params: userdata, {one of SQLITE_INSERT, SQLITE_DELETE, or SQLITE_UPDATE},
- ** database name, table name (containing the affected row), rowid of the row
- */
- static void db_update_hook_callback(void *user, int op, char const *dbname, char const *tblname, sqlite3_int64 rowid) {
- sdb *db = (sdb*)user;
- lua_State *L = db->L;
- int top = lua_gettop(L);
- lua_Number n;
- /* setup lua callback call */
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->update_hook_cb); /* get callback */
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->update_hook_udata); /* get callback user data */
- lua_pushinteger(L, op);
- lua_pushstring(L, dbname); /* update_hook database name */
- lua_pushstring(L, tblname); /* update_hook database name */
- PUSH_INT64(L, rowid, lua_pushfstring(L, "%ll", rowid));
- /* call lua function */
- lua_pcall(L, 5, 0, 0);
- /* ignore any error generated by this function */
- lua_settop(L, top);
- }
- static int db_update_hook(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- if (lua_gettop(L) < 2 || lua_isnil(L, 2)) {
- luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_udata);
- db->update_hook_cb =
- db->update_hook_udata = LUA_NOREF;
- /* clear update_hook handler */
- sqlite3_update_hook(db->db, NULL, NULL);
- }
- else {
- luaL_checktype(L, 2, LUA_TFUNCTION);
- /* make sure we have an userdata field (even if nil) */
- lua_settop(L, 3);
- luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_udata);
- db->update_hook_udata = luaL_ref(L, LUA_REGISTRYINDEX);
- db->update_hook_cb = luaL_ref(L, LUA_REGISTRYINDEX);
- /* set update_hook handler */
- sqlite3_update_hook(db->db, db_update_hook_callback, db);
- }
- return 0;
- }
- /*
- ** commit_hook callback:
- ** Params: database, callback function, userdata
- **
- ** callback function:
- ** Params: userdata
- ** Returned value: Return false or nil to continue the COMMIT operation normally.
- ** return true (non false, non nil), then the COMMIT is converted into a ROLLBACK.
- */
- static int db_commit_hook_callback(void *user) {
- sdb *db = (sdb*)user;
- lua_State *L = db->L;
- int top = lua_gettop(L);
- int rollback = 0;
- /* setup lua callback call */
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->commit_hook_cb); /* get callback */
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->commit_hook_udata); /* get callback user data */
- /* call lua function */
- if (!lua_pcall(L, 1, 1, 0))
- rollback = lua_toboolean(L, -1); /* use result if there was no error */
- lua_settop(L, top);
- return rollback;
- }
- static int db_commit_hook(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- if (lua_gettop(L) < 2 || lua_isnil(L, 2)) {
- luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_udata);
- db->commit_hook_cb =
- db->commit_hook_udata = LUA_NOREF;
- /* clear commit_hook handler */
- sqlite3_commit_hook(db->db, NULL, NULL);
- }
- else {
- luaL_checktype(L, 2, LUA_TFUNCTION);
- /* make sure we have an userdata field (even if nil) */
- lua_settop(L, 3);
- luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_udata);
- db->commit_hook_udata = luaL_ref(L, LUA_REGISTRYINDEX);
- db->commit_hook_cb = luaL_ref(L, LUA_REGISTRYINDEX);
- /* set commit_hook handler */
- sqlite3_commit_hook(db->db, db_commit_hook_callback, db);
- }
- return 0;
- }
- /*
- ** rollback hook callback:
- ** Params: database, callback function, userdata
- **
- ** callback function:
- ** Params: userdata
- */
- static void db_rollback_hook_callback(void *user) {
- sdb *db = (sdb*)user;
- lua_State *L = db->L;
- int top = lua_gettop(L);
- /* setup lua callback call */
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->rollback_hook_cb); /* get callback */
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->rollback_hook_udata); /* get callback user data */
- /* call lua function */
- lua_pcall(L, 1, 0, 0);
- /* ignore any error generated by this function */
- lua_settop(L, top);
- }
- static int db_rollback_hook(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- if (lua_gettop(L) < 2 || lua_isnil(L, 2)) {
- luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_udata);
- db->rollback_hook_cb =
- db->rollback_hook_udata = LUA_NOREF;
- /* clear rollback_hook handler */
- sqlite3_rollback_hook(db->db, NULL, NULL);
- }
- else {
- luaL_checktype(L, 2, LUA_TFUNCTION);
- /* make sure we have an userdata field (even if nil) */
- lua_settop(L, 3);
- luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_udata);
- db->rollback_hook_udata = luaL_ref(L, LUA_REGISTRYINDEX);
- db->rollback_hook_cb = luaL_ref(L, LUA_REGISTRYINDEX);
- /* set rollback_hook handler */
- sqlite3_rollback_hook(db->db, db_rollback_hook_callback, db);
- }
- return 0;
- }
- #endif /* #if !defined(LSQLITE_OMIT_UPDATE_HOOK) || !LSQLITE_OMIT_UPDATE_HOOK */
- #if !defined(SQLITE_OMIT_PROGRESS_CALLBACK) || !SQLITE_OMIT_PROGRESS_CALLBACK
- /*
- ** progress handler:
- ** Params: database, number of opcodes, callback function, userdata
- **
- ** callback function:
- ** Params: userdata
- ** returns: 0 to return immediatly and return SQLITE_ABORT, non-zero to continue
- */
- static int db_progress_callback(void *user) {
- int result = 1; /* abort by default */
- sdb *db = (sdb*)user;
- lua_State *L = db->L;
- int top = lua_gettop(L);
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->progress_cb);
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->progress_udata);
- /* call lua function */
- if (!lua_pcall(L, 1, 1, 0))
- result = lua_toboolean(L, -1);
- lua_settop(L, top);
- return result;
- }
- static int db_progress_handler(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- if (lua_gettop(L) < 2 || lua_isnil(L, 2)) {
- luaL_unref(L, LUA_REGISTRYINDEX, db->progress_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->progress_udata);
- db->progress_cb =
- db->progress_udata = LUA_NOREF;
- /* clear busy handler */
- sqlite3_progress_handler(db->db, 0, NULL, NULL);
- }
- else {
- int nop = luaL_checkint(L, 2); /* number of opcodes */
- luaL_checktype(L, 3, LUA_TFUNCTION);
- /* make sure we have an userdata field (even if nil) */
- lua_settop(L, 4);
- luaL_unref(L, LUA_REGISTRYINDEX, db->progress_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->progress_udata);
- db->progress_udata = luaL_ref(L, LUA_REGISTRYINDEX);
- db->progress_cb = luaL_ref(L, LUA_REGISTRYINDEX);
- /* set progress callback */
- sqlite3_progress_handler(db->db, nop, db_progress_callback, db);
- }
- return 0;
- }
- #else /* #if !defined(SQLITE_OMIT_PROGRESS_CALLBACK) || !SQLITE_OMIT_PROGRESS_CALLBACK */
- static int db_progress_handler(lua_State *L) {
- lua_pushliteral(L, "progress callback support disabled at compile time");
- lua_error(L);
- return 0;
- }
- #endif /* #if !defined(SQLITE_OMIT_PROGRESS_CALLBACK) || !SQLITE_OMIT_PROGRESS_CALLBACK */
- /* Online Backup API */
- #if 0
- 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);
- #endif
- struct sdb_bu {
- sqlite3_backup *bu; /* backup structure */
- };
- static int cleanupbu(lua_State *L, sdb_bu *sbu) {
- if (!sbu->bu) return 0; /* already finished */
- /* remove table from registry */
- lua_pushlightuserdata(L, sbu->bu);
- lua_pushnil(L);
- lua_rawset(L, LUA_REGISTRYINDEX);
- lua_pushinteger(L, sqlite3_backup_finish(sbu->bu));
- sbu->bu = NULL;
- return 1;
- }
- static int lsqlite_backup_init(lua_State *L) {
- sdb *target_db = lsqlite_checkdb(L, 1);
- const char *target_nm = luaL_checkstring(L, 2);
- sdb *source_db = lsqlite_checkdb(L, 3);
- const char *source_nm = luaL_checkstring(L, 4);
- sqlite3_backup *bu = sqlite3_backup_init(target_db->db, target_nm, source_db->db, source_nm);
- if (NULL != bu) {
- sdb_bu *sbu = (sdb_bu*)lua_newuserdata(L, sizeof(sdb_bu));
- luaL_getmetatable(L, sqlite_bu_meta);
- lua_setmetatable(L, -2); /* set metatable */
- sbu->bu = bu;
- /* create table from registry */
- /* to prevent referenced databases from being garbage collected while bu is live */
- lua_pushlightuserdata(L, bu);
- lua_createtable(L, 2, 0);
- /* add source and target dbs to table at indices 1 and 2 */
- lua_pushvalue(L, 1); /* target db */
- lua_rawseti(L, -2, 1);
- lua_pushvalue(L, 3); /* source db */
- lua_rawseti(L, -2, 2);
- /* put table in registry with key lightuserdata bu */
- lua_rawset(L, LUA_REGISTRYINDEX);
- return 1;
- }
- else {
- return 0;
- }
- }
- static sdb_bu *lsqlite_getbu(lua_State *L, int index) {
- sdb_bu *sbu = (sdb_bu*)luaL_checkudata(L, index, sqlite_bu_meta);
- if (sbu == NULL) luaL_typerror(L, index, "sqlite database backup");
- return sbu;
- }
- static sdb_bu *lsqlite_checkbu(lua_State *L, int index) {
- sdb_bu *sbu = lsqlite_getbu(L, index);
- if (sbu->bu == NULL) luaL_argerror(L, index, "attempt to use closed sqlite database backup");
- return sbu;
- }
- static int dbbu_gc(lua_State *L) {
- sdb_bu *sbu = lsqlite_getbu(L, 1);
- if (sbu->bu != NULL) {
- cleanupbu(L, sbu);
- lua_pop(L, 1);
- }
- /* else ignore if already finished */
- return 0;
- }
- static int dbbu_step(lua_State *L) {
- sdb_bu *sbu = lsqlite_checkbu(L, 1);
- int nPage = luaL_checkint(L, 2);
- lua_pushinteger(L, sqlite3_backup_step(sbu->bu, nPage));
- return 1;
- }
- static int dbbu_remaining(lua_State *L) {
- sdb_bu *sbu = lsqlite_checkbu(L, 1);
- lua_pushinteger(L, sqlite3_backup_remaining(sbu->bu));
- return 1;
- }
- static int dbbu_pagecount(lua_State *L) {
- sdb_bu *sbu = lsqlite_checkbu(L, 1);
- lua_pushinteger(L, sqlite3_backup_pagecount(sbu->bu));
- return 1;
- }
- static int dbbu_finish(lua_State *L) {
- sdb_bu *sbu = lsqlite_checkbu(L, 1);
- return cleanupbu(L, sbu);
- }
- /* end of Online Backup API */
- /*
- ** busy handler:
- ** Params: database, callback function, userdata
- **
- ** callback function:
- ** Params: userdata, number of tries
- ** returns: 0 to return immediatly and return SQLITE_BUSY, non-zero to try again
- */
- static int db_busy_callback(void *user, int tries) {
- int retry = 0; /* abort by default */
- sdb *db = (sdb*)user;
- lua_State *L = db->L;
- int top = lua_gettop(L);
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->busy_cb);
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->busy_udata);
- lua_pushinteger(L, tries);
- /* call lua function */
- if (!lua_pcall(L, 2, 1, 0))
- retry = lua_toboolean(L, -1);
- lua_settop(L, top);
- return retry;
- }
- static int db_busy_handler(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- if (lua_gettop(L) < 2 || lua_isnil(L, 2)) {
- luaL_unref(L, LUA_REGISTRYINDEX, db->busy_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->busy_udata);
- db->busy_cb =
- db->busy_udata = LUA_NOREF;
- /* clear busy handler */
- sqlite3_busy_handler(db->db, NULL, NULL);
- }
- else {
- luaL_checktype(L, 2, LUA_TFUNCTION);
- /* make sure we have an userdata field (even if nil) */
- lua_settop(L, 3);
- luaL_unref(L, LUA_REGISTRYINDEX, db->busy_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->busy_udata);
- db->busy_udata = luaL_ref(L, LUA_REGISTRYINDEX);
- db->busy_cb = luaL_ref(L, LUA_REGISTRYINDEX);
- /* set busy handler */
- sqlite3_busy_handler(db->db, db_busy_callback, db);
- }
- return 0;
- }
- static int db_busy_timeout(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- int timeout = luaL_checkint(L, 2);
- sqlite3_busy_timeout(db->db, timeout);
- /* if there was a timeout callback registered, it is now
- ** invalid/useless. free any references we may have */
- luaL_unref(L, LUA_REGISTRYINDEX, db->busy_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->busy_udata);
- db->busy_cb =
- db->busy_udata = LUA_NOREF;
- return 0;
- }
- /*
- ** Params: db, sql, callback, user
- ** returns: code [, errmsg]
- **
- ** Callback:
- ** Params: user, number of columns, values, names
- ** Returns: 0 to continue, other value will cause abort
- */
- static int db_exec_callback(void* user, int columns, char **data, char **names) {
- int result = SQLITE_ABORT; /* abort by default */
- lua_State *L = (lua_State*)user;
- int n;
- int top = lua_gettop(L);
- lua_pushvalue(L, 3); /* function to call */
- lua_pushvalue(L, 4); /* user data */
- lua_pushinteger(L, columns); /* total number of rows in result */
- /* column values */
- lua_pushvalue(L, 6);
- for (n = 0; n < columns;) {
- lua_pushstring(L, data[n++]);
- lua_rawseti(L, -2, n);
- }
- /* columns names */
- lua_pushvalue(L, 5);
- if (lua_isnil(L, -1)) {
- lua_pop(L, 1);
- lua_createtable(L, columns, 0);
- lua_pushvalue(L, -1);
- lua_replace(L, 5);
- for (n = 0; n < columns;) {
- lua_pushstring(L, names[n++]);
- lua_rawseti(L, -2, n);
- }
- }
- /* call lua function */
- if (!lua_pcall(L, 4, 1, 0)) {
- #if LUA_VERSION_NUM > 502
- if (lua_isinteger(L, -1))
- result = lua_tointeger(L, -1);
- else
- #endif
- if (lua_isnumber(L, -1))
- result = lua_tonumber(L, -1);
- }
- lua_settop(L, top);
- return result;
- }
- static int db_exec(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- const char *sql = luaL_checkstring(L, 2);
- int result;
- if (!lua_isnoneornil(L, 3)) {
- /* stack:
- ** 3: callback function
- ** 4: userdata
- ** 5: column names
- ** 6: reusable column values
- */
- luaL_checktype(L, 3, LUA_TFUNCTION);
- lua_settop(L, 4); /* 'trap' userdata - nil extra parameters */
- lua_pushnil(L); /* column names not known at this point */
- lua_newtable(L); /* column values table */
- result = sqlite3_exec(db->db, sql, db_exec_callback, L, NULL);
- }
- else {
- /* no callbacks */
- result = sqlite3_exec(db->db, sql, NULL, NULL, NULL);
- }
- lua_pushinteger(L, result);
- return 1;
- }
- /*
- ** Params: db, sql
- ** returns: code, compiled length or error message
- */
- static int db_prepare(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- const char *sql = luaL_checkstring(L, 2);
- int sql_len = lua_strlen(L, 2);
- const char *sqltail;
- sdb_vm *svm;
- lua_settop(L,2); /* db,sql is on top of stack for call to newvm */
- svm = newvm(L, db);
- if (sqlite3_prepare_v2(db->db, sql, sql_len, &svm->vm, &sqltail) != SQLITE_OK) {
- lua_pushnil(L);
- lua_pushinteger(L, sqlite3_errcode(db->db));
- if (cleanupvm(L, svm) == 1)
- lua_pop(L, 1); /* this should not happen since sqlite3_prepare_v2 will not set ->vm on error */
- return 2;
- }
- /* vm already in the stack */
- lua_pushstring(L, sqltail);
- return 2;
- }
- static int db_do_next_row(lua_State *L, int packed) {
- int result;
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm;
- int columns;
- int i;
- result = stepvm(L, svm);
- vm = svm->vm; /* stepvm may change svm->vm if re-prepare is needed */
- svm->has_values = result == SQLITE_ROW ? 1 : 0;
- svm->columns = columns = sqlite3_data_count(vm);
- if (result == SQLITE_ROW) {
- if (packed) {
- if (packed == 1) {
- lua_createtable(L, columns, 0);
- for (i = 0; i < columns;) {
- vm_push_column(L, vm, i);
- lua_rawseti(L, -2, ++i);
- }
- }
- else {
- lua_createtable(L, 0, columns);
- for (i = 0; i < columns; ++i) {
- lua_pushstring(L, sqlite3_column_name(vm, i));
- vm_push_column(L, vm, i);
- lua_rawset(L, -3);
- }
- }
- return 1;
- }
- else {
- lua_checkstack(L, columns);
- for (i = 0; i < columns; ++i)
- vm_push_column(L, vm, i);
- return svm->columns;
- }
- }
- if (svm->temp) {
- /* finalize and check for errors */
- result = sqlite3_finalize(vm);
- svm->vm = NULL;
- cleanupvm(L, svm);
- }
- else if (result == SQLITE_DONE) {
- result = sqlite3_reset(vm);
- }
- if (result != SQLITE_OK) {
- lua_pushstring(L, sqlite3_errmsg(svm->db->db));
- lua_error(L);
- }
- return 0;
- }
- static int db_next_row(lua_State *L) {
- return db_do_next_row(L, 0);
- }
- static int db_next_packed_row(lua_State *L) {
- return db_do_next_row(L, 1);
- }
- static int db_next_named_row(lua_State *L) {
- return db_do_next_row(L, 2);
- }
- static int dbvm_do_rows(lua_State *L, int(*f)(lua_State *)) {
- /* sdb_vm *svm = */
- lsqlite_checkvm(L, 1);
- lua_pushvalue(L,1);
- lua_pushcfunction(L, f);
- lua_insert(L, -2);
- return 2;
- }
- static int dbvm_rows(lua_State *L) {
- return dbvm_do_rows(L, db_next_packed_row);
- }
- static int dbvm_nrows(lua_State *L) {
- return dbvm_do_rows(L, db_next_named_row);
- }
- static int dbvm_urows(lua_State *L) {
- return dbvm_do_rows(L, db_next_row);
- }
- static int db_do_rows(lua_State *L, int(*f)(lua_State *)) {
- sdb *db = lsqlite_checkdb(L, 1);
- const char *sql = luaL_checkstring(L, 2);
- sdb_vm *svm;
- lua_settop(L,2); /* db,sql is on top of stack for call to newvm */
- svm = newvm(L, db);
- svm->temp = 1;
- if (sqlite3_prepare_v2(db->db, sql, -1, &svm->vm, NULL) != SQLITE_OK) {
- lua_pushstring(L, sqlite3_errmsg(svm->db->db));
- if (cleanupvm(L, svm) == 1)
- lua_pop(L, 1); /* this should not happen since sqlite3_prepare_v2 will not set ->vm on error */
- lua_error(L);
- }
- lua_pushcfunction(L, f);
- lua_insert(L, -2);
- return 2;
- }
- static int db_rows(lua_State *L) {
- return db_do_rows(L, db_next_packed_row);
- }
- static int db_nrows(lua_State *L) {
- return db_do_rows(L, db_next_named_row);
- }
- /* unpacked version of db:rows */
- static int db_urows(lua_State *L) {
- return db_do_rows(L, db_next_row);
- }
- static int db_tostring(lua_State *L) {
- char buff[32];
- sdb *db = lsqlite_getdb(L, 1);
- if (db->db == NULL)
- strcpy(buff, "closed");
- else
- c_sprintf(buff, "%p", lua_touserdata(L, 1));
- lua_pushfstring(L, "sqlite database (%s)", buff);
- return 1;
- }
- static int db_close(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- lua_pushinteger(L, cleanupdb(L, db));
- return 1;
- }
- static int db_close_vm(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- /* cleanup temporary only tables? */
- int temp = lua_toboolean(L, 2);
- /* free associated virtual machines */
- lua_pushlightuserdata(L, db);
- lua_rawget(L, LUA_REGISTRYINDEX);
- /* close all used handles */
- lua_pushnil(L);
- while (lua_next(L, -2)) {
- sdb_vm *svm = lua_touserdata(L, -2); /* key: vm; val: sql text */
- if ((!temp || svm->temp) && svm->vm)
- {
- sqlite3_finalize(svm->vm);
- svm->vm = NULL;
- }
- /* leave key in the stack */
- lua_pop(L, 1);
- }
- return 0;
- }
- /* From: Wolfgang Oertl
- When using lsqlite3 in a multithreaded environment, each thread has a separate Lua
- environment, but full userdata structures can't be passed from one thread to another.
- This is possible with lightuserdata, however. See: lsqlite_open_ptr().
- */
- static int db_get_ptr(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- lua_pushlightuserdata(L, db->db);
- return 1;
- }
- static int db_gc(lua_State *L) {
- sdb *db = lsqlite_getdb(L, 1);
- if (db->db != NULL) /* ignore closed databases */
- cleanupdb(L, db);
- return 0;
- }
- /*
- ** =======================================================
- ** General library functions
- ** =======================================================
- */
- static int lsqlite_version(lua_State *L) {
- lua_pushstring(L, sqlite3_libversion());
- return 1;
- }
- static int lsqlite_complete(lua_State *L) {
- const char *sql = luaL_checkstring(L, 1);
- lua_pushboolean(L, sqlite3_complete(sql));
- return 1;
- }
- #if 0
- static int lsqlite_complete(lua_State *L) {
- lua_pushliteral(L, "sql complete support disabled at compile time");
- lua_error(L);
- return 0;
- }
- #endif
- #ifndef _WIN32
- static int lsqlite_temp_directory(lua_State *L) {
- const char *oldtemp = sqlite3_temp_directory;
- if (!lua_isnone(L, 1)) {
- const char *temp = luaL_optstring(L, 1, NULL);
- if (sqlite3_temp_directory) {
- sqlite3_free((char*)sqlite3_temp_directory);
- }
- if (temp) {
- sqlite3_temp_directory = sqlite3_mprintf("%s", temp);
- }
- else {
- sqlite3_temp_directory = NULL;
- }
- }
- lua_pushstring(L, oldtemp);
- return 1;
- }
- #endif
- static int lsqlite_do_open(lua_State *L, const char *filename, int flags) {
- sdb *db = newdb(L); /* create and leave in stack */
- if (SQLITE3_OPEN(filename, &db->db, flags) == SQLITE_OK) {
- /* database handle already in the stack - return it */
- return 1;
- }
- /* failed to open database */
- lua_pushnil(L); /* push nil */
- lua_pushinteger(L, sqlite3_errcode(db->db));
- lua_pushstring(L, sqlite3_errmsg(db->db)); /* push error message */
- /* clean things up */
- cleanupdb(L, db);
- /* return */
- return 3;
- }
- static int lsqlite_open(lua_State *L) {
- const char *filename = luaL_checkstring(L, 1);
- int flags = luaL_optinteger(L, 2, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
- return lsqlite_do_open(L, filename, flags);
- }
- static int lsqlite_open_memory(lua_State *L) {
- return lsqlite_do_open(L, ":memory:", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
- }
- /* From: Wolfgang Oertl
- When using lsqlite3 in a multithreaded environment, each thread has a separate Lua
- environment, but full userdata structures can't be passed from one thread to another.
- This is possible with lightuserdata, however. See: db_get_ptr().
- */
- static int lsqlite_open_ptr(lua_State *L) {
- sqlite3 *db_ptr;
- sdb *db;
- int rc;
- luaL_checktype(L, 1, LUA_TLIGHTUSERDATA);
- db_ptr = lua_touserdata(L, 1);
- /* This is the only API function that runs sqlite3SafetyCheck regardless of
- * SQLITE_ENABLE_API_ARMOR and does almost nothing (without an SQL
- * statement) */
- rc = sqlite3_exec(db_ptr, NULL, NULL, NULL, NULL);
- if (rc != SQLITE_OK)
- luaL_argerror(L, 1, "not a valid SQLite3 pointer");
- db = newdb(L); /* create and leave in stack */
- db->db = db_ptr;
- return 1;
- }
- #ifndef LSQLITE_VERSION
- /* should be defined in rockspec, but just in case... */
- #define LSQLITE_VERSION "unknown"
- #endif
- /* Version number of this library
- */
- static int lsqlite_lversion(lua_State *L) {
- lua_pushstring(L, LSQLITE_VERSION);
- return 1;
- }
- /*
- ** =======================================================
- ** Register functions
- ** =======================================================
- */
- /* ======================================================= */
- static const LUA_REG_TYPE dblib[] = {
- { LSTRKEY( "isopen" ), LFUNCVAL( db_isopen ) },
- { LSTRKEY( "last_insert_rowid" ), LFUNCVAL ( db_last_insert_rowid ) },
- { LSTRKEY( "changes" ), LFUNCVAL ( db_changes ) },
- { LSTRKEY( "total_changes" ), LFUNCVAL ( db_total_changes ) },
- { LSTRKEY( "errcode" ), LFUNCVAL ( db_errcode ) },
- { LSTRKEY( "error_code" ), LFUNCVAL ( db_errcode ) },
- { LSTRKEY( "errmsg" ), LFUNCVAL ( db_errmsg ) },
- { LSTRKEY( "error_message" ), LFUNCVAL ( db_errmsg ) },
- { LSTRKEY( "interrupt" ), LFUNCVAL ( db_interrupt ) },
- { LSTRKEY( "db_filename" ), LFUNCVAL ( db_db_filename ) },
- { LSTRKEY( "create_function" ), LFUNCVAL ( db_create_function ) },
- { LSTRKEY( "create_aggregate" ), LFUNCVAL ( db_create_aggregate ) },
- { LSTRKEY( "create_collation" ), LFUNCVAL ( db_create_collation ) },
- { LSTRKEY( "load_extension" ), LFUNCVAL ( db_load_extension ) },
- { LSTRKEY( "trace" ), LFUNCVAL ( db_trace ) },
- { LSTRKEY( "progress_handler" ), LFUNCVAL ( db_progress_handler ) },
- { LSTRKEY( "busy_timeout" ), LFUNCVAL ( db_busy_timeout ) },
- { LSTRKEY( "busy_handler" ), LFUNCVAL ( db_busy_handler ) },
- #if !defined(LSQLITE_OMIT_UPDATE_HOOK) || !LSQLITE_OMIT_UPDATE_HOOK
- { LSTRKEY( "update_hook" ), LFUNCVAL ( db_update_hook ) },
- { LSTRKEY( "commit_hook" ), LFUNCVAL ( db_commit_hook ) },
- { LSTRKEY( "rollback_hook" ), LFUNCVAL ( db_rollback_hook ) },
- #endif
- { LSTRKEY( "prepare" ), LFUNCVAL ( db_prepare ) },
- { LSTRKEY( "rows" ), LFUNCVAL ( db_rows ) },
- { LSTRKEY( "urows" ), LFUNCVAL ( db_urows ) },
- { LSTRKEY( "nrows" ), LFUNCVAL ( db_nrows ) },
- { LSTRKEY( "exec" ), LFUNCVAL ( db_exec ) },
- { LSTRKEY( "execute" ), LFUNCVAL ( db_exec ) },
- { LSTRKEY( "close" ), LFUNCVAL ( db_close ) },
- { LSTRKEY( "close_vm" ), LFUNCVAL ( db_close_vm ) },
- { LSTRKEY( "get_ptr" ), LFUNCVAL ( db_get_ptr ) },
- { LSTRKEY( "__tostring" ), LFUNCVAL ( db_tostring ) },
- { LSTRKEY( "__gc" ), LFUNCVAL ( db_gc ) },
- { LSTRKEY( "__index" ), LROVAL ( dblib ) },
- { LNILKEY, LNILVAL }
- };
- static const LUA_REG_TYPE vmlib[] = {
- { LSTRKEY( "isopen" ), LFUNCVAL ( dbvm_isopen ) },
- { LSTRKEY( "step" ), LFUNCVAL ( dbvm_step ) },
- { LSTRKEY( "reset" ), LFUNCVAL ( dbvm_reset ) },
- { LSTRKEY( "finalize" ), LFUNCVAL ( dbvm_finalize ) },
- { LSTRKEY( "columns" ), LFUNCVAL ( dbvm_columns ) },
- { LSTRKEY( "bind" ), LFUNCVAL ( dbvm_bind ) },
- { LSTRKEY( "bind_values" ), LFUNCVAL ( dbvm_bind_values ) },
- { LSTRKEY( "bind_names" ), LFUNCVAL ( dbvm_bind_names ) },
- { LSTRKEY( "bind_blob" ), LFUNCVAL ( dbvm_bind_blob ) },
- { LSTRKEY( "bind_parameter_count" ),LFUNCVAL ( dbvm_bind_parameter_count )},
- { LSTRKEY( "bind_parameter_name" ), LFUNCVAL ( dbvm_bind_parameter_name )},
- { LSTRKEY( "get_value" ), LFUNCVAL ( dbvm_get_value ) },
- { LSTRKEY( "get_values" ), LFUNCVAL ( dbvm_get_values ) },
- { LSTRKEY( "get_name" ), LFUNCVAL ( dbvm_get_name ) },
- { LSTRKEY( "get_names" ), LFUNCVAL ( dbvm_get_names ) },
- { LSTRKEY( "get_type" ), LFUNCVAL ( dbvm_get_type ) },
- { LSTRKEY( "get_types" ), LFUNCVAL ( dbvm_get_types ) },
- { LSTRKEY( "get_uvalues" ), LFUNCVAL ( dbvm_get_uvalues ) },
- { LSTRKEY( "get_unames" ), LFUNCVAL ( dbvm_get_unames ) },
- { LSTRKEY( "get_utypes" ), LFUNCVAL ( dbvm_get_utypes ) },
- { LSTRKEY( "get_named_values" ), LFUNCVAL ( dbvm_get_named_values ) },
- { LSTRKEY( "get_named_types" ), LFUNCVAL ( dbvm_get_named_types ) },
- { LSTRKEY( "rows" ), LFUNCVAL ( dbvm_rows ) },
- { LSTRKEY( "urows" ), LFUNCVAL ( dbvm_urows ) },
- { LSTRKEY( "nrows" ), LFUNCVAL ( dbvm_nrows ) },
- { LSTRKEY( "last_insert_rowid" ), LFUNCVAL ( dbvm_last_insert_rowid ) },
- /* compatibility names (added by request) */
- { LSTRKEY( "idata" ), LFUNCVAL ( dbvm_get_values ) },
- { LSTRKEY( "inames" ), LFUNCVAL ( dbvm_get_names ) },
- { LSTRKEY( "itypes" ), LFUNCVAL ( dbvm_get_types ) },
- { LSTRKEY( "data" ), LFUNCVAL ( dbvm_get_named_values ) },
- { LSTRKEY( "type" ), LFUNCVAL ( dbvm_get_named_types ) },
- { LSTRKEY( "__tostring" ), LFUNCVAL ( dbvm_tostring ) },
- { LSTRKEY( "__gc" ), LFUNCVAL ( dbvm_gc ) },
- { LSTRKEY( "__index" ), LROVAL ( vmlib ) },
- { LNILKEY, LNILVAL }
- };
- static const LUA_REG_TYPE ctxlib[] = {
- { LSTRKEY( "user_data" ), LFUNCVAL ( lcontext_user_data ) },
- { LSTRKEY( "get_aggregate_data" ), LFUNCVAL ( lcontext_get_aggregate_context ) },
- { LSTRKEY( "set_aggregate_data" ), LFUNCVAL ( lcontext_set_aggregate_context ) },
- { LSTRKEY( "aggregate_count" ), LFUNCVAL ( lcontext_aggregate_count ) },
- { LSTRKEY( "result" ), LFUNCVAL ( lcontext_result ) },
- { LSTRKEY( "result_null" ), LFUNCVAL ( lcontext_result_null ) },
- { LSTRKEY( "result_number" ), LFUNCVAL ( lcontext_result_double ) },
- { LSTRKEY( "result_double" ), LFUNCVAL ( lcontext_result_double ) },
- { LSTRKEY( "result_int" ), LFUNCVAL ( lcontext_result_int ) },
- { LSTRKEY( "result_text" ), LFUNCVAL ( lcontext_result_text ) },
- { LSTRKEY( "result_blob" ), LFUNCVAL ( lcontext_result_blob ) },
- { LSTRKEY( "result_error" ), LFUNCVAL ( lcontext_result_error ) },
- { LSTRKEY( "__tostring" ), LFUNCVAL ( lcontext_tostring ) },
- { LSTRKEY( "__index" ), LROVAL ( ctxlib ) },
- { LNILKEY, LNILVAL }
- };
- static const LUA_REG_TYPE dbbulib[] = {
- { LSTRKEY( "step" ), LFUNCVAL ( dbbu_step ) },
- { LSTRKEY( "remaining" ), LFUNCVAL ( dbbu_remaining ) },
- { LSTRKEY( "pagecount" ), LFUNCVAL ( dbbu_pagecount ) },
- { LSTRKEY( "finish" ), LFUNCVAL ( dbbu_finish ) },
- // { LSTRKEY( "__tostring" ), LFUNCVAL ( dbbu_tostring ) },
- { LSTRKEY( "__gc" ), LFUNCVAL ( dbbu_gc ) },
- { LSTRKEY( "__index" ), LROVAL ( dbbulib ) },
- { LNILKEY, LNILVAL }
- };
- #define SC(s) { LSTRKEY( #s ), LNUMVAL ( SQLITE_ ## s ) },
- #define LSC(s) { LSTRKEY( #s ), LNUMVAL ( LSQLITE_ ## s ) },
- static const LUA_REG_TYPE sqlitelib[] = {
- { LSTRKEY( "lversion" ), LFUNCVAL ( lsqlite_lversion ) },
- { LSTRKEY( "version" ), LFUNCVAL ( lsqlite_version ) },
- { LSTRKEY( "complete" ), LFUNCVAL ( lsqlite_complete ) },
- #ifndef _WIN32
- { LSTRKEY( "temp_directory" ), LFUNCVAL ( lsqlite_temp_directory ) },
- #endif
- { LSTRKEY( "open" ), LFUNCVAL ( lsqlite_open ) },
- { LSTRKEY( "open_memory" ), LFUNCVAL ( lsqlite_open_memory ) },
- { LSTRKEY( "open_ptr" ), LFUNCVAL ( lsqlite_open_ptr ) },
- { LSTRKEY( "backup_init" ), LFUNCVAL ( lsqlite_backup_init ) },
- SC(OK) SC(ERROR) SC(INTERNAL) SC(PERM)
- SC(ABORT) SC(BUSY) SC(LOCKED) SC(NOMEM)
- SC(READONLY) SC(INTERRUPT) SC(IOERR) SC(CORRUPT)
- SC(NOTFOUND) SC(FULL) SC(CANTOPEN) SC(PROTOCOL)
- SC(EMPTY) SC(SCHEMA) SC(TOOBIG) SC(CONSTRAINT)
- SC(MISMATCH) SC(MISUSE) SC(NOLFS)
- SC(FORMAT) SC(NOTADB)
- /* sqlite_step specific return values */
- SC(RANGE) SC(ROW) SC(DONE)
- /* column types */
- SC(INTEGER) SC(FLOAT) SC(TEXT) SC(BLOB)
- SC(NULL)
- /* Authorizer Action Codes */
- SC(CREATE_INDEX )
- SC(CREATE_TABLE )
- SC(CREATE_TEMP_INDEX )
- SC(CREATE_TEMP_TABLE )
- SC(CREATE_TEMP_TRIGGER)
- SC(CREATE_TEMP_VIEW )
- SC(CREATE_TRIGGER )
- SC(CREATE_VIEW )
- SC(DELETE )
- SC(DROP_INDEX )
- SC(DROP_TABLE )
- SC(DROP_TEMP_INDEX )
- SC(DROP_TEMP_TABLE )
- SC(DROP_TEMP_TRIGGER )
- SC(DROP_TEMP_VIEW )
- SC(DROP_TRIGGER )
- SC(DROP_VIEW )
- SC(INSERT )
- SC(PRAGMA )
- SC(READ )
- SC(SELECT )
- SC(TRANSACTION )
- SC(UPDATE )
- SC(ATTACH )
- SC(DETACH )
- SC(ALTER_TABLE )
- SC(REINDEX )
- SC(ANALYZE )
- SC(CREATE_VTABLE )
- SC(DROP_VTABLE )
- SC(FUNCTION )
- SC(SAVEPOINT )
- /* file open flags */
- SC(OPEN_READONLY)
- SC(OPEN_READWRITE)
- SC(OPEN_CREATE)
- SC(OPEN_URI)
- SC(OPEN_MEMORY)
- SC(OPEN_NOMUTEX)
- SC(OPEN_FULLMUTEX)
- SC(OPEN_SHAREDCACHE)
- SC(OPEN_PRIVATECACHE)
- { LNILKEY, LNILVAL }
- };
- LUALIB_API int luaopen_lsqlite3(lua_State *L) {
- luaL_rometatable(L, sqlite_meta, (void *)dblib);
- luaL_rometatable(L, sqlite_vm_meta, (void *)vmlib);
- luaL_rometatable(L, sqlite_bu_meta, (void *)dbbulib);
- luaL_rometatable(L, sqlite_ctx_meta, (void *)ctxlib);
- return 1;
- }
- NODEMCU_MODULE(SQLITE3, "sqlite3", sqlitelib, luaopen_lsqlite3);
|