1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-29 08:01:23 +03:00

Minor cleanups, reorgs, and doc updates for the JS APIs. Renamed sqlite3(-api)-worker.js to sqlite3(-api)-worker1.js, for symmetry with sqlite3-api-oo1.js.

FossilOrigin-Name: f5059ee6f9fc55a381cbf08a30dfb9a5636c0b44341e42f4e9f12a3b109b5507
This commit is contained in:
stephan
2022-08-17 16:44:05 +00:00
parent 6e901b07a3
commit 453af2f6cc
12 changed files with 214 additions and 211 deletions

View File

@ -128,7 +128,7 @@ sqlite3-api.jses := \
$(dir.jacc)/jaccwabyt.js \ $(dir.jacc)/jaccwabyt.js \
$(dir.api)/sqlite3-api-glue.js \ $(dir.api)/sqlite3-api-glue.js \
$(dir.api)/sqlite3-api-oo1.js \ $(dir.api)/sqlite3-api-oo1.js \
$(dir.api)/sqlite3-api-worker.js $(dir.api)/sqlite3-api-worker1.js
#sqlite3-api.jses += $(dir.api)/sqlite3-api-opfs.js #sqlite3-api.jses += $(dir.api)/sqlite3-api-opfs.js
sqlite3-api.jses += $(dir.api)/sqlite3-api-cleanup.js sqlite3-api.jses += $(dir.api)/sqlite3-api-cleanup.js

View File

@ -60,17 +60,17 @@ browser client:
high-level sqlite3 JS wrappers and should feel relatively familiar high-level sqlite3 JS wrappers and should feel relatively familiar
to anyone familiar with such APIs. That said, it is not a "required to anyone familiar with such APIs. That said, it is not a "required
component" and can be elided from builds which do not want it. component" and can be elided from builds which do not want it.
- `sqlite3-api-worker.js`\ - `sqlite3-api-worker1.js`\
A Worker-thread-based API which uses OO API #1 to provide an A Worker-thread-based API which uses OO API #1 to provide an
interface to a database which can be driven from the main Window interface to a database which can be driven from the main Window
thread via the Worker message-passing interface. Like OO API #1, thread via the Worker message-passing interface. Like OO API #1,
this is an optional component, offering one of any number of this is an optional component, offering one of any number of
potential implementations for such an API. potential implementations for such an API.
- `sqlite3-worker.js`\ - `sqlite3-worker1.js`\
Is not part of the amalgamated sources and is intended to be Is not part of the amalgamated sources and is intended to be
loaded by a client Worker thread. It loads the sqlite3 module loaded by a client Worker thread. It loads the sqlite3 module
and runs the Worker API which is implemented in and runs the Worker #1 API which is implemented in
`sqlite3-api-worker.js`. `sqlite3-api-worker1.js`.
- `sqlite3-api-opfs.js`\ - `sqlite3-api-opfs.js`\
is an in-development/experimental sqlite3 VFS wrapper, the goal of is an in-development/experimental sqlite3 VFS wrapper, the goal of
which being to use Google Chrome's Origin-Private FileSystem (OPFS) which being to use Google Chrome's Origin-Private FileSystem (OPFS)

View File

@ -128,7 +128,7 @@
*/ */
__prepare.basic = wasm.xWrap('sqlite3_prepare_v3', __prepare.basic = wasm.xWrap('sqlite3_prepare_v3',
"int", ["sqlite3*", "string", "int", ["sqlite3*", "string",
"int"/*MUST always be negative*/, "int"/*ignored for this impl!*/,
"int", "**", "int", "**",
"**"/*MUST be 0 or null or undefined!*/]); "**"/*MUST be 0 or null or undefined!*/]);
/** /**
@ -148,19 +148,10 @@
/* Documented in the api object's initializer. */ /* Documented in the api object's initializer. */
capi.sqlite3_prepare_v3 = function f(pDb, sql, sqlLen, prepFlags, ppStmt, pzTail){ capi.sqlite3_prepare_v3 = function f(pDb, sql, sqlLen, prepFlags, ppStmt, pzTail){
/* 2022-07-08: xWrap() 'string' arg handling may be able do this
special-case handling for us. It needs to be tested. Or maybe
not: we always want to treat pzTail as null when passed a
non-pointer SQL string and the argument adapters don't have
enough state to know that. Maybe they could/should, by passing
the currently-collected args as an array as the 2nd arg to the
argument adapters? Or maybe we collect all args in an array,
pass that to an optional post-args-collected callback, and give
it a chance to manipulate the args before we pass them on? */
if(util.isSQLableTypedArray(sql)) sql = util.typedArrayToString(sql); if(util.isSQLableTypedArray(sql)) sql = util.typedArrayToString(sql);
switch(typeof sql){ switch(typeof sql){
case 'string': return __prepare.basic(pDb, sql, -1, prepFlags, ppStmt, null); case 'string': return __prepare.basic(pDb, sql, -1, prepFlags, ppStmt, null);
case 'number': return __prepare.full(pDb, sql, sqlLen||-1, prepFlags, ppStmt, pzTail); case 'number': return __prepare.full(pDb, sql, sqlLen, prepFlags, ppStmt, pzTail);
default: default:
return util.sqlite3_wasm_db_error( return util.sqlite3_wasm_db_error(
pDb, capi.SQLITE_MISUSE, pDb, capi.SQLITE_MISUSE,

View File

@ -322,15 +322,14 @@
} }
}, },
/** /**
Similar to this.filename but will return NULL for Similar to this.filename but will return NULL for special names
special names like ":memory:". Not of much use until like ":memory:". Not of much use until we have filesystem
we have filesystem support. Throws if the DB has support. Throws if the DB has been closed. If passed an
been closed. If passed an argument it then it will return argument it then it will return the filename of the ATTACHEd db
the filename of the ATTACHEd db with that name, else it assumes with that name, else it assumes a name of `main`.
a name of `main`.
*/ */
fileName: function(dbName){ fileName: function(dbName='main'){
return capi.sqlite3_db_filename(affirmDbOpen(this).pointer, dbName||"main"); return capi.sqlite3_db_filename(affirmDbOpen(this).pointer, dbName);
}, },
/** /**
Returns true if this db instance has a name which resolves to a Returns true if this db instance has a name which resolves to a
@ -759,7 +758,7 @@
capi.sqlite3_result_null(pCx); capi.sqlite3_result_null(pCx);
break; break;
}else if(util.isBindableTypedArray(val)){ }else if(util.isBindableTypedArray(val)){
const pBlob = capi.wasm.mallocFromTypedArray(val); const pBlob = capi.wasm.allocFromTypedArray(val);
capi.sqlite3_result_blob(pCx, pBlob, val.byteLength, capi.sqlite3_result_blob(pCx, pBlob, val.byteLength,
capi.SQLITE_TRANSIENT); capi.SQLITE_TRANSIENT);
capi.wasm.dealloc(pBlob); capi.wasm.dealloc(pBlob);
@ -1072,7 +1071,7 @@
capi.wasm.scopedAllocPop(stack); capi.wasm.scopedAllocPop(stack);
} }
}else{ }else{
const pBlob = capi.wasm.mallocFromTypedArray(val); const pBlob = capi.wasm.allocFromTypedArray(val);
try{ try{
rc = capi.sqlite3_bind_blob(stmt.pointer, ndx, pBlob, val.byteLength, rc = capi.sqlite3_bind_blob(stmt.pointer, ndx, pBlob, val.byteLength,
capi.SQLITE_TRANSIENT); capi.SQLITE_TRANSIENT);

View File

@ -172,36 +172,6 @@ self.sqlite3ApiBootstrap = function(config){
counterparts. counterparts.
*/ */
const capi = { const capi = {
/**
An Error subclass which is thrown by this object's alloc() method
on OOM.
*/
WasmAllocError: WasmAllocError,
/**
The API's one single point of access to the WASM-side memory
allocator. Works like malloc(3) (and is likely bound to
malloc()) but throws an WasmAllocError if allocation fails. It is
important that any code which might pass through the sqlite3 C
API NOT throw and must instead return SQLITE_NOMEM (or
equivalent, depending on the context).
That said, very few cases in the API can result in
client-defined functions propagating exceptions via the C-style
API. Most notably, this applies ot User-defined SQL Functions
(UDFs) registered via sqlite3_create_function_v2(). For that
specific case it is recommended that all UDF creation be
funneled through a utility function and that a wrapper function
be added around the UDF which catches any exception and sets
the error state to OOM. (The overall complexity of registering
UDFs essentially requires a helper for doing so!)
*/
alloc: undefined/*installed later*/,
/**
The API's one single point of access to the WASM-side memory
deallocator. Works like free(3) (and is likely bound to
free()).
*/
dealloc: undefined/*installed later*/,
/** /**
When using sqlite3_open_v2() it is important to keep the following When using sqlite3_open_v2() it is important to keep the following
in mind: in mind:
@ -365,6 +335,33 @@ self.sqlite3ApiBootstrap = function(config){
|| toss("API config object requires a WebAssembly.Memory object", || toss("API config object requires a WebAssembly.Memory object",
"in either config.exports.memory (exported)", "in either config.exports.memory (exported)",
"or config.memory (imported)."), "or config.memory (imported)."),
/**
The API's one single point of access to the WASM-side memory
allocator. Works like malloc(3) (and is likely bound to
malloc()) but throws an WasmAllocError if allocation fails. It is
important that any code which might pass through the sqlite3 C
API NOT throw and must instead return SQLITE_NOMEM (or
equivalent, depending on the context).
That said, very few cases in the API can result in
client-defined functions propagating exceptions via the C-style
API. Most notably, this applies ot User-defined SQL Functions
(UDFs) registered via sqlite3_create_function_v2(). For that
specific case it is recommended that all UDF creation be
funneled through a utility function and that a wrapper function
be added around the UDF which catches any exception and sets
the error state to OOM. (The overall complexity of registering
UDFs essentially requires a helper for doing so!)
*/
alloc: undefined/*installed later*/,
/**
The API's one single point of access to the WASM-side memory
deallocator. Works like free(3) (and is likely bound to
free()).
*/
dealloc: undefined/*installed later*/
/* Many more wasm-related APIs get installed later on. */ /* Many more wasm-related APIs get installed later on. */
}/*wasm*/ }/*wasm*/
}/*capi*/; }/*capi*/;
@ -387,7 +384,7 @@ self.sqlite3ApiBootstrap = function(config){
Int8Array types and will throw if srcTypedArray is of Int8Array types and will throw if srcTypedArray is of
any other type. any other type.
*/ */
capi.wasm.mallocFromTypedArray = function(srcTypedArray){ capi.wasm.allocFromTypedArray = function(srcTypedArray){
affirmBindableTypedArray(srcTypedArray); affirmBindableTypedArray(srcTypedArray);
const pRet = this.alloc(srcTypedArray.byteLength || 1); const pRet = this.alloc(srcTypedArray.byteLength || 1);
this.heapForSize(srcTypedArray.constructor).set(srcTypedArray.byteLength ? srcTypedArray : [0], pRet); this.heapForSize(srcTypedArray.constructor).set(srcTypedArray.byteLength ? srcTypedArray : [0], pRet);
@ -400,11 +397,13 @@ self.sqlite3ApiBootstrap = function(config){
const f = capi.wasm.exports[key]; const f = capi.wasm.exports[key];
if(!(f instanceof Function)) toss("Missing required exports[",key,"] function."); if(!(f instanceof Function)) toss("Missing required exports[",key,"] function.");
} }
capi.wasm.alloc = function(n){ capi.wasm.alloc = function(n){
const m = this.exports[keyAlloc](n); const m = this.exports[keyAlloc](n);
if(!m) throw new WasmAllocError("Failed to allocate "+n+" bytes."); if(!m) throw new WasmAllocError("Failed to allocate "+n+" bytes.");
return m; return m;
}.bind(capi.wasm) }.bind(capi.wasm)
capi.wasm.dealloc = (m)=>capi.wasm.exports[keyDealloc](m); capi.wasm.dealloc = (m)=>capi.wasm.exports[keyDealloc](m);
/** /**
@ -554,7 +553,8 @@ self.sqlite3ApiBootstrap = function(config){
["sqlite3_value_text", "string", "*"], ["sqlite3_value_text", "string", "*"],
["sqlite3_value_type", "int", "*"], ["sqlite3_value_type", "int", "*"],
["sqlite3_vfs_find", "*", "string"], ["sqlite3_vfs_find", "*", "string"],
["sqlite3_vfs_register", "int", "*", "int"] ["sqlite3_vfs_register", "int", "*", "int"],
["sqlite3_wasm_vfs_unlink", "int", "string"]
]/*capi.wasm.bindingSignatures*/; ]/*capi.wasm.bindingSignatures*/;
if(false && capi.wasm.compileOptionUsed('SQLITE_ENABLE_NORMALIZE')){ if(false && capi.wasm.compileOptionUsed('SQLITE_ENABLE_NORMALIZE')){
@ -583,18 +583,26 @@ self.sqlite3ApiBootstrap = function(config){
If the wasm environment has a persistent storage directory, If the wasm environment has a persistent storage directory,
its path is returned by this function. If it does not then its path is returned by this function. If it does not then
it returns one of: it returns "" (noting that "" is a falsy value).
- `undefined` if initIfNeeded is false and this function has The first time this is called, this function inspects the current
never been called before. environment to determine whether persistence filesystem support
is available and, if it is, enables it (if needed).
- `""` if no persistent storage is available. TODOs and caveats:
Note that in both cases the return value is falsy. - The directory name (mount point) for persistent storage is
currently hard-coded. It needs to be configurable.
- 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).
*/ */
capi.sqlite3_web_persistent_dir = function(initIfNeeded=true){ capi.sqlite3_web_persistent_dir = function(){
if(undefined !== __persistentDir) return __persistentDir; if(undefined !== __persistentDir) return __persistentDir;
else if(!initIfNeeded) return;
// If we have no OPFS, there is no persistent dir // If we have no OPFS, there is no persistent dir
if(!self.FileSystemHandle || !self.FileSystemDirectoryHandle if(!self.FileSystemHandle || !self.FileSystemDirectoryHandle
|| !self.FileSystemFileHandle){ || !self.FileSystemFileHandle){
@ -625,8 +633,22 @@ self.sqlite3ApiBootstrap = function(config){
} }
}.bind(capi); }.bind(capi);
/**
Returns true if sqlite3.capi.sqlite3_web_persistent_dir() is a
non-empty string and the given name has that string as its
prefix, else returns false.
*/
capi.sqlite3_web_filename_is_persistent = function(name){
const p = this.sqlite3_web_persistent_dir();
return (p && name) ? name.startsWith(p) : false;
}.bind(capi);
/* The remainder of the API will be set up in later steps. */ /* The remainder of the API will be set up in later steps. */
return { return {
/**
An Error subclass which is thrown by this.wasm.alloc() on OOM.
*/
WasmAllocError: WasmAllocError,
capi, capi,
postInit: [ postInit: [
/* some pieces of the API may install functions into this array, /* some pieces of the API may install functions into this array,
@ -635,8 +657,6 @@ self.sqlite3ApiBootstrap = function(config){
the current global object and sqlite3 is the object returned the current global object and sqlite3 is the object returned
from sqlite3ApiBootstrap(). This array will be removed at the from sqlite3ApiBootstrap(). This array will be removed at the
end of the API setup process. */], end of the API setup process. */],
/** Config is needed downstream for gluing pieces together. It
will be removed at the end of the API setup process. */
config config
}; };
}/*sqlite3ApiBootstrap()*/; }/*sqlite3ApiBootstrap()*/;

View File

@ -10,26 +10,40 @@
*********************************************************************** ***********************************************************************
This file implements a Worker-based wrapper around SQLite3 OO API This file implements the initializer for the sqlite3 "Worker API
#1. #1", a very basic DB access API intended to be scripted from a main
window thread via Worker-style messages. Because of limitations in
that type of communication, this API is minimalistic and only
capable of serving relatively basic DB requests (e.g. it cannot
process nested query loops concurrently).
This file requires that the core C-style sqlite3 API and OO API #1
have been loaded.
*/
/**
This function implements a Worker-based wrapper around SQLite3 OO
API #1, colloquially known as "Worker API #1".
In order to permit this API to be loaded in worker threads without In order to permit this API to be loaded in worker threads without
automatically registering onmessage handlers, initializing the automatically registering onmessage handlers, initializing the
worker API requires calling initWorkerAPI(). If this function worker API requires calling initWorker1API(). If this function
is called from a non-worker thread then it throws an exception. is called from a non-worker thread then it throws an exception.
When initialized, it installs message listeners to receive messages When initialized, it installs message listeners to receive Worker
from the main thread and then it posts a message in the form: messages and then it posts a message in the form:
``` ```
{type:'sqlite3-api',data:'worker-ready'} {type:'sqlite3-api',data:'worker1-ready'}
``` ```
This file requires that the core C-style sqlite3 API and OO API #1 to let the client know that it has been initialized. Clients may
have been loaded and that self.sqlite3 contains both, optionally depend on this function not returning until
as documented for those APIs. initialization is complete, as the initialization is synchronous.
In some contexts, however, listening for the above message is
a better fit.
*/ */
self.sqlite3.initWorkerAPI = function(){ self.sqlite3.initWorker1API = function(){
'use strict'; 'use strict';
/** /**
UNDER CONSTRUCTION UNDER CONSTRUCTION
@ -39,39 +53,12 @@ self.sqlite3.initWorkerAPI = function(){
cannot pass callback functions between the window thread and a cannot pass callback functions between the window thread and a
worker thread, so we have to receive all db results via worker thread, so we have to receive all db results via
asynchronous message-passing. That requires an asychronous API asynchronous message-passing. That requires an asychronous API
with a distinctly different shape that the main OO API. with a distinctly different shape than OO API #1.
Certain important considerations here include: TODOs include, but are not necessarily limited to:
- Support only one db connection or multiple? The former is far - Support for handling multiple DBs via this interface is under
easier, but there's always going to be a user out there who wants development.
to juggle six database handles at once. Do we add that complexity
or tell such users to write their own code using the provided
lower-level APIs?
- Fetching multiple results: do we pass them on as a series of
messages, with start/end messages on either end, or do we collect
all results and bundle them back in a single message? The former
is, generically speaking, more memory-efficient but the latter
far easier to implement in this environment. The latter is
untennable for large data sets. Despite a web page hypothetically
being a relatively limited environment, there will always be
those users who feel that they should/need to be able to work
with multi-hundred-meg (or larger) blobs, and passing around
arrays of those may quickly exhaust the JS engine's memory.
TODOs include, but are not limited to:
- The ability to manage multiple DB handles. This can
potentially be done via a simple mapping of DB.filename or
DB.pointer (`sqlite3*` handle) to DB objects. The open()
interface would need to provide an ID (probably DB.pointer) back
to the user which can optionally be passed as an argument to
the other APIs (they'd default to the first-opened DB, for
ease of use). Client-side usability of this feature would
benefit from making another wrapper class (or a singleton)
available to the main thread, with that object proxying all(?)
communication with the worker.
- Revisit how virtual files are managed. We currently delete DBs - Revisit how virtual files are managed. We currently delete DBs
from the virtual filesystem when we close them, for the sake of from the virtual filesystem when we close them, for the sake of
@ -79,6 +66,8 @@ self.sqlite3.initWorkerAPI = function(){
require that we give up that habit. Similarly, fully supporting require that we give up that habit. Similarly, fully supporting
ATTACH, where a user can upload multiple DBs and ATTACH them, ATTACH, where a user can upload multiple DBs and ATTACH them,
also requires the that we manage the VFS entries better. also requires the that we manage the VFS entries better.
Related: we most definitely do not want to delete persistent DBs
(e.g. stored on OPFS) when they're closed.
*/ */
const toss = (...args)=>{throw new Error(args.join(' '))}; const toss = (...args)=>{throw new Error(args.join(' '))};
if('function' !== typeof importScripts){ if('function' !== typeof importScripts){
@ -116,8 +105,7 @@ self.sqlite3.initWorkerAPI = function(){
// same filename and close/reopen it (or just pass it back as is?). // same filename and close/reopen it (or just pass it back as is?).
if(!arg && this.defaultDb) return this.defaultDb; if(!arg && this.defaultDb) return this.defaultDb;
//???if(this.defaultDb) this.defaultDb.close(); //???if(this.defaultDb) this.defaultDb.close();
let db; const db = (Array.isArray(arg) ? new DB(...arg) : new DB(arg));
db = (Array.isArray(arg) ? new DB(...arg) : new DB(arg));
this.dbs[getDbId(db)] = db; this.dbs[getDbId(db)] = db;
if(!this.defaultDb) this.defaultDb = db; if(!this.defaultDb) this.defaultDb = db;
return db; return db;
@ -125,13 +113,17 @@ self.sqlite3.initWorkerAPI = function(){
close: function(db,alsoUnlink){ close: function(db,alsoUnlink){
if(db){ if(db){
delete this.dbs[getDbId(db)]; delete this.dbs[getDbId(db)];
db.close(alsoUnlink); const filename = db.fileName();
db.close();
if(db===this.defaultDb) this.defaultDb = undefined; if(db===this.defaultDb) this.defaultDb = undefined;
if(alsoUnlink && filename){
sqlite3.capi.sqlite3_wasm_vfs_unlink(filename);
}
} }
}, },
post: function(type,data,xferList){ post: function(type,data,xferList){
if(xferList){ if(xferList){
self.postMessage({type, data},xferList); self.postMessage( {type, data}, xferList );
xferList.length = 0; xferList.length = 0;
}else{ }else{
self.postMessage({type, data}); self.postMessage({type, data});
@ -172,6 +164,68 @@ self.sqlite3.initWorkerAPI = function(){
*/ */
const wMsgHandler = { const wMsgHandler = {
xfer: [/*Temp holder for "transferable" postMessage() state.*/], xfer: [/*Temp holder for "transferable" postMessage() state.*/],
/**
Proxy for the DB constructor. Expects to be passed a single
object or a falsy value to use defaults. The object may
have a filename property to name the db file (see the DB
constructor for peculiarities and transformations) and/or a
buffer property (a Uint8Array holding a complete database
file's contents). The response is an object:
{
filename: db filename (possibly differing from the input),
dbId: an opaque ID value which must be passed to other calls
in this API to tell them which db to use. If it is not
provided to future calls, they will default to
operating on the first-opened db.
messageId: if the client-sent message included this field,
it is mirrored in the response.
}
*/
open: function(ev){
const args = [], data = (ev.data || {});
if(data.simulateError){ // undocumented internal testing option
toss("Throwing because of simulateError flag.");
}
if(data.filename) args.push(data.filename);
const db = wState.open(args);
return {
filename: db.filename,
dbId: getDbId(db)
};
},
/**
Proxy for DB.close(). If ev.data may either be a boolean or
an object with an `unlink` property. If that value is
truthy then the db file (if the db is currently open) will
be unlinked from the virtual filesystem, else it will be
kept intact. The response object is:
{
filename: db filename _if_ the db is opened when this
is called, else the undefined value,
unlink: boolean. If true, unlink() (delete) the db file
after closing int. Any error while deleting it is
ignored.
}
It does not error if the given db is already closed or no db is
provided. It is simply does nothing useful in that case.
*/
close: function(ev){
const db = getMsgDb(ev,false);
const response = {
filename: db && db.filename,
dbId: db ? getDbId(db) : undefined
};
if(db){
wState.close(db, !!((ev.data && 'object'===typeof ev.data)
? ev.data.unlink : false));
}
return response;
},
/** /**
Proxy for DB.exec() which expects a single argument of type Proxy for DB.exec() which expects a single argument of type
string (SQL to execute) or an options object in the form string (SQL to execute) or an options object in the form
@ -266,10 +320,16 @@ self.sqlite3.initWorkerAPI = function(){
exports of ":memory:" and "" (temp file) DBs. The latter is exports of ":memory:" and "" (temp file) DBs. The latter is
ostensibly easy because the file is (potentially) on disk, but ostensibly easy because the file is (potentially) on disk, but
the former does not have a structure which maps directly to a the former does not have a structure which maps directly to a
db file image. db file image. We can VACUUM INTO a :memory:/temp db into a
file for that purpose, though.
*/ */
export: function(ev){ export: function(ev){
toss("export() requires reimplementing for portability reasons."); toss("export() requires reimplementing for portability reasons.");
/**
We need to reimplement this to use the Emscripten FS
interface. That part used to be in the OO#1 API but that
dependency was removed from that level of the API.
*/
/**const db = getMsgDb(ev); /**const db = getMsgDb(ev);
const response = { const response = {
buffer: db.exportBinaryImage(), buffer: db.exportBinaryImage(),
@ -279,66 +339,6 @@ self.sqlite3.initWorkerAPI = function(){
this.xfer.push(response.buffer.buffer); this.xfer.push(response.buffer.buffer);
return response;**/ return response;**/
}/*export()*/, }/*export()*/,
/**
Proxy for the DB constructor. Expects to be passed a single
object or a falsy value to use defaults. The object may
have a filename property to name the db file (see the DB
constructor for peculiarities and transformations) and/or a
buffer property (a Uint8Array holding a complete database
file's contents). The response is an object:
{
filename: db filename (possibly differing from the input),
id: an opaque ID value intended for future distinction
between multiple db handles. Messages including a specific
ID will use the DB for that ID.
}
If the Worker's db is currently opened, this call closes it
before proceeding.
*/
open: function(ev){
wState.close(/*true???*/);
const args = [], data = (ev.data || {});
if(data.simulateError){
toss("Throwing because of open.simulateError flag.");
}
if(data.filename) args.push(data.filename);
if(data.buffer){
args.push(data.buffer);
this.xfer.push(data.buffer.buffer);
}
const db = wState.open(args);
return {
filename: db.filename,
dbId: getDbId(db)
};
},
/**
Proxy for DB.close(). If ev.data may either be a boolean or
an object with an `unlink` property. If that value is
truthy then the db file (if the db is currently open) will
be unlinked from the virtual filesystem, else it will be
kept intact. The response object is:
{
filename: db filename _if_ the db is opened when this
is called, else the undefined value
}
*/
close: function(ev){
const db = getMsgDb(ev,false);
const response = {
filename: db && db.filename
};
if(db){
wState.close(db, !!((ev.data && 'object'===typeof ev.data)
? ev.data.unlink : ev.data));
}
return response;
},
toss: function(ev){ toss: function(ev){
toss("Testing worker exception"); toss("Testing worker exception");
} }
@ -352,7 +352,8 @@ self.sqlite3.initWorkerAPI = function(){
{ type: apiCommand, { type: apiCommand,
dbId: optional DB ID value (else uses a default db handle) dbId: optional DB ID value (else uses a default db handle)
data: apiArguments data: apiArguments,
messageId: optional client-specific value
} }
As a rule, these commands respond with a postMessage() of their As a rule, these commands respond with a postMessage() of their
@ -416,5 +417,5 @@ self.sqlite3.initWorkerAPI = function(){
response.departureTime = ev.departureTime; response.departureTime = ev.departureTime;
wState.post(evType, response, wMsgHandler.xfer); wState.post(evType, response, wMsgHandler.xfer);
}; };
setTimeout(()=>self.postMessage({type:'sqlite3-api',data:'worker-ready'}), 0); setTimeout(()=>self.postMessage({type:'sqlite3-api',data:'worker1-ready'}), 0);
}.bind({self, sqlite3: self.sqlite3}); }.bind({self, sqlite3: self.sqlite3});

View File

@ -14,7 +14,7 @@
sqlite3.js, initializes the module, and postMessage()'s a message sqlite3.js, initializes the module, and postMessage()'s a message
after the module is initialized: after the module is initialized:
{type: 'sqlite3-api', data: 'worker-ready'} {type: 'sqlite3-api', data: 'worker1-ready'}
This seemingly superfluous level of indirection is necessary when This seemingly superfluous level of indirection is necessary when
loading sqlite3.js via a Worker. Instantiating a worker with new loading sqlite3.js via a Worker. Instantiating a worker with new
@ -28,4 +28,4 @@
*/ */
"use strict"; "use strict";
importScripts('sqlite3.js'); importScripts('sqlite3.js');
sqlite3InitModule().then((EmscriptenModule)=>EmscriptenModule.sqlite3.initWorkerAPI()); sqlite3InitModule().then((EmscriptenModule)=>EmscriptenModule.sqlite3.initWorker1API());

View File

@ -163,10 +163,10 @@
} }
try { try {
throw new capi.WasmAllocError; throw new sqlite3.WasmAllocError;
}catch(e){ }catch(e){
T.assert(e instanceof Error) T.assert(e instanceof Error)
.assert(e instanceof capi.WasmAllocError); .assert(e instanceof sqlite3.WasmAllocError);
} }
try { try {

View File

@ -6,10 +6,10 @@
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon"> <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
<link rel="stylesheet" href="common/emscripten.css"/> <link rel="stylesheet" href="common/emscripten.css"/>
<link rel="stylesheet" href="common/testing.css"/> <link rel="stylesheet" href="common/testing.css"/>
<title>sqlite3-worker.js tests</title> <title>sqlite3-worker1.js tests</title>
</head> </head>
<body> <body>
<header id='titlebar'><span>sqlite3-worker.js tests</span></header> <header id='titlebar'><span>sqlite3-worker1.js tests</span></header>
<!-- emscripten bits --> <!-- emscripten bits -->
<figure id="module-spinner"> <figure id="module-spinner">
<div class="spinner"></div> <div class="spinner"></div>

View File

@ -10,12 +10,12 @@
*********************************************************************** ***********************************************************************
A basic test script for sqlite3-worker.js. A basic test script for sqlite3-worker1.js.
*/ */
'use strict'; 'use strict';
(function(){ (function(){
const T = self.SqliteTestUtil; const T = self.SqliteTestUtil;
const SW = new Worker("sqlite3-worker.js"); const SW = new Worker("sqlite3-worker1.js");
const DbState = { const DbState = {
id: undefined id: undefined
}; };
@ -261,16 +261,8 @@
will fail and we have no way of cancelling them once they've will fail and we have no way of cancelling them once they've
been posted to the worker. been posted to the worker.
We currently do (2) because (A) it's certainly the most Which approach we use below depends on the boolean value of
client-friendly thing to do and (B) it seems likely that most waitForOpen.
apps using this API will only have a single db to work with so
won't need to juggle multiple DB ids. If we revert to (1) then
the following call to runTests2() needs to be moved into the
callback function of the runOneTest() check for the 'open'
command. Note, also, that using approach (2) does not keep the
user from instead using approach (1), noting that doing so
requires explicit handling of the 'open' message to account for
it.
*/ */
const waitForOpen = 1, const waitForOpen = 1,
simulateOpenError = 0 /* if true, the remaining tests will simulateOpenError = 0 /* if true, the remaining tests will
@ -315,7 +307,7 @@
switch(ev.type){ switch(ev.type){
case 'sqlite3-api': case 'sqlite3-api':
switch(ev.data){ switch(ev.data){
case 'worker-ready': case 'worker1-ready':
log("Message:",ev); log("Message:",ev);
self.sqlite3TestModule.setStatus(null); self.sqlite3TestModule.setStatus(null);
runTests(); runTests();

View File

@ -1,5 +1,5 @@
C wasm:\sminor\scleanups\sin\sthe\sOO\sAPI\s#1\sdemo. C Minor\scleanups,\sreorgs,\sand\sdoc\supdates\sfor\sthe\sJS\sAPIs.\sRenamed\ssqlite3(-api)-worker.js\sto\ssqlite3(-api)-worker1.js,\sfor\ssymmetry\swith\ssqlite3-api-oo1.js.
D 2022-08-16T17:29:59.160 D 2022-08-17T16:44:05.090
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -474,19 +474,19 @@ F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb
F ext/wasm/EXPORTED_FUNCTIONS.fiddle db7a4602f043cf4a5e4135be3609a487f9f1c83f05778bfbdf93766be4541b96 F ext/wasm/EXPORTED_FUNCTIONS.fiddle db7a4602f043cf4a5e4135be3609a487f9f1c83f05778bfbdf93766be4541b96
F ext/wasm/EXPORTED_RUNTIME_METHODS.fiddle a004bd5eeeda6d3b28d16779b7f1a80305bfe009dfc7f0721b042967f0d39d02 F ext/wasm/EXPORTED_RUNTIME_METHODS.fiddle a004bd5eeeda6d3b28d16779b7f1a80305bfe009dfc7f0721b042967f0d39d02
F ext/wasm/GNUmakefile b5b34ee01efcf7c3d6c53d54a332545f2670e7a5a0c63d6de847d3726e5bc521 F ext/wasm/GNUmakefile 19c21ce4df5583278cc495bffbe03c69dc64af60fa9dac01766d0192bd191ac6
F ext/wasm/README.md 4b00ae7c7d93c4591251245f0996a319e2651361013c98d2efb0b026771b7331 F ext/wasm/README.md 4b00ae7c7d93c4591251245f0996a319e2651361013c98d2efb0b026771b7331
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api 77ef4bcf37e362b9ad61f9c175dfc0f1b3e571563fb311b96581cf422ee6a8ec F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api 77ef4bcf37e362b9ad61f9c175dfc0f1b3e571563fb311b96581cf422ee6a8ec
F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287 F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287
F ext/wasm/api/README.md b6d0fb64bfdf7bf9ce6938ea4104228f6f5bbef600f5d910b2f8c8694195988c F ext/wasm/api/README.md d876597edd2b9542b6ea031adaaff1c042076fde7b670b1dc6d8a87b28a6631b
F ext/wasm/api/post-js-footer.js b64319261d920211b8700004d08b956a6c285f3b0bba81456260a713ed04900c F ext/wasm/api/post-js-footer.js b64319261d920211b8700004d08b956a6c285f3b0bba81456260a713ed04900c
F ext/wasm/api/post-js-header.js 0e853b78db83cb1c06b01663549e0e8b4f377f12f5a2d9a4a06cb776c003880b F ext/wasm/api/post-js-header.js 0e853b78db83cb1c06b01663549e0e8b4f377f12f5a2d9a4a06cb776c003880b
F ext/wasm/api/sqlite3-api-cleanup.js 149fd63a0400cd1d69548887ffde2ed89c13283384a63c2e9fcfc695e38a9e11 F ext/wasm/api/sqlite3-api-cleanup.js 149fd63a0400cd1d69548887ffde2ed89c13283384a63c2e9fcfc695e38a9e11
F ext/wasm/api/sqlite3-api-glue.js 82c09f49c69984009ba5af2b628e67cc26c5dd203d383cd3091d40dab4e6514b F ext/wasm/api/sqlite3-api-glue.js 4a09dd1153874f7a716cf953329bc1e78bf24e0870a9aad15214ffd51ac913bc
F ext/wasm/api/sqlite3-api-oo1.js 1d63e7e453e38ff2ad0c5e8bf68345f6fc5fe99fbc4a893cc982b4c50d904ca0 F ext/wasm/api/sqlite3-api-oo1.js d68dc7a692bc54385d9b851e914b386a146dc6c86624bfeb4672280a2d822082
F ext/wasm/api/sqlite3-api-opfs.js c93cdd14f81a26b3a64990515ee05c7e29827fbc8fba4e4c2fef3a37a984db89 F ext/wasm/api/sqlite3-api-opfs.js c93cdd14f81a26b3a64990515ee05c7e29827fbc8fba4e4c2fef3a37a984db89
F ext/wasm/api/sqlite3-api-prologue.js c0f335bf8b44071da0204b8fa95ce78fd737033b155e7bcfdaee6ae64600802f F ext/wasm/api/sqlite3-api-prologue.js 96997e411b41ff3d4024c2ad625c5cdb7b6a619ba8beece4662ad190191b1119
F ext/wasm/api/sqlite3-api-worker.js 1124f404ecdf3c14d9f829425cef778cd683911a9883f0809a463c3c7773c9fd F ext/wasm/api/sqlite3-api-worker1.js 74130ec4979baeaf3e909c7619b99e9f466e2d816cd07370987ff639d168ef45 w ext/wasm/api/sqlite3-api-worker.js
F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9 F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9
F ext/wasm/api/sqlite3-wasm.c 0e78035045e3328fb050ec9580c6bfb714c756a1d3b917259e58baf9b0332c98 F ext/wasm/api/sqlite3-wasm.c 0e78035045e3328fb050ec9580c6bfb714c756a1d3b917259e58baf9b0332c98
F ext/wasm/common/SqliteTestUtil.js e41a1406f18da9224523fad0c48885caf995b56956a5b9852909c0989e687e90 F ext/wasm/common/SqliteTestUtil.js e41a1406f18da9224523fad0c48885caf995b56956a5b9852909c0989e687e90
@ -508,11 +508,11 @@ F ext/wasm/scratchpad-opfs-main.js a819ed26047c5539630cea59add6a5082ba04cdf82da2
F ext/wasm/scratchpad-opfs-worker.html 66c1d15d678f3bd306373d76b61c6c8aef988f61f4a8dd40185d452f9c6d2bf5 F ext/wasm/scratchpad-opfs-worker.html 66c1d15d678f3bd306373d76b61c6c8aef988f61f4a8dd40185d452f9c6d2bf5
F ext/wasm/scratchpad-opfs-worker.js 3ec2868c669713145c76eb5877c64a1b20741f741817b87c907a154b676283a9 F ext/wasm/scratchpad-opfs-worker.js 3ec2868c669713145c76eb5877c64a1b20741f741817b87c907a154b676283a9
F ext/wasm/scratchpad-opfs-worker2.js de3ea77548243a638c8426b7e43cc1dbfc511013228ab98436eb102923ed6689 F ext/wasm/scratchpad-opfs-worker2.js de3ea77548243a638c8426b7e43cc1dbfc511013228ab98436eb102923ed6689
F ext/wasm/sqlite3-worker.js 1325ca8d40129a82531902a3a077b795db2eeaee81746e5a0c811a04b415fa7f F ext/wasm/sqlite3-worker1.js e93fe8e5da7cb56dcf4d1bb0aa44bf681b509e1c56f2a75885c0f408f034c42b w ext/wasm/sqlite3-worker.js
F ext/wasm/testing1.html 528001c7e32ee567abc195aa071fd9820cc3c8ffc9c8a39a75e680db05f0c409 F ext/wasm/testing1.html 528001c7e32ee567abc195aa071fd9820cc3c8ffc9c8a39a75e680db05f0c409
F ext/wasm/testing1.js a25069e20d5f8dc548cc98bcf7002cec812084421a1f7f70ffae2c706d1167b2 F ext/wasm/testing1.js 9a97a7e45ce122b479b4a706ae1024abded67fd5f34a5764e41ff5efde8dfa17
F ext/wasm/testing2.html 73e5048e666fd6fb28b6e635677a9810e1e139c599ddcf28d687c982134b92b8 F ext/wasm/testing2.html a66951c38137ff1d687df79466351f3c734fa9c6d9cce71d3cf97c291b2167e3
F ext/wasm/testing2.js dbb825174878716fab42c340962c0c1b32bfbe26dd16c7b082d30d35f510466c F ext/wasm/testing2.js e16ae385cd24c4a4ec5de6f1c02e621d243e1f179204ac8df31068faa9e31b1a
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
@ -2006,8 +2006,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P d6d79b661a1c6137d4693393e02416da4858d58dc84d144081a48d523655b483 P b9cdcc06a8f70694d10ee5b1a0fd9f08f4c705ce576e5103bbafb36fc9cc2122
R 495d381dcb72f9436340c5a0c3371031 R 0f6a8177d32b201ea7bdd0eb1ddeff9b
U stephan U stephan
Z f43bcfbf56838f97d3048cbeb389d31b Z 89af6a2fddda724fc088d602c326bc26
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
b9cdcc06a8f70694d10ee5b1a0fd9f08f4c705ce576e5103bbafb36fc9cc2122 f5059ee6f9fc55a381cbf08a30dfb9a5636c0b44341e42f4e9f12a3b109b5507