diff options
author | stephan <stephan@noemail.net> | 2022-12-09 00:50:39 +0000 |
---|---|---|
committer | stephan <stephan@noemail.net> | 2022-12-09 00:50:39 +0000 |
commit | d27c3e4e7e5ce92a34864ed08f1231918f753c4b (patch) | |
tree | 3881b8fc18cb464630292401ee3a14c1ba7d292f | |
parent | 2797ac028cb43a89cef2bd308a3422d334318990 (diff) | |
download | sqlite-d27c3e4e7e5ce92a34864ed08f1231918f753c4b.tar.gz sqlite-d27c3e4e7e5ce92a34864ed08f1231918f753c4b.zip |
Reorganization and renaming in the new VFS/vtab JS pieces.
FossilOrigin-Name: 1c2dda177a11fcc5b66e5554507c23ba4b9948a710b3bccfb26963b9851d40a4
-rw-r--r-- | ext/wasm/api/sqlite3-v-helper.js | 173 | ||||
-rw-r--r-- | ext/wasm/api/sqlite3-vfs-opfs.c-pp.js | 2 | ||||
-rw-r--r-- | ext/wasm/tester1.c-pp.js | 374 | ||||
-rw-r--r-- | manifest | 18 | ||||
-rw-r--r-- | manifest.uuid | 2 |
5 files changed, 295 insertions, 274 deletions
diff --git a/ext/wasm/api/sqlite3-v-helper.js b/ext/wasm/api/sqlite3-v-helper.js index 25f71556a..a1a34c3fa 100644 --- a/ext/wasm/api/sqlite3-v-helper.js +++ b/ext/wasm/api/sqlite3-v-helper.js @@ -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()*/); diff --git a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js index 49ebfbd80..ea8bc9b29 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js @@ -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} }); diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js index c8225568d..e57f1c002 100644 --- a/ext/wasm/tester1.c-pp.js +++ b/ext/wasm/tester1.c-pp.js @@ -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); } - 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 @@ -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 @@ -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. diff --git a/manifest.uuid b/manifest.uuid index 6ab5406df..af2aada55 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0fe71287c953bd813a34ba383f5debd4d1fc8bf3c74e1e27adacec0d6e207ded
\ No newline at end of file +1c2dda177a11fcc5b66e5554507c23ba4b9948a710b3bccfb26963b9851d40a4
\ No newline at end of file |