├── LICENSE ├── Makefile ├── README.md ├── lua.mak └── src └── lua.c /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2016, Abilio Marques 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those 25 | of the authors and should not be interpreted as representing official policies, 26 | either expressed or implied, of the FreeBSD Project. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # To build this on FreeBSD install lua5.3 (or similar) and sqlite3 2 | # 3 | # on Linux you must install: 4 | # liblua5.3-dev or similar 5 | # libsqlite3-dev or similar 6 | 7 | 8 | LUA_VERSION=5.3 9 | 10 | # next 3 lines where tested on FreeBSD and Ubuntu 11 | LUA_CFLAGS=`pkg-config --cflags --silence-errors lua$(LUA_VERSION) || pkg-config --cflags --silence-errors lua-$(LUA_VERSION) || pkg-config --cflags --silence-errors lua` 12 | LUA_LIB=`pkg-config --libs --silence-errors lua$(LUA_VERSION) || pkg-config --libs --silence-errors lua-$(LUA_VERSION) || pkg-config --libs --silence-errors lua` 13 | SQLITE_FLAGS=`pkg-config --cflags --silence-errors sqlite3` 14 | 15 | all: lua.so 16 | 17 | lua.so: lua.o 18 | cc -shared -o lua.so lua.o $(LUA_LIB) 19 | @[ "`uname -s`" == "Darwin" ] && mv lua.so lua.dylib || : 20 | 21 | lua.o: src/lua.c 22 | cc -c $(LUA_CFLAGS) $(SQLITE_FLAGS) -O3 src/lua.c 23 | 24 | clean: 25 | rm lua.o 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SQLite's Moon: Lua for SQLite 2 | 3 | Create new SQL functions! Write them using [Lua](http://www.lua.org/). 4 | 5 | 6 | # Usage 7 | 8 | This is an [SQLite](http://sqlite.org/) plugin. After loading it, you can use the function ```createlua``` to define your own functions, like this: 9 | 10 | ``` 11 | SELECT createlua({parameters}); 12 | ``` 13 | 14 | This query will return ```ok``` if everything went fine. 15 | 16 | SQL supports two types of functions: 17 | * Scalar: returns a result for each record. 18 | * Aggregate: process all records, then return a single final result. 19 | 20 | 21 | ## Scalar 22 | 23 | When creating a scalar function, you must provide 2 parameters, in the following order: 24 | * Name: the function you are defining. 25 | * Code: well... the Lua code. Returns the result. 26 | 27 | For example, to create a function that calculates the cosine of an angle: 28 | ``` 29 | SELECT createlua('cos', 'return math.cos(arg[1])'); 30 | ``` 31 | 32 | And now you can calculate cosines on a query: 33 | ``` 34 | CREATE TABLE t(angle NUMERIC); 35 | INSERT INTO t(angle) VALUES (0),(1.571),(3.1416); 36 | 37 | SELECT cos(angle) FROM t; -- should return approximately {1, 0, -1} 38 | ``` 39 | 40 | 41 | ## Aggregate 42 | 43 | When creating aggregate functions, you must provide 4 parameters, in the following order: 44 | * Name: the function you are defining. 45 | * Init: this code will execute before the first record is processed. 46 | * Step: code called on each record. 47 | * Final: code for the last step after all records have been processed. Returns the result. 48 | 49 | For example, to create a function that calculates the [geometric mean](https://en.wikipedia.org/wiki/Geometric_mean) of a set of numbers: 50 | 51 | ``` 52 | SELECT createlua('gmean', 53 | 'prod = 1; n = 0;', 54 | 'n = n + 1; prod = prod * arg[1];', 55 | 'return prod ^ (1/n);'); 56 | ``` 57 | 58 | And now, used on a query: 59 | 60 | ``` 61 | CREATE TABLE data(val NUMERIC); 62 | INSERT INTO data(val) VALUES (2), (4), (8); 63 | 64 | SELECT gmean(val) FROM data; -- should return 4 65 | ``` 66 | 67 | 68 | # Parameters 69 | 70 | Parameters supplied to the functions can be accessed from within Lua. The array: ```arg[i]``` contains the values. ```arg``` is a zero-based array (1 <= i <= n), like is customary in Lua. 71 | 72 | Example: 73 | ``` 74 | -- this is a pattern matching example using Lua's internal function 75 | SELECT createlua('regex', 'return string.match(arg[1], arg[2])'); 76 | 77 | SELECT regex('abc 24 ef', '([0-9]+)'); -- Should return 24 78 | ``` 79 | 80 | 81 | # Reading from files 82 | 83 | You can use the auxiliary function named ```loadfile``` to get the content of a file. This is useful to declare long functions. The signature is: 84 | 85 | ``` 86 | loadfile(filename,[type]) 87 | ``` 88 | 89 | For example, to create a function which source code is stored in a file named ```longcode.lua```, do: 90 | 91 | ``` 92 | select createlua('longcode', select loadfile('longcode.lua')); 93 | ``` 94 | 95 | ```loadfile``` can take an optional type parameter. If type is 'b', the file content will be read as a blob. This can be useful for other applications, e.g., reading binary files inside the database. 96 | 97 | 98 | # Notes 99 | 100 | * Functions must always return a value. For aggregates, this is only performed on the final step. 101 | * You can redefine a function at any time by calling ```createlua``` again. This holds true even for SQLite's native functions. 102 | * Currently, you can't return an array into SQLite. 103 | * Even when Lua can return multiple values simultaneously, only the first one will be passed back to SQLite. 104 | 105 | 106 | # Building 107 | 108 | On FreeBSD, you must have ```lua5.3```and ```sqlite3``` installed. For Linux (Ubuntu flavored), the equivalents are ```liblua5.3-dev``` and ```libsqlite3-dev```. The library names and their locations could be different on other Operating Systems. If that's the case, you may need to edit the Makefile. 109 | 110 | On Windows, using Visual Studio, you can use the provided ```lua.mak```. You'll need to extract the Lua src directory content in a folder named lua. Also the files sqlite3.h and sqlite3ext.h, must be extracted inside a folder named sqlite. These files are part of the [sqlite source code amalgamation](https://www.sqlite.org/download.html). Afterwards, you can compile the dll like this: 111 | ``` 112 | nmake -f lua.mak 113 | ``` 114 | 115 | This code should remain compatible with future versions of Lua. It has also been tested with Lua 5.2. You'll only need to alter the ```LUA_VERSION``` parameter inside the Makefile. 116 | 117 | 118 | # Loading 119 | 120 | To use this plugin from within the sqlite3 command line tool, you must run: 121 | 122 | ```.load path-to-plugin/lua``` (for security reasons, SQLite needs you to provide the library path if the plugin is not located inside ```LD_LIBRARY_PATH```. Current directory '.' is a valid path, e.g., ```.load ./lua```). 123 | 124 | You could also use this from within almost any code that uses sqlite3 as a library. Refer to SQLite website to get more information about ```sqlite3_load_extension``` and ```sqlite3_enable_load_extension``` or look for their equivalents in your language bindings' documentation. 125 | 126 | 127 | ## License 128 | 129 | The work here contained is published under the Simplified BSD License. Read LICENSE for more information. 130 | -------------------------------------------------------------------------------- /lua.mak: -------------------------------------------------------------------------------- 1 | # to run this: "nmake -f lua.mak" 2 | # please extract the lua src directory inside a folder called lua 3 | # extract sqlite3.h and sqlite3ext.h inside a folder called sqlite 4 | 5 | # it should generate lua.dll as the output 6 | 7 | CPP=cl.exe 8 | 9 | 10 | ALL : 11 | @if not exist ".\lua\lua.h" echo "please extract the lua src directory contents inside the lua folder" 12 | @if not exist ".\lua" mkdir lua 13 | 14 | @if not exist ".\sqlite\sqlite3.h" echo "please extract SQLite's header files inside the sqlite folder" 15 | @if not exist ".\sqlite" mkdir sqlite 16 | 17 | # we're going to use wildcards, and lua\lua.c is not needed (actually, it conflicts as it has it's own main). 18 | @if exist ".\lua\lua.c" rm .\lua\lua.c 19 | 20 | $(CPP) /Ot /GD /nologo /W3 /I .\lua /I .\sqlite .\lua\*.c .\src\lua.c -link -dll -out:lua.dll 21 | @erase *.obj 22 | @erase lua.exp lua.lib 23 | -------------------------------------------------------------------------------- /src/lua.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * SQLite's Moon: Lua for SQLite 4 | * 5 | * Create new SQL functions! Write them using Lua. 6 | * 7 | * By: Abilio Marques 8 | * 9 | * 10 | * After loading this plugin, you can use the newly function "createlua" to create your own 11 | * functions. 12 | * 13 | * See README.md for more information on how to use it. 14 | * 15 | * This code is published under the Simplified BSD License 16 | * 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | SQLITE_EXTENSION_INIT1; 27 | #if defined( _WIN32 ) 28 | #define _USE_MATH_DEFINES 29 | #endif /* _WIN32 */ 30 | 31 | 32 | // 33 | // Get a new LUA state 34 | // 35 | 36 | static void *createLuaState(void) { 37 | lua_State *L; 38 | 39 | L = luaL_newstate(); 40 | if (L == NULL) return NULL; 41 | 42 | luaL_openlibs(L); 43 | return L; 44 | } 45 | 46 | 47 | // 48 | // Destroy a previously allocated LUA state 49 | // 50 | 51 | static void destroyLuaState(void *state) { 52 | if (state != NULL) { 53 | lua_gc(state, LUA_GCCOLLECT, 0); 54 | lua_close(state); 55 | } 56 | } 57 | 58 | 59 | // 60 | // Loads an SQLite value into the LUA stack. 61 | // Tries to match the types 62 | // 63 | 64 | static void pushSqliteLua(int i, sqlite3_value *value, lua_State *destination) { 65 | int n; 66 | double d; 67 | const char *str; 68 | 69 | lua_pushnumber(destination, i); 70 | 71 | switch (sqlite3_value_type(value)) { 72 | 73 | case SQLITE_FLOAT: 74 | d = sqlite3_value_double(value); 75 | lua_pushnumber(destination, d); 76 | break; 77 | 78 | case SQLITE_INTEGER: 79 | n = sqlite3_value_int(value); 80 | lua_pushinteger(destination, n); 81 | break; 82 | 83 | case SQLITE_NULL: 84 | lua_pushnil(destination); 85 | break; 86 | 87 | case SQLITE_TEXT: 88 | str = (char *) sqlite3_value_text(value); 89 | lua_pushstring(destination, str); 90 | break; 91 | 92 | case SQLITE_BLOB: 93 | str = sqlite3_value_blob(value); 94 | n = sqlite3_value_bytes(value); 95 | lua_pushlstring(destination, str, n); 96 | break; 97 | } 98 | 99 | lua_settable(destination, -3); 100 | 101 | } 102 | 103 | 104 | // 105 | // Gets a value from the Lua stack and returns it as an SQLite value. 106 | // Tries to match the types 107 | // 108 | 109 | static void popLuaSqlite(lua_State *from, sqlite3_context *ctx) { 110 | int n; 111 | double d; 112 | const char *str; 113 | 114 | if (lua_gettop(from) == 0) { 115 | sqlite3_result_null(ctx); 116 | return; 117 | } 118 | 119 | switch (lua_type(from, -1)) { 120 | 121 | case LUA_TNUMBER: 122 | d = lua_tonumber(from, -1); 123 | if (floor(d) == d) { 124 | sqlite3_result_int(ctx, (int) d); 125 | } else { 126 | sqlite3_result_double(ctx, d); 127 | } 128 | break; 129 | 130 | case LUA_TSTRING: 131 | str = lua_tostring(from, -1); 132 | sqlite3_result_text(ctx, str, -1, SQLITE_TRANSIENT); 133 | break; 134 | 135 | case LUA_TBOOLEAN: 136 | n = lua_toboolean(from, -1); 137 | sqlite3_result_int(ctx, n); 138 | break; 139 | 140 | case LUA_TNIL: 141 | sqlite3_result_null(ctx); 142 | break; 143 | 144 | default: 145 | sqlite3_result_error(ctx, "Unsupported return type", -1); 146 | break; 147 | } 148 | 149 | lua_pop(from, 1); 150 | } 151 | 152 | 153 | static lua_State *getAssociatedLuaState(sqlite3_context *ctx) { 154 | return sqlite3_user_data(ctx); 155 | } 156 | 157 | 158 | // 159 | // Loads a code chunk into the Lua stack 160 | // 161 | 162 | static int pushLuaChunk(lua_State *where, const unsigned char *code, const unsigned char *init, 163 | const unsigned char *final) { 164 | 165 | lua_pop(where, lua_gettop(where)); // clean the stack 166 | 167 | if (luaL_loadstring(where, (char *) code) != LUA_OK) return 1; 168 | 169 | if (init != NULL && final != NULL) { 170 | if (luaL_loadstring(where, (char *) init) != LUA_OK) return 2; 171 | if (luaL_loadstring(where, (char *) final) != LUA_OK) return 3; 172 | } 173 | 174 | return 0; 175 | } 176 | 177 | 178 | // 179 | // Loads the passed values inside arg[] 180 | // 181 | 182 | static void pushLuaParams(lua_State *where, int num_values, sqlite3_value **values) { 183 | int i; 184 | 185 | lua_createtable(where, num_values, 0); 186 | 187 | for (i = 0; i < num_values; i++) { 188 | pushSqliteLua(i + 1, values[i], where); 189 | } 190 | 191 | lua_setglobal(where, "arg"); 192 | } 193 | 194 | 195 | // 196 | // Executes code chunk previously stored in the Lua stack 197 | // 198 | 199 | static void executeLuaChunk(lua_State *where, int returnsValue, int chunk) { 200 | lua_pushvalue(where, chunk); 201 | lua_pcall(where, 0, returnsValue, 0); 202 | } 203 | 204 | 205 | // 206 | // Check for return value 207 | // 208 | static int checkStackLen(lua_State *stack, sqlite3_context *ctx, int validLen) { 209 | if (lua_gettop(stack) != validLen) { 210 | sqlite3_result_error(ctx, "Invalid Lua stack length! " \ 211 | "This normally happens if your code doesn't return any value.", -1); 212 | return 0; 213 | } 214 | 215 | return 1; 216 | } 217 | 218 | // 219 | // Store a pointer into a Lua table located at pos 220 | // 221 | 222 | static void storePointer(lua_State *where, int pos, const char *name, void *p) { 223 | lua_pushstring(where, name); 224 | lua_pushlightuserdata(where, p); 225 | lua_settable(where, pos); 226 | } 227 | 228 | 229 | // 230 | // Find a pointer inside a Lua table located at pos 231 | // 232 | 233 | static lua_State *findPointer(lua_State *where, int pos, const char *name) { 234 | lua_State *result; 235 | 236 | 237 | lua_pushstring(where, name); 238 | lua_pushnil(where); /* first key */ 239 | while (lua_next(where, pos) != 0) { 240 | 241 | if (lua_compare(where, -3, -2, LUA_OPEQ)) { 242 | // found the item 243 | result = lua_touserdata(where, -1); 244 | 245 | // remove the remains from the stack (two copies of the name + the value) 246 | lua_pop(where, 3); 247 | return result; 248 | } 249 | 250 | lua_pop(where, 1); 251 | } 252 | lua_pop(where, 1); // remove the name we were looking for from the stack 253 | return NULL; 254 | } 255 | 256 | 257 | // 258 | // Executes scalar function (called by SQLite) 259 | // 260 | 261 | static void sql_scalar_lua(sqlite3_context *ctx, int num_values, sqlite3_value **values) { 262 | lua_State *L; 263 | 264 | L = getAssociatedLuaState(ctx); 265 | pushLuaParams(L, num_values, values); 266 | executeLuaChunk(L, 1, 1); 267 | if (checkStackLen(L, ctx, 2)) popLuaSqlite(L, ctx); // stack size = 2 (code and return val) 268 | } 269 | 270 | 271 | // 272 | // Executes init and step parts of an aggregate function (called by SQLite) 273 | // 274 | 275 | static void sql_aggregate_lua(sqlite3_context *ctx, int num_values, sqlite3_value **values) { 276 | lua_State *L; 277 | int *notFirstTime = sqlite3_aggregate_context(ctx, sizeof(int)); 278 | 279 | if (notFirstTime == NULL) { 280 | sqlite3_result_error_nomem(ctx); 281 | return; 282 | } 283 | 284 | L = getAssociatedLuaState(ctx); 285 | 286 | if (*notFirstTime == 0) { 287 | // it must execute the init chunk once 288 | executeLuaChunk(L, 0, 2); 289 | *notFirstTime = 1; 290 | } 291 | 292 | pushLuaParams(L, num_values, values); 293 | executeLuaChunk(L, 0, 1); 294 | } 295 | 296 | 297 | // 298 | // Executes the final code chunk of an aggregate function (called by SQLite) 299 | // 300 | 301 | static void sql_aggregate_lua_final(sqlite3_context *ctx) { 302 | lua_State *L; 303 | L = getAssociatedLuaState(ctx); 304 | 305 | executeLuaChunk(L, 1, 3); 306 | 307 | if (checkStackLen(L, ctx, 4)) popLuaSqlite(L, ctx); // stack size = 4 (3x code and return val) 308 | } 309 | 310 | 311 | // 312 | // Check that all the function creation parameters are strings 313 | // 314 | 315 | static const char *checkCreateluaParameters(int num_values, sqlite3_value **values) { 316 | int i, adj; 317 | 318 | const char *errors[] = { 319 | "Invalid function name, string expected", 320 | "Invalid function code, string expected", 321 | "Invalid init code, string expected", 322 | "Invalid step code, string expected", 323 | "Invalid final code, string expected" 324 | }; 325 | 326 | for (i = 0; i < num_values; i++) { 327 | adj = (num_values == 2 || i == 0 ? 0 : 1); 328 | if (sqlite3_value_type(values[i]) != SQLITE_TEXT) return errors[i + adj]; 329 | } 330 | 331 | return NULL; 332 | 333 | } 334 | 335 | 336 | // 337 | // check result of code compilation and print a human readable result 338 | // 339 | 340 | static void messageCodeCompilingResult(sqlite3_context *ctx, int res, int num_values) { 341 | switch (res) { 342 | case 0: 343 | sqlite3_result_text(ctx, "ok", -1, SQLITE_TRANSIENT); 344 | break; 345 | 346 | case 1: 347 | if (num_values == 2) { 348 | sqlite3_result_error(ctx, "compilation problem, please check source code", -1); 349 | } else { 350 | sqlite3_result_error(ctx, "compilation problem, please check step source code", -1); 351 | } 352 | break; 353 | 354 | case 2: 355 | sqlite3_result_error(ctx, "compilation problem, please check init source code", -1); 356 | break; 357 | 358 | case 3: 359 | sqlite3_result_error(ctx, "compilation problem, please check final source code", -1); 360 | break; 361 | } 362 | } 363 | 364 | 365 | // 366 | // Create a new SQL Lua function (called by SQLite) 367 | // 368 | 369 | static void sql_createlua(sqlite3_context *ctx, int num_values, sqlite3_value **values) { 370 | lua_State *L, *functionTable; 371 | 372 | const char *msg, *name; 373 | int retVal; 374 | 375 | msg = checkCreateluaParameters(num_values, values); 376 | if (msg != NULL) { 377 | sqlite3_result_error(ctx, msg, -1); 378 | return; 379 | } 380 | 381 | name = (char *) sqlite3_value_text(values[0]); 382 | 383 | functionTable = getAssociatedLuaState(ctx); 384 | 385 | L = findPointer(functionTable, 1, name); 386 | if (L == NULL) { 387 | L = createLuaState(); 388 | storePointer(functionTable, 1, name, L); 389 | 390 | // now register the function within SQLite 391 | if (num_values == 2) { 392 | // scalar 393 | sqlite3_create_function_v2(sqlite3_context_db_handle(ctx), (char *) name, -1, 394 | SQLITE_UTF8, (void *) L, sql_scalar_lua, NULL, NULL, destroyLuaState); 395 | } else { 396 | // aggregate 397 | sqlite3_create_function_v2(sqlite3_context_db_handle(ctx), (char *) name, -1, 398 | SQLITE_UTF8, (void *) L, NULL, sql_aggregate_lua, sql_aggregate_lua_final, destroyLuaState); 399 | } 400 | 401 | } 402 | 403 | // load the code inside the stack 404 | if (num_values == 2) { 405 | // scalar 406 | retVal = pushLuaChunk(L, sqlite3_value_text(values[1]), NULL, NULL); 407 | } else { 408 | // aggregate 409 | retVal = pushLuaChunk(L, sqlite3_value_text(values[2]), sqlite3_value_text(values[1]), 410 | sqlite3_value_text(values[3])); 411 | } 412 | 413 | if (retVal != 0) { 414 | sqlite3_create_function_v2(sqlite3_context_db_handle(ctx), (char *) name, -1, 415 | SQLITE_UTF8, NULL, NULL, NULL, NULL, NULL); 416 | } 417 | 418 | messageCodeCompilingResult(ctx, retVal, num_values); 419 | } 420 | 421 | 422 | // 423 | // Load data from a file (return a text or a blob) 424 | // 425 | 426 | static void sql_loadFile(sqlite3_context *ctx, int num_values, sqlite3_value **values) { 427 | FILE *f; 428 | char *buffer = 0; 429 | int length; 430 | 431 | f = fopen((const char*)sqlite3_value_text(values[0]), "rb"); 432 | 433 | if (!f) { 434 | sqlite3_result_error(ctx, "Unable to open the file", -1); 435 | return; 436 | } 437 | 438 | fseek(f, 0, SEEK_END); 439 | length = ftell(f); 440 | fseek(f, 0, SEEK_SET); 441 | 442 | buffer = sqlite3_malloc(length + 1); 443 | 444 | if (buffer) { 445 | fread(buffer, 1, length, f); 446 | 447 | if (num_values == 2 && sqlite3_value_text(values[1])[0] == 'b') { 448 | sqlite3_result_blob(ctx, buffer, length, sqlite3_free); 449 | } else { 450 | sqlite3_result_text(ctx, buffer, length, sqlite3_free); 451 | } 452 | } else { 453 | sqlite3_result_error(ctx, "unable to get free memory to hold the file contents", -1); 454 | } 455 | 456 | fclose (f); 457 | } 458 | 459 | 460 | // 461 | // plugin main 462 | // 463 | #ifdef _WIN32 464 | __declspec(dllexport) 465 | #endif 466 | int sqlite3_extension_init(sqlite3 *db, char **error, const sqlite3_api_routines *api) { 467 | lua_State *mainState; // going to hold the list of created functions 468 | 469 | SQLITE_EXTENSION_INIT2(api); 470 | 471 | 472 | mainState = createLuaState(); 473 | if (mainState == NULL) return 0; 474 | lua_newtable(mainState); 475 | 476 | sqlite3_create_function_v2(db, "createlua", 2, SQLITE_UTF8, mainState, sql_createlua, 477 | NULL, NULL, NULL); 478 | sqlite3_create_function_v2(db, "createlua", 4, SQLITE_UTF8, mainState, sql_createlua, 479 | NULL, NULL, destroyLuaState); 480 | 481 | sqlite3_create_function_v2(db, "loadfile", 1, SQLITE_UTF8, NULL, sql_loadFile, 482 | NULL, NULL, NULL); 483 | sqlite3_create_function_v2(db, "loadfile", 2, SQLITE_UTF8, NULL, sql_loadFile, 484 | NULL, NULL, NULL); 485 | 486 | return SQLITE_OK; 487 | } 488 | --------------------------------------------------------------------------------