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

Reorganization and renaming in the new VFS/vtab JS pieces.

FossilOrigin-Name: 1c2dda177a11fcc5b66e5554507c23ba4b9948a710b3bccfb26963b9851d40a4
This commit is contained in:
stephan
2022-12-09 00:50:39 +00:00
parent 2797ac028c
commit d27c3e4e7e
5 changed files with 296 additions and 275 deletions

View File

@ -17,10 +17,10 @@
'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;
/**
@ -78,15 +78,15 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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
@ -109,7 +109,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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)){
@ -169,8 +169,6 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}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);
@ -180,7 +178,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}
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
@ -197,45 +195,69 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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;
};
@ -260,13 +282,13 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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
@ -274,21 +296,21 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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);
}
}
}
@ -305,7 +327,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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.
@ -414,7 +436,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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*`
@ -423,7 +445,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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,
@ -432,7 +454,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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
@ -451,7 +473,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}
```
*/
/**vh.exceptionToRc = vt.exceptionToRc =
/**vfs.exceptionToRc = vtab.exceptionToRc =
(e, defaultRc=capi.SQLITE_ERROR)=>(
(e instanceof sqlite3.WasmAllocError)
? capi.SQLITE_NOMEM
@ -490,7 +512,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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*/}
@ -501,7 +523,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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
@ -510,10 +532,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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) }
};
*/
@ -534,10 +556,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
};
```
*/
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:
@ -556,8 +578,9 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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.
@ -599,35 +622,44 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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);
}
};
}
@ -652,11 +684,11 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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*/
);
}
@ -669,10 +701,17 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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()*/);

View File

@ -1268,7 +1268,7 @@ const installOpfsVfs = function callee(options){
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}
});

View File

@ -1676,7 +1676,7 @@ self.sqlite3InitModule = sqlite3InitModule;
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
});
@ -1684,195 +1684,178 @@ self.sqlite3InitModule = sqlite3InitModule;
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);
}
},
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);
}
},
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);
}
},
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);
}
},
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;
}catch(e){
if(!(e instanceof sqlite3.WasmAllocError)){
wasm.dealloc(wasm.getPtrValue, pzErr);
wasm.setPtrValue(pzErr, wasm.allocCString(e.message));
},
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);
}
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);
}
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();
},
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();
//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
@ -1890,7 +1873,7 @@ self.sqlite3InitModule = sqlite3InitModule;
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
});
@ -1926,8 +1909,8 @@ self.sqlite3InitModule = sqlite3InitModule;
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;
@ -1935,12 +1918,12 @@ self.sqlite3InitModule = sqlite3InitModule;
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);
@ -1948,19 +1931,19 @@ self.sqlite3InitModule = sqlite3InitModule;
},
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);
@ -1973,34 +1956,33 @@ self.sqlite3InitModule = sqlite3InitModule;
},
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

View File

@ -1,5 +1,5 @@
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
@ -509,8 +509,8 @@ F ext/wasm/api/sqlite3-api-prologue.js 1380e933325c11786b2afc93fc8ff88c2fd1ffeac
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
@ -555,7 +555,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
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
@ -2067,8 +2067,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
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.

View File

@ -1 +1 @@
0fe71287c953bd813a34ba383f5debd4d1fc8bf3c74e1e27adacec0d6e207ded
1c2dda177a11fcc5b66e5554507c23ba4b9948a710b3bccfb26963b9851d40a4