SQL statements, and not used within string literals or the like.
</p>
<hr>
- <div id='toolbar'>
- <select class='disable-during-eval' id='sql-select'>
- <option disabled selected>Populated via script code</option>
- </select>
- <button class='disable-during-eval' id='sql-run'>Run selected SQL</button>
- <button class='disable-during-eval' id='sql-run-next'>Run next...</button>
- <button class='disable-during-eval' id='sql-run-remaining'>Run all remaining...</button>
- <button class='disable-during-eval' id='export-metrics'>Export metrics (WIP)</button>
- <button class='disable-during-eval' id='db-reset'>Reset db</button>
- <button id='output-clear'>Clear output</button>
- <span class='input-wrapper flex-col'>
- <label for='select-impl'>Storage impl:</label>
- <select id='select-impl'>
- <option value='virtualfs'>Virtual filesystem</option>
- <option value='memdb'>:memory:</option>
- <option value='wasmfs-opfs'>WASMFS OPFS</option>
- <option value='websql'>WebSQL</option>
+ <fieldset id='toolbar'>
+ <div>
+ <select class='disable-during-eval' id='sql-select'>
+ <option disabled selected>Populated via script code</option>
</select>
- </span>
+ <button class='disable-during-eval' id='sql-run'>Run selected SQL</button>
+ <button class='disable-during-eval' id='sql-run-next'>Run next...</button>
+ <button class='disable-during-eval' id='sql-run-remaining'>Run all remaining...</button>
+ <button class='disable-during-eval' id='export-metrics' disabled>Export metrics (WIP)<br>(broken by refactoring)</button>
+ <button class='disable-during-eval' id='db-reset'>Reset db</button>
+ <button id='output-clear'>Clear output</button>
+ <span class='input-wrapper flex-col'>
+ <label for='select-impl'>Storage impl:</label>
+ <select id='select-impl'>
+ <option value='virtualfs'>Virtual filesystem</option>
+ <option value='memdb'>:memory:</option>
+ <option value='wasmfs-opfs'>WASMFS OPFS</option>
+ <option value='websql'>WebSQL</option>
+ </select>
+ </span>
+ </fieldset>
</div>
<hr>
<span class='input-wrapper'>
display: flex;
flex-direction: column;
}
- #toolbar {
+ #toolbar > div {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
- #toolbar > * {
+ #toolbar > div > * {
margin: 0.25em;
}
</style>
const name = JSON.stringify(row.name);
const type = row.type;
switch(type){
- case 'table': case 'view': case 'trigger':{
+ case 'index': case 'table':
+ case 'trigger': case 'view': {
const sql2 = 'DROP '+type+' '+name;
- warn(db.id,':',sql2);
- tx.executeSql(sql2, [], atEnd, onErr);
+ tx.executeSql(sql2, [], ()=>{}, onErr);
break;
}
default:
- warn("Unhandled db entry type:",type,name);
+ warn("Unhandled db entry type:",type,'name =',name);
break;
}
}
}
capi.sqlite3_finalize(pStmt);
pStmt = 0;
- while(toDrop.length){
+ let doBreak = !toDrop.length;
+ while(!doBreak){
const name = toDrop.pop();
const type = toDrop.pop();
let sql2;
- switch(type){
- case 'table': case 'view': case 'trigger':
- sql2 = 'DROP '+type+' '+name;
- break;
- default:
- warn("Unhandled db entry type:",type,name);
- continue;
+ if(name){
+ switch(type){
+ case 'table': case 'view': case 'trigger': case 'index':
+ sql2 = 'DROP '+type+' '+name;
+ break;
+ default:
+ warn("Unhandled db entry type:",type,name);
+ continue;
+ }
+ }else{
+ sql2 = "VACUUM";
+ doBreak = true;
+ break;
}
wasm.setPtrValue(ppStmt, 0);
warn(db.id,':',sql2);
btnClear: E('#output-clear'),
btnReset: E('#db-reset'),
cbReverseLog: E('#cb-reverse-log-order'),
- selImpl: E('#select-impl')
+ selImpl: E('#select-impl'),
+ fsToolbar: E('#toolbar')
},
db: Object.create(null),
dbs: Object.create(null),
return;
}
// Run this async so that the UI can be updated for the above header...
- const dumpMetrics = ()=>{
+ const endRun = ()=>{
metrics.evalSqlEnd = performance.now();
metrics.evalTimeTotal = (metrics.evalSqlEnd - metrics.evalSqlStart);
- this.logHtml(db.id,"metrics:");//,JSON.stringify(metrics, undefined, ' '));
+ this.logHtml(db.id,"metrics:",JSON.stringify(metrics, undefined, ' '));
this.logHtml("prepare() count:",metrics.stmtCount);
this.logHtml("Time in prepare_v2():",metrics.prepTotal,"ms",
"("+(metrics.prepTotal / metrics.stmtCount),"ms per prepare())");
/* WebSQL cannot execute multiple statements, nor can it execute SQL without
an explicit transaction. Thus we have to do some fragile surgery on the
input SQL. Since we're only expecting carefully curated inputs, the hope is
- that this will suffice. */
- metrics.evalSqlStart = performance.now();
+ that this will suffice. PS: it also can't run most SQL functions, e.g. even
+ instr() results in "not authorized". */
+ if('string'!==typeof sql){ // assume TypedArray
+ sql = new TextDecoder().decode(sql);
+ }
+ sql = sql.replace(/-- [^\n]+\n/g,''); // comment lines interfere with our split()
const sqls = sql.split(/;+\n/);
- const rxBegin = /^BEGIN/i, rxCommit = /^COMMIT/i, rxComment = /^\s*--/;
+ const rxBegin = /^BEGIN/i, rxCommit = /^COMMIT/i;
try {
const nextSql = ()=>{
let x = sqls.shift();
- while(x && rxComment.test(x)) x = sqls.shift();
+ while(sqls.length && !x) x = sqls.shift();
return x && x.trim();
};
+ const who = this;
const transaction = function(tx){
- let s;
- for(;s = nextSql(); s = s.nextSql()){
- if(rxBegin.test(s)) continue;
- else if(rxCommit.test(s)) break;
- ++metrics.stmtCount;
- const t = performance.now();
- tx.executeSql(s);
- metrics.stepTotal += performance.now() - t;
+ try {
+ let s;
+ /* Try to approximate the spirit of the input scripts
+ by running batches bound by BEGIN/COMMIT statements. */
+ for(s = nextSql(); !!s; s = nextSql()){
+ if(rxBegin.test(s)) continue;
+ else if(rxCommit.test(s)) break;
+ //console.log("websql sql again",sqls.length, s);
+ ++metrics.stmtCount;
+ const t = performance.now();
+ tx.executeSql(s,[], ()=>{}, (t,e)=>{
+ console.error("WebSQL error",e,"SQL =",s);
+ who.logErr(e.message);
+ throw e;
+ });
+ metrics.stepTotal += performance.now() - t;
+ }
+ }catch(e){
+ who.logErr("transaction():",e.message);
+ throw e;
}
};
- while(sqls.length){
- db.handle.transaction(transaction);
- }
- resolve(this);
+ const n = sqls.length;
+ const nextBatch = function(){
+ if(sqls.length){
+ console.log("websql sqls.length",sqls.length,'of',n);
+ db.handle.transaction(transaction, reject, nextBatch);
+ }else{
+ resolve(who);
+ }
+ };
+ metrics.evalSqlStart = performance.now();
+ nextBatch();
}catch(e){
- this.gotErr = e;
+ //this.gotErr = e;
+ console.error("websql error:",e);
reject(e);
- return;
}
}.bind(this);
}else{/*sqlite3 db...*/
resolve(this);
}catch(e){
if(pStmt) capi.sqlite3_finalize(pStmt);
- this.gotErr = e;
+ //this.gotErr = e;
reject(e);
- return;
}finally{
wasm.scopedAllocPop(stack);
}
return p.catch(
(e)=>this.logErr("Error via execSql("+name+",...):",e.message)
).finally(()=>{
- dumpMetrics();
+ endRun();
this.blockControls(false);
});
},
/** Disable or enable certain UI controls. */
blockControls: function(disable){
- document.querySelectorAll('.disable-during-eval').forEach((e)=>e.disabled = disable);
+ //document.querySelectorAll('.disable-during-eval').forEach((e)=>e.disabled = disable);
+ this.e.fsToolbar.disabled = disable;
},
/**
*/
metricsToArrays: function(){
const rc = [];
- Object.keys(this.metrics).sort().forEach((k)=>{
- const m = this.metrics[k];
+ Object.keys(this.dbs).sort().forEach((k)=>{
+ const d = this.dbs[k];
+ const m = d.metrics;
delete m.evalSqlStart;
delete m.evalSqlEnd;
const mk = Object.keys(m).sort();
}
const row = [k.split('/').pop()/*remove dir prefix from filename*/];
rc.push(row);
- mk.forEach((kk)=>row.push(m[kk]));
+ row.push(...mk.map((kk)=>m[kk]));
});
return rc;
},
metricsToBlob: function(colSeparator='\t'){
- if(1){
- this.logErr("TODO: re-do metrics dump");
- return;
- }
const ar = [], ma = this.metricsToArrays();
if(!ma.length){
this.logErr("Metrics are empty. Run something.");
databases to clean them up.
*/
clearStorage: function(onlySelectedDb=false){
- const list = onlySelectDb
- ? [('boolean'===typeof onlySelectDb)
+ const list = onlySelectedDb
+ ? [('boolean'===typeof onlySelectedDb)
? this.dbs[this.e.selImpl.value]
- : onlySelectDb]
+ : onlySelectedDb]
: Object.values(this.dbs);
for(let db of list){
if(db && db.handle){
this.logHtml("Clearing db",db.id);
- d.clear();
+ db.clear();
}
}
},
d.filename = ':memory:';
break;
case 'wasmfs-opfs':
- d.filename = 'file:'+(this.sqlite3.capi.sqlite3_wasmfs_opfs_dir())+'/wasmfs-opfs.sqlite3';
+ d.filename = 'file:'+(
+ this.sqlite3.capi.sqlite3_wasmfs_opfs_dir()
+ )+'/wasmfs-opfs.sqlite3b';
break;
case 'websql':
d.filename = 'websql.db';
self._MODULE = theEmccModule /* this is only to facilitate testing from the console */;
sqlite3 = theEmccModule.sqlite3;
console.log("App",App);
+ self.App = App;
App.run(theEmccModule.sqlite3);
});
})();
-C Correct\sduplicate\scopies\sof\ssqlite3-api.js\sbeing\sembedded\sin\sthe\swasmfs-based\sbuilds.
-D 2022-09-28T13:01:49.194
+C More\swork\son\sbatch-runner.html/js\sto\sfacilitate\sspeed\scomparisons\sbetween\svarious\sVFSes\sand\sWebSQL.
+D 2022-09-28T17:52:52.224
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F ext/wasm/api/sqlite3-api-worker1.js d5d5b7fac4c4731c38c7e03f4f404b2a95c388a2a1d8bcf361caada572f107e0
F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9
F ext/wasm/api/sqlite3-wasm.c b756b9c1fee9d0598f715e6df6bf089b750da24aa91bb7ef9277a037d81e7612
-F ext/wasm/batch-runner.html 168fda0f66369edec6427991683af3ed3919f3713158b70571d296f9a269a281
-F ext/wasm/batch-runner.js c8d13f673a68e2094264a0284f8775dbda4a12e609d20c501316fe641a05c760
+F ext/wasm/batch-runner.html c363032aba7a525920f61f8be112a29459f73f07e46f0ba3b7730081a617826e
+F ext/wasm/batch-runner.js 756528ff41c0a2d81607fe82d088f305c379279cc84661c9422a7993b3ac544d
F ext/wasm/common/SqliteTestUtil.js c997c12188c97109f344701a58dd627b9c0f98f32cc6a88413f6171f2191531c
F ext/wasm/common/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f
F ext/wasm/common/testing.css 3a5143699c2b73a85b962271e1a9b3241b30d90e30d895e4f55665e648572962
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P f5d6bf8616341037fa3e229edf820d19acef3e0a6207a652b2b143de0a493214
-R 2d5aa67e77362d00ccd0491d8ca53ec4
+P bbfcfba260f39a9c91e82d87e06b1c2cb297c03498b4530aa3e7e01ef9916012
+R 0e9f94b500e19b6ceb4224cc315ebb8b
U stephan
-Z c9260f6deeb302437c703eb12e2e08ac
+Z cfbdefed825643b9f5c5b839e4caa73f
# Remove this line to create a well-formed Fossil manifest.