Skip to content

Commit 1ce570b

Browse files
committed
Added custom functions.
1 parent 3fdb218 commit 1ce570b

File tree

8 files changed

+271835
-204814
lines changed

8 files changed

+271835
-204814
lines changed

Makefile

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ EMSCRIPTEN?=/usr/bin
44

55
EMCC=$(EMSCRIPTEN)/emcc
66

7-
CFLAGS=-DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_DISABLE_LFS -DLONGDOUBLE_TYPE=double -DSQLITE_INT64_TYPE="long long int" -DSQLITE_THREADSAFE=0
7+
CFLAGS=-DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_DISABLE_LFS -DLONGDOUBLE_TYPE=double -DSQLITE_INT64_TYPE="long long int" -DSQLITE_THREADSAFE=0 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS
88

99
all: js/sql.js
1010

11-
debug: EMFLAGS= -O1 -g -s INLINING_LIMIT=10
11+
# RESERVED_FUNCTION_POINTERS setting is used for registering custom functions
12+
debug: EMFLAGS= -O1 -g -s INLINING_LIMIT=10 -s RESERVED_FUNCTION_POINTERS=64
1213
debug: js/sql-debug.js
1314

14-
optimized: EMFLAGS= --memory-init-file 0 --closure 1 -O3 -s INLINING_LIMIT=50
15+
optimized: EMFLAGS= --memory-init-file 0 --closure 1 -O3 -s INLINING_LIMIT=50 -s RESERVED_FUNCTION_POINTERS=64
1516
optimized: js/sql-optimized.js
1617

1718
js/sql.js: optimized

coffee/api-data.coffee

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,6 @@ SQLite.FLOAT=2
3939
SQLite.TEXT=3
4040
SQLite.BLOB=4
4141
SQLite.NULL=5
42+
43+
# Encodings, used for registering functions.
44+
SQLite.UTF8=1

coffee/api.coffee

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,53 @@ class Database
413413
@handleError sqlite3_close_v2 @db
414414
FS.unlink '/' + @filename
415415
@db = null
416+
417+
### Register a custom function with SQLite
418+
@param name [String] the name of the function as referenced in SQL statements.
419+
@param numParams [Number] the number of parameters the function expects.
420+
@param func [Function] the actual function to be executed.
421+
@param dbg_func [Function, optional] useful for breakpointing and testing the wrapper function.
422+
###
423+
'create_function': (name, numParams, func, dbg_func=(->)) ->
424+
wrapped_func = (cx, argc, argv) ->
425+
# Debug function, useful for breakpointing if you need to debug this
426+
dbg_func()
427+
428+
# Parse the args from sqlite into JS objects
429+
args = []
430+
for i in [0..argc]
431+
value_ptr = getValue(argv+(4*i), 'i32')
432+
value_type = sqlite3_value_type(value_ptr)
433+
data_func = switch
434+
when value_type == 1 then sqlite3_value_int
435+
when value_type == 2 then sqlite3_value_double
436+
when value_type == 3 then sqlite3_value_text
437+
when value_type == 4 then (ptr) ->
438+
size = sqlite3_value_bytes(ptr)
439+
blob_ptr = sqlite3_value_blob(ptr)
440+
blob_arg = new Uint8Array(size)
441+
blob_arg[j] = HEAP8[blob_ptr+j] for j in [0 ... size]
442+
blob_arg
443+
else (ptr) -> null
444+
445+
arg = data_func(value_ptr)
446+
args.push arg
447+
448+
# Invoke the user defined function with arguments from SQLite
449+
result = func.apply(null, args)
450+
451+
# Return the result of the user defined function to SQLite
452+
if not result
453+
sqlite3_result_null cx
454+
else
455+
switch typeof(result)
456+
when 'number' then sqlite3_result_double(cx, result)
457+
when 'string' then sqlite3_result_text(cx, result, -1, -1)
458+
459+
# Generate a pointer to the wrapped, user defined function, and register with SQLite.
460+
func_ptr = Runtime.addFunction(wrapped_func)
461+
@handleError sqlite3_create_function_v2 @db, name, numParams, SQLite.UTF8, 0, func_ptr, 0, 0, 0
462+
return @
416463

417464
### Analyze a result code, return null if no error occured, and throw
418465
an error with a descriptive message otherwise

coffee/exports.coffee

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,18 @@ sqlite3_clear_bindings = Module['cwrap'] 'sqlite3_clear_bindings', 'number', ['n
4141
# int sqlite3_finalize(sqlite3_stmt *pStmt);
4242
sqlite3_finalize = Module['cwrap'] 'sqlite3_finalize', 'number', ['number']
4343

44+
## Create custom functions
45+
sqlite3_create_function_v2 = Module['cwrap'] 'sqlite3_create_function_v2', 'number', ['number', 'string', 'number', 'number', 'number', 'number', 'number', 'number', 'number']
46+
sqlite3_value_type = Module['cwrap'] 'sqlite3_value_type', 'number', ['number']
47+
sqlite3_value_bytes = Module['cwrap'] 'sqlite3_value_bytes', 'number', ['number']
48+
sqlite3_value_text = Module['cwrap'] 'sqlite3_value_text', 'string', ['number']
49+
sqlite3_value_int = Module['cwrap'] 'sqlite3_value_int', 'number', ['number']
50+
sqlite3_value_blob = Module['cwrap'] 'sqlite3_value_blob', 'number', ['number']
51+
sqlite3_value_double = Module['cwrap'] 'sqlite3_value_double', 'number', ['number']
52+
sqlite3_result_double = Module['cwrap'] 'sqlite3_result_double', '', ['number', 'number']
53+
sqlite3_result_null = Module['cwrap'] 'sqlite3_result_null', '', ['number']
54+
sqlite3_result_text = Module['cwrap'] 'sqlite3_result_text', '', ['number', 'string', 'number', 'number']
55+
4456
# Export the API
4557
this['SQL'] = {'Database':Database}
4658
Module[i] = this['SQL'][i] for i of this['SQL']

exported_functions

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,15 @@
2222
"_sqlite3_reset",
2323
"_sqlite3_clear_bindings",
2424
"_sqlite3_finalize",
25-
"_sqlite3_close_v2"
25+
"_sqlite3_close_v2",
26+
"_sqlite3_create_function_v2",
27+
"_sqlite3_value_bytes",
28+
"_sqlite3_value_type",
29+
"_sqlite3_value_text",
30+
"_sqlite3_value_int",
31+
"_sqlite3_value_blob",
32+
"_sqlite3_value_double",
33+
"_sqlite3_result_double",
34+
"_sqlite3_result_null",
35+
"_sqlite3_result_text"
2636
]

0 commit comments

Comments
 (0)