aboutsummaryrefslogtreecommitdiff
path: root/ext/wasm/tester1.c-pp.js
diff options
context:
space:
mode:
authorstephan <stephan@noemail.net>2022-12-07 07:22:34 +0000
committerstephan <stephan@noemail.net>2022-12-07 07:22:34 +0000
commit1eb1b59b893efb2fd4244d0116beb3c7db250d48 (patch)
tree170cfb4dee2fbff0cd96bf8761ee234b1e7d88b2 /ext/wasm/tester1.c-pp.js
parent30da58c5d66c386129a872ccd3a13b452c67717a (diff)
downloadsqlite-1eb1b59b893efb2fd4244d0116beb3c7db250d48.tar.gz
sqlite-1eb1b59b893efb2fd4244d0116beb3c7db250d48.zip
Work on an alternate (slightly simpler) approach to binding JS vtabs. Non-eponymous vtabs are not working, for reasons as yet unknown.
FossilOrigin-Name: 6a0fefb93bcccd950df211cf5c2f49660c7b92115dd01b2b508a4ab9e3ab3d23
Diffstat (limited to 'ext/wasm/tester1.c-pp.js')
-rw-r--r--ext/wasm/tester1.c-pp.js413
1 files changed, 297 insertions, 116 deletions
diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js
index 910bbc94e..83b02522e 100644
--- a/ext/wasm/tester1.c-pp.js
+++ b/ext/wasm/tester1.c-pp.js
@@ -301,14 +301,12 @@ self.sqlite3InitModule = sqlite3InitModule;
addTest: function(name, callback){
let predicate;
if(1===arguments.length){
- const opt = arguments[0];
- predicate = opt.predicate;
- name = opt.name;
- callback = opt.test;
+ this.currentTestGroup.addTest(arguments[0]);
+ }else{
+ this.currentTestGroup.addTest({
+ name, predicate, test: callback
+ });
}
- this.currentTestGroup.addTest({
- name, predicate, test: callback
- });
return this;
},
runTests: async function(sqlite3){
@@ -399,12 +397,21 @@ self.sqlite3InitModule = sqlite3InitModule;
catch(e){T.assert("test ing ." === e.message)}
try{ throw new sqlite3.SQLite3Error(capi.SQLITE_SCHEMA) }
- catch(e){ T.assert('SQLITE_SCHEMA' === e.message) }
+ catch(e){
+ T.assert('SQLITE_SCHEMA' === e.message)
+ .assert(capi.SQLITE_SCHEMA === e.resultCode);
+ }
try{ sqlite3.SQLite3Error.toss(capi.SQLITE_CORRUPT,{cause: true}) }
catch(e){
- T.assert('SQLITE_CORRUPT'===e.message)
+ T.assert('SQLITE_CORRUPT' === e.message)
+ .assert(capi.SQLITE_CORRUPT === e.resultCode)
.assert(true===e.cause);
}
+ try{ sqlite3.SQLite3Error.toss("resultCode check") }
+ catch(e){
+ T.assert(capi.SQLITE_ERROR === e.resultCode)
+ .assert('resultCode check' === e.message);
+ }
})
////////////////////////////////////////////////////////////////////
.t('strglob/strlike', function(sqlite3){
@@ -988,6 +995,20 @@ self.sqlite3InitModule = sqlite3InitModule;
const dbFile = '/tester1.db';
wasm.sqlite3_wasm_vfs_unlink(0, dbFile);
const db = this.db = new sqlite3.oo1.DB(dbFile, 0 ? 'ct' : 'c');
+ db.onclose = {
+ disposeThese: [],
+ after: function(){
+ while(this.disposeThese.length){
+ const v = this.disposeThese.shift();
+ console.debug("db.onclose cleaning up:",v);
+ if(wasm.isPtr(v)) wasm.dealloc(v);
+ else if(v instanceof sqlite3.StructBinder.StructType){
+ v.dispose();
+ }
+ }
+ }
+ };
+
T.assert(Number.isInteger(db.pointer))
.mustThrowMatching(()=>db.pointer=1, /read-only/)
.assert(0===sqlite3.capi.sqlite3_extended_result_codes(db.pointer,1))
@@ -1539,10 +1560,96 @@ self.sqlite3InitModule = sqlite3InitModule;
T.mustThrow(()=>db.exec("select * from foo.bar"));
})
+ ////////////////////////////////////////////////////////////////////
+ .t({
+ name: 'C-side WASM tests',
+ predicate: ()=>(haveWasmCTests() || "Not compiled in."),
+ test: function(){
+ const w = wasm, db = this.db;
+ const stack = w.scopedAllocPush();
+ let ptrInt;
+ const origValue = 512;
+ const ptrValType = 'i32';
+ try{
+ ptrInt = w.scopedAlloc(4);
+ w.setMemValue(ptrInt,origValue, ptrValType);
+ const cf = w.xGet('sqlite3_wasm_test_intptr');
+ const oldPtrInt = ptrInt;
+ //log('ptrInt',ptrInt);
+ //log('getMemValue(ptrInt)',w.getMemValue(ptrInt));
+ T.assert(origValue === w.getMemValue(ptrInt, ptrValType));
+ const rc = cf(ptrInt);
+ //log('cf(ptrInt)',rc);
+ //log('ptrInt',ptrInt);
+ //log('getMemValue(ptrInt)',w.getMemValue(ptrInt,ptrValType));
+ T.assert(2*origValue === rc).
+ assert(rc === w.getMemValue(ptrInt,ptrValType)).
+ assert(oldPtrInt === ptrInt);
+ const pi64 = w.scopedAlloc(8)/*ptr to 64-bit integer*/;
+ const o64 = 0x010203040506/*>32-bit integer*/;
+ const ptrType64 = 'i64';
+ if(w.bigIntEnabled){
+ w.setMemValue(pi64, o64, ptrType64);
+ //log("pi64 =",pi64, "o64 = 0x",o64.toString(16), o64);
+ const v64 = ()=>w.getMemValue(pi64,ptrType64)
+ //log("getMemValue(pi64)",v64());
+ T.assert(v64() == o64);
+ //T.assert(o64 === w.getMemValue(pi64, ptrType64));
+ const cf64w = w.xGet('sqlite3_wasm_test_int64ptr');
+ cf64w(pi64);
+ //log("getMemValue(pi64)",v64());
+ T.assert(v64() == BigInt(2 * o64));
+ cf64w(pi64);
+ T.assert(v64() == BigInt(4 * o64));
+
+ const biTimes2 = w.xGet('sqlite3_wasm_test_int64_times2');
+ T.assert(BigInt(2 * o64) ===
+ biTimes2(BigInt(o64)/*explicit conv. required to avoid TypeError
+ in the call :/ */));
+
+ const pMin = w.scopedAlloc(16);
+ const pMax = pMin + 8;
+ const g64 = (p)=>w.getMemValue(p,ptrType64);
+ w.setMemValue(pMin, 0, ptrType64);
+ w.setMemValue(pMax, 0, ptrType64);
+ const minMaxI64 = [
+ w.xCall('sqlite3_wasm_test_int64_min'),
+ w.xCall('sqlite3_wasm_test_int64_max')
+ ];
+ T.assert(minMaxI64[0] < BigInt(Number.MIN_SAFE_INTEGER)).
+ assert(minMaxI64[1] > BigInt(Number.MAX_SAFE_INTEGER));
+ //log("int64_min/max() =",minMaxI64, typeof minMaxI64[0]);
+ w.xCall('sqlite3_wasm_test_int64_minmax', pMin, pMax);
+ T.assert(g64(pMin) === minMaxI64[0], "int64 mismatch").
+ assert(g64(pMax) === minMaxI64[1], "int64 mismatch");
+ //log("pMin",g64(pMin), "pMax",g64(pMax));
+ w.setMemValue(pMin, minMaxI64[0], ptrType64);
+ T.assert(g64(pMin) === minMaxI64[0]).
+ assert(minMaxI64[0] === db.selectValue("select ?",g64(pMin))).
+ assert(minMaxI64[1] === db.selectValue("select ?",g64(pMax)));
+ const rxRange = /too big/;
+ T.mustThrowMatching(()=>{db.prepare("select ?").bind(minMaxI64[0] - BigInt(1))},
+ rxRange).
+ mustThrowMatching(()=>{db.prepare("select ?").bind(minMaxI64[1] + BigInt(1))},
+ (e)=>rxRange.test(e.message));
+ }else{
+ log("No BigInt support. Skipping related tests.");
+ log("\"The problem\" here is that we can manipulate, at the byte level,",
+ "heap memory to set 64-bit values, but we can't get those values",
+ "back into JS because of the lack of 64-bit integer support.");
+ }
+ }finally{
+ const x = w.scopedAlloc(1), y = w.scopedAlloc(1), z = w.scopedAlloc(1);
+ //log("x=",x,"y=",y,"z=",z); // just looking at the alignment
+ w.scopedAllocPop(stack);
+ }
+ }
+ }/* jaccwabyt-specific tests */)
+
////////////////////////////////////////////////////////////////////////
.t({
- name: 'Custom virtual tables',
- predicate: ()=>wasm.bigIntEnabled,
+ name: 'virtual table #1',
+ predicate: ()=>!!capi.sqlite3_index_info,
test: function(sqlite3){
warn("The vtab/module JS bindings are experimental and subject to change.");
const vth = sqlite3.VtabHelper;
@@ -1566,63 +1673,63 @@ self.sqlite3InitModule = sqlite3InitModule;
pDb, "CREATE TABLE ignored(a,b)"
);
if(0===rc){
- const t = vth.xWrapVtab();
+ const t = vth.xVtab();
wasm.setPtrValue(ppVtab, t.pointer);
- T.assert(t === vth.xWrapVtab(wasm.getPtrValue(ppVtab)));
+ T.assert(t === vth.xVtab(wasm.getPtrValue(ppVtab)));
}
return rc;
}catch(e){
if(!(e instanceof sqlite3.WasmAllocError)){
wasm.setPtrValue(pzErr, wasm.allocCString(e.message));
}
- return vth.xMethodError('xConnect',e);
+ return vth.xError('xConnect',e);
}
},
xDisconnect: function(pVtab){
try {
- const t = vth.xWrapVtab(pVtab, true);
+ const t = vth.xVtab(pVtab, true);
t.dispose();
return 0;
}catch(e){
- return vth.xMethodError('xDisconnect',e);
+ return vth.xError('xDisconnect',e);
}
},
xOpen: function(pVtab, ppCursor){
try{
- const t = vth.xWrapVtab(pVtab), c = vth.xWrapCursor();
+ const t = vth.xVtab(pVtab), c = vth.xCursor();
T.assert(t instanceof capi.sqlite3_vtab)
.assert(c instanceof capi.sqlite3_vtab_cursor);
wasm.setPtrValue(ppCursor, c.pointer);
c._rowId = 0;
return 0;
}catch(e){
- return vth.xMethodError('xOpen',e);
+ return vth.xError('xOpen',e);
}
},
xClose: function(pCursor){
try{
- const c = vth.xWrapCursor(pCursor,true);
+ const c = vth.xCursor(pCursor,true);
T.assert(c instanceof capi.sqlite3_vtab_cursor)
- .assert(!vth.xWrapCursor(pCursor));
+ .assert(!vth.xCursor(pCursor));
c.dispose();
return 0;
}catch(e){
- return vth.xMethodError('xClose',e);
+ return vth.xError('xClose',e);
}
},
xNext: function(pCursor){
try{
- const c = vth.xWrapCursor(pCursor);
+ const c = vth.xCursor(pCursor);
++c._rowId;
return 0;
}catch(e){
- return vth.xMethodError('xNext',e);
+ return vth.xError('xNext',e);
}
},
xColumn: function(pCursor, pCtx, iCol){
try{
- const c = vth.xWrapCursor(pCursor);
+ const c = vth.xCursor(pCursor);
switch(iCol){
case tmplCols.A:
capi.sqlite3_result_int(pCtx, 1000 + c._rowId);
@@ -1634,38 +1741,41 @@ self.sqlite3InitModule = sqlite3InitModule;
}
return 0;
}catch(e){
- return vth.xMethodError('xColumn',e);
+ return vth.xError('xColumn',e);
}
},
xRowid: function(pCursor, ppRowid64){
try{
- const c = vth.xWrapCursor(pCursor);
- vth.setRowId(ppRowid64, c._rowId);
+ const c = vth.xCursor(pCursor);
+ vth.xRowid(ppRowid64, c._rowId);
return 0;
}catch(e){
- return vth.xMethodError('xRowid',e);
+ return vth.xError('xRowid',e);
}
},
xEof: function(pCursor){
- const c = vth.xWrapCursor(pCursor);
- return c._rowId>=10;
+ const c = vth.xCursor(pCursor),
+ rc = c._rowId>=10;
+ c.dispose();
+ return rc;
},
xFilter: function(pCursor, idxNum, idxCStr,
argc, argv/* [sqlite3_value* ...] */){
try{
- const c = vth.xWrapCursor(pCursor);
+ const c = vth.xCursor(pCursor);
c._rowId = 0;
const list = vth.sqlite3ValuesToJs(argc, argv);
T.assert(argc === list.length);
//log(argc,"xFilter value(s):",list);
+ c.dispose();
return 0;
}catch(e){
- return vth.xMethodError('xFilter',e);
+ return vth.xError('xFilter',e);
}
},
xBestIndex: function(pVtab, pIdxInfo){
try{
- //const t = vth.xWrapVtab(pVtab);
+ //const t = vth.xVtab(pVtab);
const sii = capi.sqlite3_index_info;
const pii = new sii(pIdxInfo);
pii.$estimatedRows = 10;
@@ -1706,7 +1816,7 @@ self.sqlite3InitModule = sqlite3InitModule;
pii.dispose();
return 0;
}catch(e){
- return vth.xMethodError('xBestIndex',e);
+ return vth.xError('xBestIndex',e);
}
}
};
@@ -1727,8 +1837,8 @@ self.sqlite3InitModule = sqlite3InitModule;
}
const tmplMod = new sqlite3.capi.sqlite3_module();
- tmplMod.ondispose = [];
tmplMod.$iVersion = 0;
+ this.db.onclose.disposeThese.push(tmplMod);
vth.installMethods(tmplMod, tmplMethods, true);
if(tmplMethods.xCreate){
T.assert(tmplMod.$xCreate)
@@ -1750,94 +1860,165 @@ self.sqlite3InitModule = sqlite3InitModule;
.assert(1000===list[0][0])
.assert(2009===list[list.length-1][1])
}
- })/*vtab sanity checks*/
+ })/*custom vtab #1*/
- ////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
.t({
- name: 'C-side WASM tests',
- predicate: ()=>(haveWasmCTests() || "Not compiled in."),
- test: function(){
- const w = wasm, db = this.db;
- const stack = w.scopedAllocPush();
- let ptrInt;
- const origValue = 512;
- const ptrValType = 'i32';
- try{
- ptrInt = w.scopedAlloc(4);
- w.setMemValue(ptrInt,origValue, ptrValType);
- const cf = w.xGet('sqlite3_wasm_test_intptr');
- const oldPtrInt = ptrInt;
- //log('ptrInt',ptrInt);
- //log('getMemValue(ptrInt)',w.getMemValue(ptrInt));
- T.assert(origValue === w.getMemValue(ptrInt, ptrValType));
- const rc = cf(ptrInt);
- //log('cf(ptrInt)',rc);
- //log('ptrInt',ptrInt);
- //log('getMemValue(ptrInt)',w.getMemValue(ptrInt,ptrValType));
- T.assert(2*origValue === rc).
- assert(rc === w.getMemValue(ptrInt,ptrValType)).
- assert(oldPtrInt === ptrInt);
- const pi64 = w.scopedAlloc(8)/*ptr to 64-bit integer*/;
- const o64 = 0x010203040506/*>32-bit integer*/;
- const ptrType64 = 'i64';
- if(w.bigIntEnabled){
- w.setMemValue(pi64, o64, ptrType64);
- //log("pi64 =",pi64, "o64 = 0x",o64.toString(16), o64);
- const v64 = ()=>w.getMemValue(pi64,ptrType64)
- //log("getMemValue(pi64)",v64());
- T.assert(v64() == o64);
- //T.assert(o64 === w.getMemValue(pi64, ptrType64));
- const cf64w = w.xGet('sqlite3_wasm_test_int64ptr');
- cf64w(pi64);
- //log("getMemValue(pi64)",v64());
- T.assert(v64() == BigInt(2 * o64));
- cf64w(pi64);
- T.assert(v64() == BigInt(4 * o64));
-
- const biTimes2 = w.xGet('sqlite3_wasm_test_int64_times2');
- T.assert(BigInt(2 * o64) ===
- biTimes2(BigInt(o64)/*explicit conv. required to avoid TypeError
- in the call :/ */));
-
- const pMin = w.scopedAlloc(16);
- const pMax = pMin + 8;
- const g64 = (p)=>w.getMemValue(p,ptrType64);
- w.setMemValue(pMin, 0, ptrType64);
- w.setMemValue(pMax, 0, ptrType64);
- const minMaxI64 = [
- w.xCall('sqlite3_wasm_test_int64_min'),
- w.xCall('sqlite3_wasm_test_int64_max')
- ];
- T.assert(minMaxI64[0] < BigInt(Number.MIN_SAFE_INTEGER)).
- assert(minMaxI64[1] > BigInt(Number.MAX_SAFE_INTEGER));
- //log("int64_min/max() =",minMaxI64, typeof minMaxI64[0]);
- w.xCall('sqlite3_wasm_test_int64_minmax', pMin, pMax);
- T.assert(g64(pMin) === minMaxI64[0], "int64 mismatch").
- assert(g64(pMax) === minMaxI64[1], "int64 mismatch");
- //log("pMin",g64(pMin), "pMax",g64(pMax));
- w.setMemValue(pMin, minMaxI64[0], ptrType64);
- T.assert(g64(pMin) === minMaxI64[0]).
- assert(minMaxI64[0] === db.selectValue("select ?",g64(pMin))).
- assert(minMaxI64[1] === db.selectValue("select ?",g64(pMax)));
- const rxRange = /too big/;
- T.mustThrowMatching(()=>{db.prepare("select ?").bind(minMaxI64[0] - BigInt(1))},
- rxRange).
- mustThrowMatching(()=>{db.prepare("select ?").bind(minMaxI64[1] + BigInt(1))},
- (e)=>rxRange.test(e.message));
+ name: 'virtual table #2 (w/ automated exception wrapping)',
+ predicate: ()=>!!capi.sqlite3_index_info,
+ test: function(sqlite3){
+ warn("The vtab/module JS bindings are experimental and subject to change.");
+ const vth = sqlite3.VtabHelper;
+ const tmplCols = Object.assign(Object.create(null),{
+ A: 0, B: 1
+ });
+ /**
+ The vtab demonstrated here is a JS-ification of
+ ext/misc/templatevtab.c.
+ */
+ let throwOnConnect = 1 ? 0 : capi.SQLITE_CANTOPEN
+ /* ^^^ just for testing exception wrapping. Note that sqlite
+ always translates errors from a vtable to a generic
+ SQLITE_ERROR unless it's from xConnect()/xCreate() and that
+ callback sets an error string. */;
+ const modConfig = {
+ /* catchExceptions changes how the methods are wrapped */
+ catchExceptions: false,
+ name: "vtab2test",
+ methods:{
+ xConnect: function(pDb, pAux, argc, argv, ppVtab, pzErr){
+ if(throwOnConnect){
+ sqlite3.SQLite3Error.toss(
+ throwOnConnect,
+ "Throwing a test exception."
+ );
+ }
+ const args = wasm.cArgvToJs(argc, argv);
+ console.debug("xCreate/xConnect args:",args);
+ T.assert(args.length>=3);
+ const rc = capi.sqlite3_declare_vtab(
+ pDb, "CREATE TABLE ignored(a,b)"
+ );
+ if(0===rc){
+ const t = vth.xVtab();
+ wasm.setPtrValue(ppVtab, t.pointer);
+ T.assert(t === vth.xVtab(wasm.getPtrValue(ppVtab)));
+ }
+ return rc;
+ },
+ xDisconnect: function(pVtab){
+ const t = vth.xVtab(pVtab, true);
+ t.dispose();
+ },
+ xOpen: function(pVtab, ppCursor){
+ const t = vth.xVtab(pVtab), c = vth.xCursor();
+ T.assert(t instanceof capi.sqlite3_vtab)
+ .assert(c instanceof capi.sqlite3_vtab_cursor);
+ wasm.setPtrValue(ppCursor, c.pointer);
+ c._rowId = 0;
+ },
+ xClose: function(pCursor){
+ const c = vth.xCursor(pCursor,true);
+ T.assert(c instanceof capi.sqlite3_vtab_cursor)
+ .assert(!vth.xCursor(pCursor));
+ c.dispose();
+ },
+ xNext: function(pCursor){
+ const c = vth.xCursor(pCursor);
+ ++c._rowId;
+ },
+ xColumn: function(pCursor, pCtx, iCol){
+ const c = vth.xCursor(pCursor);
+ switch(iCol){
+ case tmplCols.A:
+ capi.sqlite3_result_int(pCtx, 1000 + c._rowId);
+ break;
+ case tmplCols.B:
+ capi.sqlite3_result_int(pCtx, 2000 + c._rowId);
+ break;
+ default: sqlite3.SQLite3Error.toss("Invalid column id",iCol);
+ }
+ },
+ xRowid: function(pCursor, ppRowid64){
+ const c = vth.xCursor(pCursor);
+ vth.xRowid(ppRowid64, c._rowId);
+ c.dispose();
+ },
+ xEof: function(pCursor){
+ const c = vth.xCursor(pCursor),
+ rc = c._rowId>=10;
+ c.dispose();
+ return rc;
+ },
+ xFilter: function(pCursor, idxNum, idxCStr,
+ argc, argv/* [sqlite3_value* ...] */){
+ const c = vth.xCursor(pCursor);
+ c._rowId = 0;
+ const list = vth.sqlite3ValuesToJs(argc, argv);
+ T.assert(argc === list.length);
+ c.dispose();
+ },
+ xBestIndex: function(pVtab, pIdxInfo){
+ //const t = vth.xVtab(pVtab);
+ const pii = vth.xIndexInfo(pIdxInfo);
+ pii.$estimatedRows = 10;
+ pii.$estimatedCost = 10.0;
+ pii.dispose();
+ }
+ }/*methods*/
+ };
+ const doEponymous =
+ /* Bug (somewhere): non-eponymous is behaving as is
+ the call to sqlite3_create_module() is missing
+ or failed:
+
+ SQL TRACE #63 create virtual table testvtab2 using vtab2test(arg1, arg2)
+
+ => sqlite3 result code 1: no such module: vtab2test
+ */ true;
+ if(doEponymous){
+ warn("Reminder: non-eponymous mode is still not working here.",
+ "Details are in the code comments.");
+ modConfig.methods.xCreate = 0;
+ }else{
+ modConfig.methods.xCreate = (...args)=>0;
+ }
+ const tmplMod = vth.setupModule(modConfig);
+ T.assert(tmplMod instanceof capi.sqlite3_module)
+ .assert(1===tmplMod.$iVersion);
+ if(doEponymous){
+ if(modConfig.methods.xCreate !== 0){
+ T.assert(modConfig.methods.xCreate === modConfig.methods.xConnect)
+ .assert(tmplMod.$xCreate === tmplMod.$xConnect);
}else{
- log("No BigInt support. Skipping related tests.");
- log("\"The problem\" here is that we can manipulate, at the byte level,",
- "heap memory to set 64-bit values, but we can't get those values",
- "back into JS because of the lack of 64-bit integer support.");
+ T.assert(0 === tmplMod.$xCreate);
}
- }finally{
- const x = w.scopedAlloc(1), y = w.scopedAlloc(1), z = w.scopedAlloc(1);
- //log("x=",x,"y=",y,"z=",z); // just looking at the alignment
- w.scopedAllocPop(stack);
}
+ this.db.onclose.disposeThese.push(tmplMod);
+ this.db.checkRc(capi.sqlite3_create_module(
+ this.db, modConfig.name, tmplMod, 0
+ ));
+ if(!doEponymous){
+ this.db.exec([
+ "create virtual table testvtab2 using ",
+ modConfig.name,
+ "(arg1, arg2)"
+ ]);
+ }
+ const list = this.db.selectArrays(
+ ["SELECT a,b FROM ",
+ (doEponymous ? modConfig.name : "testvtab2"),
+ " 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])
+ .assert(2009===list[list.length-1][1])
}
- }/* jaccwabyt-specific tests */)
+ })/*custom vtab #2*/
+ ////////////////////////////////////////////////////////////////////////
.t('Close db', function(){
T.assert(this.db).assert(wasm.isPtr(this.db.pointer));
wasm.sqlite3_wasm_db_reset(this.db);