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-api1
-rw-r--r--ext/wasm/api/README.md10
-rw-r--r--ext/wasm/api/post-js-header.js6
-rw-r--r--ext/wasm/api/sqlite3-api-glue.js281
-rw-r--r--ext/wasm/api/sqlite3-api-oo1.js5
-rw-r--r--ext/wasm/api/sqlite3-api-prologue.js30
-rw-r--r--ext/wasm/api/sqlite3-api-worker1.js49
-rw-r--r--ext/wasm/api/sqlite3-vfs-helper.c-pp.js103
-rw-r--r--ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js45
-rw-r--r--ext/wasm/api/sqlite3-vfs-opfs.c-pp.js44
-rw-r--r--ext/wasm/api/sqlite3-vtab-helper.c-pp.js (renamed from ext/wasm/api/sqlite3-v-helper.js)307
-rw-r--r--ext/wasm/api/sqlite3-wasm.c155
-rw-r--r--ext/wasm/api/sqlite3-worker1-promiser.c-pp.js25
-rw-r--r--ext/wasm/api/sqlite3-worker1.c-pp.js6
14 files changed, 561 insertions, 506 deletions
diff --git a/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api
index ad2872d83..57cd61eb9 100644
--- a/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api
+++ b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api
@@ -63,6 +63,7 @@ _sqlite3_file_control
_sqlite3_finalize
_sqlite3_free
_sqlite3_get_auxdata
+_sqlite3_get_autocommit
_sqlite3_initialize
_sqlite3_keyword_count
_sqlite3_keyword_name
diff --git a/ext/wasm/api/README.md b/ext/wasm/api/README.md
index eb0f073cf..ebd4aaacb 100644
--- a/ext/wasm/api/README.md
+++ b/ext/wasm/api/README.md
@@ -78,10 +78,12 @@ browser client:
a Promise-based interface into the Worker #1 API. This is
a far user-friendlier way to interface with databases running
in a Worker thread.
-- **`sqlite3-v-helper.js`**\
- Installs `sqlite3.vfs` and `sqlite3.vtab`, namespaces which contain
- helpers for use by downstream code which creates `sqlite3_vfs`
- and `sqlite3_module` implementations.
+- **`sqlite3-vfs-helper.js`**\
+ Installs the `sqlite3.vfs` namespace, which contain helpers for use
+ by downstream code which creates `sqlite3_vfs` implementations.
+- **`sqlite3-vtab-helper.js`**\
+ Installs the `sqlite3.vtab` namespace, which contain helpers for use
+ by downstream code which creates `sqlite3_module` implementations.
- **`sqlite3-vfs-opfs.c-pp.js`**\
is an sqlite3 VFS implementation which supports the Origin-Private
FileSystem (OPFS) as a storage layer to provide persistent storage
diff --git a/ext/wasm/api/post-js-header.js b/ext/wasm/api/post-js-header.js
index 0e27e1fd9..7fd82a7d6 100644
--- a/ext/wasm/api/post-js-header.js
+++ b/ext/wasm/api/post-js-header.js
@@ -19,8 +19,10 @@ Module.postRun.push(function(Module/*the Emscripten-style module object*/){
- sqlite3-api-glue.js => glues previous parts together
- sqlite3-api-oo.js => SQLite3 OO API #1
- sqlite3-api-worker1.js => Worker-based API
- - sqlite3-vfs-helper.js => Internal-use utilities for...
- - sqlite3-vfs-opfs.js => OPFS VFS
+ - sqlite3-vfs-helper.c-pp.js => Utilities for VFS impls
+ - sqlite3-vtab-helper.c-pp.js => Utilities for virtual table impls
+ - sqlite3-vfs-opfs.c-pp.js => OPFS VFS
+ - sqlite3-vfs-opfs-sahpool.c-pp.js => OPFS SAHPool VFS
- sqlite3-api-cleanup.js => final API cleanup
- post-js-footer.js => closes this postRun() function
*/
diff --git a/ext/wasm/api/sqlite3-api-glue.js b/ext/wasm/api/sqlite3-api-glue.js
index 60050461c..2cb4c800d 100644
--- a/ext/wasm/api/sqlite3-api-glue.js
+++ b/ext/wasm/api/sqlite3-api-glue.js
@@ -14,7 +14,8 @@
previous steps of the sqlite3-api.js bootstrapping process:
sqlite3-api-prologue.js, whwasmutil.js, and jaccwabyt.js. It
initializes the main API pieces so that the downstream components
- (e.g. sqlite3-api-oo1.js) have all that they need.
+ (e.g. sqlite3-api-oo1.js) have all of the infrastructure that they
+ need.
*/
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
'use strict';
@@ -188,6 +189,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
["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*"
@@ -328,6 +330,14 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}
if(wasm.exports.sqlite3_activate_see instanceof Function){
+ /**
+ This code is capable of using an SEE build but note that an SEE
+ WASM build is generally incompatible with SEE's license
+ conditions. It is permitted for use internally in organizations
+ which have licensed SEE, but not for public sites because
+ exposing an SEE build of sqlite3.wasm effectively provides all
+ clients with a working copy of the commercial SEE code.
+ */
wasm.bindingSignatures.push(
["sqlite3_key", "int", "sqlite3*", "string", "int"],
["sqlite3_key_v2","int","sqlite3*","string","*","int"],
@@ -340,6 +350,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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,
@@ -358,7 +370,10 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
/* Careful! Short version: de/serialize() are problematic because they
might use a different allocator than the user for managing the
deserialized block. de/serialize() are ONLY safe to use with
- sqlite3_malloc(), sqlite3_free(), and its 64-bit variants. */,
+ sqlite3_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_drop_modules", "int", ["sqlite3*", "**"]],
["sqlite3_last_insert_rowid", "i64", ["sqlite3*"]],
["sqlite3_malloc64", "*","i64"],
@@ -421,8 +436,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
// Add session/changeset APIs...
if(wasm.bigIntEnabled && !!wasm.exports.sqlite3changegroup_add){
- /* ACHTUNG: 2022-12-23: the session/changeset API bindings are
- COMPLETELY UNTESTED. */
/**
FuncPtrAdapter options for session-related callbacks with the
native signature "i(ps)". This proxy converts the 2nd argument
@@ -600,16 +613,21 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
/**
Functions which are intended solely for API-internal use by the
WASM components, not client code. These get installed into
- sqlite3.wasm. Some of them get exposed to clients via variants
- named sqlite3_js_...().
+ 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.wasm = [
- ["sqlite3_wasm_db_reset", "int", "sqlite3*"],
- ["sqlite3_wasm_db_vfs", "sqlite3_vfs*", "sqlite3*","string"],
- ["sqlite3_wasm_vfs_create_file", "int",
+ wasm.bindingSignatures.wasmInternal = [
+ ["sqlite3__wasm_db_reset", "int", "sqlite3*"],
+ ["sqlite3__wasm_db_vfs", "sqlite3_vfs*", "sqlite3*","string"],
+ ["sqlite3__wasm_vfs_create_file", "int",
"sqlite3_vfs*","string","*", "int"],
- ["sqlite3_wasm_posix_create_file", "int", "string","*", "int"],
- ["sqlite3_wasm_vfs_unlink", "int", "sqlite3_vfs*","string"]
+ ["sqlite3__wasm_posix_create_file", "int", "string","*", "int"],
+ ["sqlite3__wasm_vfs_unlink", "int", "sqlite3_vfs*","string"]
];
/**
@@ -651,7 +669,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
Use case: sqlite3_bind_pointer() and sqlite3_result_pointer()
call for "a static string and preferably a string
- literal". This converter is used to ensure that the string
+ literal." This converter is used to ensure that the string
value seen by those functions is long-lived and behaves as they
need it to.
*/
@@ -673,14 +691,15 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
`sqlite3_vfs*` via capi.sqlite3_vfs.pointer.
*/
const __xArgPtr = wasm.xWrap.argAdapter('*');
- const nilType = function(){}/*a class no value can ever be an instance of*/;
+ const nilType = function(){
+ /*a class which no value can ever be an instance of*/
+ };
wasm.xWrap.argAdapter('sqlite3_filename', __xArgPtr)
('sqlite3_context*', __xArgPtr)
('sqlite3_value*', __xArgPtr)
('void*', __xArgPtr)
('sqlite3_changegroup*', __xArgPtr)
('sqlite3_changeset_iter*', __xArgPtr)
- //('sqlite3_rebaser*', __xArgPtr)
('sqlite3_session*', __xArgPtr)
('sqlite3_stmt*', (v)=>
__xArgPtr((v instanceof (sqlite3?.oo1?.Stmt || nilType))
@@ -741,8 +760,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
for(const e of wasm.bindingSignatures){
capi[e[0]] = wasm.xWrap.apply(null, e);
}
- for(const e of wasm.bindingSignatures.wasm){
- wasm[e[0]] = wasm.xWrap.apply(null, e);
+ for(const e of wasm.bindingSignatures.wasmInternal){
+ util[e[0]] = wasm.xWrap.apply(null, e);
}
/* For C API functions which cannot work properly unless
@@ -764,9 +783,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
implicitly making it part of the public interface. */
delete wasm.bindingSignatures;
- if(wasm.exports.sqlite3_wasm_db_error){
+ if(wasm.exports.sqlite3__wasm_db_error){
const __db_err = wasm.xWrap(
- 'sqlite3_wasm_db_error', 'int', 'sqlite3*', 'int', 'string'
+ 'sqlite3__wasm_db_error', 'int', 'sqlite3*', 'int', 'string'
);
/**
Sets the given db's error state. Accepts:
@@ -784,7 +803,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
Returns the resulting code. Pass (pDb,0,0) to clear the error
state.
*/
- util.sqlite3_wasm_db_error = function(pDb, resultCode, message){
+ util.sqlite3__wasm_db_error = function(pDb, resultCode, message){
if(resultCode instanceof sqlite3.WasmAllocError){
resultCode = capi.SQLITE_NOMEM;
message = 0 /*avoid allocating message string*/;
@@ -795,17 +814,17 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
return pDb ? __db_err(pDb, resultCode, message) : resultCode;
};
}else{
- util.sqlite3_wasm_db_error = function(pDb,errCode,msg){
- console.warn("sqlite3_wasm_db_error() is not exported.",arguments);
+ util.sqlite3__wasm_db_error = function(pDb,errCode,msg){
+ console.warn("sqlite3__wasm_db_error() is not exported.",arguments);
return errCode;
};
}
}/*xWrap() bindings*/
{/* Import C-level constants and structs... */
- const cJson = wasm.xCall('sqlite3_wasm_enum_json');
+ const cJson = wasm.xCall('sqlite3__wasm_enum_json');
if(!cJson){
- toss("Maintenance required: increase sqlite3_wasm_enum_json()'s",
+ toss("Maintenance required: increase sqlite3__wasm_enum_json()'s",
"static buffer size!");
}
//console.debug('wasm.ctype length =',wasm.cstrlen(cJson));
@@ -876,7 +895,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
delete capi[k];
}
capi.sqlite3_vtab_config = wasm.xWrap(
- 'sqlite3_wasm_vtab_config','int',[
+ 'sqlite3__wasm_vtab_config','int',[
'sqlite3*', 'int', 'int']
);
}/* end vtab-related setup */
@@ -888,16 +907,16 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
consistency with non-special-case wrappings.
*/
const __dbArgcMismatch = (pDb,f,n)=>{
- return sqlite3.util.sqlite3_wasm_db_error(pDb, capi.SQLITE_MISUSE,
- f+"() requires "+n+" argument"+
- (1===n?"":'s')+".");
+ return util.sqlite3__wasm_db_error(pDb, capi.SQLITE_MISUSE,
+ f+"() requires "+n+" argument"+
+ (1===n?"":'s')+".");
};
/** Code duplication reducer for functions which take an encoding
argument and require SQLITE_UTF8. Sets the db error code to
SQLITE_FORMAT and returns that code. */
const __errEncoding = (pDb)=>{
- return util.sqlite3_wasm_db_error(
+ return util.sqlite3__wasm_db_error(
pDb, capi.SQLITE_FORMAT, "SQLITE_UTF8 is the only supported encoding."
);
};
@@ -1127,7 +1146,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}
return rc;
}catch(e){
- return util.sqlite3_wasm_db_error(pDb, e);
+ return util.sqlite3__wasm_db_error(pDb, e);
}
};
@@ -1253,7 +1272,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
return rc;
}catch(e){
console.error("sqlite3_create_function_v2() setup threw:",e);
- return util.sqlite3_wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
+ return util.sqlite3__wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
}
};
@@ -1298,7 +1317,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
return rc;
}catch(e){
console.error("sqlite3_create_window_function() setup threw:",e);
- return util.sqlite3_wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
+ return util.sqlite3__wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
}
};
/**
@@ -1393,7 +1412,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
case 'string': return __prepare.basic(pDb, xSql, xSqlLen, prepFlags, ppStmt, null);
case 'number': return __prepare.full(pDb, xSql, xSqlLen, prepFlags, ppStmt, pzTail);
default:
- return util.sqlite3_wasm_db_error(
+ return util.sqlite3__wasm_db_error(
pDb, capi.SQLITE_MISUSE,
"Invalid SQL argument type for sqlite3_prepare_v2/v3()."
);
@@ -1437,7 +1456,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}else if('string'===typeof text){
[p, n] = wasm.allocCString(text);
}else{
- return util.sqlite3_wasm_db_error(
+ return util.sqlite3__wasm_db_error(
capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE,
"Invalid 3rd argument type for sqlite3_bind_text()."
);
@@ -1445,7 +1464,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
return __bindText(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC);
}catch(e){
wasm.dealloc(p);
- return util.sqlite3_wasm_db_error(
+ return util.sqlite3__wasm_db_error(
capi.sqlite3_db_handle(pStmt), e
);
}
@@ -1471,7 +1490,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}else if('string'===typeof pMem){
[p, n] = wasm.allocCString(pMem);
}else{
- return util.sqlite3_wasm_db_error(
+ return util.sqlite3__wasm_db_error(
capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE,
"Invalid 3rd argument type for sqlite3_bind_blob()."
);
@@ -1479,7 +1498,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
return __bindBlob(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC);
}catch(e){
wasm.dealloc(p);
- return util.sqlite3_wasm_db_error(
+ return util.sqlite3__wasm_db_error(
capi.sqlite3_db_handle(pStmt), e
);
}
@@ -1503,11 +1522,11 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
case capi.SQLITE_CONFIG_SORTERREF_SIZE: // 28 /* int nByte */
case capi.SQLITE_CONFIG_STMTJRNL_SPILL: // 26 /* int nByte */
case capi.SQLITE_CONFIG_URI:// 17 /* int */
- return wasm.exports.sqlite3_wasm_config_i(op, args[0]);
+ return wasm.exports.sqlite3__wasm_config_i(op, args[0]);
case capi.SQLITE_CONFIG_LOOKASIDE: // 13 /* int int */
- return wasm.exports.sqlite3_wasm_config_ii(op, args[0], args[1]);
+ return wasm.exports.sqlite3__wasm_config_ii(op, args[0], args[1]);
case capi.SQLITE_CONFIG_MEMDB_MAXSIZE: // 29 /* sqlite3_int64 */
- return wasm.exports.sqlite3_wasm_config_j(op, args[0]);
+ return wasm.exports.sqlite3__wasm_config_j(op, args[0]);
case capi.SQLITE_CONFIG_GETMALLOC: // 5 /* sqlite3_mem_methods* */
case capi.SQLITE_CONFIG_GETMUTEX: // 11 /* sqlite3_mutex_methods* */
case capi.SQLITE_CONFIG_GETPCACHE2: // 19 /* sqlite3_pcache_methods2* */
@@ -1573,11 +1592,11 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
if( pKvvfs ){/* kvvfs-specific glue */
if(util.isUIThread()){
const kvvfsMethods = new capi.sqlite3_kvvfs_methods(
- wasm.exports.sqlite3_wasm_kvvfs_methods()
+ wasm.exports.sqlite3__wasm_kvvfs_methods()
);
delete capi.sqlite3_kvvfs_methods;
- const kvvfsMakeKey = wasm.exports.sqlite3_wasm_kvvfsMakeKeyOnPstack,
+ const kvvfsMakeKey = wasm.exports.sqlite3__wasm_kvvfsMakeKeyOnPstack,
pstack = wasm.pstack;
const kvvfsStorage = (zClass)=>
@@ -1586,7 +1605,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
/**
Implementations for members of the object referred to by
- sqlite3_wasm_kvvfs_methods(). We swap out the native
+ sqlite3__wasm_kvvfs_methods(). We swap out the native
implementations with these, which use localStorage or
sessionStorage for their backing store.
*/
@@ -1666,5 +1685,181 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}
}/*pKvvfs*/
+ /* Warn if client-level code makes use of FuncPtrAdapter. */
wasm.xWrap.FuncPtrAdapter.warnOnUse = true;
+
+ const StructBinder = sqlite3.StructBinder
+ /* we require a local alias b/c StructBinder is removed from the sqlite3
+ object during the final steps of the API cleanup. */;
+ /**
+ Installs a StructBinder-bound function pointer member of the
+ given name and function in the given StructBinder.StructType
+ target object.
+
+ It creates a WASM proxy for the given function and arranges for
+ that proxy to be cleaned up when tgt.dispose() is called. Throws
+ on the slightest hint of error, e.g. tgt is-not-a StructType,
+ name does not map to a struct-bound member, etc.
+
+ As a special case, if the given function is a pointer, then
+ `wasm.functionEntry()` is used to validate that it is a known
+ function. If so, it is used as-is with no extra level of proxying
+ or cleanup, else an exception is thrown. It is legal to pass a
+ value of 0, indicating a NULL pointer, with the caveat that 0
+ _is_ a legal function pointer in WASM but it will not be accepted
+ as such _here_. (Justification: the function at address zero must
+ be one which initially came from the WASM module, not a method we
+ want to bind to a virtual table or VFS.)
+
+ This function returns a proxy for itself which is bound to tgt
+ and takes 2 args (name,func). That function returns the same
+ thing as this one, permitting calls to be chained.
+
+ If called with only 1 arg, it has no side effects but returns a
+ func with the same signature as described above.
+
+ ACHTUNG: because we cannot generically know how to transform JS
+ exceptions into result codes, the installed functions do no
+ automatic catching of exceptions. It is critical, to avoid
+ undefined behavior in the C layer, that methods mapped via
+ this function do not throw. The exception, as it were, to that
+ rule is...
+
+ If applyArgcCheck is true then each JS function (as opposed to
+ function pointers) gets wrapped in a proxy which asserts that it
+ is passed the expected number of arguments, throwing if the
+ argument count does not match expectations. That is only intended
+ for dev-time usage for sanity checking, and may leave the C
+ environment in an undefined state.
+ */
+ const installMethod = function callee(
+ tgt, name, func, applyArgcCheck = callee.installMethodArgcCheck
+ ){
+ if(!(tgt instanceof StructBinder.StructType)){
+ toss("Usage error: target object is-not-a StructType.");
+ }else if(!(func instanceof Function) && !wasm.isPtr(func)){
+ toss("Usage errror: expecting a Function or WASM pointer to one.");
+ }
+ if(1===arguments.length){
+ return (n,f)=>callee(tgt, n, f, applyArgcCheck);
+ }
+ if(!callee.argcProxy){
+ callee.argcProxy = function(tgt, funcName, func,sig){
+ return function(...args){
+ if(func.length!==arguments.length){
+ toss("Argument mismatch for",
+ tgt.structInfo.name+"::"+funcName
+ +": Native signature is:",sig);
+ }
+ return func.apply(this, args);
+ }
+ };
+ /* An ondispose() callback for use with
+ StructBinder-created types. */
+ callee.removeFuncList = function(){
+ if(this.ondispose.__removeFuncList){
+ this.ondispose.__removeFuncList.forEach(
+ (v,ndx)=>{
+ if('number'===typeof v){
+ try{wasm.uninstallFunction(v)}
+ catch(e){/*ignore*/}
+ }
+ /* else it's a descriptive label for the next number in
+ the list. */
+ }
+ );
+ delete this.ondispose.__removeFuncList;
+ }
+ };
+ }/*static init*/
+ const sigN = tgt.memberSignature(name);
+ if(sigN.length<2){
+ toss("Member",name,"does not have a function pointer signature:",sigN);
+ }
+ const memKey = tgt.memberKey(name);
+ const fProxy = (applyArgcCheck && !wasm.isPtr(func))
+ /** This middle-man proxy is only for use during development, to
+ confirm that we always pass the proper number of
+ arguments. We know that the C-level code will always use the
+ correct argument count. */
+ ? callee.argcProxy(tgt, memKey, func, sigN)
+ : func;
+ if(wasm.isPtr(fProxy)){
+ if(fProxy && !wasm.functionEntry(fProxy)){
+ toss("Pointer",fProxy,"is not a WASM function table entry.");
+ }
+ tgt[memKey] = fProxy;
+ }else{
+ const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true));
+ tgt[memKey] = pFunc;
+ if(!tgt.ondispose || !tgt.ondispose.__removeFuncList){
+ tgt.addOnDispose('ondispose.__removeFuncList handler',
+ callee.removeFuncList);
+ tgt.ondispose.__removeFuncList = [];
+ }
+ tgt.ondispose.__removeFuncList.push(memKey, pFunc);
+ }
+ return (n,f)=>callee(tgt, n, f, applyArgcCheck);
+ }/*installMethod*/;
+ installMethod.installMethodArgcCheck = false;
+
+ /**
+ Installs methods into the given StructBinder.StructType-type
+ instance. Each entry in the given methods object must map to a
+ known member of the given StructType, else an exception will be
+ triggered. See installMethod() for more details, including the
+ semantics of the 3rd argument.
+
+ As an exception to the above, if any two or more methods in the
+ 2nd argument are the exact same function, installMethod() is
+ _not_ called for the 2nd and subsequent instances, and instead
+ those instances get assigned the same method pointer which is
+ created for the first instance. This optimization is primarily to
+ accommodate special handling of sqlite3_module::xConnect and
+ xCreate methods.
+
+ On success, returns its first argument. Throws on error.
+ */
+ const installMethods = function(
+ structInstance, methods, applyArgcCheck = installMethod.installMethodArgcCheck
+ ){
+ const seen = new Map /* map of <Function, memberName> */;
+ for(const k of Object.keys(methods)){
+ const m = methods[k];
+ const prior = seen.get(m);
+ if(prior){
+ const mkey = structInstance.memberKey(k);
+ structInstance[mkey] = structInstance[structInstance.memberKey(prior)];
+ }else{
+ installMethod(structInstance, k, m, applyArgcCheck);
+ seen.set(m, k);
+ }
+ }
+ return structInstance;
+ };
+
+ /**
+ Equivalent to calling installMethod(this,...arguments) with a
+ first argument of this object. If called with 1 or 2 arguments
+ and the first is an object, it's instead equivalent to calling
+ installMethods(this,...arguments).
+ */
+ StructBinder.StructType.prototype.installMethod = function callee(
+ name, func, applyArgcCheck = installMethod.installMethodArgcCheck
+ ){
+ return (arguments.length < 3 && name && 'object'===typeof name)
+ ? installMethods(this, ...arguments)
+ : installMethod(this, ...arguments);
+ };
+
+ /**
+ Equivalent to calling installMethods() with a first argument
+ of this object.
+ */
+ StructBinder.StructType.prototype.installMethods = function(
+ methods, applyArgcCheck = installMethod.installMethodArgcCheck
+ ){
+ return installMethods(this, methods, applyArgcCheck);
+ };
+
});
diff --git a/ext/wasm/api/sqlite3-api-oo1.js b/ext/wasm/api/sqlite3-api-oo1.js
index 4677b8976..160d59db5 100644
--- a/ext/wasm/api/sqlite3-api-oo1.js
+++ b/ext/wasm/api/sqlite3-api-oo1.js
@@ -1,3 +1,4 @@
+//#ifnot omit-oo1
/*
2022-07-22
@@ -1940,4 +1941,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}/*main-window-only bits*/
});
-
+//#else
+/* Built with the omit-oo1 flag. */
+//#endif ifnot omit-oo1
diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js
index ef1154f6b..c784b6990 100644
--- a/ext/wasm/api/sqlite3-api-prologue.js
+++ b/ext/wasm/api/sqlite3-api-prologue.js
@@ -1061,7 +1061,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
are undefined if the passed-in value did not come from
this.pointer.
*/
- restore: wasm.exports.sqlite3_wasm_pstack_restore,
+ restore: wasm.exports.sqlite3__wasm_pstack_restore,
/**
Attempts to allocate the given number of bytes from the
pstack. On success, it zeroes out a block of memory of the
@@ -1083,7 +1083,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
if('string'===typeof n && !(n = wasm.sizeofIR(n))){
WasmAllocError.toss("Invalid value for pstack.alloc(",arguments[0],")");
}
- return wasm.exports.sqlite3_wasm_pstack_alloc(n)
+ return wasm.exports.sqlite3__wasm_pstack_alloc(n)
|| WasmAllocError.toss("Could not allocate",n,
"bytes from the pstack.");
},
@@ -1163,10 +1163,10 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
*/
pointer: {
configurable: false, iterable: true, writeable: false,
- get: wasm.exports.sqlite3_wasm_pstack_ptr
+ get: wasm.exports.sqlite3__wasm_pstack_ptr
//Whether or not a setter as an alternative to restore() is
//clearer or would just lead to confusion is unclear.
- //set: wasm.exports.sqlite3_wasm_pstack_restore
+ //set: wasm.exports.sqlite3__wasm_pstack_restore
},
/**
sqlite3.wasm.pstack.quota to the total number of bytes
@@ -1175,7 +1175,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
*/
quota: {
configurable: false, iterable: true, writeable: false,
- get: wasm.exports.sqlite3_wasm_pstack_quota
+ get: wasm.exports.sqlite3__wasm_pstack_quota
},
/**
sqlite3.wasm.pstack.remaining resolves to the amount of space
@@ -1183,7 +1183,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
*/
remaining: {
configurable: false, iterable: true, writeable: false,
- get: wasm.exports.sqlite3_wasm_pstack_remaining
+ get: wasm.exports.sqlite3__wasm_pstack_remaining
}
})/*wasm.pstack properties*/;
@@ -1256,14 +1256,14 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
}
try{
if(pdir && 0===wasm.xCallWrapped(
- 'sqlite3_wasm_init_wasmfs', 'i32', ['string'], pdir
+ 'sqlite3__wasm_init_wasmfs', 'i32', ['string'], pdir
)){
return __wasmfsOpfsDir = pdir;
}else{
return __wasmfsOpfsDir = "";
}
}catch(e){
- // sqlite3_wasm_init_wasmfs() is not available
+ // sqlite3__wasm_init_wasmfs() is not available
return __wasmfsOpfsDir = "";
}
};
@@ -1365,7 +1365,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
const zSchema = schema
? (wasm.isPtr(schema) ? schema : wasm.scopedAllocCString(''+schema))
: 0;
- let rc = wasm.exports.sqlite3_wasm_db_serialize(
+ let rc = wasm.exports.sqlite3__wasm_db_serialize(
pDb, zSchema, ppOut, pSize, 0
);
if(rc){
@@ -1391,7 +1391,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
or not provided, then "main" is assumed.
*/
capi.sqlite3_js_db_vfs =
- (dbPointer, dbName=0)=>wasm.sqlite3_wasm_db_vfs(dbPointer, dbName);
+ (dbPointer, dbName=0)=>util.sqlite3__wasm_db_vfs(dbPointer, dbName);
/**
A thin wrapper around capi.sqlite3_aggregate_context() which
@@ -1449,7 +1449,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
if(!util.isInt32(dataLen) || dataLen<0){
SQLite3Error.toss("Invalid 3rd argument for sqlite3_js_posix_create_file().");
}
- const rc = wasm.sqlite3_wasm_posix_create_file(filename, pData, dataLen);
+ const rc = util.sqlite3__wasm_posix_create_file(filename, pData, dataLen);
if(rc) SQLite3Error.toss("Creation of file failed with sqlite3 result code",
capi.sqlite3_js_rc_str(rc));
}finally{
@@ -1551,7 +1551,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
SQLite3Error.toss("Invalid 4th argument for sqlite3_js_vfs_create_file().");
}
try{
- const rc = wasm.sqlite3_wasm_vfs_create_file(vfs, filename, pData, dataLen);
+ const rc = util.sqlite3__wasm_vfs_create_file(vfs, filename, pData, dataLen);
if(rc) SQLite3Error.toss("Creation of file failed with sqlite3 result code",
capi.sqlite3_js_rc_str(rc));
}finally{
@@ -1672,12 +1672,12 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
*/
capi.sqlite3_db_config = function(pDb, op, ...args){
if(!this.s){
- this.s = wasm.xWrap('sqlite3_wasm_db_config_s','int',
+ this.s = wasm.xWrap('sqlite3__wasm_db_config_s','int',
['sqlite3*', 'int', 'string:static']
/* MAINDBNAME requires a static string */);
- this.pii = wasm.xWrap('sqlite3_wasm_db_config_pii', 'int',
+ this.pii = wasm.xWrap('sqlite3__wasm_db_config_pii', 'int',
['sqlite3*', 'int', '*','int', 'int']);
- this.ip = wasm.xWrap('sqlite3_wasm_db_config_ip','int',
+ this.ip = wasm.xWrap('sqlite3__wasm_db_config_ip','int',
['sqlite3*', 'int', 'int','*']);
}
switch(op){
diff --git a/ext/wasm/api/sqlite3-api-worker1.js b/ext/wasm/api/sqlite3-api-worker1.js
index 9a386c13e..bd99f3ec8 100644
--- a/ext/wasm/api/sqlite3-api-worker1.js
+++ b/ext/wasm/api/sqlite3-api-worker1.js
@@ -1,3 +1,4 @@
+//#ifnot omit-oo1
/**
2022-07-22
@@ -62,7 +63,7 @@
```
{
- type: string, // one of: 'open', 'close', 'exec', 'config-get'
+ type: string, // one of: 'open', 'close', 'exec', 'export', 'config-get'
messageId: OPTIONAL arbitrary value. The worker will copy it as-is
into response messages to assist in client-side dispatching.
@@ -325,15 +326,46 @@
passed only a string), noting that options.resultRows and
options.columnNames may be populated by the call to db.exec().
+
+ ====================================================================
+ "export" the current db
+
+ To export the underlying database as a byte array...
+
+ Message format:
+
+ ```
+ {
+ type: "export",
+ messageId: ...as above...,
+ dbId: ...as above...
+ }
+ ```
+
+ Response:
+
+ ```
+ {
+ type: "export",
+ messageId: ...as above...,
+ dbId: ...as above...
+ result: {
+ byteArray: Uint8Array (as per sqlite3_js_db_export()),
+ filename: the db filename,
+ mimetype: "application/x-sqlite3"
+ }
+ }
+ ```
+
*/
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
+const util = sqlite3.util;
sqlite3.initWorker1API = function(){
'use strict';
const toss = (...args)=>{throw new Error(args.join(' '))};
if(!(globalThis.WorkerGlobalScope instanceof Function)){
toss("initWorker1API() must be run from a Worker thread.");
}
- const self = this.self;
const sqlite3 = this.sqlite3 || toss("Missing this.sqlite3 object.");
const DB = sqlite3.oo1.DB;
@@ -378,12 +410,12 @@ sqlite3.initWorker1API = function(){
if(db){
delete this.dbs[getDbId(db)];
const filename = db.filename;
- const pVfs = sqlite3.wasm.sqlite3_wasm_db_vfs(db.pointer, 0);
+ const pVfs = util.sqlite3__wasm_db_vfs(db.pointer, 0);
db.close();
const ddNdx = this.dbList.indexOf(db);
if(ddNdx>=0) this.dbList.splice(ddNdx, 1);
if(alsoUnlink && filename && pVfs){
- sqlite3.wasm.sqlite3_wasm_vfs_unlink(pVfs, filename);
+ util.sqlite3__wasm_vfs_unlink(pVfs, filename);
}
}
},
@@ -464,12 +496,12 @@ sqlite3.initWorker1API = function(){
}
if(pVfs){
/* 2022-11-02: this feature is as-yet untested except that
- sqlite3_wasm_vfs_create_file() has been tested from the
+ sqlite3__wasm_vfs_create_file() has been tested from the
browser dev console. */
let pMem;
try{
pMem = sqlite3.wasm.allocFromTypedArray(byteArray);
- const rc = sqlite3.wasm.sqlite3_wasm_vfs_create_file(
+ const rc = util.sqlite3__wasm_vfs_create_file(
pVfs, oargs.filename, pMem, byteArray.byteLength
);
if(rc) sqlite3.SQLite3Error.toss(rc);
@@ -657,5 +689,8 @@ sqlite3.initWorker1API = function(){
}, wState.xfer);
};
globalThis.postMessage({type:'sqlite3-api',result:'worker1-ready'});
-}.bind({self, sqlite3});
+}.bind({sqlite3});
});
+//#else
+/* Built with the omit-oo1 flag. */
+//#endif ifnot omit-oo1
diff --git a/ext/wasm/api/sqlite3-vfs-helper.c-pp.js b/ext/wasm/api/sqlite3-vfs-helper.c-pp.js
new file mode 100644
index 000000000..4d29c7b91
--- /dev/null
+++ b/ext/wasm/api/sqlite3-vfs-helper.c-pp.js
@@ -0,0 +1,103 @@
+/*
+** 2022-11-30
+**
+** The author disclaims copyright to this source code. In place of a
+** legal notice, here is a blessing:
+**
+** * May you do good and not evil.
+** * May you find forgiveness for yourself and forgive others.
+** * May you share freely, never taking more than you give.
+*/
+
+/**
+ This file installs sqlite3.vfs, a namespace of helpers for use in
+ the creation of JavaScript implementations of sqlite3_vfs.
+*/
+'use strict';
+globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
+ const wasm = sqlite3.wasm, capi = sqlite3.capi, toss = sqlite3.util.toss3;
+ const vfs = Object.create(null);
+ sqlite3.vfs = vfs;
+
+ /**
+ Uses sqlite3_vfs_register() to register this
+ sqlite3.capi.sqlite3_vfs instance. This object must have already
+ been filled out properly. If the first argument is truthy, the
+ VFS is registered as the default VFS, else it is not.
+
+ On success, returns this object. Throws on error.
+ */
+ capi.sqlite3_vfs.prototype.registerVfs = function(asDefault=false){
+ if(!(this instanceof sqlite3.capi.sqlite3_vfs)){
+ toss("Expecting a sqlite3_vfs-type argument.");
+ }
+ const rc = capi.sqlite3_vfs_register(this, asDefault ? 1 : 0);
+ if(rc){
+ toss("sqlite3_vfs_register(",this,") failed with rc",rc);
+ }
+ if(this.pointer !== capi.sqlite3_vfs_find(this.$zName)){
+ toss("BUG: sqlite3_vfs_find(vfs.$zName) failed for just-installed VFS",
+ this);
+ }
+ return this;
+ };
+
+ /**
+ A wrapper for
+ sqlite3.StructBinder.StructType.prototype.installMethods() or
+ registerVfs() to reduce installation of a VFS and/or its I/O
+ methods to a single call.
+
+ Accepts an object which contains the properties "io" and/or
+ "vfs", each of which is itself an object with following properties:
+
+ - `struct`: an sqlite3.StructBinder.StructType-type struct. This
+ must be a populated (except for the methods) object of type
+ sqlite3_io_methods (for the "io" entry) or sqlite3_vfs (for the
+ "vfs" entry).
+
+ - `methods`: an object mapping sqlite3_io_methods method names
+ (e.g. 'xClose') to JS implementations of those methods. The JS
+ implementations must be call-compatible with their native
+ counterparts.
+
+ For each of those object, this function passes its (`struct`,
+ `methods`, (optional) `applyArgcCheck`) properties to
+ installMethods().
+
+ If the `vfs` entry is set then:
+
+ - Its `struct` property's registerVfs() is called. The
+ `vfs` entry may optionally have an `asDefault` property, which
+ gets passed as the argument to registerVfs().
+
+ - If `struct.$zName` is falsy and the entry has a string-type
+ `name` property, `struct.$zName` is set to the C-string form of
+ that `name` value before registerVfs() is called. That string
+ gets added to the on-dispose state of the struct.
+
+ On success returns this object. Throws on error.
+ */
+ vfs.installVfs = function(opt){
+ let count = 0;
+ const propList = ['io','vfs'];
+ for(const key of propList){
+ const o = opt[key];
+ if(o){
+ ++count;
+ o.struct.installMethods(o.methods, !!o.applyArgcCheck);
+ if('vfs'===key){
+ if(!o.struct.$zName && 'string'===typeof o.name){
+ o.struct.addOnDispose(
+ o.struct.$zName = wasm.allocCString(o.name)
+ );
+ }
+ o.struct.registerVfs(!!o.asDefault);
+ }
+ }
+ }
+ if(!count) toss("Misuse: installVfs() options object requires at least",
+ "one of:", propList);
+ return this;
+ };
+}/*sqlite3ApiBootstrap.initializers.push()*/);
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 327b6a95a..f3664fd4b 100644
--- a/ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js
+++ b/ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js
@@ -155,8 +155,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
pool.deletePath(file.path);
}
}catch(e){
- pool.storeErr(e);
- return capi.SQLITE_IOERR;
+ return pool.storeErr(e, capi.SQLITE_IOERR);
}
}
return 0;
@@ -200,8 +199,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}
return 0;
}catch(e){
- pool.storeErr(e);
- return capi.SQLITE_IOERR;
+ return pool.storeErr(e, capi.SQLITE_IOERR);
}
},
xSectorSize: function(pFile){
@@ -217,8 +215,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
file.sah.flush();
return 0;
}catch(e){
- pool.storeErr(e);
- return capi.SQLITE_IOERR;
+ return pool.storeErr(e, capi.SQLITE_IOERR);
}
},
xTruncate: function(pFile,sz64){
@@ -231,8 +228,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
file.sah.truncate(HEADER_OFFSET_DATA + Number(sz64));
return 0;
}catch(e){
- pool.storeErr(e);
- return capi.SQLITE_IOERR;
+ return pool.storeErr(e, capi.SQLITE_IOERR);
}
},
xUnlock: function(pFile,lockType){
@@ -252,10 +248,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
wasm.heap8u().subarray(pSrc, pSrc+n),
{ at: HEADER_OFFSET_DATA + Number(offset64) }
);
- return nBytes === n ? 0 : capi.SQLITE_IOERR;
+ return n===nBytes ? 0 : toss("Unknown write() failure.");
}catch(e){
- pool.storeErr(e);
- return capi.SQLITE_IOERR;
+ return pool.storeErr(e, capi.SQLITE_IOERR);
}
}
}/*ioMethods*/;
@@ -314,8 +309,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
},
xGetLastError: function(pVfs,nOut,pOut){
const pool = getPoolForVfs(pVfs);
- pool.log(`xGetLastError ${nOut}`);
const e = pool.popErr();
+ pool.log(`xGetLastError ${nOut} e =`,e);
if(e){
const scope = wasm.scopedAllocPush();
try{
@@ -328,7 +323,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
wasm.scopedAllocPop(scope);
}
}
- return 0;
+ return e ? (e.sqlite3Rc || capi.SQLITE_IOERR) : 0;
},
//xSleep is optionally defined below
xOpen: function f(pVfs, zName, pFile, flags, pOutFlags){
@@ -762,12 +757,20 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}
/**
- Sets e as this object's current error. Pass a falsy
- (or no) value to clear it.
+ Sets e (an Error object) as this object's current error. Pass a
+ falsy (or no) value to clear it. If code is truthy it is
+ assumed to be an SQLITE_xxx result code, defaulting to
+ SQLITE_IOERR if code is falsy.
+
+ Returns the 2nd argument.
*/
- storeErr(e){
- if(e) this.error(e);
- return this.$error = e;
+ storeErr(e,code){
+ if(e){
+ e.sqlite3Rc = code || capi.SQLITE_IOERR;
+ this.error(e);
+ }
+ this.$error = e;
+ return code;
}
/**
Pops this object's Error object and returns
@@ -900,6 +903,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}/*force db out of WAL mode*/);
}catch(e){
this.setAssociatedPath(sah, '', 0);
+ throw e;
}
this.setAssociatedPath(sah, name, capi.SQLITE_OPEN_MAIN_DB);
return nWrote;
@@ -1133,8 +1137,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
existing content. Throws if the pool has no available file slots,
on I/O error, or if the input does not appear to be a
database. In the latter case, only a cursory examination is made.
- Note that this routine is _only_ for importing database files,
- not arbitrary files, the reason being that this VFS will
+ Results are undefined if the given db name refers to an opened
+ db. Note that this routine is _only_ for importing database
+ files, not arbitrary files, the reason being that this VFS will
automatically clean up any non-database files so importing them
is pointless.
diff --git a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js
index af89f216f..f7fd951a4 100644
--- a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js
+++ b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js
@@ -245,7 +245,8 @@ const installOpfsVfs = function callee(options){
opfsIoMethods.$iVersion = 1;
opfsVfs.$iVersion = 2/*yes, two*/;
opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof;
- opfsVfs.$mxPathname = 1024/*sure, why not?*/;
+ opfsVfs.$mxPathname = 1024/* sure, why not? The OPFS name length limit
+ is undocumented/unspecified. */;
opfsVfs.$zName = wasm.allocCString("opfs");
// All C-side memory of opfsVfs is zeroed out, but just to be explicit:
opfsVfs.$xDlOpen = opfsVfs.$xDlError = opfsVfs.$xDlSym = opfsVfs.$xDlClose = null;
@@ -994,27 +995,6 @@ const installOpfsVfs = function callee(options){
opfsUtil.randomFilename = randomFilename;
/**
- Re-registers the OPFS VFS. This is intended only for odd use
- cases which have to call sqlite3_shutdown() as part of their
- initialization process, which will unregister the VFS
- registered by installOpfsVfs(). If passed a truthy value, the
- OPFS VFS is registered as the default VFS, else it is not made
- the default. Returns the result of the the
- sqlite3_vfs_register() call.
-
- Design note: the problem of having to re-register things after
- a shutdown/initialize pair is more general. How to best plug
- that in to the library is unclear. In particular, we cannot
- hook in to any C-side calls to sqlite3_initialize(), so we
- cannot add an after-initialize callback mechanism.
- */
- opfsUtil.registerVfs = (asDefault=false)=>{
- return wasm.exports.sqlite3_vfs_register(
- opfsVfs.pointer, asDefault ? 1 : 0
- );
- };
-
- /**
Returns a promise which resolves to an object which represents
all files and directories in the OPFS tree. The top-most object
has two properties: `dirs` is an array of directory entries
@@ -1213,16 +1193,18 @@ const installOpfsVfs = function callee(options){
Asynchronously imports the given bytes (a byte array or
ArrayBuffer) into the given database file.
+ Results are undefined if the given db name refers to an opened
+ db.
+
If passed a function for its second argument, its behaviour
- changes to async and it imports its data in chunks fed to it by
- the given callback function. It calls the callback (which may
- be async) repeatedly, expecting either a Uint8Array or
- ArrayBuffer (to denote new input) or undefined (to denote
- EOF). For so long as the callback continues to return
- non-undefined, it will append incoming data to the given
- VFS-hosted database file. When called this way, the resolved
- value of the returned Promise is the number of bytes written to
- the target file.
+ changes: imports its data in chunks fed to it by the given
+ callback function. It calls the callback (which may be async)
+ repeatedly, expecting either a Uint8Array or ArrayBuffer (to
+ denote new input) or undefined (to denote EOF). For so long as
+ the callback continues to return non-undefined, it will append
+ incoming data to the given VFS-hosted database file. When
+ called this way, the resolved value of the returned Promise is
+ the number of bytes written to the target file.
It very specifically requires the input to be an SQLite3
database and throws if that's not the case. It does so in
diff --git a/ext/wasm/api/sqlite3-v-helper.js b/ext/wasm/api/sqlite3-vtab-helper.c-pp.js
index e63da8afc..7359ea39a 100644
--- a/ext/wasm/api/sqlite3-v-helper.js
+++ b/ext/wasm/api/sqlite3-vtab-helper.c-pp.js
@@ -10,19 +10,13 @@
*/
/**
- This file installs sqlite3.vfs, and object which exists to assist
- in the creation of JavaScript implementations of sqlite3_vfs, along
- with its virtual table counterpart, sqlite3.vtab.
+ This file installs sqlite3.vtab, a namespace of helpers for use in
+ the creation of JavaScript implementations virtual tables.
*/
'use strict';
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const wasm = sqlite3.wasm, capi = sqlite3.capi, toss = sqlite3.util.toss3;
- const vfs = Object.create(null), vtab = Object.create(null);
-
- const StructBinder = sqlite3.StructBinder
- /* we require a local alias b/c StructBinder is removed from the sqlite3
- object during the final steps of the API cleanup. */;
- sqlite3.vfs = vfs;
+ const vtab = Object.create(null);
sqlite3.vtab = vtab;
const sii = capi.sqlite3_index_info;
@@ -73,257 +67,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
};
/**
- Installs a StructBinder-bound function pointer member of the
- given name and function in the given StructType target object.
-
- It creates a WASM proxy for the given function and arranges for
- that proxy to be cleaned up when tgt.dispose() is called. Throws
- on the slightest hint of error, e.g. tgt is-not-a StructType,
- name does not map to a struct-bound member, etc.
-
- As a special case, if the given function is a pointer, then
- `wasm.functionEntry()` is used to validate that it is a known
- function. If so, it is used as-is with no extra level of proxying
- or cleanup, else an exception is thrown. It is legal to pass a
- value of 0, indicating a NULL pointer, with the caveat that 0
- _is_ a legal function pointer in WASM but it will not be accepted
- as such _here_. (Justification: the function at address zero must
- be one which initially came from the WASM module, not a method we
- want to bind to a virtual table or VFS.)
-
- This function returns a proxy for itself which is bound to tgt
- and takes 2 args (name,func). That function returns the same
- thing as this one, permitting calls to be chained.
-
- If called with only 1 arg, it has no side effects but returns a
- func with the same signature as described above.
-
- ACHTUNG: because we cannot generically know how to transform JS
- exceptions into result codes, the installed functions do no
- automatic catching of exceptions. It is critical, to avoid
- undefined behavior in the C layer, that methods mapped via
- this function do not throw. The exception, as it were, to that
- rule is...
-
- If applyArgcCheck is true then each JS function (as opposed to
- function pointers) gets wrapped in a proxy which asserts that it
- is passed the expected number of arguments, throwing if the
- argument count does not match expectations. That is only intended
- for dev-time usage for sanity checking, and will leave the C
- environment in an undefined state.
- */
- const installMethod = function callee(
- tgt, name, func, applyArgcCheck = callee.installMethodArgcCheck
- ){
- if(!(tgt instanceof StructBinder.StructType)){
- toss("Usage error: target object is-not-a StructType.");
- }else if(!(func instanceof Function) && !wasm.isPtr(func)){
- toss("Usage errror: expecting a Function or WASM pointer to one.");
- }
- if(1===arguments.length){
- return (n,f)=>callee(tgt, n, f, applyArgcCheck);
- }
- if(!callee.argcProxy){
- callee.argcProxy = function(tgt, funcName, func,sig){
- return function(...args){
- if(func.length!==arguments.length){
- toss("Argument mismatch for",
- tgt.structInfo.name+"::"+funcName
- +": Native signature is:",sig);
- }
- return func.apply(this, args);
- }
- };
- /* An ondispose() callback for use with
- StructBinder-created types. */
- callee.removeFuncList = function(){
- if(this.ondispose.__removeFuncList){
- this.ondispose.__removeFuncList.forEach(
- (v,ndx)=>{
- if('number'===typeof v){
- try{wasm.uninstallFunction(v)}
- catch(e){/*ignore*/}
- }
- /* else it's a descriptive label for the next number in
- the list. */
- }
- );
- delete this.ondispose.__removeFuncList;
- }
- };
- }/*static init*/
- const sigN = tgt.memberSignature(name);
- if(sigN.length<2){
- toss("Member",name,"does not have a function pointer signature:",sigN);
- }
- const memKey = tgt.memberKey(name);
- const fProxy = (applyArgcCheck && !wasm.isPtr(func))
- /** This middle-man proxy is only for use during development, to
- confirm that we always pass the proper number of
- arguments. We know that the C-level code will always use the
- correct argument count. */
- ? callee.argcProxy(tgt, memKey, func, sigN)
- : func;
- if(wasm.isPtr(fProxy)){
- if(fProxy && !wasm.functionEntry(fProxy)){
- toss("Pointer",fProxy,"is not a WASM function table entry.");
- }
- tgt[memKey] = fProxy;
- }else{
- const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true));
- tgt[memKey] = pFunc;
- if(!tgt.ondispose || !tgt.ondispose.__removeFuncList){
- tgt.addOnDispose('ondispose.__removeFuncList handler',
- callee.removeFuncList);
- tgt.ondispose.__removeFuncList = [];
- }
- tgt.ondispose.__removeFuncList.push(memKey, pFunc);
- }
- return (n,f)=>callee(tgt, n, f, applyArgcCheck);
- }/*installMethod*/;
- installMethod.installMethodArgcCheck = false;
-
- /**
- Installs methods into the given StructType-type instance. Each
- entry in the given methods object must map to a known member of
- the given StructType, else an exception will be triggered. See
- installMethod() for more details, including the semantics of the
- 3rd argument.
-
- As an exception to the above, if any two or more methods in the
- 2nd argument are the exact same function, installMethod() is
- _not_ called for the 2nd and subsequent instances, and instead
- those instances get assigned the same method pointer which is
- created for the first instance. This optimization is primarily to
- accommodate special handling of sqlite3_module::xConnect and
- xCreate methods.
-
- On success, returns its first argument. Throws on error.
- */
- const installMethods = function(
- structInstance, methods, applyArgcCheck = installMethod.installMethodArgcCheck
- ){
- const seen = new Map /* map of <Function, memberName> */;
- for(const k of Object.keys(methods)){
- const m = methods[k];
- const prior = seen.get(m);
- if(prior){
- const mkey = structInstance.memberKey(k);
- structInstance[mkey] = structInstance[structInstance.memberKey(prior)];
- }else{
- installMethod(structInstance, k, m, applyArgcCheck);
- seen.set(m, k);
- }
- }
- return structInstance;
- };
-
- /**
- Equivalent to calling installMethod(this,...arguments) with a
- first argument of this object. If called with 1 or 2 arguments
- and the first is an object, it's instead equivalent to calling
- installMethods(this,...arguments).
- */
- StructBinder.StructType.prototype.installMethod = function callee(
- name, func, applyArgcCheck = installMethod.installMethodArgcCheck
- ){
- return (arguments.length < 3 && name && 'object'===typeof name)
- ? installMethods(this, ...arguments)
- : installMethod(this, ...arguments);
- };
-
- /**
- Equivalent to calling installMethods() with a first argument
- of this object.
- */
- StructBinder.StructType.prototype.installMethods = function(
- methods, applyArgcCheck = installMethod.installMethodArgcCheck
- ){
- return installMethods(this, methods, applyArgcCheck);
- };
-
- /**
- Uses sqlite3_vfs_register() to register this
- sqlite3.capi.sqlite3_vfs. This object must have already been
- filled out properly. If the first argument is truthy, the VFS is
- registered as the default VFS, else it is not.
-
- On success, returns this object. Throws on error.
- */
- capi.sqlite3_vfs.prototype.registerVfs = function(asDefault=false){
- if(!(this instanceof sqlite3.capi.sqlite3_vfs)){
- toss("Expecting a sqlite3_vfs-type argument.");
- }
- const rc = capi.sqlite3_vfs_register(this, asDefault ? 1 : 0);
- if(rc){
- toss("sqlite3_vfs_register(",this,") failed with rc",rc);
- }
- if(this.pointer !== capi.sqlite3_vfs_find(this.$zName)){
- toss("BUG: sqlite3_vfs_find(vfs.$zName) failed for just-installed VFS",
- this);
- }
- return this;
- };
-
- /**
- A wrapper for installMethods() or registerVfs() to reduce
- installation of a VFS and/or its I/O methods to a single
- call.
-
- Accepts an object which contains the properties "io" and/or
- "vfs", each of which is itself an object with following properties:
-
- - `struct`: an sqlite3.StructType-type struct. This must be a
- populated (except for the methods) object of type
- sqlite3_io_methods (for the "io" entry) or sqlite3_vfs (for the
- "vfs" entry).
-
- - `methods`: an object mapping sqlite3_io_methods method names
- (e.g. 'xClose') to JS implementations of those methods. The JS
- implementations must be call-compatible with their native
- counterparts.
-
- For each of those object, this function passes its (`struct`,
- `methods`, (optional) `applyArgcCheck`) properties to
- installMethods().
-
- If the `vfs` entry is set then:
-
- - Its `struct` property's registerVfs() is called. The
- `vfs` entry may optionally have an `asDefault` property, which
- gets passed as the argument to registerVfs().
-
- - If `struct.$zName` is falsy and the entry has a string-type
- `name` property, `struct.$zName` is set to the C-string form of
- that `name` value before registerVfs() is called. That string
- gets added to the on-dispose state of the struct.
-
- On success returns this object. Throws on error.
- */
- vfs.installVfs = function(opt){
- let count = 0;
- const propList = ['io','vfs'];
- for(const key of propList){
- const o = opt[key];
- if(o){
- ++count;
- installMethods(o.struct, o.methods, !!o.applyArgcCheck);
- if('vfs'===key){
- if(!o.struct.$zName && 'string'===typeof o.name){
- o.struct.addOnDispose(
- o.struct.$zName = wasm.allocCString(o.name)
- );
- }
- o.struct.registerVfs(!!o.asDefault);
- }
- }
- }
- if(!count) toss("Misuse: installVfs() options object requires at least",
- "one of:", propList);
- return this;
- };
-
- /**
Internal factory function for xVtab and xCursor impls.
*/
const __xWrapFactory = function(methodName,StructType){
@@ -457,30 +200,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
vtab.xIndexInfo = (pIdxInfo)=>new capi.sqlite3_index_info(pIdxInfo);
/**
- Given an error object, this function returns
- sqlite3.capi.SQLITE_NOMEM if (e instanceof
- sqlite3.WasmAllocError), else it returns its
- second argument. Its intended usage is in the methods
- of a sqlite3_vfs or sqlite3_module:
-
- ```
- try{
- let rc = ...
- return rc;
- }catch(e){
- return sqlite3.vtab.exceptionToRc(e, sqlite3.capi.SQLITE_XYZ);
- // where SQLITE_XYZ is some call-appropriate result code.
- }
- ```
- */
- /**vfs.exceptionToRc = vtab.exceptionToRc =
- (e, defaultRc=capi.SQLITE_ERROR)=>(
- (e instanceof sqlite3.WasmAllocError)
- ? capi.SQLITE_NOMEM
- : defaultRc
- );*/
-
- /**
Given an sqlite3_module method name and error object, this
function returns sqlite3.capi.SQLITE_NOMEM if (e instanceof
sqlite3.WasmAllocError), else it returns its second argument. Its
@@ -526,20 +245,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
vtab.xError.errorReporter = 1 ? console.error.bind(console) : false;
/**
- "The problem" with this is that it introduces an outer function with
- a different arity than the passed-in method callback. That means we
- cannot do argc validation on these. Additionally, some methods (namely
- xConnect) may have call-specific error handling. It would be a shame to
- hard-coded that per-method support in this function.
- */
- /** vtab.methodCatcher = function(methodName, method, defaultErrRc=capi.SQLITE_ERROR){
- return function(...args){
- try { method(...args); }
- }catch(e){ return vtab.xError(methodName, e, defaultRc) }
- };
- */
-
- /**
A helper for sqlite3_vtab::xRowid() and xUpdate()
implementations. It must be passed the final argument to one of
those methods (an output pointer to an int64 row ID) and the
@@ -685,12 +390,12 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
remethods[k] = fwrap(k, m);
}
}
- installMethods(mod, remethods, false);
+ mod.installMethods(remethods, false);
}else{
// No automatic exception handling. Trust the client
// to not throw.
- installMethods(
- mod, methods, !!opt.applyArgcCheck/*undocumented option*/
+ mod.installMethods(
+ methods, !!opt.applyArgcCheck/*undocumented option*/
);
}
if(0===mod.$iVersion){
diff --git a/ext/wasm/api/sqlite3-wasm.c b/ext/wasm/api/sqlite3-wasm.c
index db77010d9..bd0eb884c 100644
--- a/ext/wasm/api/sqlite3-wasm.c
+++ b/ext/wasm/api/sqlite3-wasm.c
@@ -84,6 +84,14 @@
/**********************************************************************/
/* SQLITE_ENABLE_... */
+/*
+** Unconditionally enable API_ARMOR in the WASM build. It ensures that
+** public APIs behave predictable in the face of passing illegal NULLs
+** or ranges which might otherwise invoke undefined behavior.
+*/
+#undef SQLITE_ENABLE_API_ARMOR
+#define SQLITE_ENABLE_API_ARMOR 1
+
#ifndef SQLITE_ENABLE_BYTECODE_VTAB
# define SQLITE_ENABLE_BYTECODE_VTAB 1
#endif
@@ -122,12 +130,6 @@
#endif
/**********************************************************************/
-/* SQLITE_M... */
-#ifndef SQLITE_MAX_ALLOCATION_SIZE
-# define SQLITE_MAX_ALLOCATION_SIZE 0x1fffffff
-#endif
-
-/**********************************************************************/
/* SQLITE_O... */
#ifndef SQLITE_OMIT_DEPRECATED
# define SQLITE_OMIT_DEPRECATED 1
@@ -146,6 +148,12 @@
#endif
/**********************************************************************/
+/* SQLITE_S... */
+#ifndef SQLITE_STRICT_SUBTYPE
+# define SQLITE_STRICT_SUBTYPE 1
+#endif
+
+/**********************************************************************/
/* SQLITE_T... */
#ifndef SQLITE_TEMP_STORE
# define SQLITE_TEMP_STORE 2
@@ -230,28 +238,28 @@
** Another option is to malloc() a chunk of our own and call that our
** "stack".
*/
-SQLITE_WASM_EXPORT void * sqlite3_wasm_stack_end(void){
+SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_end(void){
extern void __heap_base
/* see https://stackoverflow.com/questions/10038964 */;
return &__heap_base;
}
-SQLITE_WASM_EXPORT void * sqlite3_wasm_stack_begin(void){
+SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_begin(void){
extern void __data_end;
return &__data_end;
}
static void * pWasmStackPtr = 0;
-SQLITE_WASM_EXPORT void * sqlite3_wasm_stack_ptr(void){
- if(!pWasmStackPtr) pWasmStackPtr = sqlite3_wasm_stack_end();
+SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_ptr(void){
+ if(!pWasmStackPtr) pWasmStackPtr = sqlite3__wasm_stack_end();
return pWasmStackPtr;
}
-SQLITE_WASM_EXPORT void sqlite3_wasm_stack_restore(void * p){
+SQLITE_WASM_EXPORT void sqlite3__wasm_stack_restore(void * p){
pWasmStackPtr = p;
}
-SQLITE_WASM_EXPORT void * sqlite3_wasm_stack_alloc(int n){
+SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_alloc(int n){
if(n<=0) return 0;
n = (n + 7) & ~7 /* align to 8-byte boundary */;
- unsigned char * const p = (unsigned char *)sqlite3_wasm_stack_ptr();
- unsigned const char * const b = (unsigned const char *)sqlite3_wasm_stack_begin();
+ unsigned char * const p = (unsigned char *)sqlite3__wasm_stack_ptr();
+ unsigned const char * const b = (unsigned const char *)sqlite3__wasm_stack_begin();
if(b + n >= p || b + n < b/*overflow*/) return 0;
return pWasmStackPtr = p - n;
}
@@ -259,7 +267,7 @@ SQLITE_WASM_EXPORT void * sqlite3_wasm_stack_alloc(int n){
/*
** State for the "pseudo-stack" allocator implemented in
-** sqlite3_wasm_pstack_xyz(). In order to avoid colliding with
+** sqlite3__wasm_pstack_xyz(). In order to avoid colliding with
** Emscripten-controled stack space, it carves out a bit of stack
** memory to use for that purpose. This memory ends up in the
** WASM-managed memory, such that routines which manipulate the wasm
@@ -283,14 +291,14 @@ static struct {
/*
** Returns the current pstack position.
*/
-SQLITE_WASM_EXPORT void * sqlite3_wasm_pstack_ptr(void){
+SQLITE_WASM_EXPORT void * sqlite3__wasm_pstack_ptr(void){
return PStack.pPos;
}
/*
** Sets the pstack position poitner to p. Results are undefined if the
-** given value did not come from sqlite3_wasm_pstack_ptr().
+** given value did not come from sqlite3__wasm_pstack_ptr().
*/
-SQLITE_WASM_EXPORT void sqlite3_wasm_pstack_restore(unsigned char * p){
+SQLITE_WASM_EXPORT void sqlite3__wasm_pstack_restore(unsigned char * p){
assert(p>=PStack.pBegin && p<=PStack.pEnd && p>=PStack.pPos);
assert(0==((unsigned long long)p & 0x7));
if(p>=PStack.pBegin && p<=PStack.pEnd /*&& p>=PStack.pPos*/){
@@ -305,7 +313,7 @@ SQLITE_WASM_EXPORT void sqlite3_wasm_pstack_restore(unsigned char * p){
** JS code from having to do so, and most uses of the pstack will
** call for doing so).
*/
-SQLITE_WASM_EXPORT void * sqlite3_wasm_pstack_alloc(int n){
+SQLITE_WASM_EXPORT void * sqlite3__wasm_pstack_alloc(int n){
if( n<=0 ) return 0;
//if( n & 0x7 ) n += 8 - (n & 0x7) /* align to 8-byte boundary */;
n = (n + 7) & ~7 /* align to 8-byte boundary */;
@@ -316,9 +324,9 @@ SQLITE_WASM_EXPORT void * sqlite3_wasm_pstack_alloc(int n){
}
/*
** Return the number of bytes left which can be
-** sqlite3_wasm_pstack_alloc()'d.
+** sqlite3__wasm_pstack_alloc()'d.
*/
-SQLITE_WASM_EXPORT int sqlite3_wasm_pstack_remaining(void){
+SQLITE_WASM_EXPORT int sqlite3__wasm_pstack_remaining(void){
assert(PStack.pPos >= PStack.pBegin);
assert(PStack.pPos <= PStack.pEnd);
return (int)(PStack.pPos - PStack.pBegin);
@@ -329,7 +337,7 @@ SQLITE_WASM_EXPORT int sqlite3_wasm_pstack_remaining(void){
** any space which is currently allocated. This value is a
** compile-time constant.
*/
-SQLITE_WASM_EXPORT int sqlite3_wasm_pstack_quota(void){
+SQLITE_WASM_EXPORT int sqlite3__wasm_pstack_quota(void){
return (int)(PStack.pEnd - PStack.pBegin);
}
@@ -348,7 +356,7 @@ SQLITE_WASM_EXPORT int sqlite3_wasm_pstack_quota(void){
** Returns err_code.
*/
SQLITE_WASM_EXPORT
-int sqlite3_wasm_db_error(sqlite3*db, int err_code, const char *zMsg){
+int sqlite3__wasm_db_error(sqlite3*db, int err_code, const char *zMsg){
if( db!=0 ){
if( 0!=zMsg ){
const int nMsg = sqlite3Strlen30(zMsg);
@@ -372,7 +380,7 @@ struct WasmTestStruct {
};
typedef struct WasmTestStruct WasmTestStruct;
SQLITE_WASM_EXPORT
-void sqlite3_wasm_test_struct(WasmTestStruct * s){
+void sqlite3__wasm_test_struct(WasmTestStruct * s){
if(s){
s->v4 *= 2;
s->v8 = s->v4 * 2;
@@ -400,7 +408,7 @@ void sqlite3_wasm_test_struct(WasmTestStruct * s){
** increased. In debug builds that will trigger an assert().
*/
SQLITE_WASM_EXPORT
-const char * sqlite3_wasm_enum_json(void){
+const char * sqlite3__wasm_enum_json(void){
static char aBuffer[1024 * 20] = {0} /* where the JSON goes */;
int n = 0, nChildren = 0, nStruct = 0
/* output counters for figuring out where commas go */;
@@ -417,7 +425,7 @@ const char * sqlite3_wasm_enum_json(void){
/* Core output macros... */
#define lenCheck assert(zPos < zEnd - 128 \
- && "sqlite3_wasm_enum_json() buffer is too small."); \
+ && "sqlite3__wasm_enum_json() buffer is too small."); \
if( zPos >= zEnd - 128 ) return 0
#define outf(format,...) \
zPos += snprintf(zPos, ((size_t)(zEnd - zPos)), format, __VA_ARGS__); \
@@ -875,7 +883,7 @@ const char * sqlite3_wasm_enum_json(void){
DefInt(SQLITE_STMTSTATUS_FILTER_HIT);
DefInt(SQLITE_STMTSTATUS_MEMUSED);
} _DefGroup;
-
+
DefGroup(syncFlags) {
DefInt(SQLITE_SYNC_NORMAL);
DefInt(SQLITE_SYNC_FULL);
@@ -899,6 +907,8 @@ const char * sqlite3_wasm_enum_json(void){
DefInt(SQLITE_DETERMINISTIC);
DefInt(SQLITE_DIRECTONLY);
DefInt(SQLITE_INNOCUOUS);
+ DefInt(SQLITE_SUBTYPE);
+ DefInt(SQLITE_RESULT_SUBTYPE);
} _DefGroup;
DefGroup(version) {
@@ -1093,7 +1103,7 @@ const char * sqlite3_wasm_enum_json(void){
M(xShadowName, "i(s)");
} _StructBinder;
#undef CurrentStruct
-
+
/**
** Workaround: in order to map the various inner structs from
** sqlite3_index_info, we have to uplift those into constructs we
@@ -1210,7 +1220,7 @@ const char * sqlite3_wasm_enum_json(void){
** call is returned.
*/
SQLITE_WASM_EXPORT
-int sqlite3_wasm_vfs_unlink(sqlite3_vfs *pVfs, const char *zName){
+int sqlite3__wasm_vfs_unlink(sqlite3_vfs *pVfs, const char *zName){
int rc = SQLITE_MISUSE /* ??? */;
if( 0==pVfs && 0!=zName ) pVfs = sqlite3_vfs_find(0);
if( zName && pVfs && pVfs->xDelete ){
@@ -1228,7 +1238,7 @@ int sqlite3_wasm_vfs_unlink(sqlite3_vfs *pVfs, const char *zName){
** given name is open.
*/
SQLITE_WASM_EXPORT
-sqlite3_vfs * sqlite3_wasm_db_vfs(sqlite3 *pDb, const char *zDbName){
+sqlite3_vfs * sqlite3__wasm_db_vfs(sqlite3 *pDb, const char *zDbName){
sqlite3_vfs * pVfs = 0;
sqlite3_file_control(pDb, zDbName ? zDbName : "main",
SQLITE_FCNTL_VFS_POINTER, &pVfs);
@@ -1251,7 +1261,7 @@ sqlite3_vfs * sqlite3_wasm_db_vfs(sqlite3 *pDb, const char *zDbName){
** SQLITE_MISUSE if pDb is NULL.
*/
SQLITE_WASM_EXPORT
-int sqlite3_wasm_db_reset(sqlite3 *pDb){
+int sqlite3__wasm_db_reset(sqlite3 *pDb){
int rc = SQLITE_MISUSE;
if( pDb ){
sqlite3_table_column_metadata(pDb, "main", 0, 0, 0, 0, 0, 0, 0);
@@ -1278,11 +1288,11 @@ int sqlite3_wasm_db_reset(sqlite3 *pDb){
** takes no measures to ensure that is the case.
**
** This implementation appears to work fine, but
-** sqlite3_wasm_db_serialize() is arguably the better way to achieve
+** sqlite3__wasm_db_serialize() is arguably the better way to achieve
** this.
*/
SQLITE_WASM_EXPORT
-int sqlite3_wasm_db_export_chunked( sqlite3* pDb,
+int sqlite3__wasm_db_export_chunked( sqlite3* pDb,
int (*xCallback)(unsigned const char *zOut, int n) ){
sqlite3_int64 nSize = 0;
sqlite3_int64 nPos = 0;
@@ -1333,7 +1343,7 @@ int sqlite3_wasm_db_export_chunked( sqlite3* pDb,
** sqlite3_free() to free it.
*/
SQLITE_WASM_EXPORT
-int sqlite3_wasm_db_serialize( sqlite3 *pDb, const char *zSchema,
+int sqlite3__wasm_db_serialize( sqlite3 *pDb, const char *zSchema,
unsigned char **pOut,
sqlite3_int64 *nOut, unsigned int mFlags ){
unsigned char * z;
@@ -1356,7 +1366,7 @@ int sqlite3_wasm_db_serialize( sqlite3 *pDb, const char *zSchema,
** this function's out-of-scope use of the sqlite3_vfs/file/io_methods
** APIs leads to triggering of assertions in the core library. Its use
** is now deprecated and VFS-specific APIs for importing files need to
-** be found to replace it. sqlite3_wasm_posix_create_file() is
+** be found to replace it. sqlite3__wasm_posix_create_file() is
** suitable for the "unix" family of VFSes.
**
** Creates a new file using the I/O API of the given VFS, containing
@@ -1397,7 +1407,7 @@ int sqlite3_wasm_db_serialize( sqlite3 *pDb, const char *zSchema,
** support is disabled or unavailable.
*/
SQLITE_WASM_EXPORT
-int sqlite3_wasm_vfs_create_file( sqlite3_vfs *pVfs,
+int sqlite3__wasm_vfs_create_file( sqlite3_vfs *pVfs,
const char *zFilename,
const unsigned char * pData,
int nData ){
@@ -1487,7 +1497,7 @@ int sqlite3_wasm_vfs_create_file( sqlite3_vfs *pVfs,
** SQLITE_IOERR on error.
*/
SQLITE_WASM_EXPORT
-int sqlite3_wasm_posix_create_file( const char *zFilename,
+int sqlite3__wasm_posix_create_file( const char *zFilename,
const unsigned char * pData,
int nData ){
int rc;
@@ -1510,17 +1520,17 @@ int sqlite3_wasm_posix_create_file( const char *zFilename,
** for use by the sqlite project's own JS/WASM bindings.
**
** Allocates sqlite3KvvfsMethods.nKeySize bytes from
-** sqlite3_wasm_pstack_alloc() and returns 0 if that allocation fails,
+** sqlite3__wasm_pstack_alloc() and returns 0 if that allocation fails,
** else it passes that string to kvstorageMakeKey() and returns a
** NUL-terminated pointer to that string. It is up to the caller to
-** use sqlite3_wasm_pstack_restore() to free the returned pointer.
+** use sqlite3__wasm_pstack_restore() to free the returned pointer.
*/
SQLITE_WASM_EXPORT
-char * sqlite3_wasm_kvvfsMakeKeyOnPstack(const char *zClass,
+char * sqlite3__wasm_kvvfsMakeKeyOnPstack(const char *zClass,
const char *zKeyIn){
assert(sqlite3KvvfsMethods.nKeySize>24);
char *zKeyOut =
- (char *)sqlite3_wasm_pstack_alloc(sqlite3KvvfsMethods.nKeySize);
+ (char *)sqlite3__wasm_pstack_alloc(sqlite3KvvfsMethods.nKeySize);
if(zKeyOut){
kvstorageMakeKey(zClass, zKeyIn, zKeyOut);
}
@@ -1535,7 +1545,7 @@ char * sqlite3_wasm_kvvfsMakeKeyOnPstack(const char *zClass,
** I/O methods and associated state.
*/
SQLITE_WASM_EXPORT
-sqlite3_kvvfs_methods * sqlite3_wasm_kvvfs_methods(void){
+sqlite3_kvvfs_methods * sqlite3__wasm_kvvfs_methods(void){
return &sqlite3KvvfsMethods;
}
@@ -1550,7 +1560,7 @@ sqlite3_kvvfs_methods * sqlite3_wasm_kvvfs_methods(void){
** valid value.
*/
SQLITE_WASM_EXPORT
-int sqlite3_wasm_vtab_config(sqlite3 *pDb, int op, int arg){
+int sqlite3__wasm_vtab_config(sqlite3 *pDb, int op, int arg){
switch(op){
case SQLITE_VTAB_DIRECTONLY:
case SQLITE_VTAB_INNOCUOUS:
@@ -1570,7 +1580,7 @@ int sqlite3_wasm_vtab_config(sqlite3 *pDb, int op, int arg){
** (int,int*) variadic args.
*/
SQLITE_WASM_EXPORT
-int sqlite3_wasm_db_config_ip(sqlite3 *pDb, int op, int arg1, int* pArg2){
+int sqlite3__wasm_db_config_ip(sqlite3 *pDb, int op, int arg1, int* pArg2){
switch(op){
case SQLITE_DBCONFIG_ENABLE_FKEY:
case SQLITE_DBCONFIG_ENABLE_TRIGGER:
@@ -1603,7 +1613,7 @@ int sqlite3_wasm_db_config_ip(sqlite3 *pDb, int op, int arg1, int* pArg2){
** (void*,int,int) variadic args.
*/
SQLITE_WASM_EXPORT
-int sqlite3_wasm_db_config_pii(sqlite3 *pDb, int op, void * pArg1, int arg2, int arg3){
+int sqlite3__wasm_db_config_pii(sqlite3 *pDb, int op, void * pArg1, int arg2, int arg3){
switch(op){
case SQLITE_DBCONFIG_LOOKASIDE:
return sqlite3_db_config(pDb, op, pArg1, arg2, arg3);
@@ -1619,7 +1629,7 @@ int sqlite3_wasm_db_config_pii(sqlite3 *pDb, int op, void * pArg1, int arg2, int
** (const char *) variadic args.
*/
SQLITE_WASM_EXPORT
-int sqlite3_wasm_db_config_s(sqlite3 *pDb, int op, const char *zArg){
+int sqlite3__wasm_db_config_s(sqlite3 *pDb, int op, const char *zArg){
switch(op){
case SQLITE_DBCONFIG_MAINDBNAME:
return sqlite3_db_config(pDb, op, zArg);
@@ -1636,7 +1646,7 @@ int sqlite3_wasm_db_config_s(sqlite3 *pDb, int op, const char *zArg){
** a single integer argument.
*/
SQLITE_WASM_EXPORT
-int sqlite3_wasm_config_i(int op, int arg){
+int sqlite3__wasm_config_i(int op, int arg){
return sqlite3_config(op, arg);
}
@@ -1648,7 +1658,7 @@ int sqlite3_wasm_config_i(int op, int arg){
** two int arguments.
*/
SQLITE_WASM_EXPORT
-int sqlite3_wasm_config_ii(int op, int arg1, int arg2){
+int sqlite3__wasm_config_ii(int op, int arg1, int arg2){
return sqlite3_config(op, arg1, arg2);
}
@@ -1660,7 +1670,7 @@ int sqlite3_wasm_config_ii(int op, int arg1, int arg2){
** a single i64 argument.
*/
SQLITE_WASM_EXPORT
-int sqlite3_wasm_config_j(int op, sqlite3_int64 arg){
+int sqlite3__wasm_config_j(int op, sqlite3_int64 arg){
return sqlite3_config(op, arg);
}
@@ -1679,17 +1689,17 @@ int sqlite3_wasm_config_j(int op, sqlite3_int64 arg){
**
** ```
** sqlite3.wasm.functionEntry(
-** sqlite3.wasm.exports.sqlite3_wasm_ptr_to_sqlite3_free()
+** sqlite3.wasm.exports.sqlite3__wasm_ptr_to_sqlite3_free()
** ) === sqlite3.wasm.exports.sqlite3_free
** ```
**
** Using a function to return this pointer, as opposed to exporting it
-** via sqlite3_wasm_enum_json(), is an attempt to work around a
+** via sqlite3__wasm_enum_json(), is an attempt to work around a
** Safari-specific quirk covered at
** https://sqlite.org/forum/info/e5b20e1feb37a19a.
**/
SQLITE_WASM_EXPORT
-void * sqlite3_wasm_ptr_to_sqlite3_free(void){
+void * sqlite3__wasm_ptr_to_sqlite3_free(void){
return (void*)sqlite3_free;
}
#endif
@@ -1719,7 +1729,7 @@ void * sqlite3_wasm_ptr_to_sqlite3_free(void){
** defined, SQLITE_NOTFOUND is returned without side effects.
*/
SQLITE_WASM_EXPORT
-int sqlite3_wasm_init_wasmfs(const char *zMountPoint){
+int sqlite3__wasm_init_wasmfs(const char *zMountPoint){
static backend_t pOpfs = 0;
if( !zMountPoint || !*zMountPoint ) zMountPoint = "/opfs";
if( !pOpfs ){
@@ -1739,7 +1749,7 @@ int sqlite3_wasm_init_wasmfs(const char *zMountPoint){
}
#else
SQLITE_WASM_EXPORT
-int sqlite3_wasm_init_wasmfs(const char *zUnused){
+int sqlite3__wasm_init_wasmfs(const char *zUnused){
//emscripten_console_warn("WASMFS OPFS is not compiled in.");
if(zUnused){/*unused*/}
return SQLITE_NOTFOUND;
@@ -1749,51 +1759,51 @@ int sqlite3_wasm_init_wasmfs(const char *zUnused){
#if SQLITE_WASM_TESTS
SQLITE_WASM_EXPORT
-int sqlite3_wasm_test_intptr(int * p){
+int sqlite3__wasm_test_intptr(int * p){
return *p = *p * 2;
}
SQLITE_WASM_EXPORT
-void * sqlite3_wasm_test_voidptr(void * p){
+void * sqlite3__wasm_test_voidptr(void * p){
return p;
}
SQLITE_WASM_EXPORT
-int64_t sqlite3_wasm_test_int64_max(void){
+int64_t sqlite3__wasm_test_int64_max(void){
return (int64_t)0x7fffffffffffffff;
}
SQLITE_WASM_EXPORT
-int64_t sqlite3_wasm_test_int64_min(void){
- return ~sqlite3_wasm_test_int64_max();
+int64_t sqlite3__wasm_test_int64_min(void){
+ return ~sqlite3__wasm_test_int64_max();
}
SQLITE_WASM_EXPORT
-int64_t sqlite3_wasm_test_int64_times2(int64_t x){
+int64_t sqlite3__wasm_test_int64_times2(int64_t x){
return x * 2;
}
SQLITE_WASM_EXPORT
-void sqlite3_wasm_test_int64_minmax(int64_t * min, int64_t *max){
- *max = sqlite3_wasm_test_int64_max();
- *min = sqlite3_wasm_test_int64_min();
+void sqlite3__wasm_test_int64_minmax(int64_t * min, int64_t *max){
+ *max = sqlite3__wasm_test_int64_max();
+ *min = sqlite3__wasm_test_int64_min();
/*printf("minmax: min=%lld, max=%lld\n", *min, *max);*/
}
SQLITE_WASM_EXPORT
-int64_t sqlite3_wasm_test_int64ptr(int64_t * p){
- /*printf("sqlite3_wasm_test_int64ptr( @%lld = 0x%llx )\n", (int64_t)p, *p);*/
+int64_t sqlite3__wasm_test_int64ptr(int64_t * p){
+ /*printf("sqlite3__wasm_test_int64ptr( @%lld = 0x%llx )\n", (int64_t)p, *p);*/
return *p = *p * 2;
}
SQLITE_WASM_EXPORT
-void sqlite3_wasm_test_stack_overflow(int recurse){
- if(recurse) sqlite3_wasm_test_stack_overflow(recurse);
+void sqlite3__wasm_test_stack_overflow(int recurse){
+ if(recurse) sqlite3__wasm_test_stack_overflow(recurse);
}
/* For testing the 'string:dealloc' whwasmutil.xWrap() conversion. */
SQLITE_WASM_EXPORT
-char * sqlite3_wasm_test_str_hello(int fail){
+char * sqlite3__wasm_test_str_hello(int fail){
char * s = fail ? 0 : (char *)sqlite3_malloc(6);
if(s){
memcpy(s, "hello", 5);
@@ -1828,12 +1838,12 @@ char * sqlite3_wasm_test_str_hello(int fail){
** optional + or - sign in front, or a hexadecimal
** literal of the form 0x...
*/
-static int sqlite3_wasm_SQLTester_strnotglob(const char *zGlob, const char *z){
+static int sqlite3__wasm_SQLTester_strnotglob(const char *zGlob, const char *z){
int c, c2;
int invert;
int seen;
typedef int (*recurse_f)(const char *,const char *);
- static const recurse_f recurse = sqlite3_wasm_SQLTester_strnotglob;
+ static const recurse_f recurse = sqlite3__wasm_SQLTester_strnotglob;
while( (c = (*(zGlob++)))!=0 ){
if( c=='*' ){
@@ -1908,11 +1918,10 @@ static int sqlite3_wasm_SQLTester_strnotglob(const char *zGlob, const char *z){
}
SQLITE_WASM_EXPORT
-int sqlite3_wasm_SQLTester_strglob(const char *zGlob, const char *z){
- return !sqlite3_wasm_SQLTester_strnotglob(zGlob, z);
+int sqlite3__wasm_SQLTester_strglob(const char *zGlob, const char *z){
+ return !sqlite3__wasm_SQLTester_strnotglob(zGlob, z);
}
-
#endif /* SQLITE_WASM_TESTS */
#undef SQLITE_WASM_EXPORT
diff --git a/ext/wasm/api/sqlite3-worker1-promiser.c-pp.js b/ext/wasm/api/sqlite3-worker1-promiser.c-pp.js
index bad599673..68846209e 100644
--- a/ext/wasm/api/sqlite3-worker1-promiser.c-pp.js
+++ b/ext/wasm/api/sqlite3-worker1-promiser.c-pp.js
@@ -1,3 +1,4 @@
+//#ifnot omit-oo1
/*
2022-08-24
@@ -155,6 +156,7 @@ globalThis.sqlite3Worker1Promiser = function callee(config = callee.defaultConfi
if(!config.worker) config.worker = callee.defaultConfig.worker;
if('function'===typeof config.worker) config.worker = config.worker();
let dbId;
+ let promiserFunc;
config.worker.onmessage = function(ev){
ev = ev.data;
debug('worker1.onmessage',ev);
@@ -162,7 +164,7 @@ globalThis.sqlite3Worker1Promiser = function callee(config = callee.defaultConfi
if(!msgHandler){
if(ev && 'sqlite3-api'===ev.type && 'worker1-ready'===ev.result) {
/*fired one time when the Worker1 API initializes*/
- if(config.onready) config.onready();
+ if(config.onready) config.onready(promiserFunc);
return;
}
msgHandler = handlerMap[ev.type] /* check for exec per-row callback */;
@@ -191,7 +193,7 @@ globalThis.sqlite3Worker1Promiser = function callee(config = callee.defaultConfi
try {msgHandler.resolve(ev)}
catch(e){msgHandler.reject(e)}
}/*worker.onmessage()*/;
- return function(/*(msgType, msgArgs) || (msgEnvelope)*/){
+ return promiserFunc = function(/*(msgType, msgArgs) || (msgEnvelope)*/){
let msg;
if(1===arguments.length){
msg = arguments[0];
@@ -199,10 +201,11 @@ globalThis.sqlite3Worker1Promiser = function callee(config = callee.defaultConfi
msg = Object.create(null);
msg.type = arguments[0];
msg.args = arguments[1];
+ msg.dbId = msg.args.dbId;
}else{
toss("Invalid arugments for sqlite3Worker1Promiser()-created factory.");
}
- if(!msg.dbId) msg.dbId = dbId;
+ if(!msg.dbId && msg.type!=='open') msg.dbId = dbId;
msg.messageId = genMsgId(msg);
msg.departureTime = performance.now();
const proxy = Object.create(null);
@@ -247,9 +250,8 @@ globalThis.sqlite3Worker1Promiser = function callee(config = callee.defaultConfi
globalThis.sqlite3Worker1Promiser.defaultConfig = {
worker: function(){
//#if target=es6-bundler-friendly
- return new Worker("sqlite3-worker1-bundler-friendly.mjs",{
- type: 'module' /* Noting that neither Firefox nor Safari suppor this,
- as of this writing. */
+ return new Worker(new URL("sqlite3-worker1-bundler-friendly.mjs", import.meta.url),{
+ type: 'module'
});
//#else
let theJs = "sqlite3-worker1.js";
@@ -267,8 +269,15 @@ globalThis.sqlite3Worker1Promiser.defaultConfig = {
}
return new Worker(theJs + globalThis.location.search);
//#endif
- }.bind({
+ }
+//#ifnot target=es6-bundler-friendly
+ .bind({
currentScript: globalThis?.document?.currentScript
- }),
+ })
+//#endif
+ ,
onerror: (...args)=>console.error('worker1 promiser error',...args)
};
+//#else
+/* Built with the omit-oo1 flag. */
+//#endif ifnot omit-oo1
diff --git a/ext/wasm/api/sqlite3-worker1.c-pp.js b/ext/wasm/api/sqlite3-worker1.c-pp.js
index f26042230..74de9ec7e 100644
--- a/ext/wasm/api/sqlite3-worker1.c-pp.js
+++ b/ext/wasm/api/sqlite3-worker1.c-pp.js
@@ -1,3 +1,4 @@
+//#ifnot omit-oo1
/*
2022-05-23
@@ -37,7 +38,7 @@ import {default as sqlite3InitModule} from './sqlite3-bundler-friendly.mjs';
"use strict";
{
const urlParams = globalThis.location
- ? new URL(self.location.href).searchParams
+ ? new URL(globalThis.location.href).searchParams
: new URLSearchParams();
let theJs = 'sqlite3.js';
if(urlParams.has('sqlite3.dir')){
@@ -48,3 +49,6 @@ import {default as sqlite3InitModule} from './sqlite3-bundler-friendly.mjs';
}
//#endif
sqlite3InitModule().then(sqlite3 => sqlite3.initWorker1API());
+//#else
+/* Built with the omit-oo1 flag. */
+//#endif ifnot omit-oo1