1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-10-24 09:53:10 +03:00

Diverse internal cleanups in the JS/WASM pieces. A potential fix for a hypothetical db-close-time resource leak of a subset of automated JS-to-WASM function conversions in Safari. That browser exposes WASM-exported functions via nullary wrappers, which causes a handful of them to misbehave (not clean up) at sqlite3_close_v2()-time.

FossilOrigin-Name: fabbc8b6d184d52a513e80fabd900f578424fc8a8055e3d64fac54b9e28ea18a
This commit is contained in:
stephan
2025-09-15 14:11:55 +00:00
parent 36595d0630
commit c35f07ec2f
4 changed files with 412 additions and 401 deletions

View File

@@ -79,252 +79,336 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
// elements instead: [x,y,z] is equivalent to x,y,z // elements instead: [x,y,z] is equivalent to x,y,z
] ]
Note that support for the API-specific data types in the Support for the API-specific data types in the result/argument
result/argument type strings gets plugged in at a later phase in type strings gets plugged in at a later phase in the API
the API initialization process. initialization process.
*/ */
wasm.bindingSignatures = [ const bindingSignatures = {
// Please keep these sorted by function name! core: [
["sqlite3_aggregate_context","void*", "sqlite3_context*", "int"], // Please keep these sorted by function name!
/* sqlite3_auto_extension() has a hand-written binding. */ ["sqlite3_aggregate_context","void*", "sqlite3_context*", "int"],
/* sqlite3_bind_blob() and sqlite3_bind_text() have hand-written /* sqlite3_auto_extension() has a hand-written binding. */
bindings to permit more flexible inputs. */ /* sqlite3_bind_blob() and sqlite3_bind_text() have hand-written
["sqlite3_bind_double","int", "sqlite3_stmt*", "int", "f64"], bindings to permit more flexible inputs. */
["sqlite3_bind_int","int", "sqlite3_stmt*", "int", "int"], ["sqlite3_bind_double","int", "sqlite3_stmt*", "int", "f64"],
["sqlite3_bind_null",undefined, "sqlite3_stmt*", "int"], ["sqlite3_bind_int","int", "sqlite3_stmt*", "int", "int"],
["sqlite3_bind_parameter_count", "int", "sqlite3_stmt*"], ["sqlite3_bind_null",undefined, "sqlite3_stmt*", "int"],
["sqlite3_bind_parameter_index","int", "sqlite3_stmt*", "string"], ["sqlite3_bind_parameter_count", "int", "sqlite3_stmt*"],
["sqlite3_bind_parameter_name", "string", "sqlite3_stmt*", "int"], ["sqlite3_bind_parameter_index","int", "sqlite3_stmt*", "string"],
["sqlite3_bind_pointer", "int", ["sqlite3_bind_parameter_name", "string", "sqlite3_stmt*", "int"],
"sqlite3_stmt*", "int", "*", "string:static", "*"], ["sqlite3_bind_pointer", "int",
["sqlite3_busy_handler","int", [ "sqlite3_stmt*", "int", "*", "string:static", "*"],
"sqlite3*", ["sqlite3_busy_handler","int", [
new wasm.xWrap.FuncPtrAdapter({ "sqlite3*",
signature: 'i(pi)', new wasm.xWrap.FuncPtrAdapter({
contextKey: (argv,argIndex)=>argv[0/* sqlite3* */] signature: 'i(pi)',
}), contextKey: (argv,argIndex)=>argv[0/* sqlite3* */]
"*" }),
]], "*"
["sqlite3_busy_timeout","int", "sqlite3*", "int"], ]],
/* sqlite3_cancel_auto_extension() has a hand-written binding. */ ["sqlite3_busy_timeout","int", "sqlite3*", "int"],
/* sqlite3_close_v2() is implemented by hand to perform some /* sqlite3_cancel_auto_extension() has a hand-written binding. */
extra work. */ /* sqlite3_close_v2() is implemented by hand to perform some
["sqlite3_changes", "int", "sqlite3*"], extra work. */
["sqlite3_clear_bindings","int", "sqlite3_stmt*"], ["sqlite3_changes", "int", "sqlite3*"],
["sqlite3_collation_needed", "int", "sqlite3*", "*", "*"/*=>v(ppis)*/], ["sqlite3_clear_bindings","int", "sqlite3_stmt*"],
["sqlite3_column_blob","*", "sqlite3_stmt*", "int"], ["sqlite3_collation_needed", "int", "sqlite3*", "*", "*"/*=>v(ppis)*/],
["sqlite3_column_bytes","int", "sqlite3_stmt*", "int"], ["sqlite3_column_blob","*", "sqlite3_stmt*", "int"],
["sqlite3_column_count", "int", "sqlite3_stmt*"], ["sqlite3_column_bytes","int", "sqlite3_stmt*", "int"],
["sqlite3_column_decltype", "string", "sqlite3_stmt*", "int"], ["sqlite3_column_count", "int", "sqlite3_stmt*"],
["sqlite3_column_double","f64", "sqlite3_stmt*", "int"], ["sqlite3_column_decltype", "string", "sqlite3_stmt*", "int"],
["sqlite3_column_int","int", "sqlite3_stmt*", "int"], ["sqlite3_column_double","f64", "sqlite3_stmt*", "int"],
["sqlite3_column_name","string", "sqlite3_stmt*", "int"], ["sqlite3_column_int","int", "sqlite3_stmt*", "int"],
["sqlite3_column_text","string", "sqlite3_stmt*", "int"], ["sqlite3_column_name","string", "sqlite3_stmt*", "int"],
["sqlite3_column_type","int", "sqlite3_stmt*", "int"], ["sqlite3_column_text","string", "sqlite3_stmt*", "int"],
["sqlite3_column_value","sqlite3_value*", "sqlite3_stmt*", "int"], ["sqlite3_column_type","int", "sqlite3_stmt*", "int"],
["sqlite3_commit_hook", "void*", [ ["sqlite3_column_value","sqlite3_value*", "sqlite3_stmt*", "int"],
"sqlite3*", ["sqlite3_commit_hook", "void*", [
new wasm.xWrap.FuncPtrAdapter({ "sqlite3*",
name: 'sqlite3_commit_hook', new wasm.xWrap.FuncPtrAdapter({
signature: 'i(p)', name: 'sqlite3_commit_hook',
contextKey: (argv)=>argv[0/* sqlite3* */] signature: 'i(p)',
}), contextKey: (argv)=>argv[0/* sqlite3* */]
'*' }),
]], '*'
["sqlite3_compileoption_get", "string", "int"], ]],
["sqlite3_compileoption_used", "int", "string"], ["sqlite3_compileoption_get", "string", "int"],
["sqlite3_complete", "int", "string:flexible"], ["sqlite3_compileoption_used", "int", "string"],
["sqlite3_context_db_handle", "sqlite3*", "sqlite3_context*"], ["sqlite3_complete", "int", "string:flexible"],
/* sqlite3_create_collation() and sqlite3_create_collation_v2() ["sqlite3_context_db_handle", "sqlite3*", "sqlite3_context*"],
use hand-written bindings to simplify passing of the callback /* sqlite3_create_collation() and sqlite3_create_collation_v2()
function. */ use hand-written bindings to simplify passing of the callback
/* sqlite3_create_function(), sqlite3_create_function_v2(), and function. */
sqlite3_create_window_function() use hand-written bindings to /* sqlite3_create_function(), sqlite3_create_function_v2(), and
simplify handling of their function-type arguments. */ sqlite3_create_window_function() use hand-written bindings to
["sqlite3_data_count", "int", "sqlite3_stmt*"], simplify handling of their function-type arguments. */
["sqlite3_db_filename", "string", "sqlite3*", "string"], ["sqlite3_data_count", "int", "sqlite3_stmt*"],
["sqlite3_db_handle", "sqlite3*", "sqlite3_stmt*"], ["sqlite3_db_filename", "string", "sqlite3*", "string"],
["sqlite3_db_name", "string", "sqlite3*", "int"], ["sqlite3_db_handle", "sqlite3*", "sqlite3_stmt*"],
["sqlite3_db_readonly", "int", "sqlite3*", "string"], ["sqlite3_db_name", "string", "sqlite3*", "int"],
["sqlite3_db_status", "int", "sqlite3*", "int", "*", "*", "int"], ["sqlite3_db_readonly", "int", "sqlite3*", "string"],
["sqlite3_errcode", "int", "sqlite3*"], ["sqlite3_db_status", "int", "sqlite3*", "int", "*", "*", "int"],
["sqlite3_errmsg", "string", "sqlite3*"], ["sqlite3_errcode", "int", "sqlite3*"],
["sqlite3_error_offset", "int", "sqlite3*"], ["sqlite3_errmsg", "string", "sqlite3*"],
["sqlite3_errstr", "string", "int"], ["sqlite3_error_offset", "int", "sqlite3*"],
["sqlite3_exec", "int", [ ["sqlite3_errstr", "string", "int"],
"sqlite3*", "string:flexible", ["sqlite3_exec", "int", [
new wasm.xWrap.FuncPtrAdapter({ "sqlite3*", "string:flexible",
signature: 'i(pipp)', new wasm.xWrap.FuncPtrAdapter({
bindScope: 'transient', signature: 'i(pipp)',
callProxy: (callback)=>{ bindScope: 'transient',
let aNames; callProxy: (callback)=>{
return (pVoid, nCols, pColVals, pColNames)=>{ let aNames;
try { return (pVoid, nCols, pColVals, pColNames)=>{
const aVals = wasm.cArgvToJs(nCols, pColVals); try {
if(!aNames) aNames = wasm.cArgvToJs(nCols, pColNames); const aVals = wasm.cArgvToJs(nCols, pColVals);
return callback(aVals, aNames) | 0; if(!aNames) aNames = wasm.cArgvToJs(nCols, pColNames);
}catch(e){ return callback(aVals, aNames) | 0;
/* If we set the db error state here, the higher-level }catch(e){
exec() call replaces it with its own, so we have no way /* If we set the db error state here, the higher-level
of reporting the exception message except the console. We exec() call replaces it with its own, so we have no way
must not propagate exceptions through the C API. Though of reporting the exception message except the console. We
we make an effort to report OOM here, sqlite3_exec() must not propagate exceptions through the C API. Though
translates that into SQLITE_ABORT as well. */ we make an effort to report OOM here, sqlite3_exec()
return e.resultCode || capi.SQLITE_ERROR; translates that into SQLITE_ABORT as well. */
return e.resultCode || capi.SQLITE_ERROR;
}
} }
} }
} }),
}), "*", "**"
"*", "**" ]],
]], ["sqlite3_expanded_sql", "string", "sqlite3_stmt*"],
["sqlite3_expanded_sql", "string", "sqlite3_stmt*"], ["sqlite3_extended_errcode", "int", "sqlite3*"],
["sqlite3_extended_errcode", "int", "sqlite3*"], ["sqlite3_extended_result_codes", "int", "sqlite3*", "int"],
["sqlite3_extended_result_codes", "int", "sqlite3*", "int"], ["sqlite3_file_control", "int", "sqlite3*", "string", "int", "*"],
["sqlite3_file_control", "int", "sqlite3*", "string", "int", "*"], ["sqlite3_finalize", "int", "sqlite3_stmt*"],
["sqlite3_finalize", "int", "sqlite3_stmt*"], ["sqlite3_free", undefined,"*"],
["sqlite3_free", undefined,"*"], ["sqlite3_get_autocommit", "int", "sqlite3*"],
["sqlite3_get_autocommit", "int", "sqlite3*"], ["sqlite3_get_auxdata", "*", "sqlite3_context*", "int"],
["sqlite3_get_auxdata", "*", "sqlite3_context*", "int"], ["sqlite3_initialize", undefined],
["sqlite3_initialize", undefined], ["sqlite3_interrupt", undefined, "sqlite3*"],
["sqlite3_interrupt", undefined, "sqlite3*"], ["sqlite3_is_interrupted", "int", "sqlite3*"],
["sqlite3_is_interrupted", "int", "sqlite3*"], ["sqlite3_keyword_count", "int"],
["sqlite3_keyword_count", "int"], ["sqlite3_keyword_name", "int", ["int", "**", "*"]],
["sqlite3_keyword_name", "int", ["int", "**", "*"]], ["sqlite3_keyword_check", "int", ["string", "int"]],
["sqlite3_keyword_check", "int", ["string", "int"]], ["sqlite3_libversion", "string"],
["sqlite3_libversion", "string"], ["sqlite3_libversion_number", "int"],
["sqlite3_libversion_number", "int"], ["sqlite3_limit", "int", ["sqlite3*", "int", "int"]],
["sqlite3_limit", "int", ["sqlite3*", "int", "int"]], ["sqlite3_malloc", "*","int"],
["sqlite3_malloc", "*","int"], ["sqlite3_open", "int", "string", "*"],
["sqlite3_open", "int", "string", "*"], ["sqlite3_open_v2", "int", "string", "*", "int", "string"],
["sqlite3_open_v2", "int", "string", "*", "int", "string"], /* sqlite3_prepare_v2() and sqlite3_prepare_v3() are handled
/* sqlite3_prepare_v2() and sqlite3_prepare_v3() are handled separately due to us requiring two different sets of semantics
separately due to us requiring two different sets of semantics for those, depending on how their SQL argument is provided. */
for those, depending on how their SQL argument is provided. */ /* sqlite3_randomness() uses a hand-written wrapper to extend
/* sqlite3_randomness() uses a hand-written wrapper to extend the range of supported argument types. */
the range of supported argument types. */ ["sqlite3_realloc", "*","*","int"],
["sqlite3_realloc", "*","*","int"], ["sqlite3_reset", "int", "sqlite3_stmt*"],
["sqlite3_reset", "int", "sqlite3_stmt*"], /* sqlite3_reset_auto_extension() has a hand-written binding. */
/* sqlite3_reset_auto_extension() has a hand-written binding. */ ["sqlite3_result_blob", undefined, "sqlite3_context*", "*", "int", "*"],
["sqlite3_result_blob", undefined, "sqlite3_context*", "*", "int", "*"], ["sqlite3_result_double", undefined, "sqlite3_context*", "f64"],
["sqlite3_result_double", undefined, "sqlite3_context*", "f64"], ["sqlite3_result_error", undefined, "sqlite3_context*", "string", "int"],
["sqlite3_result_error", undefined, "sqlite3_context*", "string", "int"], ["sqlite3_result_error_code", undefined, "sqlite3_context*", "int"],
["sqlite3_result_error_code", undefined, "sqlite3_context*", "int"], ["sqlite3_result_error_nomem", undefined, "sqlite3_context*"],
["sqlite3_result_error_nomem", undefined, "sqlite3_context*"], ["sqlite3_result_error_toobig", undefined, "sqlite3_context*"],
["sqlite3_result_error_toobig", undefined, "sqlite3_context*"], ["sqlite3_result_int", undefined, "sqlite3_context*", "int"],
["sqlite3_result_int", undefined, "sqlite3_context*", "int"], ["sqlite3_result_null", undefined, "sqlite3_context*"],
["sqlite3_result_null", undefined, "sqlite3_context*"], ["sqlite3_result_pointer", undefined,
["sqlite3_result_pointer", undefined, "sqlite3_context*", "*", "string:static", "*"],
"sqlite3_context*", "*", "string:static", "*"], ["sqlite3_result_subtype", undefined, "sqlite3_value*", "int"],
["sqlite3_result_subtype", undefined, "sqlite3_value*", "int"], ["sqlite3_result_text", undefined, "sqlite3_context*", "string", "int", "*"],
["sqlite3_result_text", undefined, "sqlite3_context*", "string", "int", "*"], ["sqlite3_result_zeroblob", undefined, "sqlite3_context*", "int"],
["sqlite3_result_zeroblob", undefined, "sqlite3_context*", "int"], ["sqlite3_rollback_hook", "void*", [
["sqlite3_rollback_hook", "void*", [ "sqlite3*",
"sqlite3*", new wasm.xWrap.FuncPtrAdapter({
new wasm.xWrap.FuncPtrAdapter({ name: 'sqlite3_rollback_hook',
name: 'sqlite3_rollback_hook',
signature: 'v(p)',
contextKey: (argv)=>argv[0/* sqlite3* */]
}),
'*'
]],
/**
We do not have a way to automatically clean up destructors
which are automatically converted from JS functions via the
final argument to sqlite3_set_auxdata(). Because of that,
automatic function conversion is not supported for this
function. Clients should use wasm.installFunction() to create
such callbacks, then pass that pointer to
sqlite3_set_auxdata(). Relying on automated conversions here
would lead to leaks of JS/WASM proxy functions because
sqlite3_set_auxdata() is frequently called in UDFs.
The sqlite3.oo1.DB class's onclose handlers can be used for this
purpose. For example:
const pAuxDtor = wasm.installFunction('v(p)', function(ptr){
//free ptr
});
myDb.onclose = {
after: ()=>{
wasm.uninstallFunction(pAuxDtor);
}
};
Then pass pAuxDtor as the final argument to appropriate
sqlite3_set_auxdata() calls.
Note that versions prior to 3.49.0 ostensibly had automatic
function conversion here but a typo prevented it from
working. Rather than fix it, it was removed because testing the
fix brought the huge potential for memory leaks to the
forefront.
*/
["sqlite3_set_auxdata", undefined, [
"sqlite3_context*", "int", "*",
true
? "*"
: new wasm.xWrap.FuncPtrAdapter({
/* If we can find a way to automate their cleanup, JS functions can
be auto-converted with this. */
name: 'xDestroyAuxData',
signature: 'v(p)', signature: 'v(p)',
contextKey: (argv, argIndex)=>argv[0/* sqlite3_context* */] contextKey: (argv)=>argv[0/* sqlite3* */]
}) }),
]], '*'
['sqlite3_set_errmsg', 'int', 'sqlite3*', 'int', 'string'], ]],
["sqlite3_shutdown", undefined], /**
["sqlite3_sourceid", "string"], We do not have a way to automatically clean up destructors
["sqlite3_sql", "string", "sqlite3_stmt*"], which are automatically converted from JS functions via the
["sqlite3_status", "int", "int", "*", "*", "int"], final argument to sqlite3_set_auxdata(). Because of that,
["sqlite3_step", "int", "sqlite3_stmt*"], automatic function conversion is not supported for this
["sqlite3_stmt_busy", "int", "sqlite3_stmt*"], function. Clients should use wasm.installFunction() to create
["sqlite3_stmt_readonly", "int", "sqlite3_stmt*"], such callbacks, then pass that pointer to
["sqlite3_stmt_status", "int", "sqlite3_stmt*", "int", "int"], sqlite3_set_auxdata(). Relying on automated conversions here
["sqlite3_strglob", "int", "string","string"], would lead to leaks of JS/WASM proxy functions because
["sqlite3_stricmp", "int", "string", "string"], sqlite3_set_auxdata() is frequently called in UDFs.
["sqlite3_strlike", "int", "string", "string","int"],
["sqlite3_strnicmp", "int", "string", "string", "int"], The sqlite3.oo1.DB class's onclose handlers can be used for this
["sqlite3_table_column_metadata", "int", purpose. For example:
"sqlite3*", "string", "string", "string",
"**", "**", "*", "*", "*"], const pAuxDtor = wasm.installFunction('v(p)', function(ptr){
["sqlite3_total_changes", "int", "sqlite3*"], //free ptr
["sqlite3_trace_v2", "int", [ });
"sqlite3*", "int", myDb.onclose = {
new wasm.xWrap.FuncPtrAdapter({ after: ()=>{
name: 'sqlite3_trace_v2::callback', wasm.uninstallFunction(pAuxDtor);
signature: 'i(ippp)', }
contextKey: (argv,argIndex)=>argv[0/* sqlite3* */] };
}),
"*" Then pass pAuxDtor as the final argument to appropriate
]], sqlite3_set_auxdata() calls.
["sqlite3_txn_state", "int", ["sqlite3*","string"]],
/* Note that sqlite3_uri_...() have very specific requirements for Note that versions prior to 3.49.0 ostensibly had automatic
their first C-string arguments, so we cannot perform any value function conversion here but a typo prevented it from
conversion on those. */ working. Rather than fix it, it was removed because testing the
["sqlite3_uri_boolean", "int", "sqlite3_filename", "string", "int"], fix brought the huge potential for memory leaks to the
["sqlite3_uri_key", "string", "sqlite3_filename", "int"], forefront.
["sqlite3_uri_parameter", "string", "sqlite3_filename", "string"], */
["sqlite3_user_data","void*", "sqlite3_context*"], ["sqlite3_set_auxdata", undefined, [
["sqlite3_value_blob", "*", "sqlite3_value*"], "sqlite3_context*", "int", "*",
["sqlite3_value_bytes","int", "sqlite3_value*"], true
["sqlite3_value_double","f64", "sqlite3_value*"], ? "*"
["sqlite3_value_dup", "sqlite3_value*", "sqlite3_value*"], : new wasm.xWrap.FuncPtrAdapter({
["sqlite3_value_free", undefined, "sqlite3_value*"], /* If we can find a way to automate their cleanup, JS functions can
["sqlite3_value_frombind", "int", "sqlite3_value*"], be auto-converted with this. */
["sqlite3_value_int","int", "sqlite3_value*"], name: 'xDestroyAuxData',
["sqlite3_value_nochange", "int", "sqlite3_value*"], signature: 'v(p)',
["sqlite3_value_numeric_type", "int", "sqlite3_value*"], contextKey: (argv, argIndex)=>argv[0/* sqlite3_context* */]
["sqlite3_value_pointer", "*", "sqlite3_value*", "string:static"], })
["sqlite3_value_subtype", "int", "sqlite3_value*"], ]],
["sqlite3_value_text", "string", "sqlite3_value*"], ['sqlite3_set_errmsg', 'int', 'sqlite3*', 'int', 'string'],
["sqlite3_value_type", "int", "sqlite3_value*"], ["sqlite3_shutdown", undefined],
["sqlite3_vfs_find", "*", "string"], ["sqlite3_sourceid", "string"],
["sqlite3_vfs_register", "int", "sqlite3_vfs*", "int"], ["sqlite3_sql", "string", "sqlite3_stmt*"],
["sqlite3_vfs_unregister", "int", "sqlite3_vfs*"] ["sqlite3_status", "int", "int", "*", "*", "int"],
]/*wasm.bindingSignatures*/; ["sqlite3_step", "int", "sqlite3_stmt*"],
["sqlite3_stmt_busy", "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",
new wasm.xWrap.FuncPtrAdapter({
name: 'sqlite3_trace_v2::callback',
signature: 'i(ippp)',
contextKey: (argv,argIndex)=>argv[0/* sqlite3* */]
}),
"*"
]],
["sqlite3_txn_state", "int", ["sqlite3*","string"]],
/* sqlite3_uri_...() have very specific requirements for their
first C-string arguments, so we cannot perform any
string-type conversion on their first argument. */
["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*"]
/* This list gets extended below */
]/*.core*/,
/**
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. (That said: we never actually build without
BigInt support, and such builds are untested.)
Not all of these functions directly require int64 but are only
for use with APIs which require int64. For example, the
vtab-related functions.
*/
int64: [
["sqlite3_bind_int64","int", ["sqlite3_stmt*", "int", "i64"]],
["sqlite3_changes64","i64", ["sqlite3*"]],
["sqlite3_column_int64","i64", ["sqlite3_stmt*", "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. Because
of this, the canonical builds of sqlite3.wasm/js guarantee that
sqlite3.wasm.alloc() and friends use those allocators. Custom builds
may not guarantee that, however. */,
["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_serialize","*", "sqlite3*", "string", "*", "int"],
["sqlite3_set_last_insert_rowid", undefined, ["sqlite3*", "i64"]],
["sqlite3_status64", "int", "int", "*", "*", "int"],
["sqlite3_total_changes64", "i64", ["sqlite3*"]],
["sqlite3_update_hook", "*", [
"sqlite3*",
new wasm.xWrap.FuncPtrAdapter({
name: 'sqlite3_update_hook',
signature: "v(iippj)",
contextKey: (argv)=>argv[0/* sqlite3* */],
callProxy: (callback)=>{
return (p,op,z0,z1,rowid)=>{
callback(p, op, wasm.cstrToJs(z0), wasm.cstrToJs(z1), rowid);
};
}
}),
"*"
]],
["sqlite3_uri_int64", "i64", ["sqlite3_filename", "string", "i64"]],
["sqlite3_value_int64","i64", "sqlite3_value*"]
/* This list gets extended below */
]/*.int64*/,
/**
Functions which are intended solely for API-internal use by the
WASM components, not client code. These get installed into
sqlite3.util. Some of them get exposed to clients via variants
in sqlite3_js_...().
2024-01-11: these were renamed, with two underscores in the
prefix, to ensure that clients do not accidentally depend on
them. They have always been documented as internal-use-only,
so no clients "should" be depending on the old names.
*/
wasmInternal: [
["sqlite3__wasm_db_reset", "int", "sqlite3*"],
["sqlite3__wasm_db_vfs", "sqlite3_vfs*", "sqlite3*","string"],
[/* DO NOT USE. This is deprecated since 2023-08-11 because it
can trigger assert() in debug builds when used with file
sizes which are not an exact multiple of a valid db page
size. This function is retained only so that
sqlite3_js_vfs_create_file() can continue to work (for a
given value of work), but that function emits a
config.warn() log message directing the reader to
alternatives. */
"sqlite3__wasm_vfs_create_file", "int", "sqlite3_vfs*","string","*", "int"
],
["sqlite3__wasm_posix_create_file", "int", "string","*", "int"],
["sqlite3__wasm_vfs_unlink", "int", "sqlite3_vfs*","string"],
["sqlite3__wasm_qfmt_token","string:dealloc", "string","int"]
]/*.wasmInternal*/
} /*bindingSignatures*/;
if( !!wasm.exports.sqlite3_progress_handler ){ if( !!wasm.exports.sqlite3_progress_handler ){
wasm.bindingSignatures.push( bindingSignatures.core.push(
["sqlite3_progress_handler", undefined, [ ["sqlite3_progress_handler", undefined, [
"sqlite3*", "int", new wasm.xWrap.FuncPtrAdapter({ "sqlite3*", "int", new wasm.xWrap.FuncPtrAdapter({
name: 'xProgressHandler', name: 'xProgressHandler',
@@ -337,14 +421,14 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
} }
if( !!wasm.exports.sqlite3_stmt_explain ){ if( !!wasm.exports.sqlite3_stmt_explain ){
wasm.bindingSignatures.push( bindingSignatures.core.push(
["sqlite3_stmt_explain", "int", "sqlite3_stmt*", "int"], ["sqlite3_stmt_explain", "int", "sqlite3_stmt*", "int"],
["sqlite3_stmt_isexplain", "int", "sqlite3_stmt*"] ["sqlite3_stmt_isexplain", "int", "sqlite3_stmt*"]
); );
} }
if( !!wasm.exports.sqlite3_set_authorizer ){ if( !!wasm.exports.sqlite3_set_authorizer ){
wasm.bindingSignatures.push( bindingSignatures.core.push(
["sqlite3_set_authorizer", "int", [ ["sqlite3_set_authorizer", "int", [
"sqlite3*", "sqlite3*",
new wasm.xWrap.FuncPtrAdapter({ new wasm.xWrap.FuncPtrAdapter({
@@ -369,7 +453,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}/* sqlite3_set_authorizer() */ }/* sqlite3_set_authorizer() */
if( !!wasm.exports.sqlite3_column_origin_name ){ if( !!wasm.exports.sqlite3_column_origin_name ){
wasm.bindingSignatures.push( bindingSignatures.core.push(
["sqlite3_column_database_name","string", "sqlite3_stmt*", "int"], ["sqlite3_column_database_name","string", "sqlite3_stmt*", "int"],
["sqlite3_column_origin_name","string", "sqlite3_stmt*", "int"], ["sqlite3_column_origin_name","string", "sqlite3_stmt*", "int"],
["sqlite3_column_table_name","string", "sqlite3_stmt*", "int"] ["sqlite3_column_table_name","string", "sqlite3_stmt*", "int"]
@@ -380,11 +464,11 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
/* ^^^ "the problem" is that this is an optional feature and the /* ^^^ "the problem" is that this is an optional feature and the
build-time function-export list does not currently take build-time function-export list does not currently take
optional features into account. */ optional features into account. */
wasm.bindingSignatures.push(["sqlite3_normalized_sql", "string", "sqlite3_stmt*"]); bindingSignatures.core.push(["sqlite3_normalized_sql", "string", "sqlite3_stmt*"]);
} }
//#if enable-see //#if enable-see
if(wasm.exports.sqlite3_key_v2 instanceof Function){ if( !!wasm.exports.sqlite3_key_v2 ){
/** /**
This code is capable of using an SEE build but note that an SEE This code is capable of using an SEE build but note that an SEE
WASM build is generally incompatible with SEE's license WASM build is generally incompatible with SEE's license
@@ -393,7 +477,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
exposing an SEE build of sqlite3.wasm effectively provides all exposing an SEE build of sqlite3.wasm effectively provides all
clients with a working copy of the commercial SEE code. clients with a working copy of the commercial SEE code.
*/ */
wasm.bindingSignatures.push( bindingSignatures.core.push(
["sqlite3_key", "int", "sqlite3*", "string", "int"], ["sqlite3_key", "int", "sqlite3*", "string", "int"],
["sqlite3_key_v2","int","sqlite3*","string","*","int"], ["sqlite3_key_v2","int","sqlite3*","string","*","int"],
["sqlite3_rekey", "int", "sqlite3*", "string", "int"], ["sqlite3_rekey", "int", "sqlite3*", "string", "int"],
@@ -403,60 +487,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
} }
//#endif enable-see //#endif enable-see
/**
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.
(That said: we never actually build without BigInt support,
and such builds are untested.)
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_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. Because
of this, the canonical builds of sqlite3.wasm/js guarantee that
sqlite3.wasm.alloc() and friends use those allocators. Custom builds
may not guarantee that, however. */,
["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_serialize","*", "sqlite3*", "string", "*", "int"],
["sqlite3_set_last_insert_rowid", undefined, ["sqlite3*", "i64"]],
["sqlite3_status64", "int", "int", "*", "*", "int"],
["sqlite3_total_changes64", "i64", ["sqlite3*"]],
["sqlite3_update_hook", "*", [
"sqlite3*",
new wasm.xWrap.FuncPtrAdapter({
name: 'sqlite3_update_hook',
signature: "v(iippj)",
contextKey: (argv)=>argv[0/* sqlite3* */],
callProxy: (callback)=>{
return (p,op,z0,z1,rowid)=>{
callback(p, op, wasm.cstrToJs(z0), wasm.cstrToJs(z1), rowid);
};
}
}),
"*"
]],
["sqlite3_uri_int64", "i64", ["sqlite3_filename", "string", "i64"]],
["sqlite3_value_int64","i64", "sqlite3_value*"]
];
if( wasm.bigIntEnabled && !!wasm.exports.sqlite3_declare_vtab ){ if( wasm.bigIntEnabled && !!wasm.exports.sqlite3_declare_vtab ){
wasm.bindingSignatures.int64.push( bindingSignatures.int64.push(
["sqlite3_create_module", "int", ["sqlite3_create_module", "int",
["sqlite3*","string","sqlite3_module*","*"]], ["sqlite3*","string","sqlite3_module*","*"]],
["sqlite3_create_module_v2", "int", ["sqlite3_create_module_v2", "int",
@@ -477,7 +509,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}/* virtual table APIs */ }/* virtual table APIs */
if(wasm.bigIntEnabled && !!wasm.exports.sqlite3_preupdate_hook){ if(wasm.bigIntEnabled && !!wasm.exports.sqlite3_preupdate_hook){
wasm.bindingSignatures.int64.push( bindingSignatures.int64.push(
["sqlite3_preupdate_blobwrite", "int", "sqlite3*"], ["sqlite3_preupdate_blobwrite", "int", "sqlite3*"],
["sqlite3_preupdate_count", "int", "sqlite3*"], ["sqlite3_preupdate_count", "int", "sqlite3*"],
["sqlite3_preupdate_depth", "int", "sqlite3*"], ["sqlite3_preupdate_depth", "int", "sqlite3*"],
@@ -522,7 +554,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
} }
}; };
wasm.bindingSignatures.int64.push(...[ bindingSignatures.int64.push(
['sqlite3changegroup_add', 'int', ['sqlite3_changegroup*', 'int', 'void*']], ['sqlite3changegroup_add', 'int', ['sqlite3_changegroup*', 'int', 'void*']],
['sqlite3changegroup_add_strm', 'int', [ ['sqlite3changegroup_add_strm', 'int', [
'sqlite3_changegroup*', 'sqlite3_changegroup*',
@@ -677,36 +709,13 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}), }),
'*' '*'
]] ]]
]); );
}/*session/changeset APIs*/ }/*session/changeset APIs*/
/**
Functions which are intended solely for API-internal use by the
WASM components, not client code. These get installed into
sqlite3.util. Some of them get exposed to clients via variants
in sqlite3_js_...().
2024-01-11: these were renamed, with two underscores in the
prefix, to ensure that clients do not accidentally depend on
them. They have always been documented as internal-use-only, so
no clients "should" be depending on the old names.
*/
wasm.bindingSignatures.wasmInternal = [
["sqlite3__wasm_db_reset", "int", "sqlite3*"],
["sqlite3__wasm_db_vfs", "sqlite3_vfs*", "sqlite3*","string"],
[/* DO NOT USE. This is deprecated since 2023-08-11 because it can
trigger assert() in debug builds when used with file sizes
which are not sizes to a multiple of a valid db page size. */
"sqlite3__wasm_vfs_create_file", "int", "sqlite3_vfs*","string","*", "int"
],
["sqlite3__wasm_posix_create_file", "int", "string","*", "int"],
["sqlite3__wasm_vfs_unlink", "int", "sqlite3_vfs*","string"],
["sqlite3__wasm_qfmt_token","string:dealloc", "string","int"]
];
/** /**
Install JS<->C struct bindings for the non-opaque struct types we Install JS<->C struct bindings for the non-opaque struct types we
need... */ need...
*/
sqlite3.StructBinder = globalThis.Jaccwabyt({ sqlite3.StructBinder = globalThis.Jaccwabyt({
heap: 0 ? wasm.memory : wasm.heap8u, heap: 0 ? wasm.memory : wasm.heap8u,
alloc: wasm.alloc, alloc: wasm.alloc,
@@ -759,10 +768,10 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
/** /**
Add some descriptive xWrap() aliases for '*' intended to (A) Add some descriptive xWrap() aliases for '*' intended to (A)
initially improve readability/correctness of improve readability/correctness of bindingSignatures and (B)
wasm.bindingSignatures and (B) provide automatic conversion provide automatic conversion from higher-level representations,
from higher-level representations, e.g. capi.sqlite3_vfs to e.g. capi.sqlite3_vfs to `sqlite3_vfs*` via (capi.sqlite3_vfs
`sqlite3_vfs*` via capi.sqlite3_vfs.pointer. instance).pointer.
*/ */
const __xArgPtr = wasm.xWrap.argAdapter('*'); const __xArgPtr = wasm.xWrap.argAdapter('*');
const nilType = function(){ const nilType = function(){
@@ -834,10 +843,10 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
"Disabling sqlite3.wasm.xWrap.doArgcCheck due to environmental quirks." "Disabling sqlite3.wasm.xWrap.doArgcCheck due to environmental quirks."
); );
} }
for(const e of wasm.bindingSignatures){ for(const e of bindingSignatures.core){
capi[e[0]] = wasm.xWrap.apply(null, e); capi[e[0]] = wasm.xWrap.apply(null, e);
} }
for(const e of wasm.bindingSignatures.wasmInternal){ for(const e of bindingSignatures.wasmInternal){
util[e[0]] = wasm.xWrap.apply(null, e); util[e[0]] = wasm.xWrap.apply(null, e);
} }
@@ -850,15 +859,16 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
return ()=>toss(fname+"() is unavailable due to lack", return ()=>toss(fname+"() is unavailable due to lack",
"of BigInt support in this build."); "of BigInt support in this build.");
}; };
for(const e of wasm.bindingSignatures.int64){ for(const e of bindingSignatures.int64){
capi[e[0]] = wasm.bigIntEnabled capi[e[0]] = wasm.bigIntEnabled
? wasm.xWrap.apply(null, e) ? wasm.xWrap.apply(null, e)
: fI64Disabled(e[0]); : fI64Disabled(e[0]);
} }
/* There's no need to expose bindingSignatures to clients, /* We don't need these anymore... */
implicitly making it part of the public interface. */ delete bindingSignatures.core;
delete wasm.bindingSignatures; delete bindingSignatures.int64;
delete bindingSignatures.wasmInternal;
/** /**
Sets the given db's error state. Accepts: Sets the given db's error state. Accepts:
@@ -913,7 +923,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
'sqlite3Status', 'sqlite3Status',
'stmtStatus', 'syncFlags', 'stmtStatus', 'syncFlags',
'trace', 'txnState', 'udfFlags', 'trace', 'txnState', 'udfFlags',
'version' ]; 'version'];
if(wasm.bigIntEnabled){ if(wasm.bigIntEnabled){
defineGroups.push('serialize', 'session', 'vtab'); defineGroups.push('serialize', 'session', 'vtab');
} }
@@ -1098,10 +1108,12 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
continue; continue;
} }
closeArgs.length = x.length/*==argument count*/ closeArgs.length = x.length/*==argument count*/
/* recall that undefined entries translate to 0 when passed to || 1 /* Recall that: (A) undefined entries translate to 0 when
WASM. */; passed to WASM and (B) Safari wraps wasm.exports.* in
nullary functions so x.length is 0 there. */;
try{ capi[name](...closeArgs) } try{ capi[name](...closeArgs) }
catch(e){ catch(e){
/* This "cannot happen" unless something is well and truly sideways. */
sqlite3.config.warn("close-time call of",name+"(",closeArgs,") threw:",e); sqlite3.config.warn("close-time call of",name+"(",closeArgs,") threw:",e);
} }
} }
@@ -1203,10 +1215,11 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
2) It accepts JS functions for its function-pointer arguments, 2) It accepts JS functions for its function-pointer arguments,
for which it will install WASM-bound proxies. The bindings for which it will install WASM-bound proxies. The bindings
are "permanent," in that they will stay in the WASM environment are "permanent," in that they will stay in the WASM
until it shuts down unless the client calls this again with the environment until it shuts down unless the client calls this
same collation name and a value of 0 or null for the again with the same collation name and a value of 0 or null
the function pointer(s). for the the function pointer(s). sqlite3_close_v2() will
also clean up such automatically-installed WASM functions.
For consistency with the C API, it requires the same number of For consistency with the C API, it requires the same number of
arguments. It returns capi.SQLITE_MISUSE if passed any other arguments. It returns capi.SQLITE_MISUSE if passed any other
@@ -1447,11 +1460,12 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
sqlite3_prepare_v3() */ sqlite3_prepare_v3() */
/** /**
Helper for string:flexible conversions which require a Helper for string:flexible conversions which requires a
byte-length counterpart argument. Passed a value and its byte-length counterpart argument. Passed a value and its
ostensible length, this function returns [V,N], where V is ostensible length, this function returns [V,N], where V is
either v or a transformed copy of v and N is either n, -1, or either v or a transformed copy of v and N is either n (if v is
the byte length of v (if it's a byte array or ArrayBuffer). a WASM pointer), -1 (if v is a string or Array), or the byte
length of v (if it's a byte array or ArrayBuffer).
*/ */
const __flexiString = (v,n)=>{ const __flexiString = (v,n)=>{
if('string'===typeof v){ if('string'===typeof v){
@@ -1484,15 +1498,14 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
"int", "**", "int", "**",
"**"/*MUST be 0 or null or undefined!*/]), "**"/*MUST be 0 or null or undefined!*/]),
/** /**
Impl which requires that the 2nd argument be a pointer Impl which requires that the 2nd argument be a pointer to the
to the SQL string, instead of being converted to a SQL string, instead of being converted to a JS string. This
string. This variant is necessary for cases where we variant is necessary for cases where we require a non-NULL
require a non-NULL value for the final argument value for the final argument (prepare/step of multiple
(exec()'ing multiple statements from one input statements from one input string). For simpler cases, where
string). For simpler cases, where only the first only the first statement in the SQL string is required, the
statement in the SQL string is required, the wrapper wrapper named sqlite3_prepare_v2() is sufficient and easier
named sqlite3_prepare_v2() is sufficient and easier to to use because it doesn't require dealing with pointers.
use because it doesn't require dealing with pointers.
*/ */
full: wasm.xWrap('sqlite3_prepare_v3', full: wasm.xWrap('sqlite3_prepare_v3',
"int", ["sqlite3*", "*", "int", "int", "int", ["sqlite3*", "*", "int", "int",

View File

@@ -542,8 +542,8 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
4th-argument value, taking care not to pass a value which 4th-argument value, taking care not to pass a value which
truncates a multi-byte UTF-8 character. When passing truncates a multi-byte UTF-8 character. When passing
WASM-format strings, it is important that the final argument be WASM-format strings, it is important that the final argument be
valid or unexpected content can result can result, or even a valid or unexpected content can result, or WASM may crash if
crash if the application reads past the WASM heap bounds. the application reads past the WASM heap bounds.
*/ */
sqlite3_bind_text: undefined/*installed later*/, sqlite3_bind_text: undefined/*installed later*/,
@@ -614,10 +614,8 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
functions passed in to this routine, and thus wrapped by this functions passed in to this routine, and thus wrapped by this
routine, get automatic conversions of arguments and result routine, get automatic conversions of arguments and result
values. The routines which perform those conversions are values. The routines which perform those conversions are
exposed for client-side use as exposed for client-side use as sqlite3_values_to_js(),
sqlite3_create_function_v2.convertUdfArgs() and sqlite3_result_js(), and sqlite3_result_error_js().
sqlite3_create_function_v2.setUdfResult(). sqlite3_create_function()
and sqlite3_create_window_function() have those same methods.
For xFunc(), xStep(), and xFinal(): For xFunc(), xStep(), and xFinal():
@@ -635,18 +633,14 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
possibly generating a console.error() message. Destructors possibly generating a console.error() message. Destructors
must not throw. must not throw.
Once installed, there is currently no way to uninstall the Automatically-converted JS-to-WASM functions will be cleaned up
automatically-converted WASM-bound JS functions from WASM. They either when (A) this function is called again with the same
can be uninstalled from the database as documented in the C name, arity, and encoding, but null/0 values for the functions,
API, but this wrapper currently has no infrastructure in place or (B) when pDb is passed to sqlite3_close_v2(). If this factor
to also free the WASM-bound JS wrappers, effectively resulting is relevant for a given client, they can create WASM-bound JS
in a memory leak if the client uninstalls the UDF. Improving that functions themselves, hold on to their pointers, and pass the
is a potential TODO, but removing client-installed UDFs is rare pointers in to here. Later on, they can free those pointers
in practice. If this factor is relevant for a given client, (using `wasm.uninstallFunction()` or equivalent).
they can create WASM-bound JS functions themselves, hold on to their
pointers, and pass the pointers in to here. Later on, they can
free those pointers (using `wasm.uninstallFunction()` or
equivalent).
C reference: https://sqlite.org/c3ref/create_function.html C reference: https://sqlite.org/c3ref/create_function.html
@@ -686,10 +680,10 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
2) sqlite3_prepare_v3(pDb, sqlPointer, sqlByteLen, prepFlags, ppStmt, sqlPointerToPointer) 2) sqlite3_prepare_v3(pDb, sqlPointer, sqlByteLen, prepFlags, ppStmt, sqlPointerToPointer)
Note that the SQL length argument (the 3rd argument) must, for The SQL length argument (the 3rd argument) must, for usage (1),
usage (1), always be negative because it must be a byte length always be negative because it must be a byte length and that
and that value is expensive to calculate from JS (where only value is expensive to calculate from JS (where only the
the character length of strings is readily available). It is character length of strings is readily available). It is
retained in this API's interface for code/documentation retained in this API's interface for code/documentation
compatibility reasons but is currently _always_ ignored. With compatibility reasons but is currently _always_ ignored. With
usage (2), the 3rd argument is used as-is but is is still usage (2), the 3rd argument is used as-is but is is still
@@ -715,8 +709,10 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
(e.g. using capi.wasm.alloc() or equivalent). In that case, (e.g. using capi.wasm.alloc() or equivalent). In that case,
the final argument may be 0/null/undefined or must be a pointer the final argument may be 0/null/undefined or must be a pointer
to which the "tail" of the compiled SQL is written, as to which the "tail" of the compiled SQL is written, as
documented for the C-side sqlite3_prepare_v3(). In case (2), documented for the C-side sqlite3_prepare_v3().
the underlying C function is called with the equivalent of:
In case (2), the underlying C function is called with the
equivalent of:
(pDb, sqlAsPointer, sqlByteLen, prepFlags, ppStmt, pzTail) (pDb, sqlAsPointer, sqlByteLen, prepFlags, ppStmt, pzTail)
@@ -1553,27 +1549,29 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
capi.sqlite3_js_vfs_create_file = function(vfs, filename, data, dataLen){ capi.sqlite3_js_vfs_create_file = function(vfs, filename, data, dataLen){
config.warn("sqlite3_js_vfs_create_file() is deprecated and", config.warn("sqlite3_js_vfs_create_file() is deprecated and",
"should be avoided because it can lead to C-level crashes.", "should be avoided because it can lead to C-level crashes.",
"See its documentation for alternative options."); "See its documentation for alternatives.");
let pData; let pData;
if(data){ if(data){
if(wasm.isPtr(data)){ if( wasm.isPtr(data) ){
pData = data; pData = data;
}else if(data instanceof ArrayBuffer){
data = new Uint8Array(data);
}
if(data instanceof Uint8Array){
pData = wasm.allocFromTypedArray(data);
if(arguments.length<4 || !util.isInt32(dataLen) || dataLen<0){
dataLen = data.byteLength;
}
}else{ }else{
SQLite3Error.toss("Invalid 3rd argument type for sqlite3_js_vfs_create_file()."); if( data instanceof ArrayBuffer ){
data = new Uint8Array(data);
}
if( data instanceof Uint8Array ){
pData = wasm.allocFromTypedArray(data);
if(arguments.length<4 || !util.isInt32(dataLen) || dataLen<0){
dataLen = data.byteLength;
}
}else{
SQLite3Error.toss("Invalid 3rd argument type for sqlite3_js_vfs_create_file().");
}
} }
}else{ }else{
pData = 0; pData = 0;
} }
if(!util.isInt32(dataLen) || dataLen<0){ if(!util.isInt32(dataLen) || dataLen<0){
wasm.dealloc(pData); if( pData && pData!==data ) wasm.dealloc(pData);
SQLite3Error.toss("Invalid 4th argument for sqlite3_js_vfs_create_file()."); SQLite3Error.toss("Invalid 4th argument for sqlite3_js_vfs_create_file().");
} }
try{ try{
@@ -1581,7 +1579,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
if(rc) SQLite3Error.toss("Creation of file failed with sqlite3 result code", if(rc) SQLite3Error.toss("Creation of file failed with sqlite3 result code",
capi.sqlite3_js_rc_str(rc)); capi.sqlite3_js_rc_str(rc));
}finally{ }finally{
wasm.dealloc(pData); if( pData && pData!==data ) wasm.dealloc(pData);
} }
}; };

View File

@@ -1,5 +1,5 @@
C Expose\ssqlite3_set_errmsg()\sto\sthe\sJNI\sbindings. C Diverse\sinternal\scleanups\sin\sthe\sJS/WASM\spieces.\sA\spotential\sfix\sfor\sa\shypothetical\sdb-close-time\sresource\sleak\sof\sa\ssubset\sof\sautomated\sJS-to-WASM\sfunction\sconversions\sin\sSafari.\sThat\sbrowser\sexposes\sWASM-exported\sfunctions\svia\snullary\swrappers,\swhich\scauses\sa\shandful\sof\sthem\sto\smisbehave\s(not\sclean\sup)\sat\ssqlite3_close_v2()-time.
D 2025-09-14T12:55:57.217 D 2025-09-15T14:11:55.851
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -596,9 +596,9 @@ F ext/wasm/api/post-js-footer.js 365405929f41ca0e6d389ed8a8da3f3c93e11d3ef43a90a
F ext/wasm/api/post-js-header.js 53740d824e5d9027eb1e6fd59e216abbd2136740ce260ea5f0699ff2acb0a701 F ext/wasm/api/post-js-header.js 53740d824e5d9027eb1e6fd59e216abbd2136740ce260ea5f0699ff2acb0a701
F ext/wasm/api/pre-js.c-pp.js 58f823de197e2c10d76179aa05410a593b7ae03e1ece983bb42ffd818e8857e1 F ext/wasm/api/pre-js.c-pp.js 58f823de197e2c10d76179aa05410a593b7ae03e1ece983bb42ffd818e8857e1
F ext/wasm/api/sqlite3-api-cleanup.js 3ac1786e461ada63033143be8c3b00b26b939540661f3e839515bb92f2e35359 F ext/wasm/api/sqlite3-api-cleanup.js 3ac1786e461ada63033143be8c3b00b26b939540661f3e839515bb92f2e35359
F ext/wasm/api/sqlite3-api-glue.c-pp.js 0c60e7b54259b061b6ed0d96c747b9c77d1c2186c5785a7d638f8afc6d3829d6 F ext/wasm/api/sqlite3-api-glue.c-pp.js 066c09125d12189863ec2b34e702b7b8a7ba25c00e73f77de0b727430ef65687
F ext/wasm/api/sqlite3-api-oo1.c-pp.js 852f2cd6acddbae487fc4f1c3ec952e6c1e2033aa4e6c7091d330d983c87c032 F ext/wasm/api/sqlite3-api-oo1.c-pp.js 852f2cd6acddbae487fc4f1c3ec952e6c1e2033aa4e6c7091d330d983c87c032
F ext/wasm/api/sqlite3-api-prologue.js 4f1c2a9dc9caf631907766e9872c27d11b255ccae779e8af01c7f8b932817214 F ext/wasm/api/sqlite3-api-prologue.js 4272131346b102d6f1bfc07524331213ff89407b76cbbde4c0b48b19c692ba94
F ext/wasm/api/sqlite3-api-worker1.c-pp.js 760191cd13416e6f5adfd9fcc8a97fed5645c9e0a5fbac213a2d4ce2d79a4334 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 760191cd13416e6f5adfd9fcc8a97fed5645c9e0a5fbac213a2d4ce2d79a4334
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89 F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
F ext/wasm/api/sqlite3-opfs-async-proxy.js 9654b565b346dc609b75d15337f20acfa7af7d9d558da1afeb9b6d8eaa404966 F ext/wasm/api/sqlite3-opfs-async-proxy.js 9654b565b346dc609b75d15337f20acfa7af7d9d558da1afeb9b6d8eaa404966
@@ -2174,8 +2174,8 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P e447a50f3a3791c264a68000948daa64edb1857d51d256fbd1ff0f2c2b330d5e P 292866a46948e8d707bd14864fd1b40eec1bd2e22dcd249ec94711b646c8a70b
R 914e412c108c33985260767ddbccf671 R 3d648bd2f0581cd393c02110c0b966eb
U stephan U stephan
Z fb5496b4e64823b519fcbc93dbe57147 Z cb971779c9e9efb3d18793a17a591051
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@@ -1 +1 @@
292866a46948e8d707bd14864fd1b40eec1bd2e22dcd249ec94711b646c8a70b fabbc8b6d184d52a513e80fabd900f578424fc8a8055e3d64fac54b9e28ea18a