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:
@@ -79,252 +79,336 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
// 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.
|
||||
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_auto_extension() has a hand-written binding. */
|
||||
/* sqlite3_bind_blob() and sqlite3_bind_text() have hand-written
|
||||
bindings to permit more flexible inputs. */
|
||||
["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_parameter_name", "string", "sqlite3_stmt*", "int"],
|
||||
["sqlite3_bind_pointer", "int",
|
||||
"sqlite3_stmt*", "int", "*", "string:static", "*"],
|
||||
["sqlite3_busy_handler","int", [
|
||||
"sqlite3*",
|
||||
new wasm.xWrap.FuncPtrAdapter({
|
||||
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_close_v2() is implemented by hand to perform some
|
||||
extra work. */
|
||||
["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_decltype", "string", "sqlite3_stmt*", "int"],
|
||||
["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_commit_hook", "void*", [
|
||||
"sqlite3*",
|
||||
new wasm.xWrap.FuncPtrAdapter({
|
||||
name: 'sqlite3_commit_hook',
|
||||
signature: 'i(p)',
|
||||
contextKey: (argv)=>argv[0/* sqlite3* */]
|
||||
}),
|
||||
'*'
|
||||
]],
|
||||
["sqlite3_compileoption_get", "string", "int"],
|
||||
["sqlite3_compileoption_used", "int", "string"],
|
||||
["sqlite3_complete", "int", "string:flexible"],
|
||||
["sqlite3_context_db_handle", "sqlite3*", "sqlite3_context*"],
|
||||
/* sqlite3_create_collation() and sqlite3_create_collation_v2()
|
||||
use hand-written bindings to simplify passing of the callback
|
||||
function. */
|
||||
/* 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_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_readonly", "int", "sqlite3*", "string"],
|
||||
["sqlite3_db_status", "int", "sqlite3*", "int", "*", "*", "int"],
|
||||
["sqlite3_errcode", "int", "sqlite3*"],
|
||||
["sqlite3_errmsg", "string", "sqlite3*"],
|
||||
["sqlite3_error_offset", "int", "sqlite3*"],
|
||||
["sqlite3_errstr", "string", "int"],
|
||||
["sqlite3_exec", "int", [
|
||||
"sqlite3*", "string:flexible",
|
||||
new wasm.xWrap.FuncPtrAdapter({
|
||||
signature: 'i(pipp)',
|
||||
bindScope: 'transient',
|
||||
callProxy: (callback)=>{
|
||||
let aNames;
|
||||
return (pVoid, nCols, pColVals, pColNames)=>{
|
||||
try {
|
||||
const aVals = wasm.cArgvToJs(nCols, pColVals);
|
||||
if(!aNames) aNames = wasm.cArgvToJs(nCols, pColNames);
|
||||
return callback(aVals, aNames) | 0;
|
||||
}catch(e){
|
||||
/* If we set the db error state here, the higher-level
|
||||
exec() call replaces it with its own, so we have no way
|
||||
of reporting the exception message except the console. We
|
||||
must not propagate exceptions through the C API. Though
|
||||
we make an effort to report OOM here, sqlite3_exec()
|
||||
translates that into SQLITE_ABORT as well. */
|
||||
return e.resultCode || capi.SQLITE_ERROR;
|
||||
const bindingSignatures = {
|
||||
core: [
|
||||
// Please keep these sorted by function name!
|
||||
["sqlite3_aggregate_context","void*", "sqlite3_context*", "int"],
|
||||
/* sqlite3_auto_extension() has a hand-written binding. */
|
||||
/* sqlite3_bind_blob() and sqlite3_bind_text() have hand-written
|
||||
bindings to permit more flexible inputs. */
|
||||
["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_parameter_name", "string", "sqlite3_stmt*", "int"],
|
||||
["sqlite3_bind_pointer", "int",
|
||||
"sqlite3_stmt*", "int", "*", "string:static", "*"],
|
||||
["sqlite3_busy_handler","int", [
|
||||
"sqlite3*",
|
||||
new wasm.xWrap.FuncPtrAdapter({
|
||||
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_close_v2() is implemented by hand to perform some
|
||||
extra work. */
|
||||
["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_decltype", "string", "sqlite3_stmt*", "int"],
|
||||
["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_commit_hook", "void*", [
|
||||
"sqlite3*",
|
||||
new wasm.xWrap.FuncPtrAdapter({
|
||||
name: 'sqlite3_commit_hook',
|
||||
signature: 'i(p)',
|
||||
contextKey: (argv)=>argv[0/* sqlite3* */]
|
||||
}),
|
||||
'*'
|
||||
]],
|
||||
["sqlite3_compileoption_get", "string", "int"],
|
||||
["sqlite3_compileoption_used", "int", "string"],
|
||||
["sqlite3_complete", "int", "string:flexible"],
|
||||
["sqlite3_context_db_handle", "sqlite3*", "sqlite3_context*"],
|
||||
/* sqlite3_create_collation() and sqlite3_create_collation_v2()
|
||||
use hand-written bindings to simplify passing of the callback
|
||||
function. */
|
||||
/* 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_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_readonly", "int", "sqlite3*", "string"],
|
||||
["sqlite3_db_status", "int", "sqlite3*", "int", "*", "*", "int"],
|
||||
["sqlite3_errcode", "int", "sqlite3*"],
|
||||
["sqlite3_errmsg", "string", "sqlite3*"],
|
||||
["sqlite3_error_offset", "int", "sqlite3*"],
|
||||
["sqlite3_errstr", "string", "int"],
|
||||
["sqlite3_exec", "int", [
|
||||
"sqlite3*", "string:flexible",
|
||||
new wasm.xWrap.FuncPtrAdapter({
|
||||
signature: 'i(pipp)',
|
||||
bindScope: 'transient',
|
||||
callProxy: (callback)=>{
|
||||
let aNames;
|
||||
return (pVoid, nCols, pColVals, pColNames)=>{
|
||||
try {
|
||||
const aVals = wasm.cArgvToJs(nCols, pColVals);
|
||||
if(!aNames) aNames = wasm.cArgvToJs(nCols, pColNames);
|
||||
return callback(aVals, aNames) | 0;
|
||||
}catch(e){
|
||||
/* If we set the db error state here, the higher-level
|
||||
exec() call replaces it with its own, so we have no way
|
||||
of reporting the exception message except the console. We
|
||||
must not propagate exceptions through the C API. Though
|
||||
we make an effort to report OOM here, sqlite3_exec()
|
||||
translates that into SQLITE_ABORT as well. */
|
||||
return e.resultCode || capi.SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
"*", "**"
|
||||
]],
|
||||
["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_autocommit", "int", "sqlite3*"],
|
||||
["sqlite3_get_auxdata", "*", "sqlite3_context*", "int"],
|
||||
["sqlite3_initialize", undefined],
|
||||
["sqlite3_interrupt", undefined, "sqlite3*"],
|
||||
["sqlite3_is_interrupted", "int", "sqlite3*"],
|
||||
["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_realloc", "*","*","int"],
|
||||
["sqlite3_reset", "int", "sqlite3_stmt*"],
|
||||
/* sqlite3_reset_auto_extension() has a hand-written binding. */
|
||||
["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_rollback_hook", "void*", [
|
||||
"sqlite3*",
|
||||
new wasm.xWrap.FuncPtrAdapter({
|
||||
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',
|
||||
}),
|
||||
"*", "**"
|
||||
]],
|
||||
["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_autocommit", "int", "sqlite3*"],
|
||||
["sqlite3_get_auxdata", "*", "sqlite3_context*", "int"],
|
||||
["sqlite3_initialize", undefined],
|
||||
["sqlite3_interrupt", undefined, "sqlite3*"],
|
||||
["sqlite3_is_interrupted", "int", "sqlite3*"],
|
||||
["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_realloc", "*","*","int"],
|
||||
["sqlite3_reset", "int", "sqlite3_stmt*"],
|
||||
/* sqlite3_reset_auto_extension() has a hand-written binding. */
|
||||
["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_rollback_hook", "void*", [
|
||||
"sqlite3*",
|
||||
new wasm.xWrap.FuncPtrAdapter({
|
||||
name: 'sqlite3_rollback_hook',
|
||||
signature: 'v(p)',
|
||||
contextKey: (argv, argIndex)=>argv[0/* sqlite3_context* */]
|
||||
})
|
||||
]],
|
||||
['sqlite3_set_errmsg', 'int', 'sqlite3*', 'int', 'string'],
|
||||
["sqlite3_shutdown", undefined],
|
||||
["sqlite3_sourceid", "string"],
|
||||
["sqlite3_sql", "string", "sqlite3_stmt*"],
|
||||
["sqlite3_status", "int", "int", "*", "*", "int"],
|
||||
["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"]],
|
||||
/* 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*/;
|
||||
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)',
|
||||
contextKey: (argv, argIndex)=>argv[0/* sqlite3_context* */]
|
||||
})
|
||||
]],
|
||||
['sqlite3_set_errmsg', 'int', 'sqlite3*', 'int', 'string'],
|
||||
["sqlite3_shutdown", undefined],
|
||||
["sqlite3_sourceid", "string"],
|
||||
["sqlite3_sql", "string", "sqlite3_stmt*"],
|
||||
["sqlite3_status", "int", "int", "*", "*", "int"],
|
||||
["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 ){
|
||||
wasm.bindingSignatures.push(
|
||||
bindingSignatures.core.push(
|
||||
["sqlite3_progress_handler", undefined, [
|
||||
"sqlite3*", "int", new wasm.xWrap.FuncPtrAdapter({
|
||||
name: 'xProgressHandler',
|
||||
@@ -337,14 +421,14 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
}
|
||||
|
||||
if( !!wasm.exports.sqlite3_stmt_explain ){
|
||||
wasm.bindingSignatures.push(
|
||||
bindingSignatures.core.push(
|
||||
["sqlite3_stmt_explain", "int", "sqlite3_stmt*", "int"],
|
||||
["sqlite3_stmt_isexplain", "int", "sqlite3_stmt*"]
|
||||
);
|
||||
}
|
||||
|
||||
if( !!wasm.exports.sqlite3_set_authorizer ){
|
||||
wasm.bindingSignatures.push(
|
||||
bindingSignatures.core.push(
|
||||
["sqlite3_set_authorizer", "int", [
|
||||
"sqlite3*",
|
||||
new wasm.xWrap.FuncPtrAdapter({
|
||||
@@ -369,7 +453,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
}/* sqlite3_set_authorizer() */
|
||||
|
||||
if( !!wasm.exports.sqlite3_column_origin_name ){
|
||||
wasm.bindingSignatures.push(
|
||||
bindingSignatures.core.push(
|
||||
["sqlite3_column_database_name","string", "sqlite3_stmt*", "int"],
|
||||
["sqlite3_column_origin_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
|
||||
build-time function-export list does not currently take
|
||||
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(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
|
||||
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
|
||||
clients with a working copy of the commercial SEE code.
|
||||
*/
|
||||
wasm.bindingSignatures.push(
|
||||
bindingSignatures.core.push(
|
||||
["sqlite3_key", "int", "sqlite3*", "string", "int"],
|
||||
["sqlite3_key_v2","int","sqlite3*","string","*","int"],
|
||||
["sqlite3_rekey", "int", "sqlite3*", "string", "int"],
|
||||
@@ -403,60 +487,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
}
|
||||
//#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 ){
|
||||
wasm.bindingSignatures.int64.push(
|
||||
bindingSignatures.int64.push(
|
||||
["sqlite3_create_module", "int",
|
||||
["sqlite3*","string","sqlite3_module*","*"]],
|
||||
["sqlite3_create_module_v2", "int",
|
||||
@@ -477,7 +509,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
}/* virtual table APIs */
|
||||
|
||||
if(wasm.bigIntEnabled && !!wasm.exports.sqlite3_preupdate_hook){
|
||||
wasm.bindingSignatures.int64.push(
|
||||
bindingSignatures.int64.push(
|
||||
["sqlite3_preupdate_blobwrite", "int", "sqlite3*"],
|
||||
["sqlite3_preupdate_count", "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_strm', 'int', [
|
||||
'sqlite3_changegroup*',
|
||||
@@ -677,36 +709,13 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
}),
|
||||
'*'
|
||||
]]
|
||||
]);
|
||||
);
|
||||
}/*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
|
||||
need... */
|
||||
need...
|
||||
*/
|
||||
sqlite3.StructBinder = globalThis.Jaccwabyt({
|
||||
heap: 0 ? wasm.memory : wasm.heap8u,
|
||||
alloc: wasm.alloc,
|
||||
@@ -759,10 +768,10 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
|
||||
/**
|
||||
Add some descriptive xWrap() aliases for '*' intended to (A)
|
||||
initially improve readability/correctness of
|
||||
wasm.bindingSignatures and (B) provide automatic conversion
|
||||
from higher-level representations, e.g. capi.sqlite3_vfs to
|
||||
`sqlite3_vfs*` via capi.sqlite3_vfs.pointer.
|
||||
improve readability/correctness of bindingSignatures and (B)
|
||||
provide automatic conversion from higher-level representations,
|
||||
e.g. capi.sqlite3_vfs to `sqlite3_vfs*` via (capi.sqlite3_vfs
|
||||
instance).pointer.
|
||||
*/
|
||||
const __xArgPtr = wasm.xWrap.argAdapter('*');
|
||||
const nilType = function(){
|
||||
@@ -834,10 +843,10 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
"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);
|
||||
}
|
||||
for(const e of wasm.bindingSignatures.wasmInternal){
|
||||
for(const e of bindingSignatures.wasmInternal){
|
||||
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",
|
||||
"of BigInt support in this build.");
|
||||
};
|
||||
for(const e of wasm.bindingSignatures.int64){
|
||||
for(const e of bindingSignatures.int64){
|
||||
capi[e[0]] = wasm.bigIntEnabled
|
||||
? wasm.xWrap.apply(null, e)
|
||||
: fI64Disabled(e[0]);
|
||||
}
|
||||
|
||||
/* There's no need to expose bindingSignatures to clients,
|
||||
implicitly making it part of the public interface. */
|
||||
delete wasm.bindingSignatures;
|
||||
/* We don't need these anymore... */
|
||||
delete bindingSignatures.core;
|
||||
delete bindingSignatures.int64;
|
||||
delete bindingSignatures.wasmInternal;
|
||||
|
||||
/**
|
||||
Sets the given db's error state. Accepts:
|
||||
@@ -913,7 +923,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
'sqlite3Status',
|
||||
'stmtStatus', 'syncFlags',
|
||||
'trace', 'txnState', 'udfFlags',
|
||||
'version' ];
|
||||
'version'];
|
||||
if(wasm.bigIntEnabled){
|
||||
defineGroups.push('serialize', 'session', 'vtab');
|
||||
}
|
||||
@@ -1098,10 +1108,12 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
continue;
|
||||
}
|
||||
closeArgs.length = x.length/*==argument count*/
|
||||
/* recall that undefined entries translate to 0 when passed to
|
||||
WASM. */;
|
||||
|| 1 /* Recall that: (A) undefined entries translate to 0 when
|
||||
passed to WASM and (B) Safari wraps wasm.exports.* in
|
||||
nullary functions so x.length is 0 there. */;
|
||||
try{ capi[name](...closeArgs) }
|
||||
catch(e){
|
||||
/* This "cannot happen" unless something is well and truly sideways. */
|
||||
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,
|
||||
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 calls this again with the
|
||||
same collation name and a value of 0 or null for the
|
||||
the function pointer(s).
|
||||
are "permanent," in that they will stay in the WASM
|
||||
environment until it shuts down unless the client calls this
|
||||
again with the same collation name and a value of 0 or null
|
||||
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
|
||||
arguments. It returns capi.SQLITE_MISUSE if passed any other
|
||||
@@ -1447,11 +1460,12 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
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
|
||||
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
|
||||
the byte length of v (if it's a byte array or ArrayBuffer).
|
||||
either v or a transformed copy of v and N is either n (if v is
|
||||
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)=>{
|
||||
if('string'===typeof v){
|
||||
@@ -1484,15 +1498,14 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
"int", "**",
|
||||
"**"/*MUST be 0 or null or undefined!*/]),
|
||||
/**
|
||||
Impl which requires that the 2nd argument be a pointer
|
||||
to the SQL string, instead of being converted to a
|
||||
string. This variant is necessary for cases where we
|
||||
require a non-NULL value for the final argument
|
||||
(exec()'ing multiple statements from one input
|
||||
string). For simpler cases, where only the first
|
||||
statement in the SQL string is required, the wrapper
|
||||
named sqlite3_prepare_v2() is sufficient and easier to
|
||||
use because it doesn't require dealing with pointers.
|
||||
Impl which requires that the 2nd argument be a pointer to the
|
||||
SQL string, instead of being converted to a JS string. This
|
||||
variant is necessary for cases where we require a non-NULL
|
||||
value for the final argument (prepare/step of multiple
|
||||
statements from one input string). For simpler cases, where
|
||||
only the first statement in the SQL string is required, the
|
||||
wrapper named sqlite3_prepare_v2() is sufficient and easier
|
||||
to use because it doesn't require dealing with pointers.
|
||||
*/
|
||||
full: wasm.xWrap('sqlite3_prepare_v3',
|
||||
"int", ["sqlite3*", "*", "int", "int",
|
||||
|
||||
@@ -542,8 +542,8 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
4th-argument value, taking care not to pass a value which
|
||||
truncates a multi-byte UTF-8 character. When passing
|
||||
WASM-format strings, it is important that the final argument be
|
||||
valid or unexpected content can result can result, or even a
|
||||
crash if the application reads past the WASM heap bounds.
|
||||
valid or unexpected content can result, or WASM may crash if
|
||||
the application reads past the WASM heap bounds.
|
||||
*/
|
||||
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
|
||||
routine, get automatic conversions of arguments and result
|
||||
values. The routines which perform those conversions are
|
||||
exposed for client-side use as
|
||||
sqlite3_create_function_v2.convertUdfArgs() and
|
||||
sqlite3_create_function_v2.setUdfResult(). sqlite3_create_function()
|
||||
and sqlite3_create_window_function() have those same methods.
|
||||
exposed for client-side use as sqlite3_values_to_js(),
|
||||
sqlite3_result_js(), and sqlite3_result_error_js().
|
||||
|
||||
For xFunc(), xStep(), and xFinal():
|
||||
|
||||
@@ -635,18 +633,14 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
possibly generating a console.error() message. Destructors
|
||||
must not throw.
|
||||
|
||||
Once installed, there is currently no way to uninstall the
|
||||
automatically-converted WASM-bound JS functions from WASM. They
|
||||
can be uninstalled from the database as documented in the C
|
||||
API, but this wrapper currently has no infrastructure in place
|
||||
to also free the WASM-bound JS wrappers, effectively resulting
|
||||
in a memory leak if the client uninstalls the UDF. Improving that
|
||||
is a potential TODO, but removing client-installed UDFs is rare
|
||||
in practice. If this factor is relevant for a given client,
|
||||
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).
|
||||
Automatically-converted JS-to-WASM functions will be cleaned up
|
||||
either when (A) this function is called again with the same
|
||||
name, arity, and encoding, but null/0 values for the functions,
|
||||
or (B) when pDb is passed to sqlite3_close_v2(). If this factor
|
||||
is relevant for a given client, 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
|
||||
|
||||
@@ -686,10 +680,10 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
|
||||
2) sqlite3_prepare_v3(pDb, sqlPointer, sqlByteLen, prepFlags, ppStmt, sqlPointerToPointer)
|
||||
|
||||
Note that the SQL length argument (the 3rd argument) must, for
|
||||
usage (1), always be negative because it must be a byte length
|
||||
and that value is expensive to calculate from JS (where only
|
||||
the character length of strings is readily available). It is
|
||||
The SQL length argument (the 3rd argument) must, for usage (1),
|
||||
always be negative because it must be a byte length and that
|
||||
value is expensive to calculate from JS (where only the
|
||||
character length of strings is readily available). It is
|
||||
retained in this API's interface for code/documentation
|
||||
compatibility reasons but is currently _always_ ignored. With
|
||||
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,
|
||||
the final argument may be 0/null/undefined or must be a pointer
|
||||
to which the "tail" of the compiled SQL is written, as
|
||||
documented for the C-side sqlite3_prepare_v3(). In case (2),
|
||||
the underlying C function is called with the equivalent of:
|
||||
documented for the C-side sqlite3_prepare_v3().
|
||||
|
||||
In case (2), the underlying C function is called with the
|
||||
equivalent of:
|
||||
|
||||
(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){
|
||||
config.warn("sqlite3_js_vfs_create_file() is deprecated and",
|
||||
"should be avoided because it can lead to C-level crashes.",
|
||||
"See its documentation for alternative options.");
|
||||
"See its documentation for alternatives.");
|
||||
let pData;
|
||||
if(data){
|
||||
if(wasm.isPtr(data)){
|
||||
if( wasm.isPtr(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{
|
||||
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{
|
||||
pData = 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().");
|
||||
}
|
||||
try{
|
||||
@@ -1581,7 +1579,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
if(rc) SQLite3Error.toss("Creation of file failed with sqlite3 result code",
|
||||
capi.sqlite3_js_rc_str(rc));
|
||||
}finally{
|
||||
wasm.dealloc(pData);
|
||||
if( pData && pData!==data ) wasm.dealloc(pData);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
14
manifest
14
manifest
@@ -1,5 +1,5 @@
|
||||
C Expose\ssqlite3_set_errmsg()\sto\sthe\sJNI\sbindings.
|
||||
D 2025-09-14T12:55:57.217
|
||||
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-15T14:11:55.851
|
||||
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
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/pre-js.c-pp.js 58f823de197e2c10d76179aa05410a593b7ae03e1ece983bb42ffd818e8857e1
|
||||
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-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-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
|
||||
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.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P e447a50f3a3791c264a68000948daa64edb1857d51d256fbd1ff0f2c2b330d5e
|
||||
R 914e412c108c33985260767ddbccf671
|
||||
P 292866a46948e8d707bd14864fd1b40eec1bd2e22dcd249ec94711b646c8a70b
|
||||
R 3d648bd2f0581cd393c02110c0b966eb
|
||||
U stephan
|
||||
Z fb5496b4e64823b519fcbc93dbe57147
|
||||
Z cb971779c9e9efb3d18793a17a591051
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
@@ -1 +1 @@
|
||||
292866a46948e8d707bd14864fd1b40eec1bd2e22dcd249ec94711b646c8a70b
|
||||
fabbc8b6d184d52a513e80fabd900f578424fc8a8055e3d64fac54b9e28ea18a
|
||||
|
||||
Reference in New Issue
Block a user