1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-10-21 11:13:54 +03:00

Overhaul the wasm build to (A) support more coexisting variants, e.g. 32/64-bit of both vanilla and esm, and (B) build each variant to its own subdir so that they can build in parallel. It can, with make -j4, now build all new variants in half the time it previously took for just the 32-bit builds. The new build logging output, though unconventional, serves two purposes: (A) improve my build-time situational awareness and (B) it help demystify some of the build steps and output files.

FossilOrigin-Name: 2f4be98614b49def2c2951887796c736269ef3bb7ba5b045cae5f748ae165a83
This commit is contained in:
stephan
2025-09-25 15:17:58 +00:00
21 changed files with 1776 additions and 2365 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -69,6 +69,7 @@ const toExportForESM =
EmscriptenModule /* see post-js-header/footer.js */,
!!ff.__isUnderTest
);
sIMS.debugModule("sqlite3InitModule() sqlite3 =",s);
//const rv = s.asyncPostInit();
//delete s.asyncPostInit;
//#if wasmfs

View File

@@ -36,7 +36,6 @@ if( 'undefined' === typeof EmscriptenModule/*from post-js-header.js*/ ){
throw new Error("sqlite3-api-cleanup.js expects to be running in the "+
"context of its Emscripten module loader.");
}
try{
/* Config options for sqlite3ApiBootstrap(). */
const bootstrapConfig = Object.assign(
@@ -60,6 +59,8 @@ try{
bootstrapConfig.wasmPtrIR =
'number'===(typeof bootstrapConfig.exports.sqlite3_libversion())
? 'i32' :'i64';
const sIMS = sqlite3InitScriptInfo;
sIMS.debugModule("Bootstrapping lib config", sIMS);
/**
For purposes of the Emscripten build, call sqlite3ApiBootstrap().

View File

@@ -252,10 +252,12 @@ globalThis.sqlite3Worker1Promiser = function callee(config = callee.defaultConfi
globalThis.sqlite3Worker1Promiser.defaultConfig = {
worker: function(){
//#if target=es6-module
//#if target=es6-bundler-friendly
return new Worker(new URL("sqlite3-worker1-bundler-friendly.mjs", import.meta.url),{
type: 'module'
});
//#elif target=es6-module
return new Worker(new URL("sqlite3-worker1.js", import.meta.url));
//#else
let theJs = "sqlite3-worker1.js";
if(this.currentScript){

View File

@@ -34,6 +34,8 @@
*/
//#if target=es6-bundler-friendly
import {default as sqlite3InitModule} from './sqlite3-bundler-friendly.mjs';
//#elif target=es6-module
return new Worker(new URL("sqlite3.js", import.meta.url));
//#else
"use strict";
{

View File

@@ -1,86 +0,0 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
<link rel="stylesheet" href="common/testing.css"/>
<title>sqlite3-api batch SQL runner for the SAHPool VFS</title>
</head>
<body>
<header id='titlebar'><span>sqlite3-api batch SQL runner for the SAHPool VFS</span></header>
<div>
<span class='input-wrapper'>
<input type='checkbox' class='disable-during-eval' id='cb-reverse-log-order' checked></input>
<label for='cb-reverse-log-order' id='lbl-reverse-log-order'>Reverse log order</label>
</span>
</div>
<div id='test-output' class='reverse'></div>
<script>
(function(){
const E = (sel)=>document.querySelector(sel);
const eOut = E('#test-output');
const log2 = function(cssClass,...args){
let ln;
if(1 || cssClass){
ln = document.createElement('div');
if(cssClass) ln.classList.add(cssClass);
ln.append(document.createTextNode(args.join(' ')));
}else{
// This doesn't work with the "reverse order" option!
ln = document.createTextNode(args.join(' ')+'\n');
}
eOut.append(ln);
};
const log = (...args)=>{
//console.log(...args);
log2('', ...args);
};
const logErr = function(...args){
console.error(...args);
log2('error', ...args);
};
const logWarn = function(...args){
console.warn(...args);
log2('warning', ...args);
};
const cbReverseLog = E('#cb-reverse-log-order');
const lblReverseLog = E('#lbl-reverse-log-order');
if(cbReverseLog.checked){
lblReverseLog.classList.add('warning');
eOut.classList.add('reverse');
}
cbReverseLog.addEventListener('change', function(){
if(this.checked){
eOut.classList.add('reverse');
lblReverseLog.classList.add('warning');
}else{
eOut.classList.remove('reverse');
lblReverseLog.classList.remove('warning');
}
}, false);
const w = new Worker('batch-runner-sahpool.js?sqlite3.dir=jswasm');
w.onmessage = function(msg){
msg = msg.data;
switch(msg.type){
case 'stdout': log(...msg.data); break;
case 'warn': logWarn(...msg.data); break;
case 'error': logErr(...msg.data); break;
default:
logErr("Unhandled worker message type:",msg);
break;
}
};
})();
</script>
<style>
#test-output {
white-space: break-spaces;
overflow: auto;
}
</style>
</body>
</html>

View File

@@ -1,341 +0,0 @@
/*
2023-11-30
The author disclaims copyright to this source code. In place of a
legal notice, here is a blessing:
* May you do good and not evil.
* May you find forgiveness for yourself and forgive others.
* May you share freely, never taking more than you give.
***********************************************************************
A basic batch SQL runner for the SAHPool VFS. This file must be run in
a worker thread. This is not a full-featured app, just a way to get some
measurements for batch execution of SQL for the OPFS SAH Pool VFS.
*/
'use strict';
const wMsg = function(msgType,...args){
postMessage({
type: msgType,
data: args
});
};
const toss = function(...args){throw new Error(args.join(' '))};
const warn = (...args)=>{ wMsg('warn',...args); };
const error = (...args)=>{ wMsg('error',...args); };
const log = (...args)=>{ wMsg('stdout',...args); }
let sqlite3;
const urlParams = new URL(globalThis.location.href).searchParams;
const cacheSize = (()=>{
if(urlParams.has('cachesize')) return +urlParams.get('cachesize');
return 200;
})();
/** Throws if the given sqlite3 result code is not 0. */
const checkSqliteRc = (dbh,rc)=>{
if(rc) toss("Prepare failed:",sqlite3.capi.sqlite3_errmsg(dbh));
};
const sqlToDrop = [
"SELECT type,name FROM sqlite_schema ",
"WHERE name NOT LIKE 'sqlite\\_%' escape '\\' ",
"AND name NOT LIKE '\\_%' escape '\\'"
].join('');
const clearDbSqlite = function(db){
// This would be SO much easier with the oo1 API, but we specifically want to
// inject metrics we can't get via that API, and we cannot reliably (OPFS)
// open the same DB twice to clear it using that API, so...
const rc = sqlite3.wasm.exports.sqlite3_wasm_db_reset(db.handle);
log("reset db rc =",rc,db.id, db.filename);
};
const App = {
db: undefined,
cache:Object.create(null),
log: log,
warn: warn,
error: error,
metrics: {
fileCount: 0,
runTimeMs: 0,
prepareTimeMs: 0,
stepTimeMs: 0,
stmtCount: 0,
strcpyMs: 0,
sqlBytes: 0
},
fileList: undefined,
execSql: async function(name,sql){
const db = this.db;
const banner = "========================================";
this.log(banner,
"Running",name,'('+sql.length,'bytes)');
const capi = this.sqlite3.capi, wasm = this.sqlite3.wasm;
let pStmt = 0, pSqlBegin;
const metrics = db.metrics = Object.create(null);
metrics.prepTotal = metrics.stepTotal = 0;
metrics.stmtCount = 0;
metrics.malloc = 0;
metrics.strcpy = 0;
if(this.gotErr){
this.error("Cannot run SQL: error cleanup is pending.");
return;
}
// Run this async so that the UI can be updated for the above header...
const endRun = ()=>{
metrics.evalSqlEnd = performance.now();
metrics.evalTimeTotal = (metrics.evalSqlEnd - metrics.evalSqlStart);
this.log("metrics:",JSON.stringify(metrics, undefined, ' '));
this.log("prepare() count:",metrics.stmtCount);
this.log("Time in prepare_v2():",metrics.prepTotal,"ms",
"("+(metrics.prepTotal / metrics.stmtCount),"ms per prepare())");
this.log("Time in step():",metrics.stepTotal,"ms",
"("+(metrics.stepTotal / metrics.stmtCount),"ms per step())");
this.log("Total runtime:",metrics.evalTimeTotal,"ms");
this.log("Overhead (time - prep - step):",
(metrics.evalTimeTotal - metrics.prepTotal - metrics.stepTotal)+"ms");
this.log(banner,"End of",name);
this.metrics.prepareTimeMs += metrics.prepTotal;
this.metrics.stepTimeMs += metrics.stepTotal;
this.metrics.stmtCount += metrics.stmtCount;
this.metrics.strcpyMs += metrics.strcpy;
this.metrics.sqlBytes += sql.length;
};
const runner = function(resolve, reject){
++this.metrics.fileCount;
metrics.evalSqlStart = performance.now();
const stack = wasm.scopedAllocPush();
try {
let t, rc;
let sqlByteLen = sql.byteLength;
const [ppStmt, pzTail] = wasm.scopedAllocPtr(2);
t = performance.now();
pSqlBegin = wasm.scopedAlloc( sqlByteLen + 1/*SQL + NUL*/) || toss("alloc(",sqlByteLen,") failed");
metrics.malloc = performance.now() - t;
metrics.byteLength = sqlByteLen;
let pSql = pSqlBegin;
const pSqlEnd = pSqlBegin + sqlByteLen;
t = performance.now();
wasm.heap8().set(sql, pSql);
wasm.poke(pSql + sqlByteLen, 0);
//log("SQL:",wasm.cstrToJs(pSql));
metrics.strcpy = performance.now() - t;
let breaker = 0;
while(pSql && wasm.peek8(pSql)){
wasm.pokePtr(ppStmt, 0);
wasm.pokePtr(pzTail, 0);
t = performance.now();
rc = capi.sqlite3_prepare_v2(
db.handle, pSql, sqlByteLen, ppStmt, pzTail
);
metrics.prepTotal += performance.now() - t;
checkSqliteRc(db.handle, rc);
pStmt = wasm.peekPtr(ppStmt);
pSql = wasm.peekPtr(pzTail);
sqlByteLen = pSqlEnd - pSql;
if(!pStmt) continue/*empty statement*/;
++metrics.stmtCount;
t = performance.now();
rc = capi.sqlite3_step(pStmt);
capi.sqlite3_finalize(pStmt);
pStmt = 0;
metrics.stepTotal += performance.now() - t;
switch(rc){
case capi.SQLITE_ROW:
case capi.SQLITE_DONE: break;
default: checkSqliteRc(db.handle, rc); toss("Not reached.");
}
}
resolve(this);
}catch(e){
if(pStmt) capi.sqlite3_finalize(pStmt);
this.gotErr = e;
reject(e);
}finally{
capi.sqlite3_exec(db.handle,"rollback;",0,0,0);
wasm.scopedAllocPop(stack);
}
}.bind(this);
const p = new Promise(runner);
return p.catch(
(e)=>this.error("Error via execSql("+name+",...):",e.message)
).finally(()=>{
endRun();
});
},
/**
Loads batch-runner.list and populates the selection list from
it. Returns a promise which resolves to nothing in particular
when it completes. Only intended to be run once at the start
of the app.
*/
loadSqlList: async function(){
const infile = 'batch-runner.list';
this.log("Loading list of SQL files:", infile);
let txt;
try{
const r = await fetch(infile);
if(404 === r.status){
toss("Missing file '"+infile+"'.");
}
if(!r.ok) toss("Loading",infile,"failed:",r.statusText);
txt = await r.text();
}catch(e){
this.error(e.message);
throw e;
}
App.fileList = txt.split(/\n+/).filter(x=>!!x);
this.log("Loaded",infile);
},
/** Fetch ./fn and return its contents as a Uint8Array. */
fetchFile: async function(fn, cacheIt=false){
if(cacheIt && this.cache[fn]) return this.cache[fn];
this.log("Fetching",fn,"...");
let sql;
try {
const r = await fetch(fn);
if(!r.ok) toss("Fetch failed:",r.statusText);
sql = new Uint8Array(await r.arrayBuffer());
}catch(e){
this.error(e.message);
throw e;
}
this.log("Fetched",sql.length,"bytes from",fn);
if(cacheIt) this.cache[fn] = sql;
return sql;
}/*fetchFile()*/,
/**
Converts this.metrics() to a form which is suitable for easy conversion to
CSV. It returns an array of arrays. The first sub-array is the column names.
The 2nd and subsequent are the values, one per test file (only the most recent
metrics are kept for any given file).
*/
metricsToArrays: function(){
const rc = [];
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();
if(!rc.length){
rc.push(['db', ...mk]);
}
const row = [k.split('/').pop()/*remove dir prefix from filename*/];
rc.push(row);
row.push(...mk.map((kk)=>m[kk]));
});
return rc;
},
metricsToBlob: function(colSeparator='\t'){
const ar = [], ma = this.metricsToArrays();
if(!ma.length){
this.error("Metrics are empty. Run something.");
return;
}
ma.forEach(function(row){
ar.push(row.join(colSeparator),'\n');
});
return new Blob(ar);
},
/**
Fetch file fn and eval it as an SQL blob. This is an async
operation and returns a Promise which resolves to this
object on success.
*/
evalFile: async function(fn){
const sql = await this.fetchFile(fn);
return this.execSql(fn,sql);
}/*evalFile()*/,
/**
Fetches the handle of the db associated with
this.e.selImpl.value, opening it if needed.
*/
initDb: function(){
const capi = this.sqlite3.capi, wasm = this.sqlite3.wasm;
const stack = wasm.scopedAllocPush();
let pDb = 0;
const d = Object.create(null);
d.filename = "/batch.db";
try{
const oFlags = capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
const ppDb = wasm.scopedAllocPtr();
const rc = capi.sqlite3_open_v2(d.filename, ppDb, oFlags, this.PoolUtil.vfsName);
pDb = wasm.peekPtr(ppDb)
if(rc) toss("sqlite3_open_v2() failed with code",rc);
capi.sqlite3_exec(pDb, "PRAGMA cache_size="+cacheSize, 0, 0, 0);
this.log("cache_size =",cacheSize);
}catch(e){
if(pDb) capi.sqlite3_close_v2(pDb);
throw e;
}finally{
wasm.scopedAllocPop(stack);
}
d.handle = pDb;
this.log("Opened db:",d.filename,'@',d.handle);
return d;
},
closeDb: function(){
if(this.db.handle){
this.sqlite3.capi.sqlite3_close_v2(this.db.handle);
this.db.handle = undefined;
}
},
run: async function(sqlite3){
delete this.run;
this.sqlite3 = sqlite3;
const capi = sqlite3.capi, wasm = sqlite3.wasm;
this.log("Loaded module:",capi.sqlite3_libversion(), capi.sqlite3_sourceid());
this.log("WASM heap size =",wasm.heap8().length);
let timeStart;
sqlite3.installOpfsSAHPoolVfs({
clearOnInit: true, initialCapacity: 4,
name: 'batch-sahpool',
verbosity: 2
}).then(PoolUtil=>{
App.PoolUtil = PoolUtil;
App.db = App.initDb();
})
.then(async ()=>this.loadSqlList())
.then(async ()=>{
timeStart = performance.now();
for(let i = 0; i < App.fileList.length; ++i){
const fn = App.fileList[i];
await App.evalFile(fn);
if(App.gotErr) throw App.gotErr;
}
})
.then(()=>{
App.metrics.runTimeMs = performance.now() - timeStart;
App.log("total metrics:",JSON.stringify(App.metrics, undefined, ' '));
App.log("Reload the page to run this again.");
App.closeDb();
App.PoolUtil.removeVfs();
})
.catch(e=>this.error("ERROR:",e));
}/*run()*/
}/*App*/;
let sqlite3Js = 'sqlite3.js';
if(urlParams.has('sqlite3.dir')){
sqlite3Js = urlParams.get('sqlite3.dir') + '/' + sqlite3Js;
}
importScripts(sqlite3Js);
globalThis.sqlite3InitModule().then(async function(sqlite3_){
log("Done initializing. Running batch runner...");
sqlite3 = sqlite3_;
App.run(sqlite3_);
});

View File

@@ -1,90 +0,0 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
<link rel="stylesheet" href="common/emscripten.css"/>
<link rel="stylesheet" href="common/testing.css"/>
<title>sqlite3-api batch SQL runner</title>
</head>
<body>
<header id='titlebar'><span>sqlite3-api batch SQL runner</span></header>
<!-- emscripten bits -->
<figure id="module-spinner">
<div class="spinner"></div>
<div class='center'><strong>Initializing app...</strong></div>
<div class='center'>
On a slow internet connection this may take a moment. If this
message displays for "a long time", intialization may have
failed and the JavaScript console may contain clues as to why.
</div>
</figure>
<div class="emscripten" id="module-status">Downloading...</div>
<div class="emscripten">
<progress value="0" max="100" id="module-progress" hidden='1'></progress>
</div><!-- /emscripten bits -->
<p>
This page is for batch-running extracts from the output
of <tt>speedtest1 --script</tt>, as well as other standalone SQL
scripts.
</p>
<p id='warn-list' class='warning'>ACHTUNG: this file requires a generated input list
file. Run "make batch" from this directory to generate it.
</p>
<p id='warn-opfs' class='warning hidden'>WARNING: if the WASMFS/OPFS layer crashes, this page may
become completely unresponsive and need to be closed and reloaded to recover.
</p>
<p id='warn-websql' class='warning hidden'>WARNING: WebSQL's limited API requires that
this app split up SQL batches into separate statements for execution. That will
only work so long as semicolon characters are <em>only</em> used to terminate
SQL statements, and not used within string literals or the like.
</p>
<hr>
<fieldset id='toolbar'>
<div>
<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' 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'>
<input type='checkbox' class='disable-during-eval' id='cb-reverse-log-order' checked></input>
<label for='cb-reverse-log-order'>Reverse log order (newest first)</label>
</span>
<div id='test-output'></div>
<script src="jswasm/sqlite3.js"></script>
<script src="common/SqliteTestUtil.js"></script>
<script src="batch-runner.js"></script>
<style>
.flex-col {
display: flex;
flex-direction: column;
}
#toolbar > div {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
#toolbar > div > * {
margin: 0.25em;
}
</style>
</body>
</html>

View File

@@ -1,604 +0,0 @@
/*
2022-08-29
The author disclaims copyright to this source code. In place of a
legal notice, here is a blessing:
* May you do good and not evil.
* May you find forgiveness for yourself and forgive others.
* May you share freely, never taking more than you give.
***********************************************************************
A basic batch SQL runner for sqlite3-api.js. This file must be run in
main JS thread and sqlite3.js must have been loaded before it.
*/
'use strict';
(function(){
const toss = function(...args){throw new Error(args.join(' '))};
const warn = console.warn.bind(console);
let sqlite3;
const urlParams = new URL(self.location.href).searchParams;
const cacheSize = (()=>{
if(urlParams.has('cachesize')) return +urlParams.get('cachesize');
return 200;
})();
/** Throws if the given sqlite3 result code is not 0. */
const checkSqliteRc = (dbh,rc)=>{
if(rc) toss("Prepare failed:",sqlite3.capi.sqlite3_errmsg(dbh));
};
const sqlToDrop = [
"SELECT type,name FROM sqlite_schema ",
"WHERE name NOT LIKE 'sqlite\\_%' escape '\\' ",
"AND name NOT LIKE '\\_%' escape '\\'"
].join('');
const clearDbWebSQL = function(db){
db.handle.transaction(function(tx){
const onErr = (e)=>console.error(e);
const callback = function(tx, result){
const rows = result.rows;
let i, n;
i = n = rows.length;
while(i--){
const row = rows.item(i);
const name = JSON.stringify(row.name);
const type = row.type;
switch(type){
case 'index': case 'table':
case 'trigger': case 'view': {
const sql2 = 'DROP '+type+' '+name;
tx.executeSql(sql2, [], ()=>{}, onErr);
break;
}
default:
warn("Unhandled db entry type:",type,'name =',name);
break;
}
}
};
tx.executeSql(sqlToDrop, [], callback, onErr);
db.handle.changeVersion(db.handle.version, "", ()=>{}, onErr, ()=>{});
});
};
const clearDbSqlite = function(db){
// This would be SO much easier with the oo1 API, but we specifically want to
// inject metrics we can't get via that API, and we cannot reliably (OPFS)
// open the same DB twice to clear it using that API, so...
const rc = sqlite3.wasm.exports.sqlite3_wasm_db_reset(db.handle);
App.logHtml("reset db rc =",rc,db.id, db.filename);
};
const E = (s)=>document.querySelector(s);
const App = {
e: {
output: E('#test-output'),
selSql: E('#sql-select'),
btnRun: E('#sql-run'),
btnRunNext: E('#sql-run-next'),
btnRunRemaining: E('#sql-run-remaining'),
btnExportMetrics: E('#export-metrics'),
btnClear: E('#output-clear'),
btnReset: E('#db-reset'),
cbReverseLog: E('#cb-reverse-log-order'),
selImpl: E('#select-impl'),
fsToolbar: E('#toolbar')
},
db: Object.create(null),
dbs: Object.create(null),
cache:{},
metrics: {
fileCount: 0,
runTimeMs: 0,
prepareTimeMs: 0,
stepTimeMs: 0,
stmtCount: 0,
strcpyMs: 0,
sqlBytes: 0
},
log: console.log.bind(console),
warn: console.warn.bind(console),
cls: function(){this.e.output.innerHTML = ''},
logHtml2: function(cssClass,...args){
const ln = document.createElement('div');
if(cssClass) ln.classList.add(cssClass);
ln.append(document.createTextNode(args.join(' ')));
this.e.output.append(ln);
//this.e.output.lastElementChild.scrollIntoViewIfNeeded();
},
logHtml: function(...args){
console.log(...args);
if(1) this.logHtml2('', ...args);
},
logErr: function(...args){
console.error(...args);
if(1) this.logHtml2('error', ...args);
},
execSql: async function(name,sql){
const db = this.getSelectedDb();
const banner = "========================================";
this.logHtml(banner,
"Running",name,'('+sql.length,'bytes) using',db.id);
const capi = this.sqlite3.capi, wasm = this.sqlite3.wasm;
let pStmt = 0, pSqlBegin;
const metrics = db.metrics = Object.create(null);
metrics.prepTotal = metrics.stepTotal = 0;
metrics.stmtCount = 0;
metrics.malloc = 0;
metrics.strcpy = 0;
this.blockControls(true);
if(this.gotErr){
this.logErr("Cannot run SQL: error cleanup is pending.");
return;
}
// Run this async so that the UI can be updated for the above header...
const endRun = ()=>{
metrics.evalSqlEnd = performance.now();
metrics.evalTimeTotal = (metrics.evalSqlEnd - metrics.evalSqlStart);
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())");
this.logHtml("Time in step():",metrics.stepTotal,"ms",
"("+(metrics.stepTotal / metrics.stmtCount),"ms per step())");
this.logHtml("Total runtime:",metrics.evalTimeTotal,"ms");
this.logHtml("Overhead (time - prep - step):",
(metrics.evalTimeTotal - metrics.prepTotal - metrics.stepTotal)+"ms");
this.logHtml(banner,"End of",name);
this.metrics.prepareTimeMs += metrics.prepTotal;
this.metrics.stepTimeMs += metrics.stepTotal;
this.metrics.stmtCount += metrics.stmtCount;
this.metrics.strcpyMs += metrics.strcpy;
this.metrics.sqlBytes += sql.length;
};
let runner;
if('websql'===db.id){
const who = this;
runner = function(resolve, reject){
/* 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. 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;
try {
const nextSql = ()=>{
let x = sqls.shift();
while(sqls.length && !x) x = sqls.shift();
return x && x.trim();
};
const who = this;
const transaction = function(tx){
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;
return false;
});
metrics.stepTotal += performance.now() - t;
}
}catch(e){
who.logErr("transaction():",e.message);
throw e;
}
};
const n = sqls.length;
const nextBatch = function(){
if(sqls.length){
console.log("websql sqls.length",sqls.length,'of',n);
db.handle.transaction(transaction, (e)=>{
who.logErr("Ignoring and contiuing:",e.message)
//reject(e);
return false;
}, nextBatch);
}else{
resolve(who);
}
};
metrics.evalSqlStart = performance.now();
nextBatch();
}catch(e){
//this.gotErr = e;
console.error("websql error:",e);
who.logErr(e.message);
//reject(e);
}
}.bind(this);
}else{/*sqlite3 db...*/
runner = function(resolve, reject){
++this.metrics.fileCount;
metrics.evalSqlStart = performance.now();
const stack = wasm.scopedAllocPush();
try {
let t;
let sqlByteLen = sql.byteLength;
const [ppStmt, pzTail] = wasm.scopedAllocPtr(2);
t = performance.now();
pSqlBegin = wasm.scopedAlloc( sqlByteLen + 1/*SQL + NUL*/) || toss("alloc(",sqlByteLen,") failed");
metrics.malloc = performance.now() - t;
metrics.byteLength = sqlByteLen;
let pSql = pSqlBegin;
const pSqlEnd = pSqlBegin + sqlByteLen;
t = performance.now();
wasm.heap8().set(sql, pSql);
wasm.poke(pSql + sqlByteLen, 0);
metrics.strcpy = performance.now() - t;
let breaker = 0;
while(pSql && wasm.peek(pSql,'i8')){
wasm.pokePtr(ppStmt, 0);
wasm.pokePtr(pzTail, 0);
t = performance.now();
let rc = capi.sqlite3_prepare_v3(
db.handle, pSql, sqlByteLen, 0, ppStmt, pzTail
);
metrics.prepTotal += performance.now() - t;
checkSqliteRc(db.handle, rc);
pStmt = wasm.peekPtr(ppStmt);
pSql = wasm.peekPtr(pzTail);
sqlByteLen = pSqlEnd - pSql;
if(!pStmt) continue/*empty statement*/;
++metrics.stmtCount;
t = performance.now();
rc = capi.sqlite3_step(pStmt);
capi.sqlite3_finalize(pStmt);
pStmt = 0;
metrics.stepTotal += performance.now() - t;
switch(rc){
case capi.SQLITE_ROW:
case capi.SQLITE_DONE: break;
default: checkSqliteRc(db.handle, rc); toss("Not reached.");
}
}
resolve(this);
}catch(e){
if(pStmt) capi.sqlite3_finalize(pStmt);
//this.gotErr = e;
reject(e);
}finally{
capi.sqlite3_exec(db.handle,"rollback;",0,0,0);
wasm.scopedAllocPop(stack);
}
}.bind(this);
}
let p;
if(1){
p = new Promise(function(res,rej){
setTimeout(()=>runner(res, rej), 0)/*give UI a chance to output the "running" banner*/;
});
}else{
p = new Promise(runner);
}
return p.catch(
(e)=>this.logErr("Error via execSql("+name+",...):",e.message)
).finally(()=>{
endRun();
this.blockControls(false);
});
},
clearDb: function(){
const db = this.getSelectedDb();
if('websql'===db.id){
this.logErr("TODO: clear websql db.");
return;
}
if(!db.handle) return;
const capi = this.sqlite3, wasm = this.sqlite3.wasm;
//const scope = wasm.scopedAllocPush(
this.logErr("TODO: clear db");
},
/**
Loads batch-runner.list and populates the selection list from
it. Returns a promise which resolves to nothing in particular
when it completes. Only intended to be run once at the start
of the app.
*/
loadSqlList: async function(){
const sel = this.e.selSql;
sel.innerHTML = '';
this.blockControls(true);
const infile = 'batch-runner.list';
this.logHtml("Loading list of SQL files:", infile);
let txt;
try{
const r = await fetch(infile);
if(404 === r.status){
toss("Missing file '"+infile+"'.");
}
if(!r.ok) toss("Loading",infile,"failed:",r.statusText);
txt = await r.text();
const warning = E('#warn-list');
if(warning) warning.remove();
}catch(e){
this.logErr(e.message);
throw e;
}finally{
this.blockControls(false);
}
const list = txt.split(/\n+/);
let opt;
if(0){
opt = document.createElement('option');
opt.innerText = "Select file to evaluate...";
opt.value = '';
opt.disabled = true;
opt.selected = true;
sel.appendChild(opt);
}
list.forEach(function(fn){
if(!fn) return;
opt = document.createElement('option');
opt.value = fn;
opt.innerText = fn.split('/').pop();
sel.appendChild(opt);
});
this.logHtml("Loaded",infile);
},
/** Fetch ./fn and return its contents as a Uint8Array. */
fetchFile: async function(fn, cacheIt=false){
if(cacheIt && this.cache[fn]) return this.cache[fn];
this.logHtml("Fetching",fn,"...");
let sql;
try {
const r = await fetch(fn);
if(!r.ok) toss("Fetch failed:",r.statusText);
sql = new Uint8Array(await r.arrayBuffer());
}catch(e){
this.logErr(e.message);
throw e;
}
this.logHtml("Fetched",sql.length,"bytes from",fn);
if(cacheIt) this.cache[fn] = sql;
return sql;
}/*fetchFile()*/,
/** Disable or enable certain UI controls. */
blockControls: function(disable){
//document.querySelectorAll('.disable-during-eval').forEach((e)=>e.disabled = disable);
this.e.fsToolbar.disabled = disable;
},
/**
Converts this.metrics() to a form which is suitable for easy conversion to
CSV. It returns an array of arrays. The first sub-array is the column names.
The 2nd and subsequent are the values, one per test file (only the most recent
metrics are kept for any given file).
*/
metricsToArrays: function(){
const rc = [];
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();
if(!rc.length){
rc.push(['db', ...mk]);
}
const row = [k.split('/').pop()/*remove dir prefix from filename*/];
rc.push(row);
row.push(...mk.map((kk)=>m[kk]));
});
return rc;
},
metricsToBlob: function(colSeparator='\t'){
const ar = [], ma = this.metricsToArrays();
if(!ma.length){
this.logErr("Metrics are empty. Run something.");
return;
}
ma.forEach(function(row){
ar.push(row.join(colSeparator),'\n');
});
return new Blob(ar);
},
downloadMetrics: function(){
const b = this.metricsToBlob();
if(!b) return;
const url = URL.createObjectURL(b);
const a = document.createElement('a');
a.href = url;
a.download = 'batch-runner-js-'+((new Date().getTime()/1000) | 0)+'.csv';
this.logHtml("Triggering download of",a.download);
document.body.appendChild(a);
a.click();
setTimeout(()=>{
document.body.removeChild(a);
URL.revokeObjectURL(url);
}, 500);
},
/**
Fetch file fn and eval it as an SQL blob. This is an async
operation and returns a Promise which resolves to this
object on success.
*/
evalFile: async function(fn){
const sql = await this.fetchFile(fn);
return this.execSql(fn,sql);
}/*evalFile()*/,
/**
Clears all DB tables in all _opened_ databases. Because of
disparities between backends, we cannot simply "unlink" the
databases to clean them up.
*/
clearStorage: function(onlySelectedDb=false){
const list = onlySelectedDb
? [('boolean'===typeof onlySelectedDb)
? this.dbs[this.e.selImpl.value]
: onlySelectedDb]
: Object.values(this.dbs);
for(let db of list){
if(db && db.handle){
this.logHtml("Clearing db",db.id);
db.clear();
}
}
},
/**
Fetches the handle of the db associated with
this.e.selImpl.value, opening it if needed.
*/
getSelectedDb: function(){
if(!this.dbs.memdb){
for(let opt of this.e.selImpl.options){
const d = this.dbs[opt.value] = Object.create(null);
d.id = opt.value;
switch(d.id){
case 'virtualfs':
d.filename = 'file:/virtualfs.sqlite3?vfs=unix-none';
break;
case 'memdb':
d.filename = ':memory:';
break;
case 'wasmfs-opfs':
d.filename = 'file:'+(
this.sqlite3.capi.sqlite3_wasmfs_opfs_dir()
)+'/wasmfs-opfs.sqlite3b';
break;
case 'websql':
d.filename = 'websql.db';
break;
default:
this.logErr("Unhandled db selection option (see details in the console).",opt);
toss("Unhandled db init option");
}
}
}/*first-time init*/
const dbId = this.e.selImpl.value;
const d = this.dbs[dbId];
if(d.handle) return d;
if('websql' === dbId){
d.handle = self.openDatabase('batch-runner', '0.1', 'foo', 1024 * 1024 * 50);
d.clear = ()=>clearDbWebSQL(d);
d.handle.transaction(function(tx){
tx.executeSql("PRAGMA cache_size="+cacheSize);
App.logHtml(dbId,"cache_size =",cacheSize);
});
}else{
const capi = this.sqlite3.capi, wasm = this.sqlite3.wasm;
const stack = wasm.scopedAllocPush();
let pDb = 0;
try{
const oFlags = capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
const ppDb = wasm.scopedAllocPtr();
const rc = capi.sqlite3_open_v2(d.filename, ppDb, oFlags, null);
pDb = wasm.peekPtr(ppDb)
if(rc) toss("sqlite3_open_v2() failed with code",rc);
capi.sqlite3_exec(pDb, "PRAGMA cache_size="+cacheSize, 0, 0, 0);
this.logHtml(dbId,"cache_size =",cacheSize);
}catch(e){
if(pDb) capi.sqlite3_close_v2(pDb);
}finally{
wasm.scopedAllocPop(stack);
}
d.handle = pDb;
d.clear = ()=>clearDbSqlite(d);
}
d.clear();
this.logHtml("Opened db:",dbId,d.filename);
console.log("db =",d);
return d;
},
run: function(sqlite3){
delete this.run;
this.sqlite3 = sqlite3;
const capi = sqlite3.capi, wasm = sqlite3.wasm;
this.logHtml("Loaded module:",capi.sqlite3_libversion(), capi.sqlite3_sourceid());
this.logHtml("WASM heap size =",wasm.heap8().length);
this.loadSqlList();
if(capi.sqlite3_wasmfs_opfs_dir()){
E('#warn-opfs').classList.remove('hidden');
}else{
E('#warn-opfs').remove();
E('option[value=wasmfs-opfs]').disabled = true;
}
if('function' === typeof self.openDatabase){
E('#warn-websql').classList.remove('hidden');
}else{
E('option[value=websql]').disabled = true;
E('#warn-websql').remove();
}
const who = this;
if(this.e.cbReverseLog.checked){
this.e.output.classList.add('reverse');
}
this.e.cbReverseLog.addEventListener('change', function(){
who.e.output.classList[this.checked ? 'add' : 'remove']('reverse');
}, false);
this.e.btnClear.addEventListener('click', ()=>this.cls(), false);
this.e.btnRun.addEventListener('click', function(){
if(!who.e.selSql.value) return;
who.evalFile(who.e.selSql.value);
}, false);
this.e.btnRunNext.addEventListener('click', function(){
++who.e.selSql.selectedIndex;
if(!who.e.selSql.value) return;
who.evalFile(who.e.selSql.value);
}, false);
this.e.btnReset.addEventListener('click', function(){
who.clearStorage(true);
}, false);
this.e.btnExportMetrics.addEventListener('click', function(){
who.logHtml2('warning',"Triggering download of metrics CSV. Check your downloads folder.");
who.downloadMetrics();
//const m = who.metricsToArrays();
//console.log("Metrics:",who.metrics, m);
});
this.e.selImpl.addEventListener('change', function(){
who.getSelectedDb();
});
this.e.btnRunRemaining.addEventListener('click', async function(){
let v = who.e.selSql.value;
const timeStart = performance.now();
while(v){
await who.evalFile(v);
if(who.gotError){
who.logErr("Error handling script",v,":",who.gotError.message);
break;
}
++who.e.selSql.selectedIndex;
v = who.e.selSql.value;
}
const timeTotal = performance.now() - timeStart;
who.logHtml("Run-remaining time:",timeTotal,"ms ("+(timeTotal/1000/60)+" minute(s))");
who.clearStorage();
App.metrics.runTimeMs = timeTotal;
who.logHtml("Total metrics:",JSON.stringify(App.metrics,undefined,' '));
}, false);
}/*run()*/
}/*App*/;
self.sqlite3TestModule.initSqlite3().then(function(sqlite3_){
sqlite3 = sqlite3_;
self.App = App /* only to facilitate dev console access */;
App.run(sqlite3);
});
})();

View File

@@ -278,6 +278,8 @@ void fatalv(char const *zFmt, va_list va){
vfprintf(stderr, zFmt, va);
}
fputc('\n', stderr);
fflush(stdout);
fflush(stderr);
exit(1);
}
@@ -1417,15 +1419,16 @@ void cmpp_process_keyword(CmppTokenizer * const t){
void cmpp_process_file(const char * zName){
FileWrapper fw = FileWrapper_empty;
CmppTokenizer ct = CmppTokenizer_empty;
FileWrapper_open(&fw, zName, "r");
FileWrapper_slurp(&fw);
g_debug(1,("Read %u byte(s) from [%s]\n", fw.nContent, fw.zName));
ct.zName = zName;
ct.zBegin = fw.zContent;
ct.zEnd = fw.zContent + fw.nContent;
while(cmpp_next_keyword_line(&ct)){
cmpp_process_keyword(&ct);
if( fw.zContent ){
ct.zName = zName;
ct.zBegin = fw.zContent;
ct.zEnd = fw.zContent + fw.nContent;
while(cmpp_next_keyword_line(&ct)){
cmpp_process_keyword(&ct);
}
}
FileWrapper_close(&fw);
if(0!=ct.level.ndx){
@@ -1438,13 +1441,13 @@ void cmpp_process_file(const char * zName){
static void usage(int isErr){
FILE * const fOut = isErr ? stderr : stdout;
fprintf(fOut,
"Usage: %s [flags] [infile]\n"
"Usage: %s [flags] [infile...]\n"
"Flags:\n",
g.zArgv0);
#define arg(F,D) fprintf(fOut," %s\n %s\n",F, D)
arg("-f|--file FILE","Read input from FILE (default=- (stdin)).\n"
" Alternately, the first non-flag argument is assumed to "
"be the input file.");
" Alternately, non-flag arguments are assumed to "
"be the input files.");
arg("-o|--outfile FILE","Send output to FILE (default=- (stdout))");
arg("-DXYZ","Define XYZ to true");
arg("-UXYZ","Undefine XYZ (equivalent to false)");
@@ -1459,13 +1462,16 @@ int main(int argc, char const * const * argv){
int rc = 0;
int i;
int inclCount = 0;
const char * zInfile = 0;
int nFile = 0;
char const *zFileList[128] = {0};
#define M(X) (0==strcmp(X,zArg))
#define ISFLAG(X) else if(M(X))
#define ISFLAG2(X,Y) else if(M(X) || M(Y))
#define ARGVAL \
if(i+1>=argc) fatal("Missing value for flag '%s'", zArg); \
zArg = argv[++i]
memset(zFileList, 0, sizeof(zFileList));
g.zArgv0 = argv[0];
atexit(cmpp_atexit);
cmpp_initdb();
@@ -1497,8 +1503,11 @@ int main(int argc, char const * const * argv){
ISFLAG2("f","file"){
ARGVAL;
do_infile:
if(zInfile) fatal("Cannot use -i more than once.");
zInfile = zArg;
if( nFile>=sizeof(zFileList)/sizeof(zFileList[0]) ){
fatal("Too many file arguments. Max is %d.",
(int)(sizeof(zFileList)/sizeof(zFileList[0])));
}
zFileList[nFile++] = zArg;
}
ISFLAG2("d","delimiter"){
ARGVAL;
@@ -1508,17 +1517,21 @@ int main(int argc, char const * const * argv){
}
ISFLAG("debug"){
++g.doDebug;
}else if(!zInfile && '-'!=argv[i][0]){
}else if('-'!=*zArg){
goto do_infile;
}else{
fatal("Unhandled flag: %s", argv[i]);
}
}
if(!zInfile) zInfile = "-";
if(!nFile){
zFileList[nFile++] = "-";
}
if(!g.out.zName) g.out.zName = "-";
if(!inclCount) db_include_dir_add(".");
FileWrapper_open(&g.out, g.out.zName, "w");
cmpp_process_file(zInfile);
for(i = 0; i < nFile; ++i){
cmpp_process_file(zFileList[i]);
}
FileWrapper_close(&g.out);
end:
return rc ? EXIT_FAILURE : EXIT_SUCCESS;

View File

@@ -1,186 +0,0 @@
#!/do/not/make
#^^^ help emacs select edit mode
#
# Intended to include'd by ./GNUmakefile.
#######################################################################
########################################################################
# shell.c and its build flags...
ifneq (1,$(MAKING_CLEAN))
make-np-0 = make -C $(dir.top) -n -p
make-np-1 = sed -e 's/(TOP)/(dir.top)/g'
# Extract SHELL_OPT and SHELL_DEP from the top-most makefile and import
# them as vars here...
$(eval $(shell $(make-np-0) | grep -e '^SHELL_OPT ' | $(make-np-1)))
$(eval $(shell $(make-np-0) | grep -e '^SHELL_DEP ' | $(make-np-1)))
# ^^^ can't do that in 1 invocation b/c newlines get stripped
ifeq (,$(SHELL_OPT))
$(error Could not parse SHELL_OPT from $(dir.top)/Makefile.)
endif
ifeq (,$(SHELL_DEP))
$(error Could not parse SHELL_DEP from $(dir.top)/Makefile.)
endif
$(dir.top)/shell.c: $(SHELL_DEP) $(dir.tool)/mkshellc.tcl $(sqlite3.c)
$(MAKE) -C $(dir.top) shell.c
endif
# /shell.c
########################################################################
EXPORTED_FUNCTIONS.fiddle = $(dir.tmp)/EXPORTED_FUNCTIONS.fiddle
fiddle.emcc-flags = \
$(emcc.cflags) $(emcc_opt_full) \
--minify 0 \
-sALLOW_TABLE_GROWTH \
-sMEMORY64=$(emcc.MEMORY64) \
-sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.8) \
-sABORTING_MALLOC \
-sSTRICT_JS=0 \
-sENVIRONMENT=web,worker \
-sMODULARIZE \
-sDYNAMIC_EXECUTION=0 \
-sWASM_BIGINT=$(emcc.WASM_BIGINT) \
-sEXPORT_NAME=$(sqlite3.js.init-func) \
-Wno-limited-postlink-optimizations \
$(emcc.exportedRuntimeMethods),FS \
-sEXPORTED_FUNCTIONS=@$(abspath $(EXPORTED_FUNCTIONS.fiddle)) \
$(SQLITE_OPT.full-featured) \
$(SQLITE_OPT.common) \
$(SHELL_OPT) \
-UHAVE_READLINE -UHAVE_EDITLINE -UHAVE_LINENOISE \
-USQLITE_HAVE_ZLIB \
-USQLITE_WASM_BARE_BONES \
-DSQLITE_SHELL_FIDDLE
# Flags specifically for debug builds of fiddle. Performance suffers
# greatly in debug builds.
fiddle.emcc-flags.debug = $(fiddle.emcc-flags) \
-DSQLITE_DEBUG \
-DSQLITE_ENABLE_SELECTTRACE \
-DSQLITE_ENABLE_WHERETRACE
fiddle.EXPORTED_FUNCTIONS.in = \
EXPORTED_FUNCTIONS.fiddle.in \
$(dir.api)/EXPORTED_FUNCTIONS.sqlite3-core \
$(dir.api)/EXPORTED_FUNCTIONS.sqlite3-extras
$(EXPORTED_FUNCTIONS.fiddle): $(MKDIR.bld) $(fiddle.EXPORTED_FUNCTIONS.in) \
$(MAKEFILE.fiddle)
sort -u $(fiddle.EXPORTED_FUNCTIONS.in) > $@
fiddle.cses = $(dir.top)/shell.c $(sqlite3-wasm.c)
clean: clean-fiddle
clean-fiddle:
rm -f $(dir.fiddle)/fiddle-module.js \
$(dir.fiddle)/*.wasm \
$(dir.fiddle)/sqlite3-opfs-*.js \
$(dir.fiddle)/*.gz \
EXPORTED_FUNCTIONS.fiddle
rm -fr $(dir.fiddle-debug)
.PHONY: fiddle fiddle.debug
all: fiddle
########################################################################
# fiddle_remote is the remote destination for the fiddle app. It must
# be a [user@]HOST:/path for rsync. The target "should probably"
# contain a symlink of index.html -> fiddle.html.
fiddle_remote ?=
ifeq (,$(fiddle_remote))
ifneq (,$(wildcard /home/stephan))
fiddle_remote = wh:www/wasm-testing/fiddle/.
else ifneq (,$(wildcard /home/drh))
#fiddle_remote = if appropriate, add that user@host:/path here
endif
endif
push-fiddle: fiddle
@if [ x = "x$(fiddle_remote)" ]; then \
echo "fiddle_remote must be a [user@]HOST:/path for rsync"; \
exit 1; \
fi
rsync -va fiddle/ $(fiddle_remote)
# end fiddle remote push
########################################################################
########################################################################
# Explanation of the emcc build flags follows. Full docs for these can
# be found at:
#
# https://github.com/emscripten-core/emscripten/blob/main/src/settings.js
#
# -sENVIRONMENT=web: elides bootstrap code related to non-web JS
# environments like node.js. Removing this makes the output a tiny
# tick larger but hypothetically makes it more portable to
# non-browser JS environments.
#
# -sMODULARIZE: changes how the generated code is structured to avoid
# declaring a global Module object and instead installing a function
# which loads and initializes the module. The function is named...
#
# -sEXPORT_NAME=jsFunctionName (see -sMODULARIZE)
#
# -sEXPORTED_RUNTIME_METHODS=@/absolute/path/to/file: a file
# containing a list of emscripten-supplied APIs, one per line, which
# must be exported into the generated JS. Must be an absolute path!
#
# -sEXPORTED_FUNCTIONS=@/absolute/path/to/file: a file containing a
# list of C functions, one per line, which must be exported via wasm
# so they're visible to JS. C symbols names in that file must all
# start with an underscore for reasons known only to the emcc
# developers. e.g., _sqlite3_open_v2 and _sqlite3_finalize. Must be
# an absolute path!
#
# -sSTRICT_JS ensures that the emitted JS code includes the 'use
# strict' option. Note that -sSTRICT is more broadly-scoped and
# results in build errors.
#
# -sALLOW_TABLE_GROWTH is required for (at a minimum) the UDF-binding
# feature. Without it, JS functions cannot be made to proxy C-side
# callbacks.
#
# -sABORTING_MALLOC causes the JS-bound _malloc() to abort rather than
# return 0 on OOM. If set to 0 then all code which uses _malloc()
# must, just like in C, check the result before using it, else
# they're likely to corrupt the JS/WASM heap by writing to its
# address of 0. It is, as of this writing, enabled in Emscripten by
# default but we enable it explicitly in case that default changes.
#
# -sDYNAMIC_EXECUTION=0 disables eval() and the Function constructor.
# If the build runs without these, it's preferable to use this flag
# because certain execution environments disallow those constructs.
# This flag is not strictly necessary, however.
#
# --no-entry: for compiling library code with no main(). If this is
# not supplied and the code has a main(), it is called as part of the
# module init process. Note that main() is #if'd out of shell.c
# (renamed) when building in wasm mode.
#
# --pre-js/--post-js=FILE relative or absolute paths to JS files to
# prepend/append to the emcc-generated bootstrapping JS. It's
# easier/faster to develop with separate JS files (reduces rebuilding
# requirements) but certain configurations, namely -sMODULARIZE, may
# require using at least a --pre-js file. They can be used
# individually and need not be paired.
#
# -O0..-O3 and -Oz: optimization levels affect not only C-style
# optimization but whether or not the resulting generated JS code
# gets minified. -O0 compiles _much_ more quickly than -O3 or -Oz,
# and doesn't minimize any JS code, so is recommended for
# development. -O3 or -Oz are recommended for deployment, but
# primarily because -Oz will shrink the wasm file notably. JS-side
# minification makes little difference in terms of overall
# distributable size.
#
# --minify 0: supposedly disables minification of the generated JS
# code, regardless of optimization level, but that's not quite true:
# search the main makefile for wasm-strip for details. Minification
# of the JS has minimal overall effect in the larger scheme of things
# and results in JS files which can neither be edited nor viewed as
# text files in Fossil (which flags them as binary because of their
# extreme line lengths). Interestingly, whether or not the comments
# in the generated JS file get stripped is unaffected by this setting
# and depends entirely on the optimization level. Higher optimization
# levels reduce the size of the JS considerably even without
# minification.
#
########################################################################

View File

@@ -49,20 +49,23 @@
<ul id='test-list'>
<li>Core-most tests
<ul>
<li><a href='tester1.html'>tester1</a>: Core unit and
<li>tester1 (<a href='tester1.html'>32-bit</a>
<a href='tester1-64bit.html'>64-bit</a>): Core unit and
regression tests for the various APIs and surrounding
utility code.</li>
<li><a href='tester1-worker.html'>tester1-worker</a>: same thing
but running in a Worker.</li>
<li><a href='tester1-esm.html'>tester1-esm</a>: same as
<li>tester1-esm (<a href='tester1-esm.html'>32-bit</a>
<a href='tester1-esm-64bit.html'>64-bit</a>): same as
<code>tester1</code> but loads sqlite3 in the main thread via
an ES6 module.
</li>
<li><a href='tester1-worker.html?esm'>tester1-worker?esm</a>:
same as <code>tester1-esm</code> but loads a Worker Module which
then loads the sqlite3 API via an ES6 module. Note that
not all browsers permit loading modules in Worker
threads.
<li>tester1-worker (<a href='tester1-worker.html'>32-bit</a>
<a href='tester1-worker-64bit.html'>64-bit</a>): same thing
but running in a Worker.</li>
<li>tester1-worker ESM (<a href='tester1-worker.html?esm'>32-bit</a>
<a href='tester1-worker-64bit.html?esm'>64-bit</a>): same as
tester1-worker but loads a Worker Module which then
loads the sqlite3 API via an ES6 module. Not all
browsers permit loading modules in Worker threads.
</li>
</ul>
</li>
@@ -123,6 +126,13 @@
demonstrates usage of the OPFS SAHPool VFS's "pause" feature to coordinate
access to a database.
</li>
<li><a href='SQLTester/index.html'>SQLTester</a> is
another testing tool for the library but making use of
it requires tests from an external, proprietary
project. Despite not being useful to the general public,
a link to it is in this list so that its developer has
easy access to it.
</li>
</ul>
</li>
<li><strong>WASMFS</strong>-specific tests which require that

File diff suppressed because it is too large Load Diff

View File

@@ -170,9 +170,10 @@
const urlParams = new URL(self.location.href).searchParams;
const W = new Worker(
"speedtest1-worker.js?sqlite3.dir=jswasm"+
(urlParams.has('opfs-verbose') ? '&opfs-verbose' : '')+
(urlParams.has('opfs-disable') ? '&opfs-disable' : '')
"speedtest1-worker.js?sqlite3.dir=jswasm"+
'&sqlite3.debugModule'+
(urlParams.has('opfs-verbose') ? '&opfs-verbose' : '')+
(urlParams.has('opfs-disable') ? '&opfs-disable' : '')
);
const mPost = function(msgType,payload){
W.postMessage({type: msgType, data: payload});

View File

@@ -4,13 +4,25 @@
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
<link rel="stylesheet" href="../common/emscripten.css"/>
<link rel="stylesheet" href="../common/testing.css"/>
<title>sqlite3 tester #1: Worker thread</title>
<link rel="stylesheet" href="common/emscripten.css"/>
<link rel="stylesheet" href="common/testing.css"/>
<title>sqlite3 tester #1: Worker thread
//#if 64bit
(64-bit WASM)
//#else
(32-bit WASM)
//#endif
</title>
<style></style>
</head>
<body>
<h1 id='color-target'>sqlite3 tester #1: Worker thread</h1>
<h1 id='color-target'>sqlite3 tester #1: Worker thread
//#if 64bit
(64-bit WASM)
//#else
(32-bit WASM)
//#endif
</h1>
<div>Variants:
<a href='tester1.html' target='tester1.html'>conventional UI thread</a>,
<a href='tester1-worker.html' target='tester1-worker.html'>conventional worker</a>,
@@ -35,23 +47,42 @@
logTarget.append(ln);
};
const cbReverse = document.querySelector('#cb-log-reverse');
const cbReverseKey = 'tester1:cb-log-reverse';
const cbReverseIt = ()=>{
logTarget.classList[cbReverse.checked ? 'add' : 'remove']('reverse');
localStorage.setItem(cbReverseKey, cbReverse.checked ? 1 : 0);
};
cbReverse.addEventListener('change',cbReverseIt,true);
if(localStorage.getItem(cbReverseKey)){
cbReverse.checked = !!(+localStorage.getItem(cbReverseKey));
}
cbReverseIt();
const urlParams = new URL(self.location.href).searchParams;
const workerArgs = [];
if(urlParams.has('esm')){
logHtml('warning',"Attempting to run an ES6 Worker Module, "+
"which is not supported by all browsers! "+
"e.g. Firefox (as of 2023-05) cannot do this.");
workerArgs.push("tester1.mjs",{type:"module"});
const baseName =
//#if 64bit
'tester1-64bit'
//#else
'tester1'
//#endif
;
if(urlParams.has('esm')){
logHtml('warning',"Attempting to run an ES6 Worker Module, "+
"which is not supported by all browsers!.");
workerArgs.push(baseName+'.mjs', {type:"module"});
const bitness =
//#if 64bit
64
//#else
32
//#endif
;
document.querySelectorAll('title,#color-target').forEach((e)=>{
e.innerText = "sqlite3 tester #1: ES6 Worker Module";
e.innerText =
"sqlite3 tester #1: ES6 Worker Module ("+bitness+"-bit WASM)";
});
}else{
workerArgs.push("tester1.js?sqlite3.dir=jswasm");
workerArgs.push(baseName+'.js?sqlite3.dir=jswasm');
}
const w = new Worker(...workerArgs);
w.onmessage = function({data}){

View File

@@ -8,9 +8,13 @@
<link rel="stylesheet" href="common/testing.css"/>
<title>sqlite3 tester #1:
//#if target=es6-module
ES6 Module in UI thread
ES6 Module in
//#endif
UI thread
//#if 64bit
(64-bit WASM)
//#else
UI thread
(32-bit WASM)
//#endif
</title>
<style></style>
@@ -32,10 +36,19 @@ UI thread
document.querySelector('title').innerHTML;
})();</script>
//#if target=es6-module
//#if 64bit
<script src="tester1-64bit.mjs" type="module"></script>
//#else
<script src="tester1.mjs" type="module"></script>
//#endif
//#else
//#if 64bit
<script src="jswasm/sqlite3-64bit.js"></script>
<script src="tester1-64bit.js"></script>
//#else
<script src="jswasm/sqlite3.js"></script>
<script src="tester1.js"></script>
//#endif
//#endif target=es6-module
</body>
</html>

View File

@@ -44,7 +44,13 @@
./c-pp -f tester1.c-pp.js -o tester1-esm.mjs -Dtarget=es6-module
*/
//#if target=es6-module
import {default as sqlite3InitModule} from './jswasm/sqlite3.mjs';
import {default as sqlite3InitModule} from
//#if 64bit
'./jswasm/sqlite3-64bit.mjs'
//#else
'./jswasm/sqlite3.mjs'
//#endif
;
globalThis.sqlite3InitModule = sqlite3InitModule;
//#else
'use strict';
@@ -108,16 +114,15 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
logTarget.append(ln);
};
const cbReverse = document.querySelector('#cb-log-reverse');
//cbReverse.setAttribute('checked','checked');
const cbReverseKey = 'tester1:cb-log-reverse';
const cbReverseIt = ()=>{
logTarget.classList[cbReverse.checked ? 'add' : 'remove']('reverse');
//localStorage.setItem(cbReverseKey, cbReverse.checked ? 1 : 0);
localStorage.setItem(cbReverseKey, cbReverse.checked ? 1 : 0);
};
cbReverse.addEventListener('change', cbReverseIt, true);
/*if(localStorage.getItem(cbReverseKey)){
if(localStorage.getItem(cbReverseKey)){
cbReverse.checked = !!(+localStorage.getItem(cbReverseKey));
}*/
}
cbReverseIt();
}else{ /* Worker thread */
console.log("Running in a Worker thread.");
@@ -138,6 +143,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
}else{
postMessage({type:'test-result', payload:{pass}});
}
TestUtil.checkHeapSize(true);
};
const log = (...args)=>{
//console.log(...args);
@@ -298,6 +304,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
logClass(['faded','one-test-summary'],
TestUtil.counter - tc, 'assertion(s) in',
roundMs(then-now),'ms');
TestUtil.checkHeapSize();
}
logClass(['green','group-end'],
"#"+this.number+":",
@@ -348,6 +355,14 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
reportFinalTestStatus(false);
}
}.bind(this));
},
checkHeapSize: function(force=false){
const heapSize = SQLite3.wasm.heap8().byteLength;
if( force || heapSize !== TestUtil.lastHeapSize ){
TestUtil.lastHeapSize = heapSize;
log('WASM heap size:', heapSize,'bytes');
}
}
}/*TestUtil*/;
const T = TestUtil;
@@ -3807,7 +3822,11 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
are simply lost, and such scripts see the globalThis.location of
_this_ script.
*/
//#if 64bit
let sqlite3Js = 'sqlite3-64bit.js';
//#else
let sqlite3Js = 'sqlite3.js';
//#endif
const urlParams = new URL(globalThis.location.href).searchParams;
if(urlParams.has('sqlite3.dir')){
sqlite3Js = urlParams.get('sqlite3.dir') + '/' + sqlite3Js;
@@ -3840,7 +3859,6 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
}else{
logClass('warning',"BigInt/int64 support is disabled.");
}
log("WASM pointer size:",wasm.ptr.size,"bytes");
if(haveWasmCTests()){
log("sqlite3__wasm_test_...() APIs are available.");
}else{
@@ -3848,6 +3866,8 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
}
log("registered vfs list =",capi.sqlite3_js_vfs_list().join(', '));
SQLite3 = sqlite3;
log("WASM pointer size:",wasm.ptr.size,"bytes.");
TestUtil.checkHeapSize();
TestUtil.runTests(sqlite3);
});
})(self);

View File

@@ -97,7 +97,7 @@ $(speedtest1-wasmfs.mjs): $(speedtest1.cfiles) $(sqlite3-wasmfs.js) \
$(emcc.flags.sqlite3-wasmfs) \
$(emcc.flags.speedtest1-wasmfs) \
-o $@ $(speedtest1.cfiles) -lm
@$(call SQLITE.CALL.xJS.ESM-EXPORT-DEFAULT,1,1)
@$(call SQLITE.CALL.xJS.ESM-EXPORT-DEFAULT,1,1,$(logtag.wasmfs))
$(maybe-wasm-strip) $(speedtest1-wasmfs.wasm)
chmod -x $(speedtest1-wasmfs.wasm)
ls -la $@ $(speedtest1-wasmfs.wasm)

View File

@@ -1,5 +1,5 @@
C Fix\sthe\stranslation\sof\s"&#92;v"\sin\sJSON5.\n[forum:/forumpost/28e21085f9c6a4e7|Forum\spost\s28e21085f9].
D 2025-09-25T15:06:57.956
C Overhaul\sthe\swasm\sbuild\sto\s(A)\ssupport\smore\scoexisting\svariants,\se.g.\s32/64-bit\sof\sboth\svanilla\sand\sesm,\sand\s(B)\sbuild\seach\svariant\sto\sits\sown\ssubdir\sso\sthat\sthey\scan\sbuild\sin\sparallel.\sIt\scan,\swith\smake\s-j4,\snow\sbuild\sall\snew\svariants\sin\shalf\sthe\stime\sit\spreviously\stook\sfor\sjust\sthe\s32-bit\sbuilds.\sThe\snew\sbuild\slogging\soutput,\sthough\sunconventional,\sserves\stwo\spurposes:\s(A)\simprove\smy\sbuild-time\ssituational\sawareness\sand\s(B)\sit\shelp\sdemystify\ssome\sof\sthe\sbuild\ssteps\sand\soutput\sfiles.
D 2025-09-25T15:17:58.460
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -578,7 +578,7 @@ F ext/session/sqlite3session.c b3de195ce668cace9b324599bf6255a70290cbfb5451e826e
F ext/session/sqlite3session.h 7404723606074fcb2afdc6b72c206072cdb2b7d8ba097ca1559174a80bc26f7a
F ext/session/test_session.c 8766b5973a6323934cb51248f621c3dc87ad2a98f023c3cc280d79e7d78d36fb
F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c
F ext/wasm/GNUmakefile 39beef47c945a140f93435998f07df70e7f0157e4c198f6197dc3b8236fec7ca
F ext/wasm/GNUmakefile 473695f6c5d9fcfa4099ee1d447b3a965d387e44f213d34ed18f7abce84a7852
F ext/wasm/README-dist.txt f01081a850ce38a56706af6b481e3a7878e24e42b314cfcd4b129f0f8427066a
F ext/wasm/README.md 66ace67ae98a45e4116f2ca5425b716887bcee4d64febee804ff6398e1ae9ec7
F ext/wasm/SQLTester/GNUmakefile e0794f676d55819951bbfae45cc5e8d7818dc460492dc317ce7f0d2eca15caff
@@ -591,12 +591,12 @@ F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-extras cb4fa8842c875b6ee99381523792975
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-see fb29e62082a658f0d81102488414d422c393c4b20cc2f685b216bc566237957b
F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287
F ext/wasm/api/README.md f4c0d67caaee21a77b8938c30b5f79667bfc9d0c95d01b51df77ea35ee773884
F ext/wasm/api/extern-post-js.c-pp.js d3748c6bbdcef15d8e494e0558aad370b9c24242eb020042b3a73b4950562f5b
F ext/wasm/api/extern-post-js.c-pp.js 6bf4407c028fac7d387821420cd25f6d68ad80f7d526e86539b6a3012230917f
F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41
F ext/wasm/api/post-js-footer.js e617e5f81a907362de152576323155f02d24642e625fc05fb801b86b6a269444
F ext/wasm/api/post-js-header.js 79d078aec33d93b640a19c574b504d88bb2446432f38e2fbb3bb8e36da436e70
F ext/wasm/api/pre-js.c-pp.js 664551f490d296e0f4590d3a029787ab0782b9a1fa5954d73bde4fb2c6bfc709
F ext/wasm/api/sqlite3-api-cleanup.js f91a2afdef19c350bce99784fff20310d4d060520001059822aa36c4ce80dc56
F ext/wasm/api/sqlite3-api-cleanup.js e643a96c5323e051e29046bfd6412750917ca2c955e31c9192fb924ecc8ed004
F ext/wasm/api/sqlite3-api-glue.c-pp.js 12f5b36775fab1e7bf5385689fded2b2a9f77360562515e9849acb5e66602e2d
F ext/wasm/api/sqlite3-api-oo1.c-pp.js db4c8ebb03bac60db32ce03f8c615b00f4e4ad53e7d5de5e63d2780cba052caa
F ext/wasm/api/sqlite3-api-prologue.js 259c72c6a33ba1be2297c568cbc2ad53437d1d4b2613d7772c56a3aa00bf435d
@@ -608,13 +608,9 @@ F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js e2c0bd6917b697137035d775ed3300e6
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js f8e762aeb568e0fd050ab991c5f3420dca9c14630386e4e18d42c0624b8ff7cd
F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 9097074724172e31e56ce20ccd7482259cf72a76124213cbc9469d757676da86
F ext/wasm/api/sqlite3-wasm.c ff2dc011e17b06186b8b35e408626d7ace69a362b92c197a34d78bef25c7105a
F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js 4ad256b4ff7f839ad18931ed35d46cced544207bd2209665ec552e193f7f4544
F ext/wasm/api/sqlite3-worker1.c-pp.js 5e8706c2c4af2a57fbcdc02f4e7ef79869971bc21bb8ede777687786ce1c92d5
F ext/wasm/batch-runner-sahpool.html e9a38fdeb36a13eac7b50241dfe7ae066fe3f51f5c0b0151e7baee5fce0d07a7
F ext/wasm/batch-runner-sahpool.js 54a3ac228e6c4703fe72fb65c897e19156263a51fe9b7e21d2834a45e876aabd
F ext/wasm/batch-runner.html 4deeed44fe41496dc6898d9fb17938ea3291f40f4bfb977e29d0cef96fbbe4c8
F ext/wasm/batch-runner.js 05ec254f5dbfe605146d9640b3db17d6ef8c3fbef6aa8396051ca72bb5884e3f
F ext/wasm/c-pp.c 75e23ad9ca3a3771e70d401ba79c0bacdf7b2169d1c17f9e2639d81067e5ab95
F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js 8fb6adfbae6270344f43f2652e63780df3f86521755bde8f92cf6b809ba7891d
F ext/wasm/api/sqlite3-worker1.c-pp.js 69483df1df2d0988e708390f7b1feda769c16e9e9efd4683557f8e7197099cc0
F ext/wasm/c-pp.c 7692739ac435120c37b9de993f152c90e5dbf6a340ca6331de81d7b8b06b5307
F ext/wasm/common/SqliteTestUtil.js 7adaeffef757d8708418dc9190f72df22367b531831775804b31598b44f6aa51
F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15
F ext/wasm/common/testing.css e97549bab24126c24e0daabfe2de9bb478fb0a69fdb2ddd0a73a992c091aad6f
@@ -631,21 +627,20 @@ F ext/wasm/demo-worker1.html 2c178c1890a2beb5a5fecb1453e796d067a4b8d3d2a04d65ca2
F ext/wasm/demo-worker1.js 08720227e98fa5b44761cf6e219269cee3e9dd0421d8d91459535da776950314
F ext/wasm/dist.make 57f5da2f0de5a297b5a0bc39ffec736380050578240ab24d864c2ff1b3634a3b
F ext/wasm/example_extra_init.c 2347cd69d19d839ef4e5e77b7855103a7fe3ef2af86f2e8c95839afd8b05862f
F ext/wasm/fiddle.make 7ed14ba851d331b62ea9ddfcdb62184ff853c5620c3856631310ca0f9633ef93
F ext/wasm/fiddle/fiddle-worker.js 7798af02e672e088ff192716f80626c8895e19301a65b8af6d5d12b2d13d2451
F ext/wasm/fiddle/fiddle.js 84fd75967e0af8b69d3dd849818342227d0f81d13db92e0dcbc63649b31a4893
F ext/wasm/fiddle/index.html a27b8127ef9ecf19612da93b2a6a73bdb3777b5c56b5450bb7200a94bc108ff9
F ext/wasm/index-dist.html 56132399702b15d70c474c3f1952541e25cb0922942868f70daf188f024b3730
F ext/wasm/index.html bcaa00eca521b372a6a62c7e7b17a870b0fcdf3e418a5921df1fd61e5344080d
F ext/wasm/index.html 1b329fb63e057c02a17ce178308d6b06aac62d92af7dd6d821fb0e183e0f1557
F ext/wasm/jaccwabyt/jaccwabyt.js bbac67bc7a79dca34afe6215fd16b27768d84e22273507206f888c117e2ede7d
F ext/wasm/jaccwabyt/jaccwabyt.md 167fc0b624c9bc2c477846e336de9403842d81b1a24fc4d3b24317cb9eba734f
F ext/wasm/mkwasmbuilds.c fc6044341e6cdc8825ffc07db505c92f83cb62cb7c8d271f293f4dc8a8887468
F ext/wasm/mkwasmbuilds.c 3f27681fd3b32a78560feb3bb54f0f46a68f75024f65d9c5d4247f6bd08a04ad
F ext/wasm/module-symbols.html dc476b403369b26a1a23773e13b80f41b9a49f0825e81435fe3600a7cfbbe337
F ext/wasm/scratchpad-wasmfs.html a3d7388f3c4b263676b58b526846e9d02dfcb4014ff29d3a5040935286af5b96
F ext/wasm/scratchpad-wasmfs.mjs 66034b9256b218de59248aad796760a1584c1dd842231505895eff00dbd57c63
F ext/wasm/speedtest1-wasmfs.html 0e9d335a9b5b5fafe6e1bc8dc0f0ca7e22e6eb916682a2d7c36218bb7d67379d
F ext/wasm/speedtest1-wasmfs.mjs c77c7231338ed5c0e1ce16aa29106df8e5b5cf11a48319c49433490a8d3ded30
F ext/wasm/speedtest1-worker.html d24d1e06caf3dcd83430c8c3d87761ff7555fd06eaeaf2fc02ce49cf45f0d032
F ext/wasm/speedtest1-worker.html 068d4190f304fa1c34e6501a1b3a4c32fe8d8dac93c2d0f53d667a1cb386eedc
F ext/wasm/speedtest1-worker.js 5b7eba7cdb5239768e1ed61edb046df8e0092e6c9d6e0bc76e51536022bdccb9
F ext/wasm/speedtest1.html e2a0e0bd12243ca34b11235bf9f3c229f4574ea1125f2ecf2bf0589853d6f9c8
F ext/wasm/split-speedtest1-script.sh a3e271938d4d14ee49105eb05567c6a69ba4c1f1293583ad5af0cd3a3779e205 x
@@ -653,9 +648,9 @@ F ext/wasm/sql/000-mandelbrot.sql 775337a4b80938ac8146aedf88808282f04d02d983d826
F ext/wasm/sql/001-sudoku.sql 35b7cb7239ba5d5f193bc05ec379bcf66891bce6f2a5b3879f2f78d0917299b5
F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555e685bce3da8c3f
F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f809baaaca1a00c
F ext/wasm/tester1-worker.html ebc4b820a128963afce328ecf63ab200bd923309eb939f4110510ab449e9814c
F ext/wasm/tester1.c-pp.html 1c1bc78b858af2019e663b1a31e76657b73dc24bede28ca92fbe917c3a972af2
F ext/wasm/tester1.c-pp.js a2bc1a96dbe55e3b14ace35e8561893e84221d63794a9bc2ab5a5f1b1d6bc5a1
F ext/wasm/tester1-worker.c-pp.html b240b59cd313427434190d5795f57986b9add1a08df53921311fc0b8221b672a w ext/wasm/tester1-worker.html
F ext/wasm/tester1.c-pp.html 93fbedb6b15eaad9b03df0524c702a81896e358785655ae2c751e30ef8202e54
F ext/wasm/tester1.c-pp.js 2b2aea6d9938fcfad0e3fd8ae094bced45212b807812b60a0dbe970f7f143f82
F ext/wasm/tests/opfs/concurrency/index.html 657578a6e9ce1e9b8be951549ed93a6a471f4520a99e5b545928668f4285fb5e
F ext/wasm/tests/opfs/concurrency/test.js d08889a5bb6e61937d0b8cbb78c9efbefbf65ad09f510589c779b7cc6a803a88
F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2
@@ -664,7 +659,7 @@ F ext/wasm/tests/opfs/sahpool/digest.html 206d08a34dc8bd570b2581d3d9ab3ecad3201b
F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca01385e2732294b53f4c842328
F ext/wasm/tests/opfs/sahpool/sahpool-pausing.js f264925cfc82155de38cecb3d204c36e0f6991460fff0cb7c15079454679a4e2
F ext/wasm/tests/opfs/sahpool/sahpool-worker.js bd25a43fc2ab2d1bafd8f2854ad3943ef673f7c3be03e95ecf1612ff6e8e2a61
F ext/wasm/wasmfs.make 411dd94b40406572caddf88392a1ccc4deed0f88d260516e59ca6e0c887ee861
F ext/wasm/wasmfs.make 5de02751b3e9e79b81a52ab4fe0ed6aa6a23311a90db58fea98c1c4e2845e562
F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0
F main.mk fd45a3578989f38bbeb2564a63883f6f6c077105c9f1361c3eac411d31f3afbd
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
@@ -1650,7 +1645,7 @@ F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
F test/speed4p.test 377a0c48e5a92e0b11c1c5ebb1bc9d83a7312c922bc0cb05970ef5d6a96d1f0c
F test/speedtest.md ee958457ae1b729d9715ae33c0320600000bf1d9ddea1a88dcf79f56729d6fad
F test/speedtest.tcl 405411356fbc54af15987b7ffeec330a49138f71584220fb8fe1948b2f7ac907 x
F test/speedtest1.c a9b002a7bfed99ba3166c2a9b8ae45a95b4c2d37f891e1637c022f9e1d15e3f9
F test/speedtest1.c 6c01252e66f46de0b6b8d5316e03521e2151782104f3608c10262aa5dce85721
F test/spellfix.test 951a6405d49d1a23d6b78027d3877b4a33eeb8221dcab5704b499755bb4f552e
F test/spellfix2.test dfc8f519a3fc204cb2dfa8b4f29821ae90f6f8c3
F test/spellfix3.test 0f9efaaa502a0e0a09848028518a6fb096c8ad33
@@ -2175,8 +2170,9 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 4a1bb874f12adda26e91970b64e700cb904c126412989be4debac9a5647d6f69
R 16252f4eed24f0ab043779bc0feb3096
U drh
Z 2a05a8a00bda16fec363a8f421bf356f
P 2914e8fc7b10e8b42c9a0fbd0e71f495714cee3cae67b8c238d37b1e7ec22359 75079401753778e3bc2f7fa307de9217e8d1ec395079fc1009060f707be32943
R bf2a14e22103418be159da49f21a135f
T +closed 75079401753778e3bc2f7fa307de9217e8d1ec395079fc1009060f707be32943 Closed\sby\sintegrate-merge.
U stephan
Z c8ddfc47b782e73f61a2d31043443056
# Remove this line to create a well-formed Fossil manifest.

View File

@@ -1 +1 @@
2914e8fc7b10e8b42c9a0fbd0e71f495714cee3cae67b8c238d37b1e7ec22359
2f4be98614b49def2c2951887796c736269ef3bb7ba5b045cae5f748ae165a83

View File

@@ -572,9 +572,8 @@ char *speedtest1_once(const char *zFormat, ...){
}
rc = sqlite3_reset(pStmt);
if( rc!=SQLITE_OK ){
fprintf(stderr, "%s\nError code %d: %s\n",
sqlite3_sql(pStmt), rc, sqlite3_errmsg(g.db));
exit(1);
fatal_error("%s\nError code %d: %s\n",
sqlite3_sql(pStmt), rc, sqlite3_errmsg(g.db));
}
sqlite3_finalize(pStmt);
}
@@ -666,9 +665,8 @@ void speedtest1_run(void){
sqlite3_prepare_v2(g.db, sqlite3_sql(g.pStmt), -1, &pNew, 0);
rc = sqlite3_finalize(g.pStmt);
if( rc!=SQLITE_OK ){
fprintf(stderr, "%s\nError code %d: %s\n",
sqlite3_sql(pNew), rc, sqlite3_errmsg(g.db));
exit(1);
fatal_error("%s\nError code %d: %s\n",
sqlite3_sql(pNew), rc, sqlite3_errmsg(g.db));
}
g.pStmt = pNew;
}else
@@ -676,9 +674,8 @@ void speedtest1_run(void){
{
rc = sqlite3_reset(g.pStmt);
if( rc!=SQLITE_OK ){
fprintf(stderr, "%s\nError code %d: %s\n",
sqlite3_sql(g.pStmt), rc, sqlite3_errmsg(g.db));
exit(1);
fatal_error("%s\nError code %d: %s\n",
sqlite3_sql(g.pStmt), rc, sqlite3_errmsg(g.db));
}
}
speedtest1_shrink_memory();
@@ -2152,7 +2149,7 @@ void testset_rtree(int p1, int p2){
}
speedtest1_end_test();
}
n = g.szTest*200;
speedtest1_begin_test(120, "%d one-dimensional overlap slice queries", n);
speedtest1_prepare("SELECT count(*) FROM rt1 WHERE y1>=?1 AND y0<=?2");
@@ -2181,7 +2178,6 @@ void testset_rtree(int p1, int p2){
}
speedtest1_end_test();
}
n = g.szTest*200;
speedtest1_begin_test(125, "%d custom geometry callback queries", n);