From: stephan Date: Tue, 6 Dec 2022 11:21:46 +0000 (+0000) Subject: JS vtables: add infrastructure related to accessing and modifying sqlite3_index_info. X-Git-Tag: version-3.41.0~291^2~5 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=241cde98b89255f41ec13b35a33b3dfdaa9cf580;p=thirdparty%2Fsqlite.git JS vtables: add infrastructure related to accessing and modifying sqlite3_index_info. FossilOrigin-Name: 0d77c348039926c24e0fb50a7dc7e4b62895cd201c021f8e29832917e4b8b09f --- diff --git a/ext/wasm/api/sqlite3-v-helper.js b/ext/wasm/api/sqlite3-v-helper.js index 84272266e8..a23070b24c 100644 --- a/ext/wasm/api/sqlite3-v-helper.js +++ b/ext/wasm/api/sqlite3-v-helper.js @@ -22,6 +22,53 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ sqlite3.VfsHelper = vh; sqlite3.VtabHelper = vt; + const sii = capi.sqlite3_index_info; + /** + If n is >=0 and less than this.$nConstraint, this function + returns either a WASM pointer to the 0-based nth entry of + this.$aConstraint (if passed a truthy 2nd argument) or an + sqlite3_index_info.sqlite3_index_constraint object wrapping that + address (if passed a falsy value or no 2nd argument). Returns a + falsy value if n is out of range. + */ + sii.prototype.nthConstraint = function(n, asPtr=false){ + if(n<0 || n>=this.$nConstraint) return false; + const ptr = this.$aConstraint + ( + sii.sqlite3_index_constraint.structInfo.sizeof * n + ); + return asPtr ? ptr : new sii.sqlite3_index_constraint(ptr); + }; + + /** + Works identically to nthConstraint() but returns state from + this.$aConstraintUsage, so returns an + sqlite3_index_info.sqlite3_index_constraint_usage instance + if passed no 2nd argument or a falsy 2nd argument. + */ + sii.prototype.nthConstraintUsage = function(n, asPtr=false){ + if(n<0 || n>=this.$nConstraint) return false; + const ptr = this.$aConstraintUsage + ( + sii.sqlite3_index_constraint_usage.structInfo.sizeof * n + ); + return asPtr ? ptr : new sii.sqlite3_index_constraint_usage(ptr); + }; + + /** + If n is >=0 and less than this.$nOrderBy, this function + returns either a WASM pointer to the 0-based nth entry of + this.$aOrderBy (if passed a truthy 2nd argument) or an + sqlite3_index_info.sqlite3_index_orderby object wrapping that + address (if passed a falsy value or no 2nd argument). Returns a + falsy value if n is out of range. + */ + sii.prototype.nthOrderBy = function(n, asPtr=false){ + if(n<0 || n>=this.$nOrderBy) return false; + const ptr = this.$aOrderBy + ( + sii.sqlite3_index_orderby.structInfo.sizeof * n + ); + return asPtr ? ptr : new sii.sqlite3_index_orderby(ptr); + }; + /** Installs a StructBinder-bound function pointer member of the given name and function in the given StructType target object. @@ -109,6 +156,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ 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.__removeFuncList){ tgt.ondispose.push('ondispose.__removeFuncList handler', callee.removeFuncList); @@ -244,9 +292,9 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ vt.sqlite3ValuesToJs = capi.sqlite3_create_function_v2.udfConvertArgs; /** - Factory function for xyz2js() impls. + Factory function for wrapXyz() impls. */ - const __v2jsFactory = function(structType){ + const __xWrapFactory = function(structType){ return function(ptr,remove=false){ if(0===arguments.length) ptr = new structType; if(ptr instanceof structType){ @@ -254,7 +302,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ this.set(ptr.pointer, ptr); return ptr; }else if(!wasm.isPtr(ptr)){ - sqlite3.SQLite3Error.toss("Invalid argument to v2jsFactory"); + sqlite3.SQLite3Error.toss("Invalid argument to xWrapFactory"); } let rc = this.get(ptr); if(remove) this.delete(ptr); @@ -270,45 +318,45 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ Has 3 distinct uses: - - vtab2js() instantiates a new capi.sqlite3_vtab instance, maps + - wrapVtab() instantiates a new capi.sqlite3_vtab instance, maps its pointer for later by-pointer lookup, and returns that object. This is intended to be called from sqlite3_module::xConnect() or xCreate() implementations. - - vtab2js(pVtab) accepts a WASM pointer to a C-level + - wrapVtab(pVtab) accepts a WASM pointer to a C-level (sqlite3_vtab*) instance and returns the capi.sqlite3_vtab object created by the first form of this function, or undefined if that form has not been used. This is intended to be called from sqlite3_module methods which take a (sqlite3_vtab*) pointer _except_ for xDisconnect(), in which case use... - - vtab2js(pVtab,true) as for the previous form, but removes the + - wrapVtab(pVtab,true) as for the previous form, but removes the pointer-to-object mapping before returning. The caller must call dispose() on the returned object. This is intended to be called from sqlite3_module::xDisconnect() implementations or in error handling of a failed xCreate() or xConnect(). */ - vt.vtab2js = __v2jsFactory(capi.sqlite3_vtab); + vt.xWrapVtab = __xWrapFactory(capi.sqlite3_vtab); /** EXPERIMENTAL. DO NOT USE IN CLIENT CODE. - Works identically to vtab2js() except that it deals with + Works identically to wrapVtab() except that it deals with sqlite3_cursor objects and pointers instead of sqlite3_vtab. - - vcur2js() is intended to be called from sqlite3_module::xOpen() + - wrapCursor() is intended to be called from sqlite3_module::xOpen() - - vcur2js(pCursor) is intended to be called from all sqlite3_module + - wrapCursor(pCursor) is intended to be called from all sqlite3_module methods which take a (sqlite3_vtab_cursor*) _except_ for xClose(), in which case use... - - vcur2js(pCursor, true) will remove the m apping of pCursor to a + - wrapCursor(pCursor, true) will remove the m apping of pCursor to a capi.sqlite3_vtab_cursor object and return that object. The caller must call dispose() on the returned object. This is intended to be called form xClose() or in error handling of a failed xOpen(). */ - vt.vcur2js = __v2jsFactory(capi.sqlite3_vtab_cursor); + vt.xWrapCursor = __xWrapFactory(capi.sqlite3_vtab_cursor); /** Given an error object, this function returns diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js index c32c4e5e84..7013f3cea8 100644 --- a/ext/wasm/tester1.c-pp.js +++ b/ext/wasm/tester1.c-pp.js @@ -1553,9 +1553,9 @@ self.sqlite3InitModule = sqlite3InitModule; pDb, "CREATE TABLE ignored(a,b)" ); if(0===rc){ - const t = vth.vtab2js(); + const t = vth.xWrapVtab(); wasm.setPtrValue(ppVtab, t.pointer); - T.assert(t === vth.vtab2js(wasm.getPtrValue(ppVtab))); + T.assert(t === vth.xWrapVtab(wasm.getPtrValue(ppVtab))); } return rc; }catch(e){ @@ -1567,7 +1567,7 @@ self.sqlite3InitModule = sqlite3InitModule; }, xDisconnect: function(pVtab){ try { - const t = vth.vtab2js(pVtab, true); + const t = vth.xWrapVtab(pVtab, true); t.dispose(); return 0; }catch(e){ @@ -1576,7 +1576,7 @@ self.sqlite3InitModule = sqlite3InitModule; }, xOpen: function(pVtab, ppCursor){ try{ - const t = vth.vtab2js(pVtab), c = vth.vcur2js(); + const t = vth.xWrapVtab(pVtab), c = vth.xWrapCursor(); T.assert(t instanceof capi.sqlite3_vtab); T.assert(c instanceof capi.sqlite3_vtab_cursor); wasm.setPtrValue(ppCursor, c.pointer); @@ -1588,9 +1588,9 @@ self.sqlite3InitModule = sqlite3InitModule; }, xClose: function(pCursor){ try{ - const c = vth.vcur2js(pCursor,true); + const c = vth.xWrapCursor(pCursor,true); T.assert(c instanceof capi.sqlite3_vtab_cursor) - .assert(!vth.vcur2js(pCursor)); + .assert(!vth.xWrapCursor(pCursor)); c.dispose(); return 0; }catch(e){ @@ -1599,7 +1599,7 @@ self.sqlite3InitModule = sqlite3InitModule; }, xNext: function(pCursor){ try{ - const c = vth.vcur2js(pCursor); + const c = vth.xWrapCursor(pCursor); ++c._rowId; return 0; }catch(e){ @@ -1609,7 +1609,7 @@ self.sqlite3InitModule = sqlite3InitModule; }, xColumn: function(pCursor, pCtx, iCol){ try{ - const c = vth.vcur2js(pCursor); + const c = vth.xWrapCursor(pCursor); switch(iCol){ case tmplCols.A: capi.sqlite3_result_int(pCtx, 1000 + c._rowId); @@ -1626,7 +1626,7 @@ self.sqlite3InitModule = sqlite3InitModule; }, xRowid: function(pCursor, ppRowid64){ try{ - const c = vth.vcur2js(pCursor); + const c = vth.xWrapCursor(pCursor); vth.setRowId(ppRowid64, c._rowId); return 0; }catch(e){ @@ -1634,14 +1634,17 @@ self.sqlite3InitModule = sqlite3InitModule; } }, xEof: function(pCursor){ - const c = vth.vcur2js(pCursor); + const c = vth.xWrapCursor(pCursor); return c._rowId>=10; }, xFilter: function(pCursor, idxNum, idxCStr, argc, argv/* [sqlite3_value* ...] */){ try{ - const c = vth.vcur2js(pCursor); + const c = vth.xWrapCursor(pCursor); c._rowId = 0; + const list = vth.sqlite3ValuesToJs(argc, argv); + T.assert(argc === list.length); + //log(argc,"xFilter value(s):",list); return 0; }catch(e){ return vth.xMethodError('xFilter',e); @@ -1649,10 +1652,44 @@ self.sqlite3InitModule = sqlite3InitModule; }, xBestIndex: function(pVtab, pIdxInfo){ try{ - const t = vth.vtab2js(pVtab); - const pii = new capi.sqlite3_index_info(pIdxInfo); + //const t = vth.xWrapVtab(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){ @@ -1692,7 +1729,9 @@ self.sqlite3InitModule = sqlite3InitModule; this.db.checkRc(rc); const list = this.db.selectArrays( - "SELECT a,b FROM testvtab order by a" + "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 + end up in xBestIndex(). */ ); T.assert(10===list.length) .assert(1000===list[0][0]) diff --git a/manifest b/manifest index 7c57dc1324..3bfa27aa70 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sdeprecated\ssymbol\ssqlite3.opfs.OpfsDb,\swhich\swas\srenamed\sto\ssqlite3.oo1.OpfsDb\son\s2022-11-29. -D 2022-12-06T09:49:04.292 +C JS\svtables:\sadd\sinfrastructure\srelated\sto\saccessing\sand\smodifying\ssqlite3_index_info. +D 2022-12-06T11:21:46.303 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -509,7 +509,7 @@ F ext/wasm/api/sqlite3-api-prologue.js a7596c30392d9ca8f5b7c14feb4e6788107d1159f 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 f79dd8d98ef3e0b55c10bb2bee7a3840fa967318e1f577c156aafc34664271d1 -F ext/wasm/api/sqlite3-v-helper.js 4451763a0cd85734f0afe18b48918cb3c88ca99cef399b7c5f12119281e7b6a8 +F ext/wasm/api/sqlite3-v-helper.js 6b408ee4e926cb0f7fe41a63a1205049283af301fe3f5de3c038845ccf9106df F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 8ec510fee735c646fb18a3b99f0ca5ca461f9e066c43cdc404d7144f12ae6ed6 F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9 F ext/wasm/api/sqlite3-wasm.c 723522a6c2a2463884a83fa1cc7ae5770deaaf0856a1058cc1023b2bfa1c898b @@ -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 81c40395be4a7e97a3ca0ff62a4e02204239b1db6f24fe15b3c96a17fb41f29b +F ext/wasm/tester1.c-pp.js c5679da7895377df03e6075fc0e9dff8b5f570bd4edb63f714154d3030279fce 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 cbf483ea0ba3e6dc08ad7ed654380f818544b4c3cedfdb8aa848a83298268ceb -R 16a04cd1971a4487c1631d3a37d3ce6e +P 0ce51bed65d5e430364f74bf959fb76c42ac5eec0769490231d8c8110a1f388c +R a1b37a98bcb406acaf386e5a65bbf6e3 U stephan -Z 455bc03c9fd6d42a81f698c07992ea6a +Z 3e0a3245949f854c4eed760afd40e3ce # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 2a7e690681..a5ae05d6f7 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0ce51bed65d5e430364f74bf959fb76c42ac5eec0769490231d8c8110a1f388c \ No newline at end of file +0d77c348039926c24e0fb50a7dc7e4b62895cd201c021f8e29832917e4b8b09f \ No newline at end of file