aboutsummaryrefslogtreecommitdiff
path: root/ext/wasm/api
diff options
context:
space:
mode:
Diffstat (limited to 'ext/wasm/api')
-rw-r--r--ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-auth1
-rw-r--r--ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-core (renamed from ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api)60
-rw-r--r--ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-preupdate6
-rw-r--r--ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-session42
-rw-r--r--ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-vtab11
-rw-r--r--ext/wasm/api/sqlite3-api-glue.c-pp.js (renamed from ext/wasm/api/sqlite3-api-glue.js)175
-rw-r--r--ext/wasm/api/sqlite3-api-oo1.c-pp.js (renamed from ext/wasm/api/sqlite3-api-oo1.js)106
-rw-r--r--ext/wasm/api/sqlite3-api-prologue.js5
-rw-r--r--ext/wasm/api/sqlite3-api-worker1.c-pp.js (renamed from ext/wasm/api/sqlite3-api-worker1.js)0
-rw-r--r--ext/wasm/api/sqlite3-opfs-async-proxy.js133
-rw-r--r--ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js64
-rw-r--r--ext/wasm/api/sqlite3-vfs-opfs.c-pp.js50
-rw-r--r--ext/wasm/api/sqlite3-vtab-helper.c-pp.js6
-rw-r--r--ext/wasm/api/sqlite3-wasm.c58
14 files changed, 370 insertions, 347 deletions
diff --git a/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-auth b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-auth
new file mode 100644
index 000000000..085090821
--- /dev/null
+++ b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-auth
@@ -0,0 +1 @@
+_sqlite3_set_authorizer
diff --git a/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-core
index 57cd61eb9..db47ee7db 100644
--- a/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api
+++ b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-core
@@ -10,6 +10,7 @@ _sqlite3_bind_int64
_sqlite3_bind_null
_sqlite3_bind_parameter_count
_sqlite3_bind_parameter_index
+_sqlite3_bind_parameter_name
_sqlite3_bind_pointer
_sqlite3_bind_text
_sqlite3_busy_handler
@@ -23,7 +24,7 @@ _sqlite3_collation_needed
_sqlite3_column_blob
_sqlite3_column_bytes
_sqlite3_column_count
-_sqlite3_column_count
+_sqlite3_column_decltype
_sqlite3_column_double
_sqlite3_column_int
_sqlite3_column_int64
@@ -40,15 +41,13 @@ _sqlite3_create_collation
_sqlite3_create_collation_v2
_sqlite3_create_function
_sqlite3_create_function_v2
-_sqlite3_create_module
-_sqlite3_create_module_v2
_sqlite3_create_window_function
_sqlite3_data_count
_sqlite3_db_filename
_sqlite3_db_handle
_sqlite3_db_name
+_sqlite3_db_readonly
_sqlite3_db_status
-_sqlite3_declare_vtab
_sqlite3_deserialize
_sqlite3_drop_modules
_sqlite3_errcode
@@ -65,6 +64,8 @@ _sqlite3_free
_sqlite3_get_auxdata
_sqlite3_get_autocommit
_sqlite3_initialize
+_sqlite3_interrupt
+_sqlite3_is_interrupted
_sqlite3_keyword_count
_sqlite3_keyword_name
_sqlite3_keyword_check
@@ -80,12 +81,6 @@ _sqlite3_open_v2
_sqlite3_overload_function
_sqlite3_prepare_v2
_sqlite3_prepare_v3
-_sqlite3_preupdate_blobwrite
-_sqlite3_preupdate_count
-_sqlite3_preupdate_depth
-_sqlite3_preupdate_hook
-_sqlite3_preupdate_new
-_sqlite3_preupdate_old
_sqlite3_progress_handler
_sqlite3_randomness
_sqlite3_realloc
@@ -108,7 +103,6 @@ _sqlite3_result_zeroblob
_sqlite3_result_zeroblob64
_sqlite3_rollback_hook
_sqlite3_serialize
-_sqlite3_set_authorizer
_sqlite3_set_auxdata
_sqlite3_set_last_insert_rowid
_sqlite3_shutdown
@@ -117,6 +111,8 @@ _sqlite3_sql
_sqlite3_status
_sqlite3_status64
_sqlite3_step
+_sqlite3_stmt_busy
+_sqlite3_stmt_explain
_sqlite3_stmt_isexplain
_sqlite3_stmt_readonly
_sqlite3_stmt_status
@@ -160,45 +156,3 @@ _sqlite3_vtab_in_next
_sqlite3_vtab_nochange
_sqlite3_vtab_on_conflict
_sqlite3_vtab_rhs_value
-_sqlite3changegroup_add
-_sqlite3changegroup_add_strm
-_sqlite3changegroup_delete
-_sqlite3changegroup_new
-_sqlite3changegroup_output
-_sqlite3changegroup_output_strm
-_sqlite3changeset_apply
-_sqlite3changeset_apply_strm
-_sqlite3changeset_apply_v2
-_sqlite3changeset_apply_v2_strm
-_sqlite3changeset_concat
-_sqlite3changeset_concat_strm
-_sqlite3changeset_conflict
-_sqlite3changeset_finalize
-_sqlite3changeset_fk_conflicts
-_sqlite3changeset_invert
-_sqlite3changeset_invert_strm
-_sqlite3changeset_new
-_sqlite3changeset_next
-_sqlite3changeset_old
-_sqlite3changeset_op
-_sqlite3changeset_pk
-_sqlite3changeset_start
-_sqlite3changeset_start_strm
-_sqlite3changeset_start_v2
-_sqlite3changeset_start_v2_strm
-_sqlite3session_attach
-_sqlite3session_changeset
-_sqlite3session_changeset_size
-_sqlite3session_changeset_strm
-_sqlite3session_config
-_sqlite3session_create
-_sqlite3session_delete
-_sqlite3session_diff
-_sqlite3session_enable
-_sqlite3session_indirect
-_sqlite3session_isempty
-_sqlite3session_memory_used
-_sqlite3session_object_config
-_sqlite3session_patchset
-_sqlite3session_patchset_strm
-_sqlite3session_table_filter
diff --git a/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-preupdate b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-preupdate
new file mode 100644
index 000000000..5c57a76b6
--- /dev/null
+++ b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-preupdate
@@ -0,0 +1,6 @@
+_sqlite3_preupdate_blobwrite
+_sqlite3_preupdate_count
+_sqlite3_preupdate_depth
+_sqlite3_preupdate_hook
+_sqlite3_preupdate_new
+_sqlite3_preupdate_old
diff --git a/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-session b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-session
new file mode 100644
index 000000000..5b7b53f95
--- /dev/null
+++ b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-session
@@ -0,0 +1,42 @@
+_sqlite3changegroup_add
+_sqlite3changegroup_add_strm
+_sqlite3changegroup_delete
+_sqlite3changegroup_new
+_sqlite3changegroup_output
+_sqlite3changegroup_output_strm
+_sqlite3changeset_apply
+_sqlite3changeset_apply_strm
+_sqlite3changeset_apply_v2
+_sqlite3changeset_apply_v2_strm
+_sqlite3changeset_concat
+_sqlite3changeset_concat_strm
+_sqlite3changeset_conflict
+_sqlite3changeset_finalize
+_sqlite3changeset_fk_conflicts
+_sqlite3changeset_invert
+_sqlite3changeset_invert_strm
+_sqlite3changeset_new
+_sqlite3changeset_next
+_sqlite3changeset_old
+_sqlite3changeset_op
+_sqlite3changeset_pk
+_sqlite3changeset_start
+_sqlite3changeset_start_strm
+_sqlite3changeset_start_v2
+_sqlite3changeset_start_v2_strm
+_sqlite3session_attach
+_sqlite3session_changeset
+_sqlite3session_changeset_size
+_sqlite3session_changeset_strm
+_sqlite3session_config
+_sqlite3session_create
+_sqlite3session_delete
+_sqlite3session_diff
+_sqlite3session_enable
+_sqlite3session_indirect
+_sqlite3session_isempty
+_sqlite3session_memory_used
+_sqlite3session_object_config
+_sqlite3session_patchset
+_sqlite3session_patchset_strm
+_sqlite3session_table_filter
diff --git a/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-vtab b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-vtab
new file mode 100644
index 000000000..1f6de9682
--- /dev/null
+++ b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-vtab
@@ -0,0 +1,11 @@
+_sqlite3_create_module
+_sqlite3_create_module_v2
+_sqlite3_declare_vtab
+_sqlite3_vtab_collation
+_sqlite3_vtab_distinct
+_sqlite3_vtab_in
+_sqlite3_vtab_in_first
+_sqlite3_vtab_in_next
+_sqlite3_vtab_nochange
+_sqlite3_vtab_on_conflict
+_sqlite3_vtab_rhs_value
diff --git a/ext/wasm/api/sqlite3-api-glue.js b/ext/wasm/api/sqlite3-api-glue.c-pp.js
index 83b2ee172..e5eb0cfeb 100644
--- a/ext/wasm/api/sqlite3-api-glue.js
+++ b/ext/wasm/api/sqlite3-api-glue.c-pp.js
@@ -95,6 +95,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
["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", [
@@ -115,6 +116,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
["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"],
@@ -152,6 +154,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
["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*"],
@@ -192,10 +195,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
["sqlite3_get_autocommit", "int", "sqlite3*"],
["sqlite3_get_auxdata", "*", "sqlite3_context*", "int"],
["sqlite3_initialize", undefined],
- /*["sqlite3_interrupt", undefined, "sqlite3*"
- ^^^ we cannot actually currently support this because JS is
- single-threaded and we don't have a portable way to access a DB
- from 2 SharedWorkers concurrently. ],*/
+ ["sqlite3_interrupt", undefined, "sqlite3*"],
+ ["sqlite3_is_interrupted", "int", "sqlite3*"],
["sqlite3_keyword_count", "int"],
["sqlite3_keyword_name", "int", ["int", "**", "*"]],
["sqlite3_keyword_check", "int", ["string", "int"]],
@@ -243,26 +244,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}),
'*'
]],
- ["sqlite3_set_authorizer", "int", [
- "sqlite3*",
- new wasm.xWrap.FuncPtrAdapter({
- name: "sqlite3_set_authorizer::xAuth",
- signature: "i(pi"+"ssss)",
- contextKey: (argv, argIndex)=>argv[0/*(sqlite3*)*/],
- callProxy: (callback)=>{
- return (pV, iCode, s0, s1, s2, s3)=>{
- try{
- s0 = s0 && wasm.cstrToJs(s0); s1 = s1 && wasm.cstrToJs(s1);
- s2 = s2 && wasm.cstrToJs(s2); s3 = s3 && wasm.cstrToJs(s3);
- return callback(pV, iCode, s0, s1, s2, s3) || 0;
- }catch(e){
- return e.resultCode || capi.SQLITE_ERROR;
- }
- }
- }
- }),
- "*"/*pUserData*/
- ]],
["sqlite3_set_auxdata", undefined, [
"sqlite3_context*", "int", "*",
new wasm.xWrap.FuncPtrAdapter({
@@ -276,8 +257,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
["sqlite3_sql", "string", "sqlite3_stmt*"],
["sqlite3_status", "int", "int", "*", "*", "int"],
["sqlite3_step", "int", "sqlite3_stmt*"],
- ["sqlite3_stmt_isexplain", "int", ["sqlite3_stmt*"]],
- ["sqlite3_stmt_readonly", "int", ["sqlite3_stmt*"]],
+ ["sqlite3_stmt_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"],
@@ -322,6 +303,38 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
["sqlite3_vfs_unregister", "int", "sqlite3_vfs*"]
]/*wasm.bindingSignatures*/;
+ if( !!wasm.exports.sqlite3_stmt_explain ){
+ wasm.bindingSignatures.push(
+ ["sqlite3_stmt_explain", "int", "sqlite3_stmt*", "int"],
+ ["sqlite3_stmt_isexplain", "int", "sqlite3_stmt*"]
+ );
+ }
+
+ if( !!wasm.exports.sqlite3_set_authorizer ){
+ wasm.bindingSignatures.push(
+ ["sqlite3_set_authorizer", "int", [
+ "sqlite3*",
+ new wasm.xWrap.FuncPtrAdapter({
+ name: "sqlite3_set_authorizer::xAuth",
+ signature: "i(pi"+"ssss)",
+ contextKey: (argv, argIndex)=>argv[0/*(sqlite3*)*/],
+ callProxy: (callback)=>{
+ return (pV, iCode, s0, s1, s2, s3)=>{
+ try{
+ s0 = s0 && wasm.cstrToJs(s0); s1 = s1 && wasm.cstrToJs(s1);
+ s2 = s2 && wasm.cstrToJs(s2); s3 = s3 && wasm.cstrToJs(s3);
+ return callback(pV, iCode, s0, s1, s2, s3) || 0;
+ }catch(e){
+ return e.resultCode || capi.SQLITE_ERROR;
+ }
+ }
+ }
+ }),
+ "*"/*pUserData*/
+ ]]
+ );
+ }/* sqlite3_set_authorizer() */
+
if(false && wasm.compileOptionUsed('SQLITE_ENABLE_NORMALIZE')){
/* ^^^ "the problem" is that this is an option feature and the
build-time function-export list does not currently take
@@ -364,11 +377,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
["sqlite3_bind_int64","int", ["sqlite3_stmt*", "int", "i64"]],
["sqlite3_changes64","i64", ["sqlite3*"]],
["sqlite3_column_int64","i64", ["sqlite3_stmt*", "int"]],
- ["sqlite3_create_module", "int",
- ["sqlite3*","string","sqlite3_module*","*"]],
- ["sqlite3_create_module_v2", "int",
- ["sqlite3*","string","sqlite3_module*","*","*"]],
- ["sqlite3_declare_vtab", "int", ["sqlite3*", "string:flexible"]],
["sqlite3_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
@@ -382,26 +390,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
["sqlite3_malloc64", "*","i64"],
["sqlite3_msize", "i64", "*"],
["sqlite3_overload_function", "int", ["sqlite3*","string","int"]],
- ["sqlite3_preupdate_blobwrite", "int", "sqlite3*"],
- ["sqlite3_preupdate_count", "int", "sqlite3*"],
- ["sqlite3_preupdate_depth", "int", "sqlite3*"],
- ["sqlite3_preupdate_hook", "*", [
- "sqlite3*",
- new wasm.xWrap.FuncPtrAdapter({
- name: 'sqlite3_preupdate_hook',
- signature: "v(ppippjj)",
- contextKey: (argv)=>argv[0/* sqlite3* */],
- callProxy: (callback)=>{
- return (p,db,op,zDb,zTbl,iKey1,iKey2)=>{
- callback(p, db, op, wasm.cstrToJs(zDb), wasm.cstrToJs(zTbl),
- iKey1, iKey2);
- };
- }
- }),
- "*"
- ]],
- ["sqlite3_preupdate_new", "int", ["sqlite3*", "int", "**"]],
- ["sqlite3_preupdate_old", "int", ["sqlite3*", "int", "**"]],
["sqlite3_realloc64", "*","*", "i64"],
["sqlite3_result_int64", undefined, "*", "i64"],
["sqlite3_result_zeroblob64", "int", "*", "i64"],
@@ -424,21 +412,59 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
"*"
]],
["sqlite3_uri_int64", "i64", ["sqlite3_filename", "string", "i64"]],
- ["sqlite3_value_int64","i64", "sqlite3_value*"],
- ["sqlite3_vtab_collation","string","sqlite3_index_info*","int"],
- ["sqlite3_vtab_distinct","int", "sqlite3_index_info*"],
- ["sqlite3_vtab_in","int", "sqlite3_index_info*", "int", "int"],
- ["sqlite3_vtab_in_first", "int", "sqlite3_value*", "**"],
- ["sqlite3_vtab_in_next", "int", "sqlite3_value*", "**"],
- /*["sqlite3_vtab_config" is variadic and requires a hand-written
- proxy.] */
- ["sqlite3_vtab_nochange","int", "sqlite3_context*"],
- ["sqlite3_vtab_on_conflict","int", "sqlite3*"],
- ["sqlite3_vtab_rhs_value","int", "sqlite3_index_info*", "int", "**"]
+ ["sqlite3_value_int64","i64", "sqlite3_value*"]
];
+ if( wasm.bigIntEnabled && !!wasm.exports.sqlite3_declare_vtab ){
+ wasm.bindingSignatures.int64.push(
+ ["sqlite3_create_module", "int",
+ ["sqlite3*","string","sqlite3_module*","*"]],
+ ["sqlite3_create_module_v2", "int",
+ ["sqlite3*","string","sqlite3_module*","*","*"]],
+ ["sqlite3_declare_vtab", "int", ["sqlite3*", "string:flexible"]],
+ ["sqlite3_vtab_collation","string","sqlite3_index_info*","int"],
+ ["sqlite3_vtab_distinct","int", "sqlite3_index_info*"],
+ ["sqlite3_vtab_in","int", "sqlite3_index_info*", "int", "int"],
+ ["sqlite3_vtab_in_first", "int", "sqlite3_value*", "**"],
+ ["sqlite3_vtab_in_next", "int", "sqlite3_value*", "**"],
+ /*["sqlite3_vtab_config" is variadic and requires a hand-written
+ proxy.] */
+ ["sqlite3_vtab_nochange","int", "sqlite3_context*"],
+ ["sqlite3_vtab_on_conflict","int", "sqlite3*"],
+ ["sqlite3_vtab_rhs_value","int", "sqlite3_index_info*", "int", "**"]
+ );
+ }/* virtual table APIs */
+
+ if(wasm.bigIntEnabled && !!wasm.exports.sqlite3_preupdate_hook){
+ wasm.bindingSignatures.int64.push(
+ ["sqlite3_preupdate_blobwrite", "int", "sqlite3*"],
+ ["sqlite3_preupdate_count", "int", "sqlite3*"],
+ ["sqlite3_preupdate_depth", "int", "sqlite3*"],
+ ["sqlite3_preupdate_hook", "*", [
+ "sqlite3*",
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'sqlite3_preupdate_hook',
+ signature: "v(ppippjj)",
+ contextKey: (argv)=>argv[0/* sqlite3* */],
+ callProxy: (callback)=>{
+ return (p,db,op,zDb,zTbl,iKey1,iKey2)=>{
+ callback(p, db, op, wasm.cstrToJs(zDb), wasm.cstrToJs(zTbl),
+ iKey1, iKey2);
+ };
+ }
+ }),
+ "*"
+ ]],
+ ["sqlite3_preupdate_new", "int", ["sqlite3*", "int", "**"]],
+ ["sqlite3_preupdate_old", "int", ["sqlite3*", "int", "**"]]
+ );
+ } /* preupdate API */
+
// Add session/changeset APIs...
- if(wasm.bigIntEnabled && !!wasm.exports.sqlite3changegroup_add){
+ if(wasm.bigIntEnabled
+ && !!wasm.exports.sqlite3changegroup_add
+ && !!wasm.exports.sqlite3session_create
+ && !!wasm.exports.sqlite3_preupdate_hook /* required by the session API */){
/**
FuncPtrAdapter options for session-related callbacks with the
native signature "i(ps)". This proxy converts the 2nd argument
@@ -714,12 +740,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
('sqlite3*', (v)=>
__xArgPtr((v instanceof (sqlite3?.oo1?.DB || nilType))
? v.pointer : v))
- ('sqlite3_index_info*', (v)=>
- __xArgPtr((v instanceof (capi.sqlite3_index_info || nilType))
- ? v.pointer : v))
- ('sqlite3_module*', (v)=>
- __xArgPtr((v instanceof (capi.sqlite3_module || nilType))
- ? v.pointer : v))
/**
`sqlite3_vfs*`:
@@ -742,6 +762,15 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
return __xArgPtr((v instanceof (capi.sqlite3_vfs || nilType))
? v.pointer : v);
});
+ if( wasm.exports.sqlite3_declare_vtab ){
+ wasm.xWrap.argAdapter('sqlite3_index_info*', (v)=>
+ __xArgPtr((v instanceof (capi.sqlite3_index_info || nilType))
+ ? v.pointer : v))
+ ('sqlite3_module*', (v)=>
+ __xArgPtr((v instanceof (capi.sqlite3_module || nilType))
+ ? v.pointer : v)
+ );
+ }
const __xRcPtr = wasm.xWrap.resultAdapter('*');
wasm.xWrap.resultAdapter('sqlite3*', __xRcPtr)
@@ -1020,12 +1049,16 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
'sqlite3_update_hook'
]) {
const x = wasm.exports[name];
+ if( !x ){
+ /* assume it was built without this API */
+ continue;
+ }
closeArgs.length = x.length/*==argument count*/
/* recall that undefined entries translate to 0 when passed to
WASM. */;
try{ capi[name](...closeArgs) }
catch(e){
- console.warn("close-time call of",name+"(",closeArgs,") threw:",e);
+ sqlite3.config.warn("close-time call of",name+"(",closeArgs,") threw:",e);
}
}
const m = __dbCleanupMap(pDb, 0);
@@ -1076,7 +1109,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
};
}/*sqlite3_close_v2()*/
- if(capi.sqlite3session_table_filter){
+ if(capi.sqlite3session_create){
const __sqlite3SessionDelete = wasm.xWrap(
'sqlite3session_delete', undefined, ['sqlite3_session*']
);
diff --git a/ext/wasm/api/sqlite3-api-oo1.js b/ext/wasm/api/sqlite3-api-oo1.c-pp.js
index e557cbd57..3d6a24c77 100644
--- a/ext/wasm/api/sqlite3-api-oo1.js
+++ b/ext/wasm/api/sqlite3-api-oo1.c-pp.js
@@ -82,10 +82,11 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
/**
A map of sqlite3_vfs pointers to SQL code or a callback function
to run when the DB constructor opens a database with the given
- VFS. In the latter case, the call signature is (theDbObject,sqlite3Namespace)
- and the callback is expected to throw on error.
+ VFS. In the latter case, the call signature is
+ (theDbObject,sqlite3Namespace) and the callback is expected to
+ throw on error.
*/
- const __vfsPostOpenSql = Object.create(null);
+ const __vfsPostOpenCallback = Object.create(null);
//#if enable-see
/**
@@ -116,7 +117,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
are set. It throws if more than one is set or if any are set to
values of an invalid type.
- Returns true if it applies the key, else an unspecified falsy value.
+ Returns true if it applies the key, else an unspecified falsy
+ value. Note that applying the key does not imply that the key is
+ correct, only that it was passed on to the db.
*/
const dbCtorApplySEEKey = function(db,opt){
if( !capi.sqlite3_key_v2 ) return;
@@ -178,10 +181,10 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
try{
stmt = db.prepare("PRAGMA "+keytype+"="+util.sqlite3__wasm_qfmt_token(key, 1));
stmt.step();
+ return true;
}finally{
if(stmt) stmt.finalize();
}
- return true;
};
//#endif enable-see
@@ -279,7 +282,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
// Check for per-VFS post-open SQL/callback...
const pVfs = capi.sqlite3_js_db_vfs(pDb)
|| toss3("Internal error: cannot get VFS for new db handle.");
- const postInitSql = __vfsPostOpenSql[pVfs];
+ const postInitSql = __vfsPostOpenCallback[pVfs];
if(postInitSql){
/**
Reminder: if this db is encrypted and the client did _not_ pass
@@ -303,18 +306,28 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
};
/**
- Sets SQL which should be exec()'d on a DB instance after it is
- opened with the given VFS pointer. The SQL may be any type
- supported by the "string:flexible" function argument conversion.
- Alternately, the 2nd argument may be a function, in which case it
- is called with (theOo1DbObject,sqlite3Namespace) at the end of
- the DB() constructor. The function must throw on error, in which
- case the db is closed and the exception is propagated. This
- function is intended only for use by DB subclasses or sqlite3_vfs
+ Sets a callback which should be called after a db is opened with
+ the given sqlite3_vfs pointer. The 2nd argument must be a
+ function, which gets called with
+ (theOo1DbObject,sqlite3Namespace) at the end of the DB()
+ constructor. The function must throw on error, in which case the
+ db is closed and the exception is propagated. This function is
+ intended only for use by DB subclasses or sqlite3_vfs
implementations.
+
+ Prior to 2024-07-22, it was legal to pass SQL code as the second
+ argument, but that can interfere with a client's ability to run
+ pragmas which must be run before anything else, namely (pragma
+ locking_mode=exclusive) for use with WAL mode. That capability
+ had only ever been used as an internal detail of the two OPFS
+ VFSes, and they no longer use it that way.
*/
- dbCtorHelper.setVfsPostOpenSql = function(pVfs, sql){
- __vfsPostOpenSql[pVfs] = sql;
+ dbCtorHelper.setVfsPostOpenCallback = function(pVfs, callback){
+ if( !(callback instanceof Function)){
+ toss3("dbCtorHelper.setVfsPostOpenCallback() should not be used with "+
+ "a non-function argument.",arguments);
+ }
+ __vfsPostOpenCallback[pVfs] = callback;
};
/**
@@ -482,6 +495,10 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
statement's preparation and when it is stepped may invalidate it.
- `parameterCount`: the number of bindable parameters in the query.
+
+ As a general rule, most methods of this class will throw if
+ called on an instance which has been finalized. For brevity's
+ sake, the method docs do not all repeat this warning.
*/
const Stmt = function(){
if(BindTypes!==arguments[2]){
@@ -1686,12 +1703,11 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
integer 0 or 1. It is not expected the distinction of binding
doubles which have no fractional parts and integers is
significant for the majority of clients due to sqlite3's data
- typing model. If [BigInt] support is enabled then this
- routine will bind BigInt values as 64-bit integers if they'll
- fit in 64 bits. If that support disabled, it will store the
- BigInt as an int32 or a double if it can do so without loss
- of precision. If the BigInt is _too BigInt_ then it will
- throw.
+ typing model. If BigInt support is enabled then this routine
+ will bind BigInt values as 64-bit integers if they'll fit in
+ 64 bits. If that support disabled, it will store the BigInt
+ as an int32 or a double if it can do so without loss of
+ precision. If the BigInt is _too BigInt_ then it will throw.
- Strings are bound as strings (use bindAsBlob() to force
blob binding).
@@ -1797,9 +1813,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
},
/**
Steps the statement one time. If the result indicates that a
- row of data is available, a truthy value is returned.
- If no row of data is available, a falsy
- value is returned. Throws on error.
+ row of data is available, a truthy value is returned. If no
+ row of data is available, a falsy value is returned. Throws on
+ error.
*/
step: function(){
affirmNotLockedByExec(this, 'step()');
@@ -1819,6 +1835,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
Functions exactly like step() except that...
1) On success, it calls this.reset() and returns this object.
+
2) On error, it throws and does not call reset().
This is intended to simplify constructs like:
@@ -1842,7 +1859,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
throws.
On success, it returns true if the step indicated that a row of
- data was available, else it returns false.
+ data was available, else it returns a falsy value.
This is intended to simplify use cases such as:
@@ -1860,6 +1877,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
catch(e){/*ignored*/}
}
},
+
/**
Fetches the value from the given 0-based column index of
the current data row, throwing if index is out of range.
@@ -1884,7 +1902,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
If ndx is a plain object, this function behaves even
differentlier: it assigns the properties of the object to
- the values of their corresponding result columns.
+ the values of their corresponding result columns and returns
+ that object.
Blobs are returned as Uint8Array instances.
@@ -2030,6 +2049,39 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
return (affirmStmtOpen(this).parameterCount
? capi.sqlite3_bind_parameter_index(this.pointer, name)
: undefined);
+ },
+ /**
+ If this statement has named bindable parameters and the given
+ index refers to one, its name is returned, else null is
+ returned. If this statement has no bound parameters, undefined
+ is returned.
+
+ Added in 3.47.
+ */
+ getParamName: function(ndx){
+ return (affirmStmtOpen(this).parameterCount
+ ? capi.sqlite3_bind_parameter_name(this.pointer, ndx)
+ : undefined);
+ },
+
+ /**
+ Behaves like sqlite3_stmt_busy() but throws if this statement
+ is closed and returns a value of type boolean instead of integer.
+
+ Added in 3.47.
+ */
+ isBusy: function(){
+ return 0!==capi.sqlite3_stmt_busy(affirmStmtOpen(this));
+ },
+
+ /**
+ Behaves like sqlite3_stmt_readonly() but throws if this statement
+ is closed and returns a value of type boolean instead of integer.
+
+ Added in 3.47.
+ */
+ isReadOnly: function(){
+ return 0!==capi.sqlite3_stmt_readonly(affirmStmtOpen(this));
}
}/*Stmt.prototype*/;
diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js
index 689c79ae3..c8db3698c 100644
--- a/ext/wasm/api/sqlite3-api-prologue.js
+++ b/ext/wasm/api/sqlite3-api-prologue.js
@@ -1278,9 +1278,10 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
option is not available on the client.
Though the mount point name returned by this function is intended
- to remain stable, clients should not hard-coded it anywhere. Always call this function to get the path.
+ to remain stable, clients should not hard-coded it
+ anywhere. Always call this function to get the path.
- Note that this function is a no-op in must builds of this
+ Note that this function is a no-op in most builds of this
library, as the WASMFS capability requires a custom
build.
*/
diff --git a/ext/wasm/api/sqlite3-api-worker1.js b/ext/wasm/api/sqlite3-api-worker1.c-pp.js
index 991862545..991862545 100644
--- a/ext/wasm/api/sqlite3-api-worker1.js
+++ b/ext/wasm/api/sqlite3-api-worker1.c-pp.js
diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.js b/ext/wasm/api/sqlite3-opfs-async-proxy.js
index a2c052d32..ca5583971 100644
--- a/ext/wasm/api/sqlite3-opfs-async-proxy.js
+++ b/ext/wasm/api/sqlite3-opfs-async-proxy.js
@@ -87,35 +87,6 @@ const installAsyncProxy = function(){
const log = (...args)=>logImpl(2, ...args);
const warn = (...args)=>logImpl(1, ...args);
const error = (...args)=>logImpl(0, ...args);
- const metrics = Object.create(null);
- metrics.reset = ()=>{
- let k;
- const r = (m)=>(m.count = m.time = m.wait = 0);
- for(k in state.opIds){
- r(metrics[k] = Object.create(null));
- }
- let s = metrics.s11n = Object.create(null);
- s = s.serialize = Object.create(null);
- s.count = s.time = 0;
- s = metrics.s11n.deserialize = Object.create(null);
- s.count = s.time = 0;
- };
- metrics.dump = ()=>{
- let k, n = 0, t = 0, w = 0;
- for(k in state.opIds){
- const m = metrics[k];
- n += m.count;
- t += m.time;
- w += m.wait;
- m.avgTime = (m.count && m.time) ? (m.time / m.count) : 0;
- }
- console.log(globalThis?.location?.href,
- "metrics for",globalThis?.location?.href,":\n",
- metrics,
- "\nTotal of",n,"op(s) for",t,"ms",
- "approx",w,"ms spent waiting on OPFS APIs.");
- console.log("Serialization metrics:",metrics.s11n);
- };
/**
__openFiles is a map of sqlite3_file pointers (integers) to
@@ -373,37 +344,6 @@ const installAsyncProxy = function(){
};
/**
- We track 2 different timers: the "metrics" timer records how much
- time we spend performing work. The "wait" timer records how much
- time we spend waiting on the underlying OPFS timer. See the calls
- to mTimeStart(), mTimeEnd(), wTimeStart(), and wTimeEnd()
- throughout this file to see how they're used.
- */
- const __mTimer = Object.create(null);
- __mTimer.op = undefined;
- __mTimer.start = undefined;
- const mTimeStart = (op)=>{
- __mTimer.start = performance.now();
- __mTimer.op = op;
- //metrics[op] || toss("Maintenance required: missing metrics for",op);
- ++metrics[op].count;
- };
- const mTimeEnd = ()=>(
- metrics[__mTimer.op].time += performance.now() - __mTimer.start
- );
- const __wTimer = Object.create(null);
- __wTimer.op = undefined;
- __wTimer.start = undefined;
- const wTimeStart = (op)=>{
- __wTimer.start = performance.now();
- __wTimer.op = op;
- //metrics[op] || toss("Maintenance required: missing metrics for",op);
- };
- const wTimeEnd = ()=>(
- metrics[__wTimer.op].wait += performance.now() - __wTimer.start
- );
-
- /**
Gets set to true by the 'opfs-async-shutdown' command to quit the
wait loop. This is only intended for debugging purposes: we cannot
inspect this file's state while the tight waitLoop() is running and
@@ -413,37 +353,24 @@ const installAsyncProxy = function(){
/**
Asynchronous wrappers for sqlite3_vfs and sqlite3_io_methods
- methods, as well as helpers like mkdir(). Maintenance reminder:
- members are in alphabetical order to simplify finding them.
+ methods, as well as helpers like mkdir().
*/
const vfsAsyncImpls = {
- 'opfs-async-metrics': async ()=>{
- mTimeStart('opfs-async-metrics');
- metrics.dump();
- storeAndNotify('opfs-async-metrics', 0);
- mTimeEnd();
- },
'opfs-async-shutdown': async ()=>{
flagAsyncShutdown = true;
storeAndNotify('opfs-async-shutdown', 0);
},
mkdir: async (dirname)=>{
- mTimeStart('mkdir');
let rc = 0;
- wTimeStart('mkdir');
try {
await getDirForFilename(dirname+"/filepart", true);
}catch(e){
state.s11n.storeException(2,e);
rc = state.sq3Codes.SQLITE_IOERR;
- }finally{
- wTimeEnd();
}
storeAndNotify('mkdir', rc);
- mTimeEnd();
},
xAccess: async (filename)=>{
- mTimeStart('xAccess');
/* OPFS cannot support the full range of xAccess() queries
sqlite3 calls for. We can essentially just tell if the file
is accessible, but if it is then it's automatically writable
@@ -456,26 +383,20 @@ const installAsyncProxy = function(){
accessible, non-0 means not accessible.
*/
let rc = 0;
- wTimeStart('xAccess');
try{
const [dh, fn] = await getDirForFilename(filename);
await dh.getFileHandle(fn);
}catch(e){
state.s11n.storeException(2,e);
rc = state.sq3Codes.SQLITE_IOERR;
- }finally{
- wTimeEnd();
}
storeAndNotify('xAccess', rc);
- mTimeEnd();
},
xClose: async function(fid/*sqlite3_file pointer*/){
const opName = 'xClose';
- mTimeStart(opName);
__implicitLocks.delete(fid);
const fh = __openFiles[fid];
let rc = 0;
- wTimeStart(opName);
if(fh){
delete __openFiles[fid];
await closeSyncHandle(fh);
@@ -487,15 +408,11 @@ const installAsyncProxy = function(){
state.s11n.serialize();
rc = state.sq3Codes.SQLITE_NOTFOUND;
}
- wTimeEnd();
storeAndNotify(opName, rc);
- mTimeEnd();
},
xDelete: async function(...args){
- mTimeStart('xDelete');
const rc = await vfsAsyncImpls.xDeleteNoWait(...args);
storeAndNotify('xDelete', rc);
- mTimeEnd();
},
xDeleteNoWait: async function(filename, syncDir = 0, recursive = false){
/* The syncDir flag is, for purposes of the VFS API's semantics,
@@ -511,7 +428,6 @@ const installAsyncProxy = function(){
is false.
*/
let rc = 0;
- wTimeStart('xDelete');
try {
while(filename){
const [hDir, filenamePart] = await getDirForFilename(filename, false);
@@ -527,14 +443,11 @@ const installAsyncProxy = function(){
state.s11n.storeException(2,e);
rc = state.sq3Codes.SQLITE_IOERR_DELETE;
}
- wTimeEnd();
return rc;
},
xFileSize: async function(fid/*sqlite3_file pointer*/){
- mTimeStart('xFileSize');
const fh = __openFiles[fid];
let rc = 0;
- wTimeStart('xFileSize');
try{
const sz = await (await getSyncHandle(fh,'xFileSize')).getSize();
state.s11n.serialize(Number(sz));
@@ -543,19 +456,15 @@ const installAsyncProxy = function(){
rc = GetSyncHandleError.convertRc(e,state.sq3Codes.SQLITE_IOERR);
}
await releaseImplicitLock(fh);
- wTimeEnd();
storeAndNotify('xFileSize', rc);
- mTimeEnd();
},
xLock: async function(fid/*sqlite3_file pointer*/,
lockType/*SQLITE_LOCK_...*/){
- mTimeStart('xLock');
const fh = __openFiles[fid];
let rc = 0;
const oldLockType = fh.xLock;
fh.xLock = lockType;
if( !fh.syncHandle ){
- wTimeStart('xLock');
try {
await getSyncHandle(fh,'xLock');
__implicitLocks.delete(fid);
@@ -564,18 +473,14 @@ const installAsyncProxy = function(){
rc = GetSyncHandleError.convertRc(e,state.sq3Codes.SQLITE_IOERR_LOCK);
fh.xLock = oldLockType;
}
- wTimeEnd();
}
storeAndNotify('xLock',rc);
- mTimeEnd();
},
xOpen: async function(fid/*sqlite3_file pointer*/, filename,
flags/*SQLITE_OPEN_...*/,
opfsFlags/*OPFS_...*/){
const opName = 'xOpen';
- mTimeStart(opName);
const create = (state.sq3Codes.SQLITE_OPEN_CREATE & flags);
- wTimeStart('xOpen');
try{
let hDir, filenamePart;
try {
@@ -583,8 +488,6 @@ const installAsyncProxy = function(){
}catch(e){
state.s11n.storeException(1,e);
storeAndNotify(opName, state.sq3Codes.SQLITE_NOTFOUND);
- mTimeEnd();
- wTimeEnd();
return;
}
if( state.opfsFlags.OPFS_UNLINK_BEFORE_OPEN & opfsFlags ){
@@ -596,7 +499,6 @@ const installAsyncProxy = function(){
}
}
const hFile = await hDir.getFileHandle(filenamePart, {create});
- wTimeEnd();
const fh = Object.assign(Object.create(null),{
fid: fid,
filenameAbs: filename,
@@ -614,60 +516,47 @@ const installAsyncProxy = function(){
__openFiles[fid] = fh;
storeAndNotify(opName, 0);
}catch(e){
- wTimeEnd();
error(opName,e);
state.s11n.storeException(1,e);
storeAndNotify(opName, state.sq3Codes.SQLITE_IOERR);
}
- mTimeEnd();
},
xRead: async function(fid/*sqlite3_file pointer*/,n,offset64){
- mTimeStart('xRead');
let rc = 0, nRead;
const fh = __openFiles[fid];
try{
- wTimeStart('xRead');
nRead = (await getSyncHandle(fh,'xRead')).read(
fh.sabView.subarray(0, n),
{at: Number(offset64)}
);
- wTimeEnd();
if(nRead < n){/* Zero-fill remaining bytes */
fh.sabView.fill(0, nRead, n);
rc = state.sq3Codes.SQLITE_IOERR_SHORT_READ;
}
}catch(e){
- if(undefined===nRead) wTimeEnd();
error("xRead() failed",e,fh);
state.s11n.storeException(1,e);
rc = GetSyncHandleError.convertRc(e,state.sq3Codes.SQLITE_IOERR_READ);
}
await releaseImplicitLock(fh);
storeAndNotify('xRead',rc);
- mTimeEnd();
},
xSync: async function(fid/*sqlite3_file pointer*/,flags/*ignored*/){
- mTimeStart('xSync');
const fh = __openFiles[fid];
let rc = 0;
if(!fh.readOnly && fh.syncHandle){
try {
- wTimeStart('xSync');
await fh.syncHandle.flush();
}catch(e){
state.s11n.storeException(2,e);
rc = state.sq3Codes.SQLITE_IOERR_FSYNC;
}
- wTimeEnd();
}
storeAndNotify('xSync',rc);
- mTimeEnd();
},
xTruncate: async function(fid/*sqlite3_file pointer*/,size){
- mTimeStart('xTruncate');
let rc = 0;
const fh = __openFiles[fid];
- wTimeStart('xTruncate');
try{
affirmNotRO('xTruncate', fh);
await (await getSyncHandle(fh,'xTruncate')).truncate(size);
@@ -677,35 +566,27 @@ const installAsyncProxy = function(){
rc = GetSyncHandleError.convertRc(e,state.sq3Codes.SQLITE_IOERR_TRUNCATE);
}
await releaseImplicitLock(fh);
- wTimeEnd();
storeAndNotify('xTruncate',rc);
- mTimeEnd();
},
xUnlock: async function(fid/*sqlite3_file pointer*/,
lockType/*SQLITE_LOCK_...*/){
- mTimeStart('xUnlock');
let rc = 0;
const fh = __openFiles[fid];
if( fh.syncHandle
&& state.sq3Codes.SQLITE_LOCK_NONE===lockType
/* Note that we do not differentiate between lock types in
this VFS. We're either locked or unlocked. */ ){
- wTimeStart('xUnlock');
try { await closeSyncHandle(fh) }
catch(e){
state.s11n.storeException(1,e);
rc = state.sq3Codes.SQLITE_IOERR_UNLOCK;
}
- wTimeEnd();
}
storeAndNotify('xUnlock',rc);
- mTimeEnd();
},
xWrite: async function(fid/*sqlite3_file pointer*/,n,offset64){
- mTimeStart('xWrite');
let rc;
const fh = __openFiles[fid];
- wTimeStart('xWrite');
try{
affirmNotRO('xWrite', fh);
rc = (
@@ -719,9 +600,7 @@ const installAsyncProxy = function(){
rc = GetSyncHandleError.convertRc(e,state.sq3Codes.SQLITE_IOERR_WRITE);
}
await releaseImplicitLock(fh);
- wTimeEnd();
storeAndNotify('xWrite',rc);
- mTimeEnd();
}
}/*vfsAsyncImpls*/;
@@ -755,8 +634,6 @@ const installAsyncProxy = function(){
}
};
state.s11n.deserialize = function(clear=false){
- ++metrics.s11n.deserialize.count;
- const t = performance.now();
const argc = viewU8[0];
const rc = argc ? [] : null;
if(argc){
@@ -781,12 +658,9 @@ const installAsyncProxy = function(){
}
if(clear) viewU8[0] = 0;
//log("deserialize:",argc, rc);
- metrics.s11n.deserialize.time += performance.now() - t;
return rc;
};
state.s11n.serialize = function(...args){
- const t = performance.now();
- ++metrics.s11n.serialize.count;
if(args.length){
//log("serialize():",args);
const typeIds = [];
@@ -817,7 +691,6 @@ const installAsyncProxy = function(){
}else{
viewU8[0] = 0;
}
- metrics.s11n.serialize.time += performance.now() - t;
};
state.s11n.storeException = state.asyncS11nExceptions
@@ -899,7 +772,6 @@ const installAsyncProxy = function(){
}
});
initS11n();
- metrics.reset();
log("init state",state);
wPost('opfs-async-inited');
waitLoop();
@@ -912,9 +784,6 @@ const installAsyncProxy = function(){
waitLoop();
}
break;
- case 'opfs-async-metrics':
- metrics.dump();
- break;
}
};
wPost('opfs-async-loaded');
diff --git a/ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js
index 3f4182dac..d423bb0bb 100644
--- a/ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js
+++ b/ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js
@@ -78,8 +78,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
capi.SQLITE_OPEN_MAIN_DB |
capi.SQLITE_OPEN_MAIN_JOURNAL |
capi.SQLITE_OPEN_SUPER_JOURNAL |
- capi.SQLITE_OPEN_WAL /* noting that WAL support is
- unavailable in the WASM build.*/;
+ capi.SQLITE_OPEN_WAL;
/** Subdirectory of the VFS's space where "opaque" (randomly-named)
files are stored. Changing this effectively invalidates the data
@@ -102,7 +101,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
clearOnInit: false,
/* Logging verbosity 3+ == everything, 2 == warnings+errors, 1 ==
errors only. */
- verbosity: 2
+ verbosity: 2,
+ forceReinitIfPreviouslyFailed: false
});
/** Logging routines, from most to least serious. */
@@ -1004,9 +1004,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
return true;
};
- /** Only for testing a rejection case. */
- let instanceCounter = 0;
-
/**
installOpfsSAHPoolVfs() asynchronously initializes the OPFS
SyncAccessHandle (a.k.a. SAH) Pool VFS. It returns a Promise which
@@ -1081,12 +1078,26 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
the default directory. If no directory is explicitly provided
then a directory name is synthesized from the `name` option.
- Peculiarities of this VFS:
+
+ - `forceReinitIfPreviouslyFailed`: (default=`false`) Is a fallback option
+ to assist in working around certain flaky environments which may
+ mysteriously fail to permit access to OPFS sync access handles on
+ an initial attempt but permit it on a second attemp. This option
+ should never be used but is provided for those who choose to
+ throw caution to the wind and trust such environments. If this
+ option is truthy _and_ the previous attempt to initialize this
+ VFS with the same `name` failed, the VFS will attempt to
+ initialize a second time instead of returning the cached
+ failure. See discussion at:
+ <https://github.com/sqlite/sqlite-wasm/issues/79>
+
+
+ Peculiarities of this VFS vis a vis other SQLite VFSes:
- Paths given to it _must_ be absolute. Relative paths will not
be properly recognized. This is arguably a bug but correcting it
requires some hoop-jumping in routines which have no business
- doing tricks.
+ doing such tricks.
- It is possible to install multiple instances under different
names, each sandboxed from one another inside their own private
@@ -1207,13 +1218,25 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
handles are currently in use, e.g. by an sqlite3 db.
*/
sqlite3.installOpfsSAHPoolVfs = async function(options=Object.create(null)){
- const vfsName = options.name || optionDefaults.name;
- if(0 && 2===++instanceCounter){
- throw new Error("Just testing rejection.");
+ options = Object.assign(Object.create(null), optionDefaults, (options||{}));
+ const vfsName = options.name;
+ if(options.$testThrowPhase1){
+ throw options.$testThrowPhase1;
}
if(initPromises[vfsName]){
- //console.warn("Returning same OpfsSAHPool result",options,vfsName,initPromises[vfsName]);
- return initPromises[vfsName];
+ try {
+ const p = await initPromises[vfsName];
+ //log("installOpfsSAHPoolVfs() returning cached result",options,vfsName,p);
+ return p;
+ }catch(e){
+ //log("installOpfsSAHPoolVfs() got cached failure",options,vfsName,e);
+ if( options.forceReinitIfPreviouslyFailed ){
+ delete initPromises[vfsName];
+ /* Fall through and try again. */
+ }else{
+ throw e;
+ }
+ }
}
if(!globalThis.FileSystemHandle ||
!globalThis.FileSystemDirectoryHandle ||
@@ -1238,8 +1261,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
ensues.
*/
return initPromises[vfsName] = apiVersionCheck().then(async function(){
- if(options.$testThrowInInit){
- throw options.$testThrowInInit;
+ if(options.$testThrowPhase2){
+ throw options.$testThrowPhase2;
}
const thePool = new OpfsSAHPool(options);
return thePool.isReady.then(async()=>{
@@ -1255,18 +1278,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
oo1.DB.dbCtorHelper.call(this, opt);
};
OpfsSAHPoolDb.prototype = Object.create(oo1.DB.prototype);
- // yes or no? OpfsSAHPoolDb.PoolUtil = poolUtil;
poolUtil.OpfsSAHPoolDb = OpfsSAHPoolDb;
- oo1.DB.dbCtorHelper.setVfsPostOpenSql(
- theVfs.pointer,
- function(oo1Db, sqlite3){
- sqlite3.capi.sqlite3_exec(oo1Db, [
- /* See notes in sqlite3-vfs-opfs.js */
- "pragma journal_mode=DELETE;",
- "pragma cache_size=-16384;"
- ], 0, 0, 0);
- }
- );
}/*extend sqlite3.oo1*/
thePool.log("VFS initialized.");
return poolUtil;
diff --git a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js
index fc0fb9db9..2d11b3583 100644
--- a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js
+++ b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js
@@ -443,7 +443,7 @@ const installOpfsVfs = function callee(options){
OPFS_UNLINK_BEFORE_OPEN: 0x02,
/**
If true, any async routine which implicitly acquires a sync
- access handle (i.e. an OPFS lock) will release that locks at
+ access handle (i.e. an OPFS lock) will release that lock at
the end of the call which acquires it. If false, such
"autolocks" are not released until the VFS is idle for some
brief amount of time.
@@ -470,9 +470,22 @@ const installOpfsVfs = function callee(options){
Atomics.notify(state.sabOPView, state.opIds.whichOp)
/* async thread will take over here */;
const t = performance.now();
- Atomics.wait(state.sabOPView, state.opIds.rc, -1)
- /* When this wait() call returns, the async half will have
- completed the operation and reported its results. */;
+ while('not-equal'!==Atomics.wait(state.sabOPView, state.opIds.rc, -1)){
+ /*
+ The reason for this loop is buried in the details of a long
+ discussion at:
+
+ https://github.com/sqlite/sqlite-wasm/issues/12
+
+ Summary: in at least one browser flavor, under high loads,
+ the wait()/notify() pairings can get out of sync. Calling
+ wait() here until it returns 'not-equal' gets them back in
+ sync.
+ */
+ }
+ /* When the above wait() call returns 'not-equal', the async
+ half will have completed the operation and reported its results
+ in the state.opIds.rc slot of the SAB. */
const rc = Atomics.load(state.sabOPView, state.opIds.rc);
metrics[op].wait += performance.now() - t;
if(rc && state.asyncS11nExceptions){
@@ -1275,40 +1288,13 @@ const installOpfsVfs = function callee(options){
OpfsDb.prototype = Object.create(sqlite3.oo1.DB.prototype);
sqlite3.oo1.OpfsDb = OpfsDb;
OpfsDb.importDb = opfsUtil.importDb;
- sqlite3.oo1.DB.dbCtorHelper.setVfsPostOpenSql(
+ sqlite3.oo1.DB.dbCtorHelper.setVfsPostOpenCallback(
opfsVfs.pointer,
function(oo1Db, sqlite3){
/* Set a relatively high default busy-timeout handler to
help OPFS dbs deal with multi-tab/multi-worker
contention. */
sqlite3.capi.sqlite3_busy_timeout(oo1Db, 10000);
- sqlite3.capi.sqlite3_exec(oo1Db, [
- /* As of July 2023, the PERSIST journal mode on OPFS is
- somewhat slower than DELETE or TRUNCATE (it was faster
- before Chrome version 108 or 109). TRUNCATE and DELETE
- have very similar performance on OPFS.
-
- Roy Hashimoto notes that TRUNCATE and PERSIST modes may
- decrease OPFS concurrency because multiple connections
- can open the journal file in those modes:
-
- https://github.com/rhashimoto/wa-sqlite/issues/68
-
- Given that, and the fact that testing has not revealed
- any appreciable difference between performance of
- TRUNCATE and DELETE modes on OPFS, we currently (as of
- 2023-07-13) default to DELETE mode.
- */
- "pragma journal_mode=DELETE;",
- /*
- This vfs benefits hugely from cache on moderate/large
- speedtest1 --size 50 and --size 100 workloads. We
- currently rely on setting a non-default cache size when
- building sqlite3.wasm. If that policy changes, the cache
- can be set here.
- */
- "pragma cache_size=-16384;"
- ], 0, 0, 0);
}
);
}/*extend sqlite3.oo1*/
diff --git a/ext/wasm/api/sqlite3-vtab-helper.c-pp.js b/ext/wasm/api/sqlite3-vtab-helper.c-pp.js
index 7359ea39a..d78fbdbf3 100644
--- a/ext/wasm/api/sqlite3-vtab-helper.c-pp.js
+++ b/ext/wasm/api/sqlite3-vtab-helper.c-pp.js
@@ -11,10 +11,14 @@
/**
This file installs sqlite3.vtab, a namespace of helpers for use in
- the creation of JavaScript implementations virtual tables.
+ the creation of JavaScript implementations virtual tables. If built
+ without virtual table support then this function does nothing.
*/
'use strict';
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
+ if( !sqlite3.wasm.exports.sqlite3_declare_vtab ){
+ return;
+ }
const wasm = sqlite3.wasm, capi = sqlite3.capi, toss = sqlite3.util.toss3;
const vtab = Object.create(null);
sqlite3.vtab = vtab;
diff --git a/ext/wasm/api/sqlite3-wasm.c b/ext/wasm/api/sqlite3-wasm.c
index 48ae2297a..7f7e69689 100644
--- a/ext/wasm/api/sqlite3-wasm.c
+++ b/ext/wasm/api/sqlite3-wasm.c
@@ -104,8 +104,8 @@
#ifndef SQLITE_ENABLE_EXPLAIN_COMMENTS
# define SQLITE_ENABLE_EXPLAIN_COMMENTS 1
#endif
-#ifndef SQLITE_ENABLE_FTS4
-# define SQLITE_ENABLE_FTS4 1
+#ifndef SQLITE_ENABLE_FTS5
+# define SQLITE_ENABLE_FTS5 1
#endif
#ifndef SQLITE_ENABLE_MATH_FUNCTIONS
# define SQLITE_ENABLE_MATH_FUNCTIONS 1
@@ -172,6 +172,48 @@
# define SQLITE_EXTRA_INIT sqlite3_wasm_extra_init
#endif
+/*
+** If SQLITE_WASM_MINIMAL is defined, undefine most of the ENABLE
+** macros.
+*/
+#ifdef SQLITE_WASM_MINIMAL
+# undef SQLITE_ENABLE_DBPAGE_VTAB
+# undef SQLITE_ENABLE_DBSTAT_VTAB
+# undef SQLITE_ENABLE_EXPLAIN_COMMENTS
+# undef SQLITE_ENABLE_FTS5
+# undef SQLITE_ENABLE_OFFSET_SQL_FUNC
+# undef SQLITE_ENABLE_PREUPDATE_HOOK
+# undef SQLITE_ENABLE_RTREE
+# undef SQLITE_ENABLE_SESSION
+# undef SQLITE_ENABLE_STMTVTAB
+# undef SQLITE_OMIT_AUTHORIZATION
+# define SQLITE_OMIT_AUTHORIZATION
+/*Reminder re. custom sqlite3.c:
+
+ fossil clean -x
+ ./configure
+ OPTS='-DSQLITE_OMIT_VIRTUALTABLE -DSQLITE_OMIT_EXPLAIN -DSQLITE_OMIT_TRIGGER' make -e sqlite3
+*/
+/*Requires a custom sqlite3.c
+# undef SQLITE_OMIT_TRIGGER
+# define SQLITE_OMIT_TRIGGER
+*/
+/*TODO (requires build tweaks)
+# undef SQLITE_OMIT_WINDOWFUNC
+# define SQLITE_OMIT_WINDOWFUNC
+*/
+/*Requires a custom sqlite3.c
+# undef SQLITE_OMIT_EXPLAIN
+# define SQLITE_OMIT_EXPLAIN
+*/
+/*Requires a custom sqlite3.c
+# undef SQLITE_OMIT_VIRTUALTABLE
+# define SQLITE_OMIT_VIRTUALTABLE
+*/
+# undef SQLITE_OMIT_JSON
+# define SQLITE_OMIT_JSON
+#endif
+
#include <assert.h>
/*
@@ -499,6 +541,7 @@ const char * sqlite3__wasm_enum_json(void){
} _DefGroup;
DefGroup(changeset){
+#ifdef SQLITE_CHANGESETSTART_INVERT
DefInt(SQLITE_CHANGESETSTART_INVERT);
DefInt(SQLITE_CHANGESETAPPLY_NOSAVEPOINT);
DefInt(SQLITE_CHANGESETAPPLY_INVERT);
@@ -513,6 +556,7 @@ const char * sqlite3__wasm_enum_json(void){
DefInt(SQLITE_CHANGESET_OMIT);
DefInt(SQLITE_CHANGESET_REPLACE);
DefInt(SQLITE_CHANGESET_ABORT);
+#endif
} _DefGroup;
DefGroup(config){
@@ -564,7 +608,6 @@ const char * sqlite3__wasm_enum_json(void){
DefInt(SQLITE_DBCONFIG_LOOKASIDE);
DefInt(SQLITE_DBCONFIG_ENABLE_FKEY);
DefInt(SQLITE_DBCONFIG_ENABLE_TRIGGER);
- DefInt(SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER);
DefInt(SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION);
DefInt(SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE);
DefInt(SQLITE_DBCONFIG_ENABLE_QPSG);
@@ -859,8 +902,10 @@ const char * sqlite3__wasm_enum_json(void){
} _DefGroup;
DefGroup(session){
+#ifdef SQLITE_SESSION_CONFIG_STRMSIZE
DefInt(SQLITE_SESSION_CONFIG_STRMSIZE);
DefInt(SQLITE_SESSION_OBJCONFIG_SIZE);
+#endif
} _DefGroup;
DefGroup(sqlite3Status){
@@ -922,6 +967,7 @@ const char * sqlite3__wasm_enum_json(void){
} _DefGroup;
DefGroup(vtab) {
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_WASM_MINIMAL)
DefInt(SQLITE_INDEX_SCAN_UNIQUE);
DefInt(SQLITE_INDEX_CONSTRAINT_EQ);
DefInt(SQLITE_INDEX_CONSTRAINT_GT);
@@ -949,6 +995,7 @@ const char * sqlite3__wasm_enum_json(void){
DefInt(SQLITE_FAIL);
//DefInt(SQLITE_ABORT); // Also an error code
DefInt(SQLITE_REPLACE);
+#endif /*!SQLITE_OMIT_VIRTUALTABLE*/
} _DefGroup;
#undef DefGroup
@@ -1108,6 +1155,7 @@ const char * sqlite3__wasm_enum_json(void){
} _StructBinder;
#undef CurrentStruct
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_WASM_MINIMAL)
/**
** Workaround: in order to map the various inner structs from
** sqlite3_index_info, we have to uplift those into constructs we
@@ -1184,6 +1232,8 @@ const char * sqlite3__wasm_enum_json(void){
} _StructBinder;
#undef CurrentStruct
+#endif /*!SQLITE_OMIT_VIRTUALTABLE*/
+
#if SQLITE_WASM_TESTS
#define CurrentStruct WasmTestStruct
StructBinder {
@@ -1553,6 +1603,7 @@ sqlite3_kvvfs_methods * sqlite3__wasm_kvvfs_methods(void){
return &sqlite3KvvfsMethods;
}
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_WASM_MINIMAL)
/*
** This function is NOT part of the sqlite3 public API. It is strictly
** for use by the sqlite project's own JS/WASM bindings.
@@ -1575,6 +1626,7 @@ int sqlite3__wasm_vtab_config(sqlite3 *pDb, int op, int arg){
return SQLITE_MISUSE;
}
}
+#endif /*!SQLITE_OMIT_VIRTUALTABLE*/
/*
** This function is NOT part of the sqlite3 public API. It is strictly