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

Ease-of-use/legibility improvements in the virtual table JS helpers.

FossilOrigin-Name: 54c7ad7e08bdb87579398ade366605bfa2e2538a94aabcc6e4cda8e173649760
This commit is contained in:
stephan
2022-12-08 17:07:27 +00:00
parent 4bfacc4b40
commit 500fa7d518
4 changed files with 199 additions and 133 deletions

View File

@ -308,12 +308,12 @@ 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 xAbc() impls. Internal factory function for xVtab and xCursor impls.
*/ */
const __xWrapFactory = function(methodName,structType){ const __xWrapFactory = function(methodName,StructType){
return function(ptr,removeMapping=false){ return function(ptr,removeMapping=false){
if(0===arguments.length) ptr = new structType; if(0===arguments.length) ptr = new StructType;
if(ptr instanceof structType){ if(ptr instanceof StructType){
//T.assert(!this.has(ptr.pointer)); //T.assert(!this.has(ptr.pointer));
this.set(ptr.pointer, ptr); this.set(ptr.pointer, ptr);
return ptr; return ptr;
@ -325,52 +325,99 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
return rc; return rc;
}.bind(new Map); }.bind(new Map);
}; };
/**
EXPERIMENTAL. DO NOT USE IN CLIENT CODE.
Has 3 distinct uses:
- 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.
- 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 xDestroy() (if there is a distinct
xCreate()) or xDisconnect() (if xCreate() is 0 or is the same
as xConnect()), in which case use...
- 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.xVtab = __xWrapFactory('xVtab',capi.sqlite3_vtab);
/** /**
EXPERIMENTAL. DO NOT USE IN CLIENT CODE. Internal helper for implementing xVtab and xCursor.
The first argument must be the logical name of the
handler ('xVtab' or 'xCursor') and the second must be
the capi.XYZ struct-type value, e.g. capi.sqlite3_vtab
or capi.sqlite3_vtab_cursor.
*/
const __xLifetimeManager = function(name, StructType){
const __xWrap = __xWrapFactory(name,StructType);
/**
This object houses a small API for managing mappings of (`T*`)
to StructType<T> objects, specifically within the lifetime
requirements of sqlite3_module methods.
*/
return Object.assign(Object.create(null),{
/** The StructType object for this object's API. */
StructType,
/**
Creates a new StructType object, writes its `pointer`
value to the given output pointer, and returns that
object. Its intended usage depends on StructType:
Works identically to wrapVtab() except that it deals with sqlite3_vtab: to be called from sqlite3_module::xConnect()
sqlite3_cursor objects and pointers instead of sqlite3_vtab. or xCreate() implementations.
- wrapCursor() is intended to be called from sqlite3_module::xOpen() sqlite3_vtab_cursor: to be called from xOpen().
- wrapCursor(pCursor) is intended to be called from all sqlite3_module This will throw if allocation of the StructType instance
methods which take a (sqlite3_vtab_cursor*) _except_ for fails or if ppOut is not a pointer-type value.
xClose(), in which case use... */
create: (ppOut)=>{
const rc = __xWrap();
wasm.setPtrValue(ppOut, rc.pointer);
return rc;
},
/**
Returns the StructType object previously mapped to the
given pointer using create(). Its intended usage depends
on StructType:
- wrapCursor(pCursor, true) will remove the mapping of pCursor to a sqlite3_vtab: to be called from sqlite3_module methods which
capi.sqlite3_vtab_cursor object and return that object. The take a (sqlite3_vtab*) pointer _except_ for
caller must call dispose() on the returned object. This is xDestroy()/xDisconnect(), in which case unget() or dispose().
intended to be called from xClose() or in error handling of a
failed xOpen(). sqlite3_vtab_cursor: to be called from any sqlite3_module methods
*/ which take a `sqlite3_vtab_cursor*` argument except xClose(),
vt.xCursor = __xWrapFactory('xCursor',capi.sqlite3_vtab_cursor); in which case use unget() or dispose().
*/
get: (pCObj)=>__xWrap(pCObj),
/**
Identical to get() but also disconnects the mapping between the
given pointer and the returned StructType object, such that
future calls to this function or get() with the same pointer
will return the undefined value. Its intended usage depends
on StructType:
sqlite3_vtab: to be called from sqlite3_module::xDisconnect() or
xDestroy() implementations or in error handling of a failed
xCreate() or xConnect().
sqlite3_vtab_cursor: to be called from xClose() or during
cleanup in a failed xOpen().
*/
unget: (pCObj)=>__xWrap(pCObj,true),
/**
Works like unget() plus it calls dispose() on the
StructType object.
*/
dispose: (pCObj)=>{
const o = __xWrap(pCObj,true);
if(o) o.dispose();
}
});
};
/**
A lifetime-management object for mapping `sqlite3_vtab*`
instances in sqlite3_module methods to capi.sqlite3_vtab
objects.
The API docs are in the API-internal __xLifetimeManager().
*/
vt.xVtab = __xLifetimeManager('xVtab', capi.sqlite3_vtab);
/**
A lifetime-management object for mapping `sqlite3_vtab_cursor*`
instances in sqlite3_module methods to capi.sqlite3_vtab_cursor
objects.
The API docs are in the API-internal __xLifetimeManager().
*/
vt.xCursor = __xLifetimeManager('xCursor', capi.sqlite3_vtab_cursor);
/** /**
Convenience form of creating an sqlite3_index_info wrapper, Convenience form of creating an sqlite3_index_info wrapper,
@ -466,16 +513,28 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
/** /**
A helper for sqlite3_vtab::xRowid() implementations. It must be A helper for sqlite3_vtab::xRowid() implementations. It must be
passed that function's 2nd argument and the value for that passed that function's 2nd argument (an output pointer to an
pointer. Returns the same as wasm.setMemValue() and will throw int64 row ID) and the value to store at the output pointer's
address. Returns the same as wasm.setMemValue() and will throw
if the 1st or 2nd arguments are invalid for that function. if the 1st or 2nd arguments are invalid for that function.
Example xRowid impl:
```
const xRowid = (pCursor, ppRowid64)=>{
const c = VtabHelper.xCursor(pCursor);
VtabHelper.xRowid(ppRowid64, c.myRowId);
return 0;
};
```
*/ */
vt.xRowid = (ppRowid64, value)=>wasm.setMemValue(ppRowid64, value, 'i64'); vt.xRowid = (ppRowid64, value)=>wasm.setMemValue(ppRowid64, value, 'i64');
/** /**
Sets up an sqlite3_module() object for later installation into A helper to initialize and set up an sqlite3_module() object for
individual databases using sqlite3_create_module(). Requires an later installation into individual databases using
object with the following properties: sqlite3_create_module(). Requires an object with the following
properties:
- `methods`: an object containing a mapping of properties with - `methods`: an object containing a mapping of properties with
the C-side names of the sqlite3_module methods, e.g. xCreate, the C-side names of the sqlite3_module methods, e.g. xCreate,
@ -506,16 +565,25 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
behavior. (VtabHelper.xError() is intended to assist in reporting behavior. (VtabHelper.xError() is intended to assist in reporting
such exceptions.) such exceptions.)
If `methods.xConnect` is `true` then the value of Certain methods may refer to the same implementation. To simplify
`methods.xCreate` is used in its place, and vice versa. This is the definition of such methods:
to facilitate creation of those methods inline in the passed-in
object without requiring the client to explicitly get a reference - If `methods.xConnect` is `true` then the value of
to one of them in order to assign it to the other one. Note that `methods.xCreate` is used in its place, and vice versa. sqlite
sqlite treats those two functions specially if they are exactly treats xConnect/xCreate functions specially if they are exactly
the same function (same pointer value). The the same function (same pointer value).
`catchExceptions`-installed handlers will account for identical
references to those two functions and will install the same - If `methods.xDisconnect` is true then the value of
wrapper function for both. `methods.xDestroy` is used in its place, and vice versa.
This is to facilitate creation of those methods inline in the
passed-in object without requiring the client to explicitly get a
reference to one of them in order to assign it to the other
one.
The `catchExceptions`-installed handlers will account for
identical references to the above functions and will install the
same wrapper function for both.
The given methods are expected to return integer values, as The given methods are expected to return integer values, as
expected by the C API. If `catchExceptions` is truthy, the return expected by the C API. If `catchExceptions` is truthy, the return
@ -525,7 +593,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
active, the method implementations must explicitly return integer active, the method implementations must explicitly return integer
values. values.
Throws on error. Returns the sqlite3_module object on success. Throws on error. Returns the opt.struct sqlite3_module object on
success.
*/ */
vt.setupModule = function(opt){ vt.setupModule = function(opt){
const mod = opt.struct || new capi.sqlite3_module(); const mod = opt.struct || new capi.sqlite3_module();
@ -533,6 +602,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const methods = opt.methods || toss("Missing 'methods' object."); const methods = opt.methods || toss("Missing 'methods' object.");
if(true===methods.xConnect) methods.xConnect = methods.xCreate; if(true===methods.xConnect) methods.xConnect = methods.xCreate;
else if(true===methods.xCreate) methods.xCreate = methods.xConnect; 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;
if(opt.catchExceptions){ if(opt.catchExceptions){
const fwrap = function(methodName, func){ const fwrap = function(methodName, func){
if(['xConnect','xCreate'].indexOf(methodName) >= 0){ if(['xConnect','xCreate'].indexOf(methodName) >= 0){
@ -577,6 +648,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
} }
this.installMethods(mod, remethods, false); this.installMethods(mod, remethods, false);
}else{ }else{
// No automatic exception handling. Trust the client
// to not throw.
this.installMethods( this.installMethods(
mod, methods, !!opt.applyArgcCheck/*undocumented option*/ mod, methods, !!opt.applyArgcCheck/*undocumented option*/
); );

View File

@ -999,7 +999,12 @@ self.sqlite3InitModule = sqlite3InitModule;
const db = this.db = new sqlite3.oo1.DB(dbFile, 0 ? 'ct' : 'c'); const db = this.db = new sqlite3.oo1.DB(dbFile, 0 ? 'ct' : 'c');
db.onclose = { db.onclose = {
disposeAfter: [], disposeAfter: [],
disposeBefore: [], disposeBefore: [
(db)=>{
//console.debug("db.onclose.before dropping modules");
//sqlite3.capi.sqlite3_drop_modules(db.pointer, 0);
}
],
before: function(db){ before: function(db){
while(this.disposeBefore.length){ while(this.disposeBefore.length){
const v = this.disposeBefore.shift(); const v = this.disposeBefore.shift();
@ -1013,8 +1018,6 @@ self.sqlite3InitModule = sqlite3InitModule;
} }
} }
} }
console.debug("db.onclose.before dropping modules");
sqlite3.capi.sqlite3_drop_modules(db.pointer, 0);
}, },
after: function(){ after: function(){
while(this.disposeAfter.length){ while(this.disposeAfter.length){
@ -1669,7 +1672,7 @@ self.sqlite3InitModule = sqlite3InitModule;
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
.t({ .t({
name: 'virtual table #1', name: 'virtual table #1: eponymous w/ manual exception handling',
predicate: ()=>!!capi.sqlite3_index_info, predicate: ()=>!!capi.sqlite3_index_info,
test: function(sqlite3){ test: function(sqlite3){
warn("The vtab/module JS bindings are experimental and subject to change."); warn("The vtab/module JS bindings are experimental and subject to change.");
@ -1694,9 +1697,8 @@ self.sqlite3InitModule = sqlite3InitModule;
pDb, "CREATE TABLE ignored(a,b)" pDb, "CREATE TABLE ignored(a,b)"
); );
if(0===rc){ if(0===rc){
const t = vth.xVtab(); const t = vth.xVtab.create(ppVtab);
wasm.setPtrValue(ppVtab, t.pointer); T.assert(t === vth.xVtab.get(wasm.getPtrValue(ppVtab)));
T.assert(t === vth.xVtab(wasm.getPtrValue(ppVtab)));
} }
return rc; return rc;
}catch(e){ }catch(e){
@ -1709,8 +1711,7 @@ self.sqlite3InitModule = sqlite3InitModule;
}, },
xDisconnect: function(pVtab){ xDisconnect: function(pVtab){
try { try {
const t = vth.xVtab(pVtab, true); vth.xVtab.unget(pVtab).dispose();
t.dispose();
return 0; return 0;
}catch(e){ }catch(e){
return vth.xError('xDisconnect',e); return vth.xError('xDisconnect',e);
@ -1718,10 +1719,10 @@ self.sqlite3InitModule = sqlite3InitModule;
}, },
xOpen: function(pVtab, ppCursor){ xOpen: function(pVtab, ppCursor){
try{ try{
const t = vth.xVtab(pVtab), c = vth.xCursor(); const t = vth.xVtab.get(pVtab),
c = vth.xCursor.create(ppCursor);
T.assert(t instanceof capi.sqlite3_vtab) T.assert(t instanceof capi.sqlite3_vtab)
.assert(c instanceof capi.sqlite3_vtab_cursor); .assert(c instanceof capi.sqlite3_vtab_cursor);
wasm.setPtrValue(ppCursor, c.pointer);
c._rowId = 0; c._rowId = 0;
return 0; return 0;
}catch(e){ }catch(e){
@ -1730,9 +1731,9 @@ self.sqlite3InitModule = sqlite3InitModule;
}, },
xClose: function(pCursor){ xClose: function(pCursor){
try{ try{
const c = vth.xCursor(pCursor,true); const c = vth.xCursor.unget(pCursor);
T.assert(c instanceof capi.sqlite3_vtab_cursor) T.assert(c instanceof capi.sqlite3_vtab_cursor)
.assert(!vth.xCursor(pCursor)); .assert(!vth.xCursor.get(pCursor));
c.dispose(); c.dispose();
return 0; return 0;
}catch(e){ }catch(e){
@ -1741,17 +1742,16 @@ self.sqlite3InitModule = sqlite3InitModule;
}, },
xNext: function(pCursor){ xNext: function(pCursor){
try{ try{
const c = vth.xCursor(pCursor); const c = vth.xCursor.get(pCursor);
++c._rowId; ++c._rowId;
return 0; return 0;
}catch(e){ }catch(e){
return vth.xError('xNext',e); return vth.xError('xNext',e);
} }
}, },
xColumn: function(pCursor, pCtx, iCol){ xColumn: function(pCursor, pCtx, iCol){
try{ try{
const c = vth.xCursor(pCursor); const c = vth.xCursor.get(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);
@ -1768,7 +1768,7 @@ self.sqlite3InitModule = sqlite3InitModule;
}, },
xRowid: function(pCursor, ppRowid64){ xRowid: function(pCursor, ppRowid64){
try{ try{
const c = vth.xCursor(pCursor); const c = vth.xCursor.get(pCursor);
vth.xRowid(ppRowid64, c._rowId); vth.xRowid(ppRowid64, c._rowId);
return 0; return 0;
}catch(e){ }catch(e){
@ -1776,7 +1776,7 @@ self.sqlite3InitModule = sqlite3InitModule;
} }
}, },
xEof: function(pCursor){ xEof: function(pCursor){
const c = vth.xCursor(pCursor), const c = vth.xCursor.get(pCursor),
rc = c._rowId>=10; rc = c._rowId>=10;
c.dispose(); c.dispose();
return rc; return rc;
@ -1784,7 +1784,7 @@ self.sqlite3InitModule = sqlite3InitModule;
xFilter: function(pCursor, idxNum, idxCStr, xFilter: function(pCursor, idxNum, idxCStr,
argc, argv/* [sqlite3_value* ...] */){ argc, argv/* [sqlite3_value* ...] */){
try{ try{
const c = vth.xCursor(pCursor); const c = vth.xCursor.get(pCursor);
c._rowId = 0; c._rowId = 0;
const list = vth.sqlite3ValuesToJs(argc, argv); const list = vth.sqlite3ValuesToJs(argc, argv);
T.assert(argc === list.length); T.assert(argc === list.length);
@ -1797,7 +1797,7 @@ self.sqlite3InitModule = sqlite3InitModule;
}, },
xBestIndex: function(pVtab, pIdxInfo){ xBestIndex: function(pVtab, pIdxInfo){
try{ try{
//const t = vth.xVtab(pVtab); //const t = vth.xVtab.get(pVtab);
const sii = capi.sqlite3_index_info; const sii = capi.sqlite3_index_info;
const pii = new sii(pIdxInfo); const pii = new sii(pIdxInfo);
pii.$estimatedRows = 10; pii.$estimatedRows = 10;
@ -1886,7 +1886,7 @@ self.sqlite3InitModule = sqlite3InitModule;
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
.t({ .t({
name: 'virtual table #2 (non-eponymous w/ automated exception wrapping)', name: 'virtual table #2: non-eponymous w/ automated exception wrapping',
predicate: ()=>!!capi.sqlite3_index_info, predicate: ()=>!!capi.sqlite3_index_info,
test: function(sqlite3){ test: function(sqlite3){
warn("The vtab/module JS bindings are experimental and subject to change."); warn("The vtab/module JS bindings are experimental and subject to change.");
@ -1926,55 +1926,41 @@ self.sqlite3InitModule = sqlite3InitModule;
pDb, "CREATE TABLE ignored(a,b)" pDb, "CREATE TABLE ignored(a,b)"
); );
if(0===rc){ if(0===rc){
const t = vth.xVtab(); const t = vth.xVtab.create(ppVtab);
wasm.setPtrValue(ppVtab, t.pointer); T.assert(t === vth.xVtab.get(wasm.getPtrValue(ppVtab)));
T.assert(t === vth.xVtab(wasm.getPtrValue(ppVtab)));
vtabTrace("xCreate",...arguments," ppVtab =",t.pointer); vtabTrace("xCreate",...arguments," ppVtab =",t.pointer);
} }
return rc; return rc;
}, },
xConnect: true,
xDestroy: function(pVtab){ xDestroy: function(pVtab){
vtabTrace("sqlite3_xDestroy",pVtab); vtabTrace("xDestroy/xDisconnect",pVtab);
const t = vth.xVtab(pVtab, true); vth.xVtab.dispose(pVtab);
T.assert(t);
t.dispose();
}, },
/*xConnect: function(pDb, pAux, argc, argv, ppVtab, pzErr){ xDisconnect: true,
vtabTrace("xConnect",...arguments);
const t = vth.xVtab();
wasm.setPtrValue(ppVtab, t.pointer);
T.assert(t === vth.xVtab(wasm.getPtrValue(ppVtab)));
vtabTrace("xConnect",...arguments,"ppVtab =",t.pointer);
},
xDisconnect: function(pVtab){
vtabTrace("xDisconnect",pVtab);
const t = vth.xVtab(pVtab, true);
T.assert(t);
t.dispose();
},*/
xOpen: function(pVtab, ppCursor){ xOpen: function(pVtab, ppCursor){
const t = vth.xVtab(pVtab), c = vth.xCursor(); const t = vth.xVtab.get(pVtab),
c = vth.xCursor.create(ppCursor);
T.assert(t instanceof capi.sqlite3_vtab) T.assert(t instanceof capi.sqlite3_vtab)
.assert(c instanceof capi.sqlite3_vtab_cursor); .assert(c instanceof capi.sqlite3_vtab_cursor);
wasm.setPtrValue(ppCursor, c.pointer);
vtabTrace("xOpen",...arguments," cursor =",c.pointer); vtabTrace("xOpen",...arguments," cursor =",c.pointer);
c._rowId = 0; c._rowId = 0;
}, },
xClose: function(pCursor){ xClose: function(pCursor){
vtabTrace("xClose",...arguments); vtabTrace("xClose",...arguments);
const c = vth.xCursor(pCursor,true); const c = vth.xCursor.unget(pCursor);
T.assert(c instanceof capi.sqlite3_vtab_cursor) T.assert(c instanceof capi.sqlite3_vtab_cursor)
.assert(!vth.xCursor(pCursor)); .assert(!vth.xCursor.get(pCursor));
c.dispose(); c.dispose();
}, },
xNext: function(pCursor){ xNext: function(pCursor){
vtabTrace("xNext",...arguments); vtabTrace("xNext",...arguments);
const c = vth.xCursor(pCursor); const c = vth.xCursor.get(pCursor);
++c._rowId; ++c._rowId;
}, },
xColumn: function(pCursor, pCtx, iCol){ xColumn: function(pCursor, pCtx, iCol){
vtabTrace("xColumn",...arguments); vtabTrace("xColumn",...arguments);
const c = vth.xCursor(pCursor); const c = vth.xCursor.get(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);
@ -1987,24 +1973,24 @@ self.sqlite3InitModule = sqlite3InitModule;
}, },
xRowid: function(pCursor, ppRowid64){ xRowid: function(pCursor, ppRowid64){
vtabTrace("xRowid",...arguments); vtabTrace("xRowid",...arguments);
const c = vth.xCursor(pCursor); const c = vth.xCursor.get(pCursor);
vth.xRowid(ppRowid64, c._rowId); vth.xRowid(ppRowid64, c._rowId);
}, },
xEof: function(pCursor){ xEof: function(pCursor){
vtabTrace("xEof",...arguments); vtabTrace("xEof",...arguments);
return vth.xCursor(pCursor)._rowId>=10; return vth.xCursor.get(pCursor)._rowId>=10;
}, },
xFilter: function(pCursor, idxNum, idxCStr, xFilter: function(pCursor, idxNum, idxCStr,
argc, argv/* [sqlite3_value* ...] */){ argc, argv/* [sqlite3_value* ...] */){
vtabTrace("xFilter",...arguments); vtabTrace("xFilter",...arguments);
const c = vth.xCursor(pCursor); const c = vth.xCursor.get(pCursor);
c._rowId = 0; c._rowId = 0;
const list = vth.sqlite3ValuesToJs(argc, argv); const list = vth.sqlite3ValuesToJs(argc, argv);
T.assert(argc === list.length); T.assert(argc === list.length);
}, },
xBestIndex: function(pVtab, pIdxInfo){ xBestIndex: function(pVtab, pIdxInfo){
vtabTrace("xBestIndex",...arguments); vtabTrace("xBestIndex",...arguments);
//const t = vth.xVtab(pVtab); //const t = vth.xVtab.get(pVtab);
const pii = vth.xIndexInfo(pIdxInfo); const pii = vth.xIndexInfo(pIdxInfo);
pii.$estimatedRows = 10; pii.$estimatedRows = 10;
pii.$estimatedCost = 10.0; pii.$estimatedCost = 10.0;
@ -2024,19 +2010,18 @@ self.sqlite3InitModule = sqlite3InitModule;
modConfig.name, modConfig.name,
"(arg1 blah, arg2 bloop)" "(arg1 blah, arg2 bloop)"
]); ]);
this.db.onclose.disposeBefore.push(function(db){ if(0){
console.debug("testvtab2 disposeBefore handler..."); /* If we DROP TABLE then xDestroy() is called. If the
db.exec( vtab is instead destroyed when the db is closed,
/** xDisconnect() is called. */
DROP TABLE is the only way to get xDestroy() to be called. this.db.onclose.disposeBefore.push(function(db){
If we DROP TABLE at the end of the containing console.debug("Explicitly dropping testvtab2 via disposeBefore handler...");
test function, xDestroy() is called. If we instead db.exec(
delay it until db.onclose.before(), we're getting /** DROP TABLE is the only way to get xDestroy() to be called. */
"no such table"? "DROP TABLE testvtab2"
*/ );
"DROP TABLE testvtab2" });
); }
});
let list = this.db.selectArrays( let list = this.db.selectArrays(
"SELECT a,b FROM testvtab2 where a<9999 and b>1 order by a, b" "SELECT a,b FROM testvtab2 where a<9999 and b>1 order by a, b"
/* Query is shaped so that it will ensure that some /* Query is shaped so that it will ensure that some
@ -2052,6 +2037,15 @@ self.sqlite3InitModule = sqlite3InitModule;
T.assert(5===list.length) T.assert(5===list.length)
.assert(1000===list[0][0]) .assert(1000===list[0][0])
.assert(2004===list[list.length-1][1]); .assert(2004===list[list.length-1][1]);
// Call it as a table-valued function...
list = this.db.selectArrays([
"SELECT a,b FROM ", modConfig.name,
" where a<9999 and b>1 order by b, a limit 1"
]);
T.assert(1===list.length)
.assert(1000===list[0][0])
.assert(2000===list[0][1]);
} }
})/*custom vtab #2*/ })/*custom vtab #2*/

View File

@ -1,5 +1,5 @@
C Initial\ssupport\sfor\svirtual\stables\simplemented\sin\sJavaScript. C Ease-of-use/legibility\simprovements\sin\sthe\svirtual\stable\sJS\shelpers.
D 2022-12-08T15:00:53.415 D 2022-12-08T17:07:27.475
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 1380e933325c11786b2afc93fc8ff88c2fd1ffeac
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 7795b84b66a7a8dedc791340709b310bb497c3c72a80bef364fa2a58e2ddae3f F ext/wasm/api/sqlite3-opfs-async-proxy.js 7795b84b66a7a8dedc791340709b310bb497c3c72a80bef364fa2a58e2ddae3f
F ext/wasm/api/sqlite3-v-helper.js ec03a222ad3551764626f14f38de1b1081bda509e098849502b498c041993a0f w ext/wasm/api/sqlite3-vfs-helper.js F ext/wasm/api/sqlite3-v-helper.js d0d647110f8595d26836951cfc5a47f15282f20e72584decc0b00e2a3f0d169c
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 97034ab4f40ec1fac71ccfaf3afffdca6b1ea2dcd95b7871527bad0f34e152b0 F ext/wasm/api/sqlite3-wasm.c 97034ab4f40ec1fac71ccfaf3afffdca6b1ea2dcd95b7871527bad0f34e152b0
@ -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 ecd0ecd6c9f0c5bce7f39a3ccb28151c7ae7b1042379a0c855e930661579f2e8 F ext/wasm/tester1.c-pp.js ff147d87a1b6b827484da0bedf6f9f03ae027d6d4aec8ab9b22b22801c6df474
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,9 +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 53dcb81b029e4422bdc0b5cf694183854b997195427d437b6154ed4dad7ad0ba 51e3c3b569dce2097063d39dc484f44b2f98cad0a902ef66765ca4cdc3e06f47 P a1454744c770a30a32a6d7b7fc59ef7be48cf67348b238540592850d7c2c7757
R 8761e73b7826ed273f62994737b011e2 R 17cb094a6db22f136920052decf90bf5
T +closed 51e3c3b569dce2097063d39dc484f44b2f98cad0a902ef66765ca4cdc3e06f47 Closed\sby\sintegrate-merge.
U stephan U stephan
Z b6d983dab7ab65c0caebb5e5bbac6324 Z fce05bcff7bc40d31cdbdf756e15ecfc
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
a1454744c770a30a32a6d7b7fc59ef7be48cf67348b238540592850d7c2c7757 54c7ad7e08bdb87579398ade366605bfa2e2538a94aabcc6e4cda8e173649760