Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
ririyeye committed Aug 12, 2024
2 parents 238e4a0 + cbd6b20 commit 4a9eea6
Show file tree
Hide file tree
Showing 7 changed files with 457 additions and 336 deletions.
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@ add_library(ffi-test SHARED
tests/fixtures/ffi-test-lib.c
)

add_library(sqlite-test SHARED
tests/fixtures/sqlite-test-ext.c
)

target_link_libraries(sqlite-test sqlite3)


if(NOT USE_EXTERNAL_FFI AND NOT MINGW AND NOT APPLE)
set(LIBFFI_SRC "${CMAKE_CURRENT_SOURCE_DIR}/deps/libffi")
set(TMP_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/ffi_root")
Expand Down
687 changes: 352 additions & 335 deletions src/bundles/c/stdlib/sqlite.c

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions src/js/stdlib/sqlite.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ class Database {
// Return the default version of the transaction function.
return properties.default.value;
}

loadExtension(file, entrypoint=undefined) {
return sqlite3.load_extension(this[kSqlite3Handle],file,entrypoint);
}
}

// Return the database's cached transaction controller, or create a new one.
Expand Down
36 changes: 36 additions & 0 deletions src/mod_sqlite3.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,13 @@ static JSValue tjs_sqlite3_open(JSContext *ctx, JSValue this_val, int argc, JSVa
return tjs_throw_sqlite3_errno(ctx, r);
}

// Enable sqlite extensions (but only via C calls)
r = sqlite3_db_config(handle, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, NULL);
if (r != SQLITE_OK) {
sqlite3_close(handle);
return tjs_throw_sqlite3_errno(ctx, r);
}

JSValue obj = tjs_new_sqlite3(ctx, handle);
if (JS_IsException(obj)) {
sqlite3_close(handle);
Expand All @@ -177,6 +184,34 @@ static JSValue tjs_sqlite3_close(JSContext *ctx, JSValue this_val, int argc, JSV
return JS_UNDEFINED;
}

static JSValue tjs_sqlite3_load_extension(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
TJSSqlite3Handle *h = tjs_sqlite3_get(ctx, argv[0]);

if (!h)
return JS_EXCEPTION;

const char *zFile = JS_ToCString(ctx, argv[1]);
const char *zProc = JS_IsUndefined(argv[2]) ? NULL : JS_ToCString(ctx, argv[2]);

if (!zFile) {
return JS_EXCEPTION;
}

// zProc can be 0, it means "sqlite, do your best to quess it"

int r = sqlite3_load_extension(h->handle, zFile, zProc, NULL);

JS_FreeCString(ctx, zFile);
if (zProc)
JS_FreeCString(ctx, zProc);

if (r != SQLITE_OK) {
return tjs_throw_sqlite3_errno(ctx, r);
}

return JS_UNDEFINED;
}

static JSValue tjs_sqlite3_exec(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
TJSSqlite3Handle *h = tjs_sqlite3_get(ctx, argv[0]);

Expand Down Expand Up @@ -518,6 +553,7 @@ static JSValue tjs_sqlite3_stmt_run(JSContext *ctx, JSValue this_val, int argc,

static const JSCFunctionListEntry tjs_sqlite3_funcs[] = {
TJS_CFUNC_DEF("open", 2, tjs_sqlite3_open),
TJS_CFUNC_DEF("load_extension", 3, tjs_sqlite3_load_extension),
TJS_CFUNC_DEF("close", 1, tjs_sqlite3_close),
TJS_CFUNC_DEF("exec", 2, tjs_sqlite3_exec),
TJS_CFUNC_DEF("prepare", 2, tjs_sqlite3_prepare),
Expand Down
29 changes: 29 additions & 0 deletions tests/fixtures/sqlite-test-ext.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include <sqlite3ext.h>

SQLITE_EXTENSION_INIT1

void fn(sqlite3_context* context ,int,sqlite3_value**){
sqlite3_result_int64(context, 43);
}

#ifdef _WIN32
__declspec(dllexport)
#endif

int sqlite_test_ext_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
/* Insert here calls to
** sqlite3_create_function_v2(),
** sqlite3_create_collation_v2(),
** sqlite3_create_module_v2(), and/or
** sqlite3_vfs_register()
** to register the new features that your extension adds.
*/
sqlite3_create_function_v2(db,"testfn",0, SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, 0, fn, 0, 0, 0);
return rc;
}
22 changes: 21 additions & 1 deletion tests/test-sqlite.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,26 @@ function testTransactionsNested() {
assert.eq(data1.length, 2);
}

function testExtensions(){
let sopath = './build/libsqlite-test.so';
switch(tjs.system.platform){
case 'linux':
sopath = './build/libsqlite-test.so';
break;
case 'darwin':
sopath = './build/libsqlite-test.dylib';
break;
case 'windows':
sopath = './build/libsqlite-test.dll';
break;
}

const db = new Database();
db.loadExtension(sopath, 'sqlite_test_ext_init')
assert.eq(db.prepare("SELECT testfn();").all()[0]["testfn()"], 43)
}

testTransactions();
testTransactionsError();
testTransactionsNested()
testTransactionsNested();
testExtensions();
8 changes: 8 additions & 0 deletions types/src/sqlite.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,5 +122,13 @@ declare module 'tjs:sqlite'{
* Closes the database. No further operations can be performed afterwards.
*/
close(): void;

/**
* Load an extension from file
* @param file location of the shared library
* @param entrypoint entrypoint, if left empty a guess is made by sqlite
*/
loadExtension(file:string, entrypoint?:string): undefined;

}
}

0 comments on commit 4a9eea6

Please sign in to comment.