├── 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 |
--------------------------------------------------------------------------------