aboutsummaryrefslogtreecommitdiff
path: root/ext/wasm/api
diff options
context:
space:
mode:
Diffstat (limited to 'ext/wasm/api')
-rw-r--r--ext/wasm/api/sqlite3-api-oo1.js131
-rw-r--r--ext/wasm/api/sqlite3-api-opfs.js128
-rw-r--r--ext/wasm/api/sqlite3-api-prologue.js87
-rw-r--r--ext/wasm/api/sqlite3-api-worker1.js6
4 files changed, 271 insertions, 81 deletions
diff --git a/ext/wasm/api/sqlite3-api-oo1.js b/ext/wasm/api/sqlite3-api-oo1.js
index 368986933..fb01e9871 100644
--- a/ext/wasm/api/sqlite3-api-oo1.js
+++ b/ext/wasm/api/sqlite3-api-oo1.js
@@ -85,9 +85,24 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
/**
A proxy for DB class constructors. It must be called with the
- being-construct DB object as its "this".
+ being-construct DB object as its "this". See the DB constructor
+ for the argument docs. This is split into a separate function
+ in order to enable simple creation of special-case DB constructors,
+ e.g. a hypothetical LocalStorageDB or OpfsDB.
+
+ Expects to be passed a configuration object with the following
+ properties:
+
+ - `.filename`: the db filename. It may be a special name like ":memory:"
+ or "".
+
+ - `.flags`: as documented in the DB constructor.
+
+ - `.vfs`: as documented in the DB constructor.
+
+ It also accepts those as the first 3 arguments.
*/
- const dbCtorHelper = function ctor(fn=':memory:', flags='c', vfsName){
+ const dbCtorHelper = function ctor(...args){
if(!ctor._name2vfs){
// Map special filenames which we handle here (instead of in C)
// to some helpful metadata...
@@ -104,25 +119,33 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
filename: isWorkerThread || (()=>'session')
};
}
- if('string'!==typeof fn){
- toss3("Invalid filename for DB constructor.");
+ const opt = ctor.normalizeArgs(...args);
+ let fn = opt.filename, vfsName = opt.vfs, flagsStr = opt.flags;
+ if(('string'!==typeof fn && 'number'!==typeof fn)
+ || 'string'!==typeof flagsStr
+ || (vfsName && ('string'!==typeof vfsName && 'number'!==typeof vfsName))){
+ console.error("Invalid DB ctor args",opt,arguments);
+ toss3("Invalid arguments for DB constructor.");
}
- const vfsCheck = ctor._name2vfs[fn];
+ let fnJs = ('number'===typeof fn) ? capi.wasm.cstringToJs(fn) : fn;
+ const vfsCheck = ctor._name2vfs[fnJs];
if(vfsCheck){
vfsName = vfsCheck.vfs;
- fn = vfsCheck.filename(fn);
+ fn = fnJs = vfsCheck.filename(fnJs);
}
let ptr, oflags = 0;
- if( flags.indexOf('c')>=0 ){
+ if( flagsStr.indexOf('c')>=0 ){
oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
}
- if( flags.indexOf('w')>=0 ) oflags |= capi.SQLITE_OPEN_READWRITE;
+ if( flagsStr.indexOf('w')>=0 ) oflags |= capi.SQLITE_OPEN_READWRITE;
if( 0===oflags ) oflags |= capi.SQLITE_OPEN_READONLY;
oflags |= capi.SQLITE_OPEN_EXRESCODE;
const stack = capi.wasm.scopedAllocPush();
try {
const ppDb = capi.wasm.scopedAllocPtr() /* output (sqlite3**) arg */;
- const pVfsName = vfsName ? capi.wasm.scopedAllocCString(vfsName) : 0;
+ const pVfsName = vfsName ? (
+ ('number'===typeof vfsName ? vfsName : capi.wasm.scopedAllocCString(vfsName))
+ ): 0;
const rc = capi.sqlite3_open_v2(fn, ppDb, oflags, pVfsName);
ptr = capi.wasm.getPtrValue(ppDb);
checkSqlite3Rc(ptr, rc);
@@ -132,11 +155,36 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}finally{
capi.wasm.scopedAllocPop(stack);
}
- this.filename = fn;
+ this.filename = fnJs;
__ptrMap.set(this, ptr);
__stmtMap.set(this, Object.create(null));
__udfMap.set(this, Object.create(null));
};
+
+ /**
+ A helper for DB constructors. It accepts either a single
+ config-style object or up to 3 arguments (filename, dbOpenFlags,
+ dbVfsName). It returns a new object containing:
+
+ { filename: ..., flags: ..., vfs: ... }
+
+ If passed an object, any additional properties it has are copied
+ as-is into the new object.
+ */
+ dbCtorHelper.normalizeArgs = function(filename,flags = 'c',vfs = null){
+ const arg = {};
+ if(1===arguments.length && 'object'===typeof arguments[0]){
+ const x = arguments[0];
+ Object.keys(x).forEach((k)=>arg[k] = x[k]);
+ if(undefined===arg.flags) arg.flags = 'c';
+ if(undefined===arg.vfs) arg.vfs = null;
+ }else{
+ arg.filename = filename;
+ arg.flags = flags;
+ arg.vfs = vfs;
+ }
+ return arg;
+ };
/**
The DB class provides a high-level OO wrapper around an sqlite3
@@ -175,6 +223,17 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
or not at all, to use the default. If passed a value, it must
be the string name of a VFS
+ The constructor optionally (and preferably) takes its arguments
+ in the form of a single configuration object with the following
+ properties:
+
+ - `.filename`: database file name
+ - `.flags`: open-mode flags
+ - `.vfs`: the VFS fname
+
+ The `filename` and `vfs` arguments may be either JS strings or
+ C-strings allocated via WASM.
+
For purposes of passing a DB instance to C-style sqlite3
functions, the DB object's read-only `pointer` property holds its
`sqlite3*` pointer value. That property can also be used to check
@@ -187,12 +246,12 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
the database. In this mode, only a single database is permitted
in each storage object. This feature is experimental and subject
to any number of changes (including outright removal). This
- support requires a specific build of sqlite3, the existence of
- which can be determined at runtime by checking for a non-0 return
- value from sqlite3.capi.sqlite3_vfs_find("kvvfs").
+ support requires the kvvfs sqlite3 VFS, the existence of which
+ can be determined at runtime by checking for a non-0 return value
+ from sqlite3.capi.sqlite3_vfs_find("kvvfs").
*/
- const DB = function ctor(fn=':memory:', flags='c', vfsName){
- dbCtorHelper.apply(this, Array.prototype.slice.call(arguments));
+ const DB = function(...args){
+ dbCtorHelper.apply(this, args);
};
/**
@@ -361,12 +420,31 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
closed. After calling close(), `this.pointer` will resolve to
`undefined`, so that can be used to check whether the db
instance is still opened.
+
+ If this.onclose.before is a function then it is called before
+ any close-related cleanup.
+
+ If this.onclose.after is a function then it is called after the
+ db is closed but before auxiliary state like this.filename is
+ cleared.
+
+ Both onclose handlers are passed this object. If this db is not
+ opened, neither of the handlers are called. Any exceptions the
+ handlers throw are ignored because "destructors must not
+ throw."
+
+ Note that garbage collection of a db handle, if it happens at
+ all, will never trigger close(), so onclose handlers are not a
+ reliable way to implement close-time cleanup or maintenance of
+ a db.
*/
close: function(){
if(this.pointer){
+ if(this.onclose && (this.onclose.before instanceof Function)){
+ try{this.onclose.before(this)}
+ catch(e){/*ignore*/}
+ }
const pDb = this.pointer;
- let s;
- const that = this;
Object.keys(__stmtMap.get(this)).forEach((k,s)=>{
if(s && s.pointer) s.finalize();
});
@@ -377,6 +455,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
__stmtMap.delete(this);
__udfMap.delete(this);
capi.sqlite3_close_v2(pDb);
+ if(this.onclose && (this.onclose.after instanceof Function)){
+ try{this.onclose.after(this)}
+ catch(e){/*ignore*/}
+ }
delete this.filename;
}
},
@@ -401,13 +483,13 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}
},
/**
- Similar to this.filename but will return NULL for special names
- like ":memory:". Not of much use until we have filesystem
- support. Throws if the DB has been closed. If passed an
- argument it then it will return the filename of the ATTACHEd db
- with that name, else it assumes a name of `main`.
+ Similar to this.filename but will return a falsy value for
+ special names like ":memory:". Throws if the DB has been
+ closed. If passed an argument it then it will return the
+ filename of the ATTACHEd db with that name, else it assumes a
+ name of `main`.
*/
- fileName: function(dbName='main'){
+ getFilename: function(dbName='main'){
return capi.sqlite3_db_filename(affirmDbOpen(this).pointer, dbName);
},
/**
@@ -1591,7 +1673,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
ooApi: "0.1"
},
DB,
- Stmt
+ Stmt,
+ dbCtorHelper
}/*oo1 object*/;
});
diff --git a/ext/wasm/api/sqlite3-api-opfs.js b/ext/wasm/api/sqlite3-api-opfs.js
index af1c6f760..ede4fb32b 100644
--- a/ext/wasm/api/sqlite3-api-opfs.js
+++ b/ext/wasm/api/sqlite3-api-opfs.js
@@ -42,8 +42,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
that number will increase as the OPFS API matures).
- The OPFS features used here are only available in dedicated Worker
- threads. This file tries to detect that case and becomes a no-op
- if those features do not seem to be available.
+ threads. This file tries to detect that case, resulting in a
+ rejected Promise if those features do not seem to be available.
- It requires the SharedArrayBuffer and Atomics classes, and the
former is only available if the HTTP server emits the so-called
@@ -72,7 +72,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
returned Promise resolves.
On success, the Promise resolves to the top-most sqlite3 namespace
- object.
+ object and that object gets a new object installed in its
+ `opfs` property, containing several OPFS-specific utilities.
*/
sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri){
const options = (asyncProxyUri && 'object'===asyncProxyUri) ? asyncProxyUri : {
@@ -89,6 +90,13 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
options.proxyUri = callee.defaultProxyUri;
}
delete sqlite3.installOpfsVfs;
+
+ /**
+ Generic utilities for working with OPFS. This will get filled out
+ by the Promise setup and, on success, installed as sqlite3.opfs.
+ */
+ const opfsUtil = Object.create(null);
+
const thePromise = new Promise(function(promiseResolve, promiseReject){
const logPrefix = "OPFS syncer:";
const warn = (...args)=>{
@@ -118,9 +126,8 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
const sqlite3_vfs = capi.sqlite3_vfs;
const sqlite3_file = capi.sqlite3_file;
const sqlite3_io_methods = capi.sqlite3_io_methods;
- const StructBinder = sqlite3.StructBinder;
const W = new Worker(options.proxyUri);
- const workerOrigOnError = W.onrror;
+ W._originalOnError = W.onerror /* will be restored later */;
W.onerror = function(err){
promiseReject(new Error("Loading OPFS async Worker failed for unknown reasons."));
};
@@ -131,17 +138,37 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
This object must initially contain only cloneable or sharable
objects. After the worker's "inited" message arrives, other types
of data may be added to it.
+
+ For purposes of Atomics.wait() and Atomics.notify(), we use a
+ SharedArrayBuffer with one slot reserved for each of the API
+ proxy's methods. The sync side of the API uses Atomics.wait()
+ on the corresponding slot and the async side uses
+ Atomics.notify() on that slot.
+
+ The approach of using a single SAB to serialize comms for all
+ instances might(?) lead to deadlock situations in multi-db
+ cases. We should probably have one SAB here with a single slot
+ for locking a per-file initialization step and then allocate a
+ separate SAB like the above one for each file. That will
+ require a bit of acrobatics but should be feasible.
*/
const state = Object.create(null);
state.verbose = options.verbose;
- state.fileBufferSize = 1024 * 64 + 8 /* size of fileHandle.sab. 64k = max sqlite3 page size */;
- state.fbInt64Offset = state.fileBufferSize - 8 /*spot in fileHandle.sab to store an int64*/;
+ state.fileBufferSize =
+ 1024 * 64 + 8 /* size of aFileHandle.sab. 64k = max sqlite3 page
+ size. The additional bytes are space for
+ holding BigInt results, since we cannot store
+ those via the Atomics API (which only works on
+ an Int32Array). */;
+ state.fbInt64Offset =
+ state.fileBufferSize - 8 /*spot in fileHandle.sab to store an int64 result */;
state.opIds = Object.create(null);
{
let i = 0;
state.opIds.xAccess = i++;
state.opIds.xClose = i++;
state.opIds.xDelete = i++;
+ state.opIds.xDeleteNoWait = i++;
state.opIds.xFileSize = i++;
state.opIds.xOpen = i++;
state.opIds.xRead = i++;
@@ -149,14 +176,8 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
state.opIds.xSync = i++;
state.opIds.xTruncate = i++;
state.opIds.xWrite = i++;
+ state.opIds.mkdir = i++;
state.opSAB = new SharedArrayBuffer(i * 4/*sizeof int32*/);
- /* The approach of using a single SAB to serialize comms for all
- instances may(?) lead to deadlock situations in multi-db
- cases. We should probably have one SAB here with a single slot
- for locking a per-file initialization step and then allocate a
- separate SAB like the above one for each file. That will
- require a bit of acrobatics but should be feasible.
- */
}
state.sq3Codes = Object.create(null);
@@ -167,15 +188,14 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
'SQLITE_IOERR_READ', 'SQLITE_IOERR_SHORT_READ',
'SQLITE_IOERR_WRITE', 'SQLITE_IOERR_FSYNC',
'SQLITE_IOERR_TRUNCATE', 'SQLITE_IOERR_DELETE',
- 'SQLITE_IOERR_ACCESS', 'SQLITE_IOERR_CLOSE'
+ 'SQLITE_IOERR_ACCESS', 'SQLITE_IOERR_CLOSE',
+ 'SQLITE_IOERR_DELETE'
].forEach(function(k){
state.sq3Codes[k] = capi[k] || toss("Maintenance required: not found:",k);
state.sq3Codes._reverse[capi[k]] = k;
});
const isWorkerErrCode = (n)=>!!state.sq3Codes._reverse[n];
- const opStore = (op,val=-1)=>Atomics.store(state.opSABView, state.opIds[op], val);
- const opWait = (op,val=-1)=>Atomics.wait(state.opSABView, state.opIds[op], val);
/**
Runs the given operation in the async worker counterpart, waits
@@ -185,9 +205,9 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
given operation's signature in the async API counterpart.
*/
const opRun = (op,args)=>{
- opStore(op);
+ Atomics.store(state.opSABView, state.opIds[op], -1);
wMsg(op, args);
- opWait(op);
+ Atomics.wait(state.opSABView, state.opIds[op], -1);
return Atomics.load(state.opSABView, state.opIds[op]);
};
@@ -268,7 +288,7 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
func with the same signature as described above.
*/
const installMethod = function callee(tgt, name, func){
- if(!(tgt instanceof StructBinder.StructType)){
+ if(!(tgt instanceof sqlite3.StructBinder.StructType)){
toss("Usage error: target object is-not-a StructType.");
}
if(1===arguments.length){
@@ -429,7 +449,10 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
return 0;
},
xDelete: function(pVfs, zName, doSyncDir){
- return opRun('xDelete', {filename: wasm.cstringToJs(zName), syncDir: doSyncDir});
+ opRun('xDelete', {filename: wasm.cstringToJs(zName), syncDir: doSyncDir});
+ /* We're ignoring errors because we cannot yet differentiate
+ between harmless and non-harmless failures. */
+ return 0;
},
xFullPathname: function(pVfs,zName,nOut,pOut){
/* Until/unless we have some notion of "current dir"
@@ -521,6 +544,65 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
for(let k of Object.keys(ioSyncWrappers)) inst(k, ioSyncWrappers[k]);
inst = installMethod(opfsVfs);
for(let k of Object.keys(vfsSyncWrappers)) inst(k, vfsSyncWrappers[k]);
+
+
+ /**
+ Syncronously deletes the given OPFS filesystem entry, ignoring
+ any errors. As this environment has no notion of "current
+ directory", the given name must be an absolute path. If the 2nd
+ argument is truthy, deletion is recursive (use with caution!).
+
+ Returns true if the deletion succeeded and fails if it fails,
+ but cannot report the nature of the failure.
+ */
+ opfsUtil.deleteEntry = function(fsEntryName,recursive){
+ return 0===opRun('xDelete', {filename:fsEntryName, recursive});
+ };
+ /**
+ Exactly like deleteEntry() but runs asynchronously.
+ */
+ opfsUtil.deleteEntryAsync = async function(fsEntryName,recursive){
+ wMsg('xDeleteNoWait', {filename: fsEntryName, recursive});
+ };
+ /**
+ Synchronously creates the given directory name, recursively, in
+ the OPFS filesystem. Returns true if it succeeds or the
+ directory already exists, else false.
+ */
+ opfsUtil.mkdir = async function(absDirName){
+ return 0===opRun('mkdir', absDirName);
+ };
+ /**
+ Synchronously checks whether the given OPFS filesystem exists,
+ returning true if it does, false if it doesn't.
+ */
+ opfsUtil.entryExists = function(fsEntryName){
+ return 0===opRun('xAccess', fsEntryName);
+ };
+
+ /**
+ Generates a random ASCII string, intended for use as a
+ temporary file name. Its argument is the length of the string,
+ defaulting to 16.
+ */
+ opfsUtil.randomFilename = randomFilename;
+
+ if(sqlite3.oo1){
+ opfsUtil.OpfsDb = function(...args){
+ const opt = sqlite3.oo1.dbCtorHelper.normalizeArgs(...args);
+ opt.vfs = opfsVfs.$zName;
+ sqlite3.oo1.dbCtorHelper.call(this, opt);
+ };
+ opfsUtil.OpfsDb.prototype = Object.create(sqlite3.oo1.DB.prototype);
+ }
+
+ /**
+ Potential TODOs:
+
+ - Expose one or both of the Worker objects via opfsUtil and
+ publish an interface for proxying the higher-level OPFS
+ features like getting a directory listing.
+ */
const sanityCheck = async function(){
const scope = wasm.scopedAllocPush();
@@ -605,7 +687,9 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
warn("Running sanity checks because of opfs-sanity-check URL arg...");
sanityCheck();
}
- W.onerror = workerOrigOnError;
+ W.onerror = W._originalOnError;
+ delete W._originalOnError;
+ sqlite3.opfs = opfsUtil;
promiseResolve(sqlite3);
log("End of OPFS sqlite3_vfs setup.", opfsVfs);
}catch(e){
diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js
index 1fc533da6..add8ad658 100644
--- a/ext/wasm/api/sqlite3-api-prologue.js
+++ b/ext/wasm/api/sqlite3-api-prologue.js
@@ -689,7 +689,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
/** State for sqlite3_web_persistent_dir(). */
let __persistentDir;
/**
- An experiment. Do not use.
+ An experiment. Do not use in client code.
If the wasm environment has a persistent storage directory,
its path is returned by this function. If it does not then
@@ -699,14 +699,18 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
environment to determine whether persistence filesystem support
is available and, if it is, enables it (if needed).
+ This function currently only recognizes the WASMFS/OPFS storage
+ combination. "Plain" OPFS is provided via a separate VFS which
+ can optionally be installed (if OPFS is available on the system)
+ using sqlite3.installOpfsVfs().
+
TODOs and caveats:
- If persistent storage is available at the root of the virtual
filesystem, this interface cannot currently distinguish that
- from the lack of persistence. That case cannot currently (with
- WASMFS/OPFS) happen, but it is conceivably possible in future
- environments or non-browser runtimes (none of which are yet
- supported targets).
+ from the lack of persistence. That can (in the mean time)
+ happen when using the JS-native "opfs" VFS, as opposed to the
+ WASMFS/OPFS combination.
*/
capi.sqlite3_web_persistent_dir = function(){
if(undefined !== __persistentDir) return __persistentDir;
@@ -764,6 +768,49 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
capi.wasm.exports.sqlite3_initialize();
}
+ /**
+ Given an `sqlite3*` and an sqlite3_vfs name, returns a truthy
+ value (see below) if that db handle uses that VFS, else returns
+ false. If pDb is falsy then this function returns a truthy value
+ if the default VFS is that VFS. Results are undefined if pDb is
+ truthy but refers to an invalid pointer.
+
+ The 2nd argument may either be a JS string or a C-string
+ allocated from the wasm environment.
+
+ The truthy value it returns is a pointer to the `sqlite3_vfs`
+ object.
+
+ To permit safe use of this function from APIs which may be called
+ via the C stack (like SQL UDFs), this function does not throw: if
+ bad arguments cause a conversion error when passing into
+ wasm-space, false is returned.
+ */
+ capi.sqlite3_web_db_uses_vfs = function(pDb,vfsName){
+ try{
+ const pK = ('number'===vfsName)
+ ? capi.wasm.exports.sqlite3_vfs_find(vfsName)
+ : capi.sqlite3_vfs_find(vfsName);
+ if(!pK) return false;
+ else if(!pDb){
+ return capi.sqlite3_vfs_find(0)===pK ? pK : false;
+ }
+ const ppVfs = capi.wasm.allocPtr();
+ try{
+ return (
+ (0===capi.sqlite3_file_control(
+ pDb, "main", capi.SQLITE_FCNTL_VFS_POINTER, ppVfs
+ )) && (capi.wasm.getPtrValue(ppVfs) === pK)
+ ) ? pK : false;
+ }finally{
+ capi.wasm.dealloc(ppVfs);
+ }
+ }catch(e){
+ /* Ignore - probably bad args to a wasm-bound function. */
+ return false;
+ }
+ };
+
if( self.window===self ){
/* Features specific to the main window thread... */
@@ -812,7 +859,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
/**
This routine guesses the approximate amount of
window.localStorage and/or window.sessionStorage in use by the
- kvvfs database backend. Its argument must be one of
+ kvvfs database backend. Its argument must be one of
('session', 'local', ''). In the first two cases, only
sessionStorage resp. localStorage is counted. If it's an empty
string (the default) then both are counted. Only storage keys
@@ -842,34 +889,6 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
return sz * 2 /* because JS uses UC16 encoding */;
};
- /**
- Given an `sqlite3*`, returns a truthy value (see below) if that
- db handle uses the "kvvfs" VFS, else returns false. If pDb is
- NULL then this function returns true if the default VFS is
- "kvvfs". Results are undefined if pDb is truthy but refers to
- an invalid pointer.
-
- The truthy value it returns is a pointer to the kvvfs
- `sqlite3_vfs` object.
- */
- capi.sqlite3_web_db_is_kvvfs = function(pDb){
- const pK = capi.sqlite3_vfs_find("kvvfs");
- if(!pK) return false;
- else if(!pDb){
- return capi.sqlite3_vfs_find(0) && pK;
- }
- const scope = capi.wasm.scopedAllocPush();
- try{
- const ppVfs = capi.wasm.scopedAllocPtr();
- return (
- (0===capi.sqlite3_file_control(
- pDb, "main", capi.SQLITE_FCNTL_VFS_POINTER, ppVfs
- )) && (capi.wasm.getPtrValue(ppVfs) === pK)
- ) ? pK : false;
- }finally{
- capi.wasm.scopedAllocPop(scope);
- }
- };
}/* main-window-only bits */
/* The remainder of the API will be set up in later steps. */
diff --git a/ext/wasm/api/sqlite3-api-worker1.js b/ext/wasm/api/sqlite3-api-worker1.js
index 00359413b..97f2677e6 100644
--- a/ext/wasm/api/sqlite3-api-worker1.js
+++ b/ext/wasm/api/sqlite3-api-worker1.js
@@ -371,10 +371,14 @@ sqlite3.initWorker1API = function(){
close: function(db,alsoUnlink){
if(db){
delete this.dbs[getDbId(db)];
- const filename = db.fileName();
+ const filename = db.getFilename();
db.close();
if(db===this.defaultDb) this.defaultDb = undefined;
if(alsoUnlink && filename){
+ /* This isn't necessarily correct: the db might be using a
+ VFS other than the default. How do we best resolve this
+ without having to special-case the kvvfs and opfs
+ VFSes? */
sqlite3.capi.wasm.sqlite3_wasm_vfs_unlink(filename);
}
}