aboutsummaryrefslogtreecommitdiff
path: root/ext/wasm/api/sqlite3-api-glue.js
diff options
context:
space:
mode:
Diffstat (limited to 'ext/wasm/api/sqlite3-api-glue.js')
-rw-r--r--ext/wasm/api/sqlite3-api-glue.js188
1 files changed, 109 insertions, 79 deletions
diff --git a/ext/wasm/api/sqlite3-api-glue.js b/ext/wasm/api/sqlite3-api-glue.js
index ac1e9fd6d..0516953f1 100644
--- a/ext/wasm/api/sqlite3-api-glue.js
+++ b/ext/wasm/api/sqlite3-api-glue.js
@@ -37,27 +37,44 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
});
delete self.Jaccwabyt;
- if(0){
- /* "The problem" is that the following isn't even remotely
- type-safe. OTOH, nothing about WASM pointers is. */
- const argPointer = wasm.xWrap.argAdapter('*');
- wasm.xWrap.argAdapter('StructType', (v)=>{
- if(v && v.constructor && v instanceof StructBinder.StructType){
- v = v.pointer;
- }
- return wasm.isPtr(v)
- ? argPointer(v)
- : toss("Invalid (object) type for StructType-type argument.");
- });
- }
-
{/* Convert Arrays and certain TypedArrays to strings for
- 'flexible-string'-type arguments */
+ 'string:flexible'-type arguments */
const xString = wasm.xWrap.argAdapter('string');
wasm.xWrap.argAdapter(
- 'flexible-string', (v)=>xString(util.flexibleString(v))
+ 'string:flexible', (v)=>xString(util.flexibleString(v))
+ );
+
+ /**
+ The 'string:static' argument adapter treats its argument as
+ either...
+
+ - WASM pointer: assumed to be a long-lived C-string which gets
+ returned as-is.
+
+ - Anything else: gets coerced to a JS string for use as a map
+ key. If a matching entry is found (as described next), it is
+ returned, else wasm.allocCString() is used to create a a new
+ string, map its pointer to (''+v) for the remainder of the
+ application's life, and returns that pointer value for this
+ call and all future calls which are passed a
+ string-equivalent argument.
+
+ 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
+ value seen by those functions is long-lived and behaves as they
+ need it to.
+ */
+ wasm.xWrap.argAdapter(
+ 'string:static',
+ function(v){
+ if(wasm.isPtr(v)) return v;
+ v = ''+v;
+ let rc = this[v];
+ return rc || (rc = this[v] = wasm.allocCString(v));
+ }.bind(Object.create(null))
);
- }
+ }/* special-case string-type argument conversions */
if(1){// WhWasmUtil.xWrap() bindings...
/**
@@ -68,15 +85,21 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
`sqlite3_vfs*` via capi.sqlite3_vfs.pointer.
*/
const aPtr = wasm.xWrap.argAdapter('*');
+ const nilType = function(){};
wasm.xWrap.argAdapter('sqlite3_filename', aPtr)
('sqlite3_stmt*', aPtr)
('sqlite3_context*', aPtr)
('sqlite3_value*', aPtr)
('void*', aPtr)
- ('sqlite3*', (v)=>{
- if(sqlite3.oo1 && v instanceof sqlite3.oo1.DB) v = v.pointer;
- return aPtr(v);
- })
+ ('sqlite3*', (v)=>
+ aPtr((v instanceof (sqlite3?.oo1?.DB || nilType))
+ ? v.pointer : v))
+ ('sqlite3_index_info*', (v)=>
+ aPtr((v instanceof (capi.sqlite3_index_info || nilType))
+ ? v.pointer : v))
+ ('sqlite3_module*', (v)=>
+ aPtr((v instanceof (capi.sqlite3_module || nilType))
+ ? v.pointer : v))
/**
`sqlite3_vfs*`:
@@ -87,14 +110,13 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
*/
('sqlite3_vfs*', (v)=>{
if('string'===typeof v){
- const x = capi.sqlite3_vfs_find(v);
/* A NULL sqlite3_vfs pointer will be treated as the default
VFS in many contexts. We specifically do not want that
behavior here. */
- if(!x) sqlite3.SQLite3Error.toss("Unknown sqlite3_vfs name:",v);
- return x;
- }else if(v instanceof sqlite3.capi.sqlite3_vfs) v = v.pointer;
- return aPtr(v);
+ return capi.sqlite3_vfs_find(v)
+ || sqlite3.SQLite3Error.toss("Unknown sqlite3_vfs name:",v);
+ }
+ return aPtr((v instanceof capi.sqlite3_vfs) ? v.pointer : v);
});
wasm.xWrap.resultAdapter('sqlite3*', aPtr)
@@ -127,7 +149,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
: fI64Disabled(e[0]);
}
- /* There's no(?) need to expose bindingSignatures to clients,
+ /* There's no need to expose bindingSignatures to clients,
implicitly making it part of the public interface. */
delete wasm.bindingSignatures;
@@ -141,22 +163,9 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
return errCode;
};
}
-
}/*xWrap() bindings*/;
/**
- When registering a VFS and its related components it may be
- necessary to ensure that JS keeps a reference to them to keep
- them from getting garbage collected. Simply pass each such value
- to this function and a reference will be held to it for the life
- of the app.
- */
- capi.sqlite3_vfs_register.addReference = function f(...args){
- if(!f._) f._ = [];
- f._.push(...args);
- };
-
- /**
Internal helper to assist in validating call argument counts in
the hand-written sqlite3_xyz() wrappers. We do this only for
consistency with non-special-case wrappings.
@@ -167,29 +176,9 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
(1===n?"":'s')+".");
};
- /**
- Helper for flexible-string conversions which require a
- byte-length counterpart argument. Passed a value and its
- ostensible length, this function returns [V,N], where V
- is either v or a transformed copy of v and N is either n,
- -1, or the byte length of v (if it's a byte array).
- */
- const __flexiString = function(v,n){
- if('string'===typeof v){
- n = -1;
- }else if(util.isSQLableTypedArray(v)){
- n = v.byteLength;
- v = util.typedArrayToString(v);
- }else if(Array.isArray(v)){
- v = v.join("");
- n = -1;
- }
- return [v, n];
- };
-
if(1){/* Special-case handling of sqlite3_exec() */
const __exec = wasm.xWrap("sqlite3_exec", "int",
- ["sqlite3*", "flexible-string", "*", "*", "**"]);
+ ["sqlite3*", "string:flexible", "*", "*", "**"]);
/* Documented in the api object's initializer. */
capi.sqlite3_exec = function f(pDb, sql, callback, pVoid, pErrMsg){
if(f.length!==arguments.length){
@@ -541,6 +530,26 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
if(1){/* Special-case handling of sqlite3_prepare_v2() and
sqlite3_prepare_v3() */
/**
+ Helper for string:flexible conversions which require a
+ byte-length counterpart argument. Passed a value and its
+ ostensible length, this function returns [V,N], where V
+ is either v or a transformed copy of v and N is either n,
+ -1, or the byte length of v (if it's a byte array).
+ */
+ const __flexiString = (v,n)=>{
+ if('string'===typeof v){
+ n = -1;
+ }else if(util.isSQLableTypedArray(v)){
+ n = v.byteLength;
+ v = util.typedArrayToString(v);
+ }else if(Array.isArray(v)){
+ v = v.join("");
+ n = -1;
+ }
+ return [v, n];
+ };
+
+ /**
Scope-local holder of the two impls of sqlite3_prepare_v2/v3().
*/
const __prepare = Object.create(null);
@@ -570,7 +579,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
"int", ["sqlite3*", "*", "int", "int",
"**", "**"]);
- /* Documented in the api object's initializer. */
+ /* Documented in the capi object's initializer. */
capi.sqlite3_prepare_v3 = function f(pDb, sql, sqlLen, prepFlags, ppStmt, pzTail){
if(f.length!==arguments.length){
return __dbArgcMismatch(pDb,"sqlite3_prepare_v3",f.length);
@@ -587,7 +596,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}
};
- /* Documented in the api object's initializer. */
+ /* Documented in the capi object's initializer. */
capi.sqlite3_prepare_v2 = function f(pDb, sql, sqlLen, ppStmt, pzTail){
return (f.length===arguments.length)
? capi.sqlite3_prepare_v3(pDb, sql, sqlLen, 0, ppStmt, pzTail)
@@ -603,13 +612,17 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}
wasm.ctype = JSON.parse(wasm.cstringToJs(cJson));
//console.debug('wasm.ctype length =',wasm.cstrlen(cJson));
- for(const t of ['access', 'blobFinalizers', 'dataTypes',
- 'encodings', 'fcntl', 'flock', 'ioCap',
- 'limits',
- 'openFlags', 'prepareFlags', 'resultCodes',
- 'serialize', 'syncFlags', 'trace', 'udfFlags',
- 'version'
- ]){
+ const defineGroups = ['access', 'authorizer',
+ 'blobFinalizers', 'dataTypes',
+ 'encodings', 'fcntl', 'flock', 'ioCap',
+ 'limits', 'openFlags',
+ 'prepareFlags', 'resultCodes',
+ 'serialize', 'syncFlags', 'trace', 'udfFlags',
+ 'version' ];
+ if(wasm.bigIntEnabled){
+ defineGroups.push('vtab');
+ }
+ for(const t of defineGroups){
for(const e of Object.entries(wasm.ctype[t])){
// ^^^ [k,v] there triggers a buggy code transformation via
// one of the Emscripten-driven optimizers.
@@ -629,19 +642,37 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
capi.sqlite3_js_rc_str = (rc)=>__rcMap[rc];
/* Bind all registered C-side structs... */
const notThese = Object.assign(Object.create(null),{
- // Structs NOT to register
- WasmTestStruct: true
+ // For each struct to NOT register, map its name to true:
+ WasmTestStruct: true,
+ /* We unregister the kvvfs VFS from Worker threads below. */
+ sqlite3_kvvfs_methods: !util.isUIThread(),
+ /* sqlite3_index_info and friends require int64: */
+ sqlite3_index_info: !wasm.bigIntEnabled,
+ sqlite3_index_constraint: !wasm.bigIntEnabled,
+ sqlite3_index_orderby: !wasm.bigIntEnabled,
+ sqlite3_index_constraint_usage: !wasm.bigIntEnabled
});
- if(!util.isUIThread()){
- /* We remove the kvvfs VFS from Worker threads below. */
- notThese.sqlite3_kvvfs_methods = true;
- }
for(const s of wasm.ctype.structs){
if(!notThese[s.name]){
capi[s.name] = sqlite3.StructBinder(s);
}
}
- }/*end C constant imports*/
+ if(capi.sqlite3_index_info){
+ /* Move these inner structs into sqlite3_index_info. Binding
+ ** them to WASM requires that we create global-scope structs to
+ ** model them with, but those are no longer needed after we've
+ ** passed them to StructBinder. */
+ for(const k of ['sqlite3_index_constraint',
+ 'sqlite3_index_orderby',
+ 'sqlite3_index_constraint_usage']){
+ capi.sqlite3_index_info[k] = capi[k];
+ delete capi[k];
+ }
+ capi.sqlite3_vtab_config =
+ (pDb, op, arg=0)=>wasm.exports.sqlite3_wasm_vtab_config(
+ wasm.xWrap.argAdapter('sqlite3*')(pDb), op, arg);
+ }/* end vtab-related setup */
+ }/*end C constant and struct imports*/
const pKvvfs = capi.sqlite3_vfs_find("kvvfs");
if( pKvvfs ){/* kvvfs-specific glue */
@@ -652,8 +683,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
delete capi.sqlite3_kvvfs_methods;
const kvvfsMakeKey = wasm.exports.sqlite3_wasm_kvvfsMakeKeyOnPstack,
- pstack = wasm.pstack,
- pAllocRaw = wasm.exports.sqlite3_wasm_pstack_alloc;
+ pstack = wasm.pstack;
const kvvfsStorage = (zClass)=>
((115/*=='s'*/===wasm.getMemValue(zClass))