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

JS vtables: add infrastructure related to accessing and modifying sqlite3_index_info.

FossilOrigin-Name: 0d77c348039926c24e0fb50a7dc7e4b62895cd201c021f8e29832917e4b8b09f
This commit is contained in:
stephan
2022-12-06 11:21:46 +00:00
parent d254db53e5
commit 241cde98b8
4 changed files with 121 additions and 34 deletions

View File

@ -22,6 +22,53 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
sqlite3.VfsHelper = vh; sqlite3.VfsHelper = vh;
sqlite3.VtabHelper = vt; 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 Installs a StructBinder-bound function pointer member of the
given name and function in the given StructType target object. 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)); const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true));
tgt[memKey] = pFunc; tgt[memKey] = pFunc;
if(!tgt.ondispose) tgt.ondispose = []; if(!tgt.ondispose) tgt.ondispose = [];
else if(!Array.isArray(tgt.ondispose)) tgt.ondispose = [tgt.ondispose];
if(!tgt.ondispose.__removeFuncList){ if(!tgt.ondispose.__removeFuncList){
tgt.ondispose.push('ondispose.__removeFuncList handler', tgt.ondispose.push('ondispose.__removeFuncList handler',
callee.removeFuncList); callee.removeFuncList);
@ -244,9 +292,9 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
vt.sqlite3ValuesToJs = capi.sqlite3_create_function_v2.udfConvertArgs; 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){ return function(ptr,remove=false){
if(0===arguments.length) ptr = new structType; if(0===arguments.length) ptr = new structType;
if(ptr instanceof structType){ if(ptr instanceof structType){
@ -254,7 +302,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
this.set(ptr.pointer, ptr); this.set(ptr.pointer, ptr);
return ptr; return ptr;
}else if(!wasm.isPtr(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); let rc = this.get(ptr);
if(remove) this.delete(ptr); if(remove) this.delete(ptr);
@ -270,45 +318,45 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
Has 3 distinct uses: 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 its pointer for later by-pointer lookup, and returns that
object. This is intended to be called from object. This is intended to be called from
sqlite3_module::xConnect() or xCreate() implementations. 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 (sqlite3_vtab*) instance and returns the capi.sqlite3_vtab
object created by the first form of this function, or undefined object created by the first form of this function, or undefined
if that form has not been used. This is intended to be called if that form has not been used. This is intended to be called
from sqlite3_module methods which take a (sqlite3_vtab*) pointer from sqlite3_module methods which take a (sqlite3_vtab*) pointer
_except_ for xDisconnect(), in which case use... _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 pointer-to-object mapping before returning. The caller must
call dispose() on the returned object. This is intended to be call dispose() on the returned object. This is intended to be
called from sqlite3_module::xDisconnect() implementations or called from sqlite3_module::xDisconnect() implementations or
in error handling of a failed xCreate() or xConnect(). 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. 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. 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 methods which take a (sqlite3_vtab_cursor*) _except_ for
xClose(), in which case use... 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 capi.sqlite3_vtab_cursor object and return that object. The
caller must call dispose() on the returned object. This is caller must call dispose() on the returned object. This is
intended to be called form xClose() or in error handling of a intended to be called form xClose() or in error handling of a
failed xOpen(). failed xOpen().
*/ */
vt.vcur2js = __v2jsFactory(capi.sqlite3_vtab_cursor); vt.xWrapCursor = __xWrapFactory(capi.sqlite3_vtab_cursor);
/** /**
Given an error object, this function returns Given an error object, this function returns

View File

@ -1553,9 +1553,9 @@ self.sqlite3InitModule = sqlite3InitModule;
pDb, "CREATE TABLE ignored(a,b)" pDb, "CREATE TABLE ignored(a,b)"
); );
if(0===rc){ if(0===rc){
const t = vth.vtab2js(); const t = vth.xWrapVtab();
wasm.setPtrValue(ppVtab, t.pointer); wasm.setPtrValue(ppVtab, t.pointer);
T.assert(t === vth.vtab2js(wasm.getPtrValue(ppVtab))); T.assert(t === vth.xWrapVtab(wasm.getPtrValue(ppVtab)));
} }
return rc; return rc;
}catch(e){ }catch(e){
@ -1567,7 +1567,7 @@ self.sqlite3InitModule = sqlite3InitModule;
}, },
xDisconnect: function(pVtab){ xDisconnect: function(pVtab){
try { try {
const t = vth.vtab2js(pVtab, true); const t = vth.xWrapVtab(pVtab, true);
t.dispose(); t.dispose();
return 0; return 0;
}catch(e){ }catch(e){
@ -1576,7 +1576,7 @@ self.sqlite3InitModule = sqlite3InitModule;
}, },
xOpen: function(pVtab, ppCursor){ xOpen: function(pVtab, ppCursor){
try{ 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(t instanceof capi.sqlite3_vtab);
T.assert(c instanceof capi.sqlite3_vtab_cursor); T.assert(c instanceof capi.sqlite3_vtab_cursor);
wasm.setPtrValue(ppCursor, c.pointer); wasm.setPtrValue(ppCursor, c.pointer);
@ -1588,9 +1588,9 @@ self.sqlite3InitModule = sqlite3InitModule;
}, },
xClose: function(pCursor){ xClose: function(pCursor){
try{ try{
const c = vth.vcur2js(pCursor,true); const c = vth.xWrapCursor(pCursor,true);
T.assert(c instanceof capi.sqlite3_vtab_cursor) T.assert(c instanceof capi.sqlite3_vtab_cursor)
.assert(!vth.vcur2js(pCursor)); .assert(!vth.xWrapCursor(pCursor));
c.dispose(); c.dispose();
return 0; return 0;
}catch(e){ }catch(e){
@ -1599,7 +1599,7 @@ self.sqlite3InitModule = sqlite3InitModule;
}, },
xNext: function(pCursor){ xNext: function(pCursor){
try{ try{
const c = vth.vcur2js(pCursor); const c = vth.xWrapCursor(pCursor);
++c._rowId; ++c._rowId;
return 0; return 0;
}catch(e){ }catch(e){
@ -1609,7 +1609,7 @@ self.sqlite3InitModule = sqlite3InitModule;
}, },
xColumn: function(pCursor, pCtx, iCol){ xColumn: function(pCursor, pCtx, iCol){
try{ try{
const c = vth.vcur2js(pCursor); const c = vth.xWrapCursor(pCursor);
switch(iCol){ switch(iCol){
case tmplCols.A: case tmplCols.A:
capi.sqlite3_result_int(pCtx, 1000 + c._rowId); capi.sqlite3_result_int(pCtx, 1000 + c._rowId);
@ -1626,7 +1626,7 @@ self.sqlite3InitModule = sqlite3InitModule;
}, },
xRowid: function(pCursor, ppRowid64){ xRowid: function(pCursor, ppRowid64){
try{ try{
const c = vth.vcur2js(pCursor); const c = vth.xWrapCursor(pCursor);
vth.setRowId(ppRowid64, c._rowId); vth.setRowId(ppRowid64, c._rowId);
return 0; return 0;
}catch(e){ }catch(e){
@ -1634,14 +1634,17 @@ self.sqlite3InitModule = sqlite3InitModule;
} }
}, },
xEof: function(pCursor){ xEof: function(pCursor){
const c = vth.vcur2js(pCursor); const c = vth.xWrapCursor(pCursor);
return c._rowId>=10; return c._rowId>=10;
}, },
xFilter: function(pCursor, idxNum, idxCStr, xFilter: function(pCursor, idxNum, idxCStr,
argc, argv/* [sqlite3_value* ...] */){ argc, argv/* [sqlite3_value* ...] */){
try{ try{
const c = vth.vcur2js(pCursor); const c = vth.xWrapCursor(pCursor);
c._rowId = 0; c._rowId = 0;
const list = vth.sqlite3ValuesToJs(argc, argv);
T.assert(argc === list.length);
//log(argc,"xFilter value(s):",list);
return 0; return 0;
}catch(e){ }catch(e){
return vth.xMethodError('xFilter',e); return vth.xMethodError('xFilter',e);
@ -1649,10 +1652,44 @@ self.sqlite3InitModule = sqlite3InitModule;
}, },
xBestIndex: function(pVtab, pIdxInfo){ xBestIndex: function(pVtab, pIdxInfo){
try{ try{
const t = vth.vtab2js(pVtab); //const t = vth.xWrapVtab(pVtab);
const pii = new capi.sqlite3_index_info(pIdxInfo); const sii = capi.sqlite3_index_info;
const pii = new sii(pIdxInfo);
pii.$estimatedRows = 10; pii.$estimatedRows = 10;
pii.$estimatedCost = 10.0; 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(); pii.dispose();
return 0; return 0;
}catch(e){ }catch(e){
@ -1692,7 +1729,9 @@ self.sqlite3InitModule = sqlite3InitModule;
this.db.checkRc(rc); this.db.checkRc(rc);
const list = this.db.selectArrays( 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) T.assert(10===list.length)
.assert(1000===list[0][0]) .assert(1000===list[0][0])

View File

@ -1,5 +1,5 @@
C Remove\sdeprecated\ssymbol\ssqlite3.opfs.OpfsDb,\swhich\swas\srenamed\sto\ssqlite3.oo1.OpfsDb\son\s2022-11-29. C JS\svtables:\sadd\sinfrastructure\srelated\sto\saccessing\sand\smodifying\ssqlite3_index_info.
D 2022-12-06T09:49:04.292 D 2022-12-06T11:21:46.303
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 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-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f
F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3 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-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-vfs-opfs.c-pp.js 8ec510fee735c646fb18a3b99f0ca5ca461f9e066c43cdc404d7144f12ae6ed6
F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9 F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9
F ext/wasm/api/sqlite3-wasm.c 723522a6c2a2463884a83fa1cc7ae5770deaaf0856a1058cc1023b2bfa1c898b 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/test-opfs-vfs.js 44363db07b2a20e73b0eb1808de4400ca71b703af718d0fa6d962f15e73bf2ac
F ext/wasm/tester1-worker.html d43f3c131d88f10d00aff3e328fed13c858d674ea2ff1ff90225506137f85aa9 F ext/wasm/tester1-worker.html d43f3c131d88f10d00aff3e328fed13c858d674ea2ff1ff90225506137f85aa9
F ext/wasm/tester1.c-pp.html d34bef3d48e5cbc1c7c06882ad240fec49bf88f5f65696cc2c72c416933aa406 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/index.html 86d8ac435074d1e7007b91105f4897f368c165e8cecb6a9aa3d81f5cf5dcbe70
F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d
F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2 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.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P cbf483ea0ba3e6dc08ad7ed654380f818544b4c3cedfdb8aa848a83298268ceb P 0ce51bed65d5e430364f74bf959fb76c42ac5eec0769490231d8c8110a1f388c
R 16a04cd1971a4487c1631d3a37d3ce6e R a1b37a98bcb406acaf386e5a65bbf6e3
U stephan U stephan
Z 455bc03c9fd6d42a81f698c07992ea6a Z 3e0a3245949f854c4eed760afd40e3ce
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
0ce51bed65d5e430364f74bf959fb76c42ac5eec0769490231d8c8110a1f388c 0d77c348039926c24e0fb50a7dc7e4b62895cd201c021f8e29832917e4b8b09f