'use strict';
self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const wasm = sqlite3.wasm, capi = sqlite3.capi, toss = sqlite3.util.toss3;
- const vh = Object.create(null), vt = Object.create(null);
+ const vfs = Object.create(null), vtab = Object.create(null);
- sqlite3.VfsHelper = vh;
- sqlite3.VtabHelper = vt;
+ sqlite3.vfs = vfs;
+ sqlite3.vtab = vtab;
const sii = capi.sqlite3_index_info;
/**
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, it is
- assumed to be an existing WASM-bound function pointer and is used
- as-is with no extra level of proxying or cleanup. Results are
- undefined if it's a pointer and it's _not_ a function pointer.
- 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.)
+ 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
for dev-time usage for sanity checking, and will leave the C
environment in an undefined state.
*/
- vh.installMethod = vt.installMethod = function callee(
+ const installMethod = function callee(
tgt, name, func, applyArgcCheck = callee.installMethodArgcCheck
){
if(!(tgt instanceof sqlite3.StructBinder.StructType)){
}else{
const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true));
tgt[memKey] = pFunc;
- if(!tgt.ondispose) tgt.ondispose = [];
- else if(!Array.isArray(tgt.ondispose)) tgt.ondispose = [tgt.ondispose];
if(!tgt.ondispose || !tgt.ondispose.__removeFuncList){
tgt.addOnDispose('ondispose.__removeFuncList handler',
callee.removeFuncList);
}
return (n,f)=>callee(tgt, n, f, applyArgcCheck);
}/*installMethod*/;
- vh.installMethod.installMethodArgcCheck = false;
+ installMethod.installMethodArgcCheck = false;
/**
Installs methods into the given StructType-type instance. Each
accommodate special handling of sqlite3_module::xConnect and
xCreate methods.
- On success, returns this object. Throws on error.
+ On success, returns its first argument. Throws on error.
*/
- vh.installMethods = vt.installMethods = function(
- structType, methods, applyArgcCheck = vh.installMethod.installMethodArgcCheck
+ 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 = structType.memberKey(k);
- structType[mkey] = structType[structType.memberKey(prior)];
+ const mkey = structInstance.memberKey(k);
+ structInstance[mkey] = structInstance[structInstance.memberKey(prior)];
}else{
- vh.installMethod(structType, k, m, applyArgcCheck);
+ installMethod(structInstance, k, m, applyArgcCheck);
seen.set(m, k);
}
}
- return this;
+ return structInstance;
};
/**
- Uses sqlite3_vfs_register() to register the
- sqlite3.capi.sqlite3_vfs-type vfs, which must have already been
- filled out properly. If the 2nd argument is truthy, the VFS is
+ 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).
+ */
+ sqlite3.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.
+ */
+ sqlite3.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.
*/
- vh.registerVfs = function(vfs, asDefault=false){
- if(!(vfs instanceof sqlite3.capi.sqlite3_vfs)){
+ 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(vfs.pointer, asDefault ? 1 : 0);
+ const rc = capi.sqlite3_vfs_register(this, asDefault ? 1 : 0);
if(rc){
- toss("sqlite3_vfs_register(",vfs,") failed with rc",rc);
+ toss("sqlite3_vfs_register(",this,") failed with rc",rc);
}
- if(vfs.pointer !== capi.sqlite3_vfs_find(vfs.$zName)){
+ if(this.pointer !== capi.sqlite3_vfs_find(this.$zName)){
toss("BUG: sqlite3_vfs_find(vfs.$zName) failed for just-installed VFS",
- vfs);
+ this);
}
return this;
};
For each of those object, this function passes its (`struct`,
`methods`, (optional) `applyArgcCheck`) properties to
- this.installMethods().
+ installMethods().
If the `vfs` entry is set then:
- - Its `struct` property is passed to this.registerVfs(). The
+ - Its `struct` property's registerVfs() is called. The
`vfs` entry may optionally have an `asDefault` property, which
- gets passed as the 2nd argument to registerVfs().
+ 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
On success returns this object. Throws on error.
*/
- vh.installVfs = function(opt){
+ vfs.installVfs = function(opt){
let count = 0;
const propList = ['io','vfs'];
for(const key of propList){
const o = opt[key];
if(o){
++count;
- this.installMethods(o.struct, o.methods, !!o.applyArgcCheck);
+ 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)
);
}
- this.registerVfs(o.struct, !!o.asDefault);
+ o.struct.registerVfs(!!o.asDefault);
}
}
}
as sqlite3_create_function_v2() and friends. Throws on error,
e.g. if it cannot figure out a sensible data conversion.
*/
- vt.sqlite3ValuesToJs = capi.sqlite3_create_function_v2.udfConvertArgs;
+ vtab.sqlite3ValuesToJs = capi.sqlite3_create_function_v2.udfConvertArgs;
/**
Internal factory function for xVtab and xCursor impls.
The API docs are in the API-internal StructPtrMapper().
*/
- vt.xVtab = StructPtrMapper('xVtab', capi.sqlite3_vtab);
+ vtab.xVtab = StructPtrMapper('xVtab', capi.sqlite3_vtab);
/**
A lifetime-management object for mapping `sqlite3_vtab_cursor*`
The API docs are in the API-internal StructPtrMapper().
*/
- vt.xCursor = StructPtrMapper('xCursor', capi.sqlite3_vtab_cursor);
+ vtab.xCursor = StructPtrMapper('xCursor', capi.sqlite3_vtab_cursor);
/**
Convenience form of creating an sqlite3_index_info wrapper,
before returning. Though not _strictly_ required, as that object
does not own the pIdxInfo memory, it is nonetheless good form.
*/
- vt.xIndexInfo = (pIdxInfo)=>new capi.sqlite3_index_info(pIdxInfo);
+ vtab.xIndexInfo = (pIdxInfo)=>new capi.sqlite3_index_info(pIdxInfo);
/**
Given an error object, this function returns
}
```
*/
- /**vh.exceptionToRc = vt.exceptionToRc =
+ /**vfs.exceptionToRc = vtab.exceptionToRc =
(e, defaultRc=capi.SQLITE_ERROR)=>(
(e instanceof sqlite3.WasmAllocError)
? capi.SQLITE_NOMEM
order to report the error, else the error is not reported.
If that function throws, that exception is ignored.
*/
- vt.xError = function f(methodName, err, defaultRc){
+ vtab.xError = function f(methodName, err, defaultRc){
if(f.errorReporter instanceof Function){
try{f.errorReporter("sqlite3_module::"+methodName+"(): "+err.message);}
catch(e){/*ignored*/}
else if(err instanceof sqlite3.SQLite3Error) rc = err.resultCode;
return rc || capi.SQLITE_ERROR;
};
- vt.xError.errorReporter = 1 ? console.error.bind(console) : false;
+ vtab.xError.errorReporter = 1 ? console.error.bind(console) : false;
/**
"The problem" with this is that it introduces an outer function with
xConnect) may have call-specific error handling. It would be a shame to
hard-coded that per-method support in this function.
*/
- /** vt.methodCatcher = function(methodName, method, defaultErrRc=capi.SQLITE_ERROR){
+ /** vtab.methodCatcher = function(methodName, method, defaultErrRc=capi.SQLITE_ERROR){
return function(...args){
try { method(...args); }
- }catch(e){ return vt.xError(methodName, e, defaultRc) }
+ }catch(e){ return vtab.xError(methodName, e, defaultRc) }
};
*/
};
```
*/
- vt.xRowid = (ppRowid64, value)=>wasm.setMemValue(ppRowid64, value, 'i64');
+ vtab.xRowid = (ppRowid64, value)=>wasm.setMemValue(ppRowid64, value, 'i64');
/**
- A helper to initialize and set up an sqlite3_module() object for
+ A helper to initialize and set up an sqlite3_module object for
later installation into individual databases using
sqlite3_create_module(). Requires an object with the following
properties:
string to the exception's error string.
- OPTIONAL `struct`: a sqlite3.capi.sqlite3_module() instance. If
- not set, one will be created automatically and (on success)
- added to the object.
+ not set, one will be created automatically. If the current
+ "this" is-a sqlite3_module then it is unconditionally used in
+ place of `struct`.
- OPTIONAL `iVersion`: if set, it must be an integer value and it
gets assigned to the `$iVersion` member of the struct object.
active, the method implementations must explicitly return integer
values.
- Throws on error. Returns the opt.struct sqlite3_module object on
- success.
+ Throws on error. On success, returns the sqlite3_module object
+ (`this` or `opt.struct` or a new sqlite3_module instance,
+ depending on how it's called).
*/
- vt.setupModule = function(opt){
- const mod = opt.struct || new capi.sqlite3_module();
+ vtab.setupModule = function(opt){
+ let createdMod = false;
+ const mod = (this instanceof capi.sqlite3_module)
+ ? this : (opt.struct || (createdMod = new capi.sqlite3_module()));
try{
const methods = opt.methods || toss("Missing 'methods' object.");
- if(true===methods.xConnect) methods.xConnect = methods.xCreate;
- else if(true===methods.xCreate) methods.xCreate = methods.xConnect;
- if(true===methods.xDisconnect) methods.xDisconnect = methods.xDestroy;
- else if(true===methods.xDestroy) methods.xDestroy = methods.xDisconnect;
+ for(const e of Object.entries({
+ // -----^ ==> [k,v] triggers a broken code transformation in
+ // some versions of the emsdk toolchain.
+ xConnect: 'xCreate', xDisconnect: 'xDestroy'
+ })){
+ // Remap X=true to X=Y for certain X/Y combinations
+ const k = e[0], v = e[1];
+ if(true === methods[k]) methods[k] = methods[v];
+ else if(true === methods[v]) methods[v] = methods[k];
+ }
if(opt.catchExceptions){
const fwrap = function(methodName, func){
if(['xConnect','xCreate'].indexOf(methodName) >= 0){
return function(pDb, pAux, argc, argv, ppVtab, pzErr){
- try{return func(...arguments) || 0;}
+ try{return func(...arguments) || 0}
catch(e){
if(!(e instanceof sqlite3.WasmAllocError)){
wasm.dealloc(wasm.getPtrValue(pzErr));
wasm.setPtrValue(pzErr, wasm.allocCString(e.message));
}
- return vt.xError(methodName, e);
+ return vtab.xError(methodName, e);
}
};
}else{
return function(...args){
- try{return func(...args) || 0;}
+ try{return func(...args) || 0}
catch(e){
- return vt.xError(methodName, e);
+ return vtab.xError(methodName, e);
}
};
}
remethods[k] = fwrap(k, m);
}
}
- this.installMethods(mod, remethods, false);
+ installMethods(mod, remethods, false);
}else{
// No automatic exception handling. Trust the client
// to not throw.
- this.installMethods(
+ installMethods(
mod, methods, !!opt.applyArgcCheck/*undocumented option*/
);
}
mod.$iVersion = v;
}
}catch(e){
- if(!opt.struct) mod.dispose();
+ if(createdMod) createdMod.dispose();
throw e;
}
- if(!opt.struct) opt.struct = mod;
return mod;
}/*setupModule()*/;
+
+ /**
+ Equivalent to calling vtab.setupModule() with this sqlite3_module
+ object as the call's `this`.
+ */
+ capi.sqlite3_module.prototype.setupModule = function(opt){
+ return vtab.setupModule.call(this, opt);
+ };
}/*sqlite3ApiBootstrap.initializers.push()*/);
and has finished initializing, so the real work can
begin...*/
try {
- sqlite3.VfsHelper.installVfs({
+ sqlite3.vfs.installVfs({
io: {struct: opfsIoMethods, methods: ioSyncWrappers},
vfs: {struct: opfsVfs, methods: vfsSyncWrappers}
});
predicate: ()=>!!capi.sqlite3_index_info,
test: function(sqlite3){
warn("The vtab/module JS bindings are experimental and subject to change.");
- const vth = sqlite3.VtabHelper;
+ const VT = sqlite3.vtab;
const tmplCols = Object.assign(Object.create(null),{
A: 0, B: 1
});
The vtab demonstrated here is a JS-ification of
ext/misc/templatevtab.c.
*/
- const tmplMethods = {
- xConnect: function(pDb, pAux, argc, argv, ppVtab, pzErr){
- try{
- const args = wasm.cArgvToJs(argc, argv);
- T.assert(args.length>=3)
- .assert(args[0] === 'testvtab')
- .assert(args[1] === 'main')
- .assert(args[2] === 'testvtab');
- console.debug("xConnect() args =",args);
- const rc = capi.sqlite3_declare_vtab(
- pDb, "CREATE TABLE ignored(a,b)"
- );
- if(0===rc){
- const t = vth.xVtab.create(ppVtab);
- T.assert(t === vth.xVtab.get(wasm.getPtrValue(ppVtab)));
+ const tmplMod = (new sqlite3.capi.sqlite3_module()).setupModule({
+ catchExceptions: false,
+ methods: {
+ xConnect: function(pDb, pAux, argc, argv, ppVtab, pzErr){
+ try{
+ const args = wasm.cArgvToJs(argc, argv);
+ T.assert(args.length>=3)
+ .assert(args[0] === 'testvtab')
+ .assert(args[1] === 'main')
+ .assert(args[2] === 'testvtab');
+ console.debug("xConnect() args =",args);
+ const rc = capi.sqlite3_declare_vtab(
+ pDb, "CREATE TABLE ignored(a,b)"
+ );
+ if(0===rc){
+ const t = VT.xVtab.create(ppVtab);
+ T.assert(t === VT.xVtab.get(wasm.getPtrValue(ppVtab)));
+ }
+ return rc;
+ }catch(e){
+ if(!(e instanceof sqlite3.WasmAllocError)){
+ wasm.dealloc(wasm.getPtrValue, pzErr);
+ wasm.setPtrValue(pzErr, wasm.allocCString(e.message));
+ }
+ return VT.xError('xConnect',e);
}
- return rc;
- }catch(e){
- if(!(e instanceof sqlite3.WasmAllocError)){
- wasm.dealloc(wasm.getPtrValue, pzErr);
- wasm.setPtrValue(pzErr, wasm.allocCString(e.message));
+ },
+ xCreate: true /* just for testing. Will be removed afterwards. */,
+ xDisconnect: function(pVtab){
+ try {
+ VT.xVtab.unget(pVtab).dispose();
+ return 0;
+ }catch(e){
+ return VT.xError('xDisconnect',e);
}
- return vth.xError('xConnect',e);
- }
- },
- xDisconnect: function(pVtab){
- try {
- vth.xVtab.unget(pVtab).dispose();
- return 0;
- }catch(e){
- return vth.xError('xDisconnect',e);
- }
- },
- xOpen: function(pVtab, ppCursor){
- try{
- const t = vth.xVtab.get(pVtab),
- c = vth.xCursor.create(ppCursor);
- T.assert(t instanceof capi.sqlite3_vtab)
- .assert(c instanceof capi.sqlite3_vtab_cursor);
- c._rowId = 0;
- return 0;
- }catch(e){
- return vth.xError('xOpen',e);
- }
- },
- xClose: function(pCursor){
- try{
- const c = vth.xCursor.unget(pCursor);
- T.assert(c instanceof capi.sqlite3_vtab_cursor)
- .assert(!vth.xCursor.get(pCursor));
- c.dispose();
- return 0;
- }catch(e){
- return vth.xError('xClose',e);
- }
- },
- xNext: function(pCursor){
- try{
- const c = vth.xCursor.get(pCursor);
- ++c._rowId;
- return 0;
- }catch(e){
- return vth.xError('xNext',e);
- }
- },
- xColumn: function(pCursor, pCtx, iCol){
- try{
- const c = vth.xCursor.get(pCursor);
- switch(iCol){
- case tmplCols.A:
- capi.sqlite3_result_int(pCtx, 1000 + c._rowId);
- break;
- case tmplCols.B:
- capi.sqlite3_result_int(pCtx, 2000 + c._rowId);
- break;
- default: sqlite3.SQLite3Error.toss("Invalid column id",iCol);
+ },
+ xOpen: function(pVtab, ppCursor){
+ try{
+ const t = VT.xVtab.get(pVtab),
+ c = VT.xCursor.create(ppCursor);
+ T.assert(t instanceof capi.sqlite3_vtab)
+ .assert(c instanceof capi.sqlite3_vtab_cursor);
+ c._rowId = 0;
+ return 0;
+ }catch(e){
+ return VT.xError('xOpen',e);
}
- return 0;
- }catch(e){
- return vth.xError('xColumn',e);
- }
- },
- xRowid: function(pCursor, ppRowid64){
- try{
- const c = vth.xCursor.get(pCursor);
- vth.xRowid(ppRowid64, c._rowId);
- return 0;
- }catch(e){
- return vth.xError('xRowid',e);
- }
- },
- xEof: function(pCursor){
- const c = vth.xCursor.get(pCursor),
- rc = c._rowId>=10;
- c.dispose();
- return rc;
- },
- xFilter: function(pCursor, idxNum, idxCStr,
- argc, argv/* [sqlite3_value* ...] */){
- try{
- const c = vth.xCursor.get(pCursor);
- c._rowId = 0;
- const list = vth.sqlite3ValuesToJs(argc, argv);
- T.assert(argc === list.length);
- //log(argc,"xFilter value(s):",list);
- c.dispose();
- return 0;
- }catch(e){
- return vth.xError('xFilter',e);
- }
- },
- xBestIndex: function(pVtab, pIdxInfo){
- try{
- //const t = vth.xVtab.get(pVtab);
- const sii = capi.sqlite3_index_info;
- const pii = new sii(pIdxInfo);
- pii.$estimatedRows = 10;
- pii.$estimatedCost = 10.0;
- //log("xBestIndex $nConstraint =",pii.$nConstraint);
- if(pii.$nConstraint>0){
- // Validate nthConstraint() and nthConstraintUsage()
- const max = pii.$nConstraint;
- for(let i=0; i < max; ++i ){
- let v = pii.nthConstraint(i,true);
- T.assert(wasm.isPtr(v));
- v = pii.nthConstraint(i);
- T.assert(v instanceof sii.sqlite3_index_constraint)
- .assert(v.pointer >= pii.$aConstraint);
- v.dispose();
- v = pii.nthConstraintUsage(i,true);
- T.assert(wasm.isPtr(v));
- v = pii.nthConstraintUsage(i);
- T.assert(v instanceof sii.sqlite3_index_constraint_usage)
- .assert(v.pointer >= pii.$aConstraintUsage);
- v.$argvIndex = i;//just to get some values into xFilter
- v.dispose();
+ },
+ xClose: function(pCursor){
+ try{
+ const c = VT.xCursor.unget(pCursor);
+ T.assert(c instanceof capi.sqlite3_vtab_cursor)
+ .assert(!VT.xCursor.get(pCursor));
+ c.dispose();
+ return 0;
+ }catch(e){
+ return VT.xError('xClose',e);
+ }
+ },
+ xNext: function(pCursor){
+ try{
+ const c = VT.xCursor.get(pCursor);
+ ++c._rowId;
+ return 0;
+ }catch(e){
+ return VT.xError('xNext',e);
+ }
+ },
+ xColumn: function(pCursor, pCtx, iCol){
+ try{
+ const c = VT.xCursor.get(pCursor);
+ switch(iCol){
+ case tmplCols.A:
+ capi.sqlite3_result_int(pCtx, 1000 + c._rowId);
+ break;
+ case tmplCols.B:
+ capi.sqlite3_result_int(pCtx, 2000 + c._rowId);
+ break;
+ default: sqlite3.SQLite3Error.toss("Invalid column id",iCol);
}
+ return 0;
+ }catch(e){
+ return VT.xError('xColumn',e);
}
- //log("xBestIndex $nOrderBy =",pii.$nOrderBy);
- if(pii.$nOrderBy>0){
- // Validate nthOrderBy()
- const max = pii.$nOrderBy;
- for(let i=0; i < max; ++i ){
- let v = pii.nthOrderBy(i,true);
- T.assert(wasm.isPtr(v));
- v = pii.nthOrderBy(i);
- T.assert(v instanceof sii.sqlite3_index_orderby)
- .assert(v.pointer >= pii.$aOrderBy);
- v.dispose();
+ },
+ xRowid: function(pCursor, ppRowid64){
+ try{
+ const c = VT.xCursor.get(pCursor);
+ VT.xRowid(ppRowid64, c._rowId);
+ return 0;
+ }catch(e){
+ return VT.xError('xRowid',e);
+ }
+ },
+ xEof: function(pCursor){
+ const c = VT.xCursor.get(pCursor),
+ rc = c._rowId>=10;
+ c.dispose();
+ return rc;
+ },
+ xFilter: function(pCursor, idxNum, idxCStr,
+ argc, argv/* [sqlite3_value* ...] */){
+ try{
+ const c = VT.xCursor.get(pCursor);
+ c._rowId = 0;
+ const list = VT.sqlite3ValuesToJs(argc, argv);
+ T.assert(argc === list.length);
+ //log(argc,"xFilter value(s):",list);
+ c.dispose();
+ return 0;
+ }catch(e){
+ return VT.xError('xFilter',e);
+ }
+ },
+ xBestIndex: function(pVtab, pIdxInfo){
+ try{
+ //const t = VT.xVtab.get(pVtab);
+ const sii = capi.sqlite3_index_info;
+ const pii = new sii(pIdxInfo);
+ pii.$estimatedRows = 10;
+ pii.$estimatedCost = 10.0;
+ //log("xBestIndex $nConstraint =",pii.$nConstraint);
+ if(pii.$nConstraint>0){
+ // Validate nthConstraint() and nthConstraintUsage()
+ const max = pii.$nConstraint;
+ for(let i=0; i < max; ++i ){
+ let v = pii.nthConstraint(i,true);
+ T.assert(wasm.isPtr(v));
+ v = pii.nthConstraint(i);
+ T.assert(v instanceof sii.sqlite3_index_constraint)
+ .assert(v.pointer >= pii.$aConstraint);
+ v.dispose();
+ v = pii.nthConstraintUsage(i,true);
+ T.assert(wasm.isPtr(v));
+ v = pii.nthConstraintUsage(i);
+ T.assert(v instanceof sii.sqlite3_index_constraint_usage)
+ .assert(v.pointer >= pii.$aConstraintUsage);
+ v.$argvIndex = i;//just to get some values into xFilter
+ v.dispose();
+ }
+ }
+ //log("xBestIndex $nOrderBy =",pii.$nOrderBy);
+ if(pii.$nOrderBy>0){
+ // Validate nthOrderBy()
+ const max = pii.$nOrderBy;
+ for(let i=0; i < max; ++i ){
+ let v = pii.nthOrderBy(i,true);
+ T.assert(wasm.isPtr(v));
+ v = pii.nthOrderBy(i);
+ T.assert(v instanceof sii.sqlite3_index_orderby)
+ .assert(v.pointer >= pii.$aOrderBy);
+ v.dispose();
+ }
}
+ pii.dispose();
+ return 0;
+ }catch(e){
+ return VT.xError('xBestIndex',e);
}
- pii.dispose();
- return 0;
- }catch(e){
- return vth.xError('xBestIndex',e);
}
}
- };
- /**
- The vtab API places relevance on whether xCreate and
- xConnect are exactly the same function (same pointer
- address). Two JS-side references to the same method will
- end up, without acrobatics to counter it, being compiled as
- two different WASM-side bindings, i.e. two different
- pointers.
-
- In order to account for this, VtabHelper.installMethods()
- checks for duplicate function entries and maps them to the
- same WASM-compiled instance.
- */
- if(1){
- tmplMethods.xCreate = tmplMethods.xConnect;
- }
-
- const tmplMod = new sqlite3.capi.sqlite3_module();
- tmplMod.$iVersion = 0;
+ });
this.db.onclose.disposeAfter.push(tmplMod);
- vth.installMethods(tmplMod, tmplMethods, true);
- if(tmplMethods.xCreate){
- T.assert(tmplMod.$xCreate)
- .assert(tmplMod.$xCreate === tmplMod.$xConnect,
- "installMethods() must avoid re-compiling identical functions");
- tmplMod.$xCreate = 0;
- }
+ T.assert(tmplMod.$xCreate)
+ .assert(tmplMod.$xCreate === tmplMod.$xConnect,
+ "setup() must make these equivalent and "+
+ "installMethods() must avoid re-compiling identical functions");
+ tmplMod.$xCreate = 0 /* make tmplMod eponymous-only */;
let rc = capi.sqlite3_create_module(
this.db, "testvtab", tmplMod, 0
);
this.db.checkRc(rc);
-
const list = this.db.selectArrays(
"SELECT a,b FROM testvtab where a<9999 and b>1 order by a, b"
/* Query is shaped so that it will ensure that some constraints
predicate: ()=>!!capi.sqlite3_index_info,
test: function(sqlite3){
warn("The vtab/module JS bindings are experimental and subject to change.");
- const vth = sqlite3.VtabHelper;
+ const VT = sqlite3.vtab;
const tmplCols = Object.assign(Object.create(null),{
A: 0, B: 1
});
pDb, "CREATE TABLE ignored(a,b)"
);
if(0===rc){
- const t = vth.xVtab.create(ppVtab);
- T.assert(t === vth.xVtab.get(wasm.getPtrValue(ppVtab)));
+ const t = VT.xVtab.create(ppVtab);
+ T.assert(t === VT.xVtab.get(wasm.getPtrValue(ppVtab)));
vtabTrace("xCreate",...arguments," ppVtab =",t.pointer);
}
return rc;
xConnect: true,
xDestroy: function(pVtab){
vtabTrace("xDestroy/xDisconnect",pVtab);
- vth.xVtab.dispose(pVtab);
+ VT.xVtab.dispose(pVtab);
},
xDisconnect: true,
xOpen: function(pVtab, ppCursor){
- const t = vth.xVtab.get(pVtab),
- c = vth.xCursor.create(ppCursor);
+ const t = VT.xVtab.get(pVtab),
+ c = VT.xCursor.create(ppCursor);
T.assert(t instanceof capi.sqlite3_vtab)
.assert(c instanceof capi.sqlite3_vtab_cursor);
vtabTrace("xOpen",...arguments," cursor =",c.pointer);
},
xClose: function(pCursor){
vtabTrace("xClose",...arguments);
- const c = vth.xCursor.unget(pCursor);
+ const c = VT.xCursor.unget(pCursor);
T.assert(c instanceof capi.sqlite3_vtab_cursor)
- .assert(!vth.xCursor.get(pCursor));
+ .assert(!VT.xCursor.get(pCursor));
c.dispose();
},
xNext: function(pCursor){
vtabTrace("xNext",...arguments);
- const c = vth.xCursor.get(pCursor);
+ const c = VT.xCursor.get(pCursor);
++c._rowId;
},
xColumn: function(pCursor, pCtx, iCol){
vtabTrace("xColumn",...arguments);
- const c = vth.xCursor.get(pCursor);
+ const c = VT.xCursor.get(pCursor);
switch(iCol){
case tmplCols.A:
capi.sqlite3_result_int(pCtx, 1000 + c._rowId);
},
xRowid: function(pCursor, ppRowid64){
vtabTrace("xRowid",...arguments);
- const c = vth.xCursor.get(pCursor);
- vth.xRowid(ppRowid64, c._rowId);
+ const c = VT.xCursor.get(pCursor);
+ VT.xRowid(ppRowid64, c._rowId);
},
xEof: function(pCursor){
vtabTrace("xEof",...arguments);
- return vth.xCursor.get(pCursor)._rowId>=10;
+ return VT.xCursor.get(pCursor)._rowId>=10;
},
xFilter: function(pCursor, idxNum, idxCStr,
argc, argv/* [sqlite3_value* ...] */){
vtabTrace("xFilter",...arguments);
- const c = vth.xCursor.get(pCursor);
+ const c = VT.xCursor.get(pCursor);
c._rowId = 0;
- const list = vth.sqlite3ValuesToJs(argc, argv);
+ const list = VT.sqlite3ValuesToJs(argc, argv);
T.assert(argc === list.length);
},
xBestIndex: function(pVtab, pIdxInfo){
vtabTrace("xBestIndex",...arguments);
- //const t = vth.xVtab.get(pVtab);
- const pii = vth.xIndexInfo(pIdxInfo);
+ //const t = VT.xVtab.get(pVtab);
+ const pii = VT.xIndexInfo(pIdxInfo);
pii.$estimatedRows = 10;
pii.$estimatedCost = 10.0;
pii.dispose();
}
}/*methods*/
};
- const tmplMod = vth.setupModule(modConfig);
- T.assert(tmplMod instanceof capi.sqlite3_module)
- .assert(1===tmplMod.$iVersion);
+ const tmplMod = VT.setupModule(modConfig);
+ T.assert(1===tmplMod.$iVersion);
this.db.onclose.disposeAfter.push(tmplMod);
this.db.checkRc(capi.sqlite3_create_module(
this.db.pointer, modConfig.name, tmplMod.pointer, 0
-C Support\s".scanstats\sest"\sto\senable\sincluding\splanner\sestimates\sin\squery\sprofiles.
-D 2022-12-08T21:05:33.635
+C Reorganization\sand\srenaming\sin\sthe\snew\sVFS/vtab\sJS\spieces.
+D 2022-12-09T00:50:39.739
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f
F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3
F ext/wasm/api/sqlite3-opfs-async-proxy.js 7795b84b66a7a8dedc791340709b310bb497c3c72a80bef364fa2a58e2ddae3f
-F ext/wasm/api/sqlite3-v-helper.js 3f0ef738f5c44943f05ec5bd86976d617e8ae229a0127a1efe81bbb4763293a7
-F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 8ec510fee735c646fb18a3b99f0ca5ca461f9e066c43cdc404d7144f12ae6ed6
+F ext/wasm/api/sqlite3-v-helper.js edcf2dd0caab42aeac41e41e3e97a36d1ada4eb2fdd02cda4488c5b9f9144e0b
+F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 78133d710bee4c48a1a30262b44a284bc017a3751caa7967bdc030f5d0178daa
F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9
F ext/wasm/api/sqlite3-wasm.c 97034ab4f40ec1fac71ccfaf3afffdca6b1ea2dcd95b7871527bad0f34e152b0
F ext/wasm/api/sqlite3-worker1-promiser.js 0c7a9826dbf82a5ed4e4f7bf7816e825a52aff253afbf3350431f5773faf0e4b
F ext/wasm/test-opfs-vfs.js 44363db07b2a20e73b0eb1808de4400ca71b703af718d0fa6d962f15e73bf2ac
F ext/wasm/tester1-worker.html d43f3c131d88f10d00aff3e328fed13c858d674ea2ff1ff90225506137f85aa9
F ext/wasm/tester1.c-pp.html d34bef3d48e5cbc1c7c06882ad240fec49bf88f5f65696cc2c72c416933aa406
-F ext/wasm/tester1.c-pp.js ff147d87a1b6b827484da0bedf6f9f03ae027d6d4aec8ab9b22b22801c6df474
+F ext/wasm/tester1.c-pp.js 6be7c89efbf4110ca55475755e14d23b34d7ca835f4775552e02ef47bac0a648
F ext/wasm/tests/opfs/concurrency/index.html 86d8ac435074d1e7007b91105f4897f368c165e8cecb6a9aa3d81f5cf5dcbe70
F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d
F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P c31e7488ac1a6b957782b72bd026b1f0590637b631e44a1fdf1dedeb5c587819
-R 196dc006e445c45f419d571c91fca0d9
-U dan
-Z b6f422040c9b3b9b458fdf6204a182d0
+P 0fe71287c953bd813a34ba383f5debd4d1fc8bf3c74e1e27adacec0d6e207ded
+R 0f31cb3eb615ba1b41f313a7cb7afe85
+U stephan
+Z 3328c6b1aad7d12dae010d17db3f3e30
# Remove this line to create a well-formed Fossil manifest.
-0fe71287c953bd813a34ba383f5debd4d1fc8bf3c74e1e27adacec0d6e207ded
\ No newline at end of file
+1c2dda177a11fcc5b66e5554507c23ba4b9948a710b3bccfb26963b9851d40a4
\ No newline at end of file