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:
@ -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*/
|
||||||
);
|
);
|
||||||
|
@ -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*/
|
||||||
|
|
||||||
|
15
manifest
15
manifest
@ -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.
|
||||||
|
@ -1 +1 @@
|
|||||||
a1454744c770a30a32a6d7b7fc59ef7be48cf67348b238540592850d7c2c7757
|
54c7ad7e08bdb87579398ade366605bfa2e2538a94aabcc6e4cda8e173649760
|
Reference in New Issue
Block a user