aboutsummaryrefslogtreecommitdiff
path: root/ext/wasm/api/sqlite3-api-glue.js
diff options
context:
space:
mode:
Diffstat (limited to 'ext/wasm/api/sqlite3-api-glue.js')
-rw-r--r--ext/wasm/api/sqlite3-api-glue.js302
1 files changed, 276 insertions, 26 deletions
diff --git a/ext/wasm/api/sqlite3-api-glue.js b/ext/wasm/api/sqlite3-api-glue.js
index e302c0191..da17fcb98 100644
--- a/ext/wasm/api/sqlite3-api-glue.js
+++ b/ext/wasm/api/sqlite3-api-glue.js
@@ -25,6 +25,251 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
delete self.WhWasmUtilInstaller;
/**
+ Signatures for the WASM-exported C-side functions. Each entry
+ is an array with 2+ elements:
+
+ [ "c-side name",
+ "result type" (wasm.xWrap() syntax),
+ [arg types in xWrap() syntax]
+ // ^^^ this needn't strictly be an array: it can be subsequent
+ // elements instead: [x,y,z] is equivalent to x,y,z
+ ]
+
+ Note that support for the API-specific data types in the
+ result/argument type strings gets plugged in at a later phase in
+ the API initialization process.
+ */
+ wasm.bindingSignatures = [
+ // Please keep these sorted by function name!
+ ["sqlite3_aggregate_context","void*", "sqlite3_context*", "int"],
+ ["sqlite3_bind_blob","int", "sqlite3_stmt*", "int", "*", "int", "*"
+ /* TODO: we should arguably write a custom wrapper which knows
+ how to handle Blob, TypedArrays, and JS strings. */
+ ],
+ ["sqlite3_bind_double","int", "sqlite3_stmt*", "int", "f64"],
+ ["sqlite3_bind_int","int", "sqlite3_stmt*", "int", "int"],
+ ["sqlite3_bind_null",undefined, "sqlite3_stmt*", "int"],
+ ["sqlite3_bind_parameter_count", "int", "sqlite3_stmt*"],
+ ["sqlite3_bind_parameter_index","int", "sqlite3_stmt*", "string"],
+ ["sqlite3_bind_pointer", "int",
+ "sqlite3_stmt*", "int", "*", "string:static", "*"],
+ ["sqlite3_bind_text","int", "sqlite3_stmt*", "int", "string", "int", "int"
+ /* We should arguably create a hand-written binding of
+ bind_text() which does more flexible text conversion, along
+ the lines of sqlite3_prepare_v3(). The slightly problematic
+ part is the final argument (text destructor). */
+ ],
+ //["sqlite3_busy_handler","int", "sqlite3*", "*", "*"],
+ // ^^^^ TODO: custom binding which auto-converts JS function arg
+ // to a WASM function, noting that calling it multiple times
+ // would introduce a leak.
+ ["sqlite3_busy_timeout","int", "sqlite3*", "int"],
+ ["sqlite3_close_v2", "int", "sqlite3*"],
+ ["sqlite3_changes", "int", "sqlite3*"],
+ ["sqlite3_clear_bindings","int", "sqlite3_stmt*"],
+ ["sqlite3_collation_needed", "int", "sqlite3*", "*", "*"/*=>v(ppis)*/],
+ ["sqlite3_column_blob","*", "sqlite3_stmt*", "int"],
+ ["sqlite3_column_bytes","int", "sqlite3_stmt*", "int"],
+ ["sqlite3_column_count", "int", "sqlite3_stmt*"],
+ ["sqlite3_column_double","f64", "sqlite3_stmt*", "int"],
+ ["sqlite3_column_int","int", "sqlite3_stmt*", "int"],
+ ["sqlite3_column_name","string", "sqlite3_stmt*", "int"],
+ ["sqlite3_column_text","string", "sqlite3_stmt*", "int"],
+ ["sqlite3_column_type","int", "sqlite3_stmt*", "int"],
+ ["sqlite3_column_value","sqlite3_value*", "sqlite3_stmt*", "int"],
+ ["sqlite3_compileoption_get", "string", "int"],
+ ["sqlite3_compileoption_used", "int", "string"],
+ ["sqlite3_complete", "int", "string:flexible"],
+ /* sqlite3_create_function(), sqlite3_create_function_v2(), and
+ sqlite3_create_window_function() use hand-written bindings to
+ simplify handling of their function-type arguments. */
+ /* sqlite3_create_collation() and sqlite3_create_collation_v2()
+ use hand-written bindings to simplify passing of the callback
+ function.
+ ["sqlite3_create_collation", "int",
+ "sqlite3*", "string", "int",//SQLITE_UTF8 is the only legal value
+ "*", "*"],
+ ["sqlite3_create_collation_v2", "int",
+ "sqlite3*", "string", "int",//SQLITE_UTF8 is the only legal value
+ "*", "*", "*"],
+ */
+ ["sqlite3_data_count", "int", "sqlite3_stmt*"],
+ ["sqlite3_db_filename", "string", "sqlite3*", "string"],
+ ["sqlite3_db_handle", "sqlite3*", "sqlite3_stmt*"],
+ ["sqlite3_db_name", "string", "sqlite3*", "int"],
+ ["sqlite3_db_status", "int", "sqlite3*", "int", "*", "*", "int"],
+ ["sqlite3_deserialize", "int", "sqlite3*", "string", "*", "i64", "i64", "int"]
+ /* Careful! Short version: de/serialize() are problematic because they
+ might use a different allocator than the user for managing the
+ deserialized block. de/serialize() are ONLY safe to use with
+ sqlite3_malloc(), sqlite3_free(), and its 64-bit variants. */,
+ ["sqlite3_errcode", "int", "sqlite3*"],
+ ["sqlite3_errmsg", "string", "sqlite3*"],
+ ["sqlite3_error_offset", "int", "sqlite3*"],
+ ["sqlite3_errstr", "string", "int"],
+ /*["sqlite3_exec", "int", "sqlite3*", "string", "*", "*", "**"
+ Handled seperately to perform translation of the callback
+ into a WASM-usable one. ],*/
+ ["sqlite3_expanded_sql", "string", "sqlite3_stmt*"],
+ ["sqlite3_extended_errcode", "int", "sqlite3*"],
+ ["sqlite3_extended_result_codes", "int", "sqlite3*", "int"],
+ ["sqlite3_file_control", "int", "sqlite3*", "string", "int", "*"],
+ ["sqlite3_finalize", "int", "sqlite3_stmt*"],
+ ["sqlite3_free", undefined,"*"],
+ ["sqlite3_get_auxdata", "*", "sqlite3_context*", "int"],
+ ["sqlite3_initialize", undefined],
+ /*["sqlite3_interrupt", undefined, "sqlite3*"
+ ^^^ we cannot actually currently support this because JS is
+ single-threaded and we don't have a portable way to access a DB
+ from 2 SharedWorkers concurrently. ],*/
+ ["sqlite3_keyword_count", "int"],
+ ["sqlite3_keyword_name", "int", ["int", "**", "*"]],
+ ["sqlite3_keyword_check", "int", ["string", "int"]],
+ ["sqlite3_libversion", "string"],
+ ["sqlite3_libversion_number", "int"],
+ ["sqlite3_limit", "int", ["sqlite3*", "int", "int"]],
+ ["sqlite3_malloc", "*","int"],
+ ["sqlite3_open", "int", "string", "*"],
+ ["sqlite3_open_v2", "int", "string", "*", "int", "string"],
+ /* sqlite3_prepare_v2() and sqlite3_prepare_v3() are handled
+ separately due to us requiring two different sets of semantics
+ for those, depending on how their SQL argument is provided. */
+ /* sqlite3_randomness() uses a hand-written wrapper to extend
+ the range of supported argument types. */
+ [
+ "sqlite3_progress_handler", undefined, [
+ "sqlite3*", "int", new wasm.xWrap.FuncPtrAdapter({
+ name: 'xProgressHandler',
+ signature: 'i(p)',
+ bindMode: 'singleton'
+ }), "*"
+ ]
+ ],
+ ["sqlite3_realloc", "*","*","int"],
+ ["sqlite3_reset", "int", "sqlite3_stmt*"],
+ ["sqlite3_result_blob", undefined, "sqlite3_context*", "*", "int", "*"],
+ ["sqlite3_result_double", undefined, "sqlite3_context*", "f64"],
+ ["sqlite3_result_error", undefined, "sqlite3_context*", "string", "int"],
+ ["sqlite3_result_error_code", undefined, "sqlite3_context*", "int"],
+ ["sqlite3_result_error_nomem", undefined, "sqlite3_context*"],
+ ["sqlite3_result_error_toobig", undefined, "sqlite3_context*"],
+ ["sqlite3_result_int", undefined, "sqlite3_context*", "int"],
+ ["sqlite3_result_null", undefined, "sqlite3_context*"],
+ ["sqlite3_result_pointer", undefined,
+ "sqlite3_context*", "*", "string:static", "*"],
+ ["sqlite3_result_subtype", undefined, "sqlite3_value*", "int"],
+ ["sqlite3_result_text", undefined, "sqlite3_context*", "string", "int", "*"],
+ ["sqlite3_result_zeroblob", undefined, "sqlite3_context*", "int"],
+ ["sqlite3_serialize","*", "sqlite3*", "string", "*", "int"],
+ ["sqlite3_set_auxdata", undefined, "sqlite3_context*", "int", "*", "*"/* => v(*) */],
+ ["sqlite3_shutdown", undefined],
+ ["sqlite3_sourceid", "string"],
+ ["sqlite3_sql", "string", "sqlite3_stmt*"],
+ ["sqlite3_status", "int", "int", "*", "*", "int"],
+ ["sqlite3_step", "int", "sqlite3_stmt*"],
+ ["sqlite3_stmt_isexplain", "int", ["sqlite3_stmt*"]],
+ ["sqlite3_stmt_readonly", "int", ["sqlite3_stmt*"]],
+ ["sqlite3_stmt_status", "int", "sqlite3_stmt*", "int", "int"],
+ ["sqlite3_strglob", "int", "string","string"],
+ ["sqlite3_stricmp", "int", "string", "string"],
+ ["sqlite3_strlike", "int", "string", "string","int"],
+ ["sqlite3_strnicmp", "int", "string", "string", "int"],
+ ["sqlite3_table_column_metadata", "int",
+ "sqlite3*", "string", "string", "string",
+ "**", "**", "*", "*", "*"],
+ ["sqlite3_total_changes", "int", "sqlite3*"],
+ ["sqlite3_trace_v2", "int", "sqlite3*", "int", "*", "*"],
+ ["sqlite3_txn_state", "int", ["sqlite3*","string"]],
+ /* Note that sqlite3_uri_...() have very specific requirements for
+ their first C-string arguments, so we cannot perform any value
+ conversion on those. */
+ ["sqlite3_uri_boolean", "int", "sqlite3_filename", "string", "int"],
+ ["sqlite3_uri_key", "string", "sqlite3_filename", "int"],
+ ["sqlite3_uri_parameter", "string", "sqlite3_filename", "string"],
+ ["sqlite3_user_data","void*", "sqlite3_context*"],
+ ["sqlite3_value_blob", "*", "sqlite3_value*"],
+ ["sqlite3_value_bytes","int", "sqlite3_value*"],
+ ["sqlite3_value_double","f64", "sqlite3_value*"],
+ ["sqlite3_value_dup", "sqlite3_value*", "sqlite3_value*"],
+ ["sqlite3_value_free", undefined, "sqlite3_value*"],
+ ["sqlite3_value_frombind", "int", "sqlite3_value*"],
+ ["sqlite3_value_int","int", "sqlite3_value*"],
+ ["sqlite3_value_nochange", "int", "sqlite3_value*"],
+ ["sqlite3_value_numeric_type", "int", "sqlite3_value*"],
+ ["sqlite3_value_pointer", "*", "sqlite3_value*", "string:static"],
+ ["sqlite3_value_subtype", "int", "sqlite3_value*"],
+ ["sqlite3_value_text", "string", "sqlite3_value*"],
+ ["sqlite3_value_type", "int", "sqlite3_value*"],
+ ["sqlite3_vfs_find", "*", "string"],
+ ["sqlite3_vfs_register", "int", "sqlite3_vfs*", "int"],
+ ["sqlite3_vfs_unregister", "int", "sqlite3_vfs*"]
+ ]/*wasm.bindingSignatures*/;
+
+ if(false && wasm.compileOptionUsed('SQLITE_ENABLE_NORMALIZE')){
+ /* ^^^ "the problem" is that this is an option feature and the
+ build-time function-export list does not currently take
+ optional features into account. */
+ wasm.bindingSignatures.push(["sqlite3_normalized_sql", "string", "sqlite3_stmt*"]);
+ }
+
+ /**
+ Functions which require BigInt (int64) support are separated from
+ the others because we need to conditionally bind them or apply
+ dummy impls, depending on the capabilities of the environment.
+
+ Note that not all of these functions directly require int64
+ but are only for use with APIs which require int64. For example,
+ the vtab-related functions.
+ */
+ wasm.bindingSignatures.int64 = [
+ ["sqlite3_bind_int64","int", ["sqlite3_stmt*", "int", "i64"]],
+ ["sqlite3_changes64","i64", ["sqlite3*"]],
+ ["sqlite3_column_int64","i64", ["sqlite3_stmt*", "int"]],
+ ["sqlite3_create_module", "int",
+ ["sqlite3*","string","sqlite3_module*","*"]],
+ ["sqlite3_create_module_v2", "int",
+ ["sqlite3*","string","sqlite3_module*","*","*"]],
+ ["sqlite3_declare_vtab", "int", ["sqlite3*", "string:flexible"]],
+ ["sqlite3_drop_modules", "int", ["sqlite3*", "**"]],
+ ["sqlite3_last_insert_rowid", "i64", ["sqlite3*"]],
+ ["sqlite3_malloc64", "*","i64"],
+ ["sqlite3_msize", "i64", "*"],
+ ["sqlite3_overload_function", "int", ["sqlite3*","string","int"]],
+ ["sqlite3_realloc64", "*","*", "i64"],
+ ["sqlite3_result_int64", undefined, "*", "i64"],
+ ["sqlite3_result_zeroblob64", "int", "*", "i64"],
+ ["sqlite3_set_last_insert_rowid", undefined, ["sqlite3*", "i64"]],
+ ["sqlite3_status64", "int", "int", "*", "*", "int"],
+ ["sqlite3_total_changes64", "i64", ["sqlite3*"]],
+ ["sqlite3_uri_int64", "i64", ["sqlite3_filename", "string", "i64"]],
+ ["sqlite3_value_int64","i64", "sqlite3_value*"],
+ ["sqlite3_vtab_collation","string","sqlite3_index_info*","int"],
+ ["sqlite3_vtab_distinct","int", "sqlite3_index_info*"],
+ ["sqlite3_vtab_in","int", "sqlite3_index_info*", "int", "int"],
+ ["sqlite3_vtab_in_first", "int", "sqlite3_value*", "**"],
+ ["sqlite3_vtab_in_next", "int", "sqlite3_value*", "**"],
+ /*["sqlite3_vtab_config" is variadic and requires a hand-written
+ proxy.] */
+ ["sqlite3_vtab_nochange","int", "sqlite3_context*"],
+ ["sqlite3_vtab_on_conflict","int", "sqlite3*"],
+ ["sqlite3_vtab_rhs_value","int", "sqlite3_index_info*", "int", "**"]
+ ];
+
+ /**
+ Functions which are intended solely for API-internal use by the
+ WASM components, not client code. These get installed into
+ sqlite3.wasm. Some of them get exposed to clients via variants
+ named sqlite3_js_...().
+ */
+ wasm.bindingSignatures.wasm = [
+ ["sqlite3_wasm_db_reset", "int", "sqlite3*"],
+ ["sqlite3_wasm_db_vfs", "sqlite3_vfs*", "sqlite3*","string"],
+ ["sqlite3_wasm_vfs_create_file", "int",
+ "sqlite3_vfs*","string","*", "int"],
+ ["sqlite3_wasm_vfs_unlink", "int", "sqlite3_vfs*","string"]
+ ];
+
+ /**
Install JS<->C struct bindings for the non-opaque struct types we
need... */
sqlite3.StructBinder = self.Jaccwabyt({
@@ -166,7 +411,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
Sets the given db's error state. Accepts:
- (sqlite3*, int code, string msg)
- - (sqlite3*, Error [,string msg])
+ - (sqlite3*, Error e [,string msg = ''+e])
If passed a WasmAllocError, the message is ingored and the
result code is SQLITE_NOMEM. If passed any other Error type,
@@ -183,7 +428,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
resultCode = capi.SQLITE_NOMEM;
message = 0 /*avoid allocating message string*/;
}else if(resultCode instanceof Error){
- message = message || resultCode.message;
+ message = message || ''+resultCode;
resultCode = (resultCode.resultCode || capi.SQLITE_ERROR);
}
return __db_err(pDb, resultCode, message);
@@ -211,15 +456,29 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const __ccv2 = wasm.xWrap(
'sqlite3_create_collation_v2', 'int',
- 'sqlite3*','string','int','*','*','*'
- /* int(*xCompare)(void*,int,const void*,int,const void*) */
- /* void(*xDestroy(void*) */);
+ 'sqlite3*','string','int','*',
+ new wasm.xWrap.FuncPtrAdapter({
+ /* int(*xCompare)(void*,int,const void*,int,const void*) */
+ name: 'xCompare',
+ signature: 'i(pipip)',
+ bindMode: 'static'
+ }),
+ new wasm.xWrap.FuncPtrAdapter({
+ /* void(*xDestroy(void*) */
+ name: 'xDestroy',
+ signature: 'v(p)',
+ bindMode: 'static'
+ })
+ );
/**
Works exactly like C's sqlite3_create_collation_v2() except that:
1) It permits its two function arguments to be JS functions,
- for which it will install WASM-bound proxies.
+ for which it will install WASM-bound proxies. The bindings
+ are "permanent," in that they will stay in the WASM environment
+ until it shuts down unless the client somehow finds and removes
+ them.
2) It returns capi.SQLITE_FORMAT if the 3rd argument is not
capi.SQLITE_UTF8. No other encodings are supported.
@@ -235,19 +494,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
pDb, capi.SQLITE_FORMAT, "SQLITE_UTF8 is the only supported encoding."
);
}
- let rc, pfCompare, pfDestroy;
+ let rc;
try{
- if(xCompare instanceof Function){
- pfCompare = wasm.installFunction(xCompare, 'i(pipip)');
- }
- if(xDestroy instanceof Function){
- pfDestroy = wasm.installFunction(xDestroy, 'v(p)');
- }
- rc = __ccv2(pDb, zName, eTextRep, pArg,
- pfCompare || xCompare, pfDestroy || xDestroy);
+ rc = __ccv2(pDb, zName, eTextRep, pArg, xCompare, xDestroy);
}catch(e){
- if(pfCompare) wasm.uninstallFunction(pfCompare);
- if(pfDestroy) wasm.uninstallFunction(pfDestroy);
rc = util.sqlite3_wasm_db_error(pDb, e);
}
return rc;
@@ -259,17 +509,20 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
: __dbArgcMismatch(pDb, 'sqlite3_create_collation', 5);
}
-
}/*sqlite3_create_collation() and friends*/
if(1){/* Special-case handling of sqlite3_exec() */
const __exec = wasm.xWrap("sqlite3_exec", "int",
- ["sqlite3*", "string:flexible", "*", "*", "**"]);
+ ["sqlite3*", "string:flexible",
+ new wasm.xWrap.FuncPtrAdapter({
+ signature: 'i(pipp)',
+ bindMode: 'transient'
+ }), "*", "**"]);
/* Documented in the api object's initializer. */
capi.sqlite3_exec = function f(pDb, sql, callback, pVoid, pErrMsg){
if(f.length!==arguments.length){
return __dbArgcMismatch(pDb,"sqlite3_exec",f.length);
- }else if('function' !== typeof callback){
+ }else if(!(callback instanceof Function)){
return __exec(pDb, sql, callback, pVoid, pErrMsg);
}
/* Wrap the callback in a WASM-bound function and convert the callback's
@@ -294,15 +547,12 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}
return rc;
};
- let pFunc, rc;
+ let rc;
try{
- pFunc = wasm.installFunction("ipipp", cbwrap);
- rc = __exec(pDb, sql, pFunc, pVoid, pErrMsg);
+ rc = __exec(pDb, sql, cbwrap, pVoid, pErrMsg);
}catch(e){
rc = util.sqlite3_wasm_db_error(pDb, capi.SQLITE_ERROR,
- "Error running exec(): "+e.message);
- }finally{
- if(pFunc) wasm.uninstallFunction(pFunc);
+ "Error running exec(): "+e);
}
return rc;
};