aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/misc/vtablog.c7
-rw-r--r--ext/wasm/GNUmakefile6
-rw-r--r--ext/wasm/api/sqlite3-api-oo1.c-pp.js329
-rw-r--r--ext/wasm/api/sqlite3-api-prologue.js17
-rw-r--r--ext/wasm/tester1.c-pp.js106
-rw-r--r--manifest30
-rw-r--r--manifest.uuid2
-rw-r--r--src/vdbeInt.h2
-rw-r--r--test/speedtest1.c14
-rwxr-xr-xtest/testrunner.tcl112
-rw-r--r--test/testrunner_estwork.tcl488
11 files changed, 974 insertions, 139 deletions
diff --git a/ext/misc/vtablog.c b/ext/misc/vtablog.c
index e8e29a86e..44acc32e6 100644
--- a/ext/misc/vtablog.c
+++ b/ext/misc/vtablog.c
@@ -14,6 +14,13 @@
** on stdout when its key interfaces are called. This is intended for
** interactive analysis and debugging of virtual table interfaces.
**
+** To build this extension as a separately loaded shared library or
+** DLL, use compiler command-lines similar to the following:
+**
+** (linux) gcc -fPIC -shared vtablog.c -o vtablog.so
+** (mac) clang -fPIC -dynamiclib vtablog.c -o vtablog.dylib
+** (windows) cl vtablog.c -link -dll -out:vtablog.dll
+**
** Usage example:
**
** .load ./vtablog
diff --git a/ext/wasm/GNUmakefile b/ext/wasm/GNUmakefile
index bf1a49111..51a6bf965 100644
--- a/ext/wasm/GNUmakefile
+++ b/ext/wasm/GNUmakefile
@@ -429,7 +429,7 @@ define SQLITE.CALL.C-PP.FILTER
$(2): $(1) $$(MAKEFILE_LIST) $$(bin.c-pp)
@mkdir -p $$(dir $$@)
$$(bin.c-pp) -f $(1) -o $$@ $(3) $(SQLITE.CALL.C-PP.FILTER.global)
-#CLEAN_FILES += $(2)
+CLEAN_FILES += $(2)
endef
# /end SQLITE.CALL.C-PP.FILTER
########################################################################
@@ -617,9 +617,9 @@ emcc.jsflags += -sDYNAMIC_EXECUTION=0
emcc.jsflags += -sNO_POLYFILL
emcc.jsflags += -sEXPORTED_FUNCTIONS=@$(EXPORTED_FUNCTIONS.api)
emcc.exportedRuntimeMethods := \
- -sEXPORTED_RUNTIME_METHODS=wasmMemory,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAP64,HEAPU64
+ -sEXPORTED_RUNTIME_METHODS=wasmMemory
# wasmMemory ==> required by our code for use with -sIMPORTED_MEMORY
-# Emscripten 4.0.7 (2025-04-15) stops exporting HEAP* by default
+# Emscripten 4.0.7 (2025-04-15) stops exporting HEAP* by default.
emcc.jsflags += $(emcc.exportedRuntimeMethods)
emcc.jsflags += -sUSE_CLOSURE_COMPILER=0
emcc.jsflags += -sIMPORTED_MEMORY
diff --git a/ext/wasm/api/sqlite3-api-oo1.c-pp.js b/ext/wasm/api/sqlite3-api-oo1.c-pp.js
index 06f916002..62c44fa9d 100644
--- a/ext/wasm/api/sqlite3-api-oo1.c-pp.js
+++ b/ext/wasm/api/sqlite3-api-oo1.c-pp.js
@@ -38,6 +38,21 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
*/
const __ptrMap = new WeakMap();
/**
+ A Set of oo1.DB or oo1.Stmt objects which are proxies for
+ (sqlite3*) resp. (sqlite3_stmt*) pointers which themselves are
+ owned elsewhere. Objects in this Set do not own their underlying
+ handle and that handle must be guaranteed (by the client) to
+ outlive the proxy. DB.close()/Stmt.finalize() methods will remove
+ the object from this Set _instead_ of closing/finalizing the
+ pointer. These proxies are primarily intended as a way to briefly
+ wrap an (sqlite3[_stmt]*) object as an oo1.DB/Stmt without taking
+ over ownership, to take advantage of simplifies usage compared to
+ the C API while not imposing any change of ownership.
+
+ See DB.wrapHandle() and Stmt.wrapHandle().
+ */
+ const __doesNotOwnHandle = new Set();
+ /**
Map of DB instances to objects, each object being a map of Stmt
wasm pointers to Stmt objects.
*/
@@ -234,73 +249,89 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
};
}
const opt = ctor.normalizeArgs(...args);
- let fn = opt.filename, vfsName = opt.vfs, flagsStr = opt.flags;
- if(('string'!==typeof fn && 'number'!==typeof fn)
- || 'string'!==typeof flagsStr
- || (vfsName && ('string'!==typeof vfsName && 'number'!==typeof vfsName))){
- sqlite3.config.error("Invalid DB ctor args",opt,arguments);
- toss3("Invalid arguments for DB constructor.");
- }
- let fnJs = ('number'===typeof fn) ? wasm.cstrToJs(fn) : fn;
- const vfsCheck = ctor._name2vfs[fnJs];
- if(vfsCheck){
- vfsName = vfsCheck.vfs;
- fn = fnJs = vfsCheck.filename(fnJs);
- }
- let pDb, oflags = 0;
- if( flagsStr.indexOf('c')>=0 ){
- oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
- }
- if( flagsStr.indexOf('w')>=0 ) oflags |= capi.SQLITE_OPEN_READWRITE;
- if( 0===oflags ) oflags |= capi.SQLITE_OPEN_READONLY;
- oflags |= capi.SQLITE_OPEN_EXRESCODE;
- const stack = wasm.pstack.pointer;
- try {
- const pPtr = wasm.pstack.allocPtr() /* output (sqlite3**) arg */;
- let rc = capi.sqlite3_open_v2(fn, pPtr, oflags, vfsName || 0);
- pDb = wasm.peekPtr(pPtr);
- checkSqlite3Rc(pDb, rc);
- capi.sqlite3_extended_result_codes(pDb, 1);
- if(flagsStr.indexOf('t')>=0){
- capi.sqlite3_trace_v2(pDb, capi.SQLITE_TRACE_STMT,
- __dbTraceToConsole, pDb);
+ //sqlite3.config.debug("DB ctor",opt);
+ let pDb;
+ if( (pDb = opt['sqlite3*']) ){
+ /* This property ^^^^^ is very specifically NOT DOCUMENTED and
+ NOT part of the public API. This is a back door for functions
+ like DB.wrapDbHandle(). */
+ //sqlite3.config.debug("creating proxy db from",opt);
+ if( !opt['sqlite3*:takeOwnership'] ){
+ /* This is object does not own its handle. */
+ __doesNotOwnHandle.add(this);
}
- }catch( e ){
- if( pDb ) capi.sqlite3_close_v2(pDb);
- throw e;
- }finally{
- wasm.pstack.restore(stack);
+ this.filename = capi.sqlite3_db_filename(pDb,'main');
+ }else{
+ let fn = opt.filename, vfsName = opt.vfs, flagsStr = opt.flags;
+ if(('string'!==typeof fn && 'number'!==typeof fn)
+ || 'string'!==typeof flagsStr
+ || (vfsName && ('string'!==typeof vfsName && 'number'!==typeof vfsName))){
+ sqlite3.config.error("Invalid DB ctor args",opt,arguments);
+ toss3("Invalid arguments for DB constructor.");
+ }
+ let fnJs = ('number'===typeof fn) ? wasm.cstrToJs(fn) : fn;
+ const vfsCheck = ctor._name2vfs[fnJs];
+ if(vfsCheck){
+ vfsName = vfsCheck.vfs;
+ fn = fnJs = vfsCheck.filename(fnJs);
+ }
+ let oflags = 0;
+ if( flagsStr.indexOf('c')>=0 ){
+ oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
+ }
+ if( flagsStr.indexOf('w')>=0 ) oflags |= capi.SQLITE_OPEN_READWRITE;
+ if( 0===oflags ) oflags |= capi.SQLITE_OPEN_READONLY;
+ oflags |= capi.SQLITE_OPEN_EXRESCODE;
+ const stack = wasm.pstack.pointer;
+ try {
+ const pPtr = wasm.pstack.allocPtr() /* output (sqlite3**) arg */;
+ let rc = capi.sqlite3_open_v2(fn, pPtr, oflags, vfsName || 0);
+ pDb = wasm.peekPtr(pPtr);
+ checkSqlite3Rc(pDb, rc);
+ capi.sqlite3_extended_result_codes(pDb, 1);
+ if(flagsStr.indexOf('t')>=0){
+ capi.sqlite3_trace_v2(pDb, capi.SQLITE_TRACE_STMT,
+ __dbTraceToConsole, pDb);
+ }
+ }catch( e ){
+ if( pDb ) capi.sqlite3_close_v2(pDb);
+ throw e;
+ }finally{
+ wasm.pstack.restore(stack);
+ }
+ this.filename = fnJs;
}
- this.filename = fnJs;
__ptrMap.set(this, pDb);
__stmtMap.set(this, Object.create(null));
- try{
+ if( !opt['sqlite3*'] ){
+ try{
//#if enable-see
- dbCtorApplySEEKey(this,opt);
+ dbCtorApplySEEKey(this,opt);
//#endif
- // Check for per-VFS post-open SQL/callback...
- const pVfs = capi.sqlite3_js_db_vfs(pDb)
- || toss3("Internal error: cannot get VFS for new db handle.");
- const postInitSql = __vfsPostOpenCallback[pVfs];
- if(postInitSql){
- /**
- Reminder: if this db is encrypted and the client did _not_ pass
- in the key, any init code will fail, causing the ctor to throw.
- We don't actually know whether the db is encrypted, so we cannot
- sensibly apply any heuristics which skip the init code only for
- encrypted databases for which no key has yet been supplied.
- */
- if(postInitSql instanceof Function){
- postInitSql(this, sqlite3);
- }else{
- checkSqlite3Rc(
- pDb, capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0)
- );
+ // Check for per-VFS post-open SQL/callback...
+ const pVfs = capi.sqlite3_js_db_vfs(pDb)
+ || toss3("Internal error: cannot get VFS for new db handle.");
+ const postInitSql = __vfsPostOpenCallback[pVfs];
+ if(postInitSql){
+ /**
+ Reminder: if this db is encrypted and the client did _not_ pass
+ in the key, any init code will fail, causing the ctor to throw.
+ We don't actually know whether the db is encrypted, so we cannot
+ sensibly apply any heuristics which skip the init code only for
+ encrypted databases for which no key has yet been supplied.
+ */
+ if(postInitSql instanceof Function){
+ postInitSql(this, sqlite3);
+ }else{
+ checkSqlite3Rc(
+ pDb, capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0)
+ );
+ }
}
+ }catch(e){
+ this.close();
+ throw e;
}
- }catch(e){
- this.close();
- throw e;
}
};
@@ -403,7 +434,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
- `vfs`: the VFS fname
//#if enable-see
-
SEE-capable builds optionally support ONE of the following
additional options:
@@ -429,7 +459,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
is supplied and the database is encrypted, execution of the
post-initialization SQL will fail, causing the constructor to
throw.
-
//#endif enable-see
The `filename` and `vfs` arguments may be either JS strings or
@@ -457,8 +486,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
/**
Internal-use enum for mapping JS types to DB-bindable types.
These do not (and need not) line up with the SQLITE_type
- values. All values in this enum must be truthy and distinct
- but they need not be numbers.
+ values. All values in this enum must be truthy and (mostly)
+ distinct but they need not be numbers.
*/
const BindTypes = {
null: 1,
@@ -467,7 +496,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
boolean: 4,
blob: 5
};
- BindTypes['undefined'] == BindTypes.null;
if(wasm.bigIntEnabled){
BindTypes.bigint = BindTypes.number;
}
@@ -486,26 +514,30 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
- `db`: the DB object which created the statement.
- `columnCount`: the number of result columns in the query, or 0
- for queries which cannot return results. This property is a proxy
- for sqlite3_column_count() and its use in loops should be avoided
- because of the call overhead associated with that. The
- `columnCount` is not cached when the Stmt is created because a
- schema change made via a separate db connection between this
- statement's preparation and when it is stepped may invalidate it.
+ for queries which cannot return results. This property is a
+ read-only proxy for sqlite3_column_count() and its use in loops
+ should be avoided because of the call overhead associated with
+ that. The `columnCount` is not cached when the Stmt is created
+ because a schema change made between this statement's preparation
+ and when it is stepped may invalidate it.
- - `parameterCount`: the number of bindable parameters in the query.
+ - `parameterCount`: the number of bindable parameters in the
+ query. Like `columnCount`, this property is ready-only and is a
+ proxy for a C API call.
As a general rule, most methods of this class will throw if
called on an instance which has been finalized. For brevity's
sake, the method docs do not all repeat this warning.
*/
- const Stmt = function(){
+ const Stmt = function(/*oo1db, stmtPtr, BindTypes [,takeOwnership=true] */){
if(BindTypes!==arguments[2]){
toss3(capi.SQLITE_MISUSE, "Do not call the Stmt constructor directly. Use DB.prepare().");
}
this.db = arguments[0];
__ptrMap.set(this, arguments[1]);
- this.parameterCount = capi.sqlite3_bind_parameter_count(this.pointer);
+ if( arguments.length>3 && !arguments[3] ){
+ __doesNotOwnHandle.add(this);
+ }
};
/** Throws if the given DB has been closed, else it is returned. */
@@ -698,10 +730,10 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
},
/**
Finalizes all open statements and closes this database
- connection. This is a no-op if the db has already been
- closed. After calling close(), `this.pointer` will resolve to
- `undefined`, so that can be used to check whether the db
- instance is still opened.
+ connection (with one exception noted below). This is a no-op if
+ the db has already been closed. After calling close(),
+ `this.pointer` will resolve to `undefined`, and that can be
+ used to check whether the db instance is still opened.
If this.onclose.before is a function then it is called before
any close-related cleanup.
@@ -721,14 +753,19 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
all, will never trigger close(), so onclose handlers are not a
reliable way to implement close-time cleanup or maintenance of
a db.
+
+ If this instance was created using DB.wrapHandle() and does not
+ own this.pointer then it does not close the db handle but it
+ does perform all other work, such as calling onclose callbacks
+ and disassociating this object from this.pointer.
*/
close: function(){
- if(this.pointer){
+ const pDb = this.pointer;
+ if(pDb){
if(this.onclose && (this.onclose.before instanceof Function)){
try{this.onclose.before(this)}
catch(e){/*ignore*/}
}
- const pDb = this.pointer;
Object.keys(__stmtMap.get(this)).forEach((k,s)=>{
if(s && s.pointer){
try{s.finalize()}
@@ -737,7 +774,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
});
__ptrMap.delete(this);
__stmtMap.delete(this);
- capi.sqlite3_close_v2(pDb);
+ if( !__doesNotOwnHandle.delete(this) ){
+ capi.sqlite3_close_v2(pDb);
+ }
if(this.onclose && (this.onclose.after instanceof Function)){
try{this.onclose.after(this)}
catch(e){/*ignore*/}
@@ -1450,9 +1489,63 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
*/
checkRc: function(resultCode){
return checkSqlite3Rc(this, resultCode);
- }
+ },
}/*DB.prototype*/;
+ /**
+ Returns a new oo1.DB instance which wraps the given (sqlite3*)
+ WASM pointer, optionally with or without taking over ownership of
+ that pointer.
+
+ The first argument must be either a non-NULL (sqlite3*) WASM
+ pointer.
+
+ The second argument, defaulting to false, specifies ownership of
+ the first argument. If it is truthy, the returned object will
+ pass that pointer to sqlite3_close() when its close() method is
+ called, otherwise it will not.
+
+ Throws if pDb is not a non-0 WASM pointer.
+
+ The caller MUST GUARANTEE that the passed-in handle will outlive
+ the returned object, i.e. that it will not be closed. If it is closed,
+ this object will hold a stale pointer and results are undefined.
+
+ Aside from its lifetime, the proxy is to be treated as any other
+ DB instance, including the requirement of calling close() on
+ it. close() will free up internal resources owned by the proxy
+ and disassociate the proxy from that handle but will not
+ actually close the proxied db handle unless this function is
+ passed a thruthy second argument.
+
+ To stress:
+
+ - DO NOT call sqlite3_close() (or similar) on the being-proxied
+ pointer while a proxy is active.
+
+ - ALWAYS eventually call close() on the returned object. If the
+ proxy does not own the underlying handle then its MUST be
+ closed BEFORE the being-proxied handle is closed.
+
+ Design notes:
+
+ - wrapHandle() "could" accept a DB object instance as its first
+ argument and proxy thatDb.pointer but there is currently no use
+ case where doing so would be useful, so it does not allow
+ that. That restriction may be lifted in a future version.
+ */
+ DB.wrapHandle = function(pDb, takeOwnership=false){
+ if( !pDb || !wasm.isPtr(pDb) ){
+ throw new sqlite3.SQLite3Error(capi.SQLITE_MISUSE,
+ "Argument must be a WASM sqlite3 pointer");
+ }
+ return new DB({
+ /* This ctor call style is very specifically internal-use-only.
+ It is not documented and may change at any time. */
+ "sqlite3*": pDb,
+ "sqlite3*:takeOwnership": !!takeOwnership
+ });
+ };
/** Throws if the given Stmt has been finalized, else stmt is
returned. */
@@ -1474,8 +1567,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
case BindTypes.string:
return t;
case BindTypes.bigint:
- if(wasm.bigIntEnabled) return t;
- /* else fall through */
+ return wasm.bigIntEnabled ? t : undefined;
default:
return util.isBindableTypedArray(v) ? BindTypes.blob : undefined;
}
@@ -1641,12 +1733,19 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
This method always throws if called when it is illegal to do
so. Namely, when triggered via a per-row callback handler of a
DB.exec() call.
+
+ If Stmt does not own its underlying (sqlite3_stmt*) (see
+ Stmt.wrapHandle()) then this function will not pass it to
+ sqlite3_finalize().
*/
finalize: function(){
- if(this.pointer){
+ const ptr = this.pointer;
+ if(ptr){
affirmNotLockedByExec(this,'finalize()');
- const rc = capi.sqlite3_finalize(this.pointer);
- delete __stmtMap.get(this.db)[this.pointer];
+ const rc = (__doesNotOwnHandle.delete(this)
+ ? 0
+ : capi.sqlite3_finalize(ptr));
+ delete __stmtMap.get(this.db)[ptr];
__ptrMap.delete(this);
__execLock.delete(this);
__stmtMayGet.delete(this);
@@ -2134,6 +2233,64 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
set: ()=>toss3("The columnCount property is read-only.")
});
+ Object.defineProperty(Stmt.prototype, 'parameterCount', {
+ enumerable: false,
+ get: function(){return capi.sqlite3_bind_parameter_count(this.pointer)},
+ set: ()=>toss3("The parameterCount property is read-only.")
+ });
+
+ /**
+ The Stmt counterpart of oo1.DB.wrapHandle(), this creates a Stmt
+ instance which wraps a WASM (sqlite3_stmt*) in the oo1 API,
+ optionally with or without taking over ownership of that pointer.
+
+ The first argument must be an oo1.DB instance[^1].
+
+ The second argument must be a valid WASM (sqlite3_stmt*), as
+ produced by sqlite3_prepare_v2() and sqlite3_prepare_v3().
+
+ The third argument, defaulting to false, specifies whether the
+ returned Stmt object takes over ownership of the underlying
+ (sqlite3_stmt*). If true, the returned object's finalize() method
+ will finalize that handle, else it will not. If it is false,
+ ownership of pStmt is unchanged and pStmt MUST outlive the
+ returned object or results are undefined.
+
+ This function throws if the arguments are invalid. On success it
+ returns a new Stmt object which wraps the given statement
+ pointer.
+
+ Like all Stmt objects, the finalize() method must eventually be
+ called on the returned object to free up internal resources,
+ regardless of whether this function's third argument is true or
+ not.
+
+ [^1]: The first argument cannot be a (sqlite3*) because the
+ resulting Stmt object requires a parent DB object. It is not yet
+ determined whether it would be of general benefit to refactor the
+ DB/Stmt pair internals to communicate in terms of the underlying
+ (sqlite3*) rather than a DB object. If so, we could laxen the
+ first argument's requirement and allow an (sqlite3*). Because
+ DB.wrapHandle() enables multiple DB objects to proxy the same
+ (sqlite3*), we cannot unambiguously translate the first arugment
+ from (sqlite3*) to DB instances for us with this function's first
+ argument.
+ */
+ Stmt.wrapHandle = function(oo1db, pStmt, takeOwnership=false){
+ let ctor = Stmt;
+ if( !(oo1db instanceof DB) || !oo1db.pointer ){
+ throw new sqlite3.SQLite3Error(sqlite3.SQLITE_MISUSE,
+ "First argument must be an opened "+
+ "sqlite3.oo1.DB instance");
+ }
+ if( !pStmt || !wasm.isPtr(pStmt) ){
+ throw new sqlite3.SQLite3Error(sqlite3.SQLITE_MISUSE,
+ "Second argument must be a WASM "+
+ "sqlite3_stmt pointer");
+ }
+ return new Stmt(oo1db, pStmt, BindTypes, !!takeOwnership);
+ }
+
/** The OO API's public namespace. */
sqlite3.oo1 = {
DB,
diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js
index 7e128a3fa..e3807a314 100644
--- a/ext/wasm/api/sqlite3-api-prologue.js
+++ b/ext/wasm/api/sqlite3-api-prologue.js
@@ -134,22 +134,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
const config = Object.assign(Object.create(null),{
exports: undefined,
memory: undefined,
- bigIntEnabled: (()=>{
- if('undefined'!==typeof Module){
- /* Emscripten module will contain HEAPU64 when built with
- -sWASM_BIGINT=1, else it will not.
-
- As of emsdk 3.1.55, when building in strict mode, HEAPxyz
- are only available if _explicitly_ included in the exports,
- else they are not. We do not (as of 2024-03-04) use -sSTRICT
- for the canonical builds.
- */
- if( !!Module.HEAPU64 ) return true;
- /* Else fall through and hope for the best. Nobody _really_
- builds this without BigInt support, do they? */
- }
- return !!globalThis.BigInt64Array;
- })(),
+ bigIntEnabled: !!globalThis.BigInt64Array,
debug: console.debug.bind(console),
warn: console.warn.bind(console),
error: console.error.bind(console),
diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js
index 5b94c7c05..dd70024ab 100644
--- a/ext/wasm/tester1.c-pp.js
+++ b/ext/wasm/tester1.c-pp.js
@@ -41,7 +41,7 @@
ES6 worker module build:
- ./c-pp -f tester1.c-pp.js -o tester1-esm.js -Dtarget=es6-module
+ ./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';
@@ -221,7 +221,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
else if(filter instanceof Function) pass = filter(err);
else if('string' === typeof filter) pass = (err.message === filter);
if(!pass){
- throw new Error(msg || ("Filter rejected this exception: "+err.message));
+ throw new Error(msg || ("Filter rejected this exception: <<"+err.message+">>"));
}
return this;
},
@@ -1209,6 +1209,104 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
}
}
})
+
+ ////////////////////////////////////////////////////////////////////
+ .t({
+ name: "oo1.DB/Stmt.wrapDbHandle()",
+ test: function(sqlite3){
+ /* Maintenance reminder: this function is early in the list to
+ demonstrate that the wrappers for this.db created by this
+ function do not interfere with downstream tests, e.g. by
+ closing this.db.pointer. */
+ //sqlite3.config.debug("Proxying",this.db);
+ const misuseMsg = "SQLITE_MISUSE: Argument must be a WASM sqlite3 pointer";
+ T.mustThrowMatching(()=>sqlite3.oo1.DB.wrapHandle(this.db), misuseMsg)
+ .mustThrowMatching(()=>sqlite3.oo1.DB.wrapHandle(0), misuseMsg);
+ let dw = sqlite3.oo1.DB.wrapHandle(this.db.pointer);
+ //sqlite3.config.debug('dw',dw);
+ T.assert( dw, '!!dw' )
+ .assert( dw instanceof sqlite3.oo1.DB, 'dw is-a oo1.DB' )
+ .assert( dw.pointer, 'dw.pointer' )
+ .assert( dw.pointer === this.db.pointer, 'dw.pointer===db.pointer' )
+ .assert( dw.filename === this.db.filename, 'dw.filename===db.filename' );
+
+ T.assert( dw === dw.exec("select 1") );
+ let q;
+ try {
+ q = dw.prepare("select 1");
+ T.assert( q.step() )
+ .assert( !q.step() );
+ }finally{
+ if( q ) q.finalize();
+ }
+ dw.close();
+ T.assert( !dw.pointer )
+ .assert( this.db === this.db.exec("select 1") );
+ dw = undefined;
+
+ let pDb = 0, pStmt = 0;
+ const stack = wasm.pstack.pointer;
+ try {
+ const ppOut = wasm.pstack.allocPtr();
+ T.assert( 0===wasm.peekPtr(ppOut) );
+ let rc = capi.sqlite3_open_v2( ":memory:", ppOut,
+ capi.SQLITE_OPEN_CREATE
+ | capi.SQLITE_OPEN_READWRITE,
+ 0);
+ T.assert( 0===rc, 'open_v2()' );
+ pDb = wasm.peekPtr(ppOut);
+ wasm.pokePtr(ppOut, 0);
+ T.assert( pDb>0, 'pDb>0' );
+ const pTmp = pDb;
+ dw = sqlite3.oo1.DB.wrapHandle(pDb, true);
+ pDb = 0;
+ //sqlite3.config.debug("dw",dw);
+ T.assert( pTmp===dw.pointer, 'pDb===dw.pointer' );
+ T.assert( dw.filename === "", "dw.filename == "+dw.filename );
+ let q = dw.prepare("select 1");
+ try {
+ T.assert( q.step(), "step()" );
+ T.assert( !q.step(), "!step()" );
+ }finally{
+ q.finalize();
+ q = undefined;
+ }
+ T.assert( dw===dw.exec("select 1") );
+ dw.affirmOpen();
+ const select1 = "select 1";
+ rc = capi.sqlite3_prepare_v2( dw, select1, -1, ppOut, 0 );
+ T.assert( 0===rc, 'prepare_v2() rc='+rc );
+ pStmt = wasm.peekPtr(ppOut);
+ T.assert( pStmt && wasm.isPtr(pStmt), 'pStmt is valid?' );
+ try {
+ //log( "capi.sqlite3_sql() =",capi.sqlite3_sql(pStmt));
+ T.assert( select1 === capi.sqlite3_sql(pStmt), 'SQL mismatch' );
+ q = sqlite3.oo1.Stmt.wrapHandle(dw, pStmt, false);
+ //log("q@"+pStmt+" does not own handle");
+ T.assert( q.step(), "step()" )
+ .assert( !q.step(), "!step()" );
+ q.finalize();
+ q = undefined;
+ T.assert( select1 === capi.sqlite3_sql(pStmt), 'SQL mismatch'
+ /* This will fail if we've mismanaged pStmt's lifetime */);
+ q = sqlite3.oo1.Stmt.wrapHandle(dw, pStmt, true);
+ pStmt = 0;
+ q.reset();
+ T.assert( q.step(), "step()" )
+ .assert( !q.step(), "!step()" );
+ }finally{
+ if( pStmt ) capi.sqlite3_finalize(pStmt)
+ if( q ) q.finalize();
+ }
+
+ }finally{
+ wasm.pstack.restore(stack);
+ if( pDb ){ capi.sqlite3_close_v2(pDb); }
+ else if( dw ){ dw.close(); }
+ }
+ }
+ })/*oo1.DB/Stmt.wrapHandle()*/
+
////////////////////////////////////////////////////////////////////
.t('sqlite3_db_config() and sqlite3_db_status()', function(sqlite3){
let rc = capi.sqlite3_db_config(this.db, capi.SQLITE_DBCONFIG_LEGACY_ALTER_TABLE, 0, 0);
@@ -1268,6 +1366,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
/columnCount property is read-only/)
.assert(1===st.columnCount)
.assert(0===st.parameterCount)
+ .assert(0===capi.sqlite3_bind_parameter_count(st))
.mustThrow(()=>st.bind(1,null))
.assert(true===st.step())
.assert(3 === st.get(0))
@@ -1490,6 +1589,8 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
let st = db.prepare("update t set b=:b where a='blob'");
try {
T.assert(0===st.columnCount)
+ .assert(1===st.parameterCount)
+ .assert(1===capi.sqlite3_bind_parameter_count(st))
.assert( false===st.isReadOnly() );
const ndx = st.getParamIndex(':b');
T.assert(1===ndx);
@@ -3329,6 +3430,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
db.exec("create table t(a)");
const stmt = db.prepare("insert into t(a) values($a)");
T.assert( 1===capi.sqlite3_bind_parameter_count(stmt) )
+ .assert( 1===stmt.parameterCount )
.assert( 1===capi.sqlite3_bind_parameter_index(stmt, "$a") )
.assert( 0===capi.sqlite3_bind_parameter_index(stmt, ":a") )
.assert( 1===stmt.getParamIndex("$a") )
diff --git a/manifest b/manifest
index a8c30532d..e8a27b895 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sthe\sempty-table\soptimization\son\sINTERSECT\sso\sthat\sit\sdoes\snot\stry\sto\nuse\san\suninitialized\sregister\sfor\sLIMIT\sprocessing.
-D 2025-07-09T20:11:49.196
+C wasm:\sintroduce\sthe\ssqlite3.oo1.DB.wrapHandle()\sand\sStmt.wrapHandle()\sAPIs,\swhich\senable\sclients\sto\swrap\s(sqlite3*)\sresp.\s(sqlite3_stmt*)\spointers\sin\stheir\soo1\sAPI\scounterparts,\soptionally\swith\sor\swithout\staking\sover\sownership\sof\sthe\spointer.
+D 2025-07-11T19:52:36.729
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -456,7 +456,7 @@ F ext/misc/uuid.c 5bb2264c1b64d163efa46509544fd7500cb8769cb7c16dd52052da8d961505
F ext/misc/vfslog.c 3932ab932eeb2601dbc4447cb14d445aaa9fbe43b863ef5f014401c3420afd20
F ext/misc/vfsstat.c 0b23c0a69a2b63dc0ef0af44f9c1fc977300c480a1f7a9814500369d8211f56e
F ext/misc/vfstrace.c 0e4b8b17ac0675ea90f6d168d8214687e06ca3efbc0060aad4814994d82b41fb
-F ext/misc/vtablog.c 62d54fb0f4ff9df72ffa44f4a226451a964e1d96ac550f2b8906feebdad00b58
+F ext/misc/vtablog.c 9f7e02e9e8de585f3bfb48405db36c2eb4b680a23a67d7a4b738dd20f6ad7aec
F ext/misc/vtshim.c e5bce24ab8c532f4fdc600148718fe1802cb6ed57417f1c1032d8961f72b0e8f
F ext/misc/wholenumber.c 0fa0c082676b7868bf2fa918e911133f2b349bcdceabd1198bba5f65b4fc0668
F ext/misc/windirent.h 02211ce51f3034c675f2dbf4d228194d51b3ee05734678bad5106fff6292e60c
@@ -621,7 +621,7 @@ F ext/session/sqlite3session.c 6b0877fe1ab832aa4b85eaca72606dfd1630a1363a1be7af1
F ext/session/sqlite3session.h 9bb1a6687b467764b35178dc29bbd2c57ab8cd3acdc8a62f088c34ad17e4fe2b
F ext/session/test_session.c 2ddff73ea368d827028c32851b291416e1008845832feb27b751d15e57e13cc3
F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c
-F ext/wasm/GNUmakefile a05bb1766f97c88cb42fbfe9e349c799c691f8ae0dc959e9d9469f0bcee89350
+F ext/wasm/GNUmakefile d62af1b0914eb2e03fa6e4e75e93acadc8f4faeb2d56335da25d61b9ea144c53
F ext/wasm/README-dist.txt f01081a850ce38a56706af6b481e3a7878e24e42b314cfcd4b129f0f8427066a
F ext/wasm/README.md b89605f65661cf35bf034ff6d43e448cc169b8017fc105d498e33b81218b482c
F ext/wasm/SQLTester/GNUmakefile e0794f676d55819951bbfae45cc5e8d7818dc460492dc317ce7f0d2eca15caff
@@ -641,8 +641,8 @@ F ext/wasm/api/post-js-header.js 53740d824e5d9027eb1e6fd59e216abbd2136740ce260ea
F ext/wasm/api/pre-js.c-pp.js a614a2c82b12c4d96d8e3ba77330329efc53c4d56a8a7e60ade900f341866cfb
F ext/wasm/api/sqlite3-api-cleanup.js 3ac1786e461ada63033143be8c3b00b26b939540661f3e839515bb92f2e35359
F ext/wasm/api/sqlite3-api-glue.c-pp.js 0b76510f3650053bac67ca8947cb6ab9d050ad2218118a2e7796dd37be832ffa
-F ext/wasm/api/sqlite3-api-oo1.c-pp.js c68d6da0088c2527156fca9163a721abe08e7bd077b15404fd8d292f4612adc1
-F ext/wasm/api/sqlite3-api-prologue.js 8708570165f5b4bce9a78ccd91bc9ddf8735970ac1c4d659e36c9a7d9a644bb4
+F ext/wasm/api/sqlite3-api-oo1.c-pp.js f59e59f0d94ba5835c6b7fc9b800a4aa5084e1224721a07e3cd6cc7fef1789c2
+F ext/wasm/api/sqlite3-api-prologue.js 4f1c2a9dc9caf631907766e9872c27d11b255ccae779e8af01c7f8b932817214
F ext/wasm/api/sqlite3-api-worker1.c-pp.js f646a65257973b8c4481f8a6a216370b85644f23e64b126e7ae113570587c0ab
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
F ext/wasm/api/sqlite3-opfs-async-proxy.js 9654b565b346dc609b75d15337f20acfa7af7d9d558da1afeb9b6d8eaa404966
@@ -698,7 +698,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
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 766a2ba51a2619d41a49be7c6a1ad014c1d23fc97b67496e4f103038203eb17d
+F ext/wasm/tester1.c-pp.js 0abba4bd54f6b22adaadf836c04d3163399f7a8a490fd60f20daac5f9c42b47d
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
@@ -854,7 +854,7 @@ F src/util.c 36fb1150062957280777655976f3f9a75db236cb8207a0770ceae8d5ec17fcd3
F src/vacuum.c 1bacdd0a81d2b5dc1c508fbf0d938c89fa78dd8d5b46ec92686d44030d4f4789
F src/vdbe.c e505b8b879a330e8dafbe3ed9582eae2fc671b44a64748d1b58c07e4e0f527da
F src/vdbe.h 93761ed7c6b8bc19524912fd9b9b587d41bf4f1d0ade650a00dadc10518d8958
-F src/vdbeInt.h 0bc581a9763be385e3af715e8c0a503ba8422c2b7074922faf4bb0d6ae31b15e
+F src/vdbeInt.h 626465ff6d673f73a2476dc230b7cd07bdaf4acea9d4ecceaa12a5174bb2c8d7
F src/vdbeapi.c f9a4881a9674fec3fa13da35044a1484d3c4b95f9ec891cc8ffb02ef2b7a41df
F src/vdbeaux.c fd2c6b19a8892c31a2adc719f156f313560f9cc490cdbd04ff08fdae5d7aedb7
F src/vdbeblob.c b3f0640db9642fbdc88bd6ebcc83d6009514cafc98f062f675f2c8d505d82692
@@ -1689,7 +1689,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 64b8804b053a796eab22f8b23fb181000f05d7b3e2aa44f022117ea543bc5a2a
+F test/speedtest1.c a9b002a7bfed99ba3166c2a9b8ae45a95b4c2d37f891e1637c022f9e1d15e3f9
F test/spellfix.test 951a6405d49d1a23d6b78027d3877b4a33eeb8221dcab5704b499755bb4f552e
F test/spellfix2.test dfc8f519a3fc204cb2dfa8b4f29821ae90f6f8c3
F test/spellfix3.test 0f9efaaa502a0e0a09848028518a6fb096c8ad33
@@ -1736,8 +1736,9 @@ F test/temptable2.test 76821347810ecc88203e6ef0dd6897b6036ac788e9dd3e6b04fd4d163
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
F test/tester.tcl 463ae33b8bf75ac77451df19bd65e7c415c2e9891227c7c9e657d0a2d8e1074a
-F test/testrunner.tcl 614c4a28f7f730acd7bec53e17d76602fb480e0d538b6ec548169e03a093f92d x
+F test/testrunner.tcl b42f7736968cafc9e69bb5d0b87fc81b375fb4c3f44e19b472cccd91d41a416a x
F test/testrunner_data.tcl 02dd645b647d907c959fbf232b7ff7d869c2ae430d5117443fc1e16a0d32243a
+F test/testrunner_estwork.tcl 7927a84327259a32854926f68a75292e33a61e7e052fdbfcb01f18696c99c724
F test/thread001.test a0985c117eab62c0c65526e9fa5d1360dd1cac5b03bde223902763274ce21899
F test/thread002.test c24c83408e35ba5a952a3638b7ac03ccdf1ce4409289c54a050ac4c5f1de7502
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
@@ -2211,8 +2212,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 498ee8d514e64cdc93a8d68e1971b6326c6132daf25067936bec921c42494caa
-R ebdf1d802e5dd88fbc80d28dd0639cd8
-U drh
-Z 51edd06328595496523194f72341809d
+P 3656acfaa3011321a6e17fb81e5bdedcfffeab6035f133ab89ae9589bf5bef72 53401b5435e30c4b47b6e203976b714d616246d734b5876a34f53f6388f872f8
+R 6e106d1cb56322541040e2b7c468c9ad
+T +closed 53401b5435e30c4b47b6e203976b714d616246d734b5876a34f53f6388f872f8 Closed\sby\sintegrate-merge.
+U stephan
+Z f91aebcbb3981855ba9f714a42d1af4f
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index b9c5f04af..ac45e07d9 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-6918ada008507b4564ca0dc5f4f6818c49a42eb14a16285b2074e21dcc8f2c3f
+e5d079549594ca44852773b8919894866394e47ad725dadc7f65242413a219d3
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index 0faa32747..07160f590 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -288,7 +288,7 @@ struct sqlite3_value {
** MEM_Int, MEM_Real, and MEM_IntReal.
**
** * MEM_Blob|MEM_Zero A blob in Mem.z of length Mem.n plus
-** MEM.u.i extra 0x00 bytes at the end.
+** Mem.u.nZero extra 0x00 bytes at the end.
**
** * MEM_Int Integer stored in Mem.u.i.
**
diff --git a/test/speedtest1.c b/test/speedtest1.c
index 10cd30f1c..968f2cb00 100644
--- a/test/speedtest1.c
+++ b/test/speedtest1.c
@@ -159,6 +159,12 @@ static void fatal_error(const char *zMsg, ...){
va_start(ap, zMsg);
vfprintf(stderr, zMsg, ap);
va_end(ap);
+#ifdef SQLITE_SPEEDTEST1_WASM
+ /* Emscripten complains when exit() is called and anything is left
+ in the I/O buffers. */
+ fflush(stdout);
+ fflush(stderr);
+#endif
exit(1);
}
@@ -2994,7 +3000,13 @@ int main(int argc, char **argv){
/* "mix1" is a macro testset: */
static char zMix1Tests[] =
- "main,orm/25,cte/20,json,fp/3,parsenumber/25,rtree/10,star,app";
+ "main,orm/25,cte/20,json,fp/3,parsenumber/25,rtree/10,star"
+#if !defined(SQLITE_SPEEDTEST1_WASM)
+ ",app"
+ /* This test misbehaves in WASM builds: sqlite3_open_v2() is
+ failing to find the db file for reasons not yet understood. */
+#endif
+ ;
#ifdef SQLITE_SPEEDTEST1_WASM
/* Resetting all state is important for the WASM build, which may
diff --git a/test/testrunner.tcl b/test/testrunner.tcl
index 0c6982f42..52bc0f34b 100755
--- a/test/testrunner.tcl
+++ b/test/testrunner.tcl
@@ -7,6 +7,18 @@ set testdir [file normalize [file dirname $argv0]]
set saved $argv
set argv [list]
source [file join $testdir testrunner_data.tcl]
+
+# Estimated amount of work required by displaytype, relative to 'tcl'
+#
+set estwork(tcl) 1
+set estwork(fuzz) 22
+set estwork(bld) 66
+set estwork(make) 102
+
+set estworkfile [file join $testdir testrunner_estwork.tcl]
+if {[file readable $estworkfile]} {
+ source $estworkfile
+}
source [file join $testdir permutations.test]
set argv $saved
cd $dir
@@ -92,6 +104,7 @@ Usage:
$a0 script ?-msvc? CONFIG
$a0 status ?-d SECS? ?--cls?
$a0 halt
+ $a0 estwork
where SWITCHES are:
--buildonly Build test exes but do not run tests
@@ -341,6 +354,7 @@ set TRG(schema) {
endtime INTEGER, -- End time
span INTEGER, -- Total run-time in milliseconds
estwork INTEGER, -- Estimated amount of work
+ estkey TEXT, -- Key used to compute estwork
state TEXT CHECK( state IN ('','ready','running','done','failed','omit','halt') ),
ntest INT, -- Number of test cases run
nerr INT, -- Number of errors reported
@@ -359,13 +373,6 @@ set TRG(schema) {
}
#-------------------------------------------------------------------------
-# Estimated amount of work required by displaytype, relative to 'tcl'
-#
-set estwork(tcl) 1
-set estwork(fuzz) 11
-set estwork(bld) 56
-set estwork(make) 97
-
#--------------------------------------------------------------------------
# Check if this script is being invoked to run a single file. If so,
# run it.
@@ -453,6 +460,59 @@ if {[llength $argv]==1
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
+# Check if this is the "estwork" command:
+#
+# Generate (on standard output) a set of estwork() values based on the lastest
+# test case, that can be used to replace the test/testrunner_estwork.tcl file.
+#
+if {[llength $argv]==1
+ && [string compare -nocase estwork [lindex $argv 0]]==0
+} {
+ sqlite3 mydb $TRG(dbname)
+ set njob [mydb one {SELECT count(*) FROM jobs WHERE state='done'}]
+ if {$njob<1000} {
+ puts "Too few completed jobs to do a work estimate."
+ puts "Have $njob but not need at least 1000."
+ mydb close
+ exit 1
+ }
+ set badjobs [mydb one {SELECT count(*) FROM jobs WHERE state<>'done'}]
+ if {$badjobs} {
+ puts "Database contains $badjobs incomplete jobs."
+ mydb close
+ exit 1
+ }
+ set half [mydb one {SELECT count(*)/2 FROM jobs WHERE displaytype='tcl'}]
+ set scale [mydb one {SELECT span FROM jobs WHERE displaytype='tcl'
+ ORDER BY span LIMIT 1 OFFSET $half}]
+ mydb eval {
+ SELECT estkey, CAST(avg(span)/$scale AS INT) AS cost
+ FROM jobs
+ GROUP BY estkey
+ HAVING cost>=2
+ } {
+ set estwork($estkey) $cost
+ }
+ set avgtcl [mydb one {SELECT avg(span) FROM jobs WHERE displaytype='tcl'}]
+ set estwork(tcl) 1
+ foreach type {bld fuzz make} {
+ set avg [mydb one {SELECT avg(span) FROM jobs WHERE displaytype=$type}]
+ if {$avg!=""} {
+ set estwork($type) [expr {int($avg/$avgtcl)}]
+ }
+ }
+ mydb close
+ puts "# Estimated relative cost of various jobs, based on the \"estkey\" field."
+ puts "# Computed by the \"test/testrunner.tcl estwork\" command."
+ puts "#"
+ foreach key [lsort [array names estwork]] {
+ puts "set [list estwork($key)] $estwork($key)"
+ }
+ exit
+}
+#--------------------------------------------------------------------------
+
+#--------------------------------------------------------------------------
# Check if this is the "help" command:
#
if {[string compare -nocase help [lindex $argv 0]]==0} {
@@ -562,8 +622,8 @@ proc show_status {db cls} {
set srcdir [file dirname [file dirname $TRG(info_script)]]
set line "Running: $S(running) (max: $nJob)"
- if {$S(running)>0 && $fin>10} {
- set tmleft [expr {($tm/$fin)*($totalw-$fin)}]
+ if {$S(running)>0 && [set pct [expr {int(($fin*100.0)/$totalw)}]]>=4} {
+ set tmleft [expr {($tm/double($fin))*($totalw-$fin)}]
if {$tmleft<0.02*$tm} {
set tmleft [expr {$tm*0.02}]
}
@@ -571,6 +631,7 @@ proc show_status {db cls} {
if {[string length $line]+[string length $etc]<80} {
append line $etc
}
+ # append line " $pct%"
}
puts [format %-79.79s $line]
if {$S(running)>0} {
@@ -985,12 +1046,31 @@ proc add_job {args} {
set state ""
if {$A(-depid)==""} { set state ready }
set type $A(-displaytype)
- set ew $estwork($type)
+ set displayname $A(-displayname)
+ switch $type {
+ tcl {
+ set ek [file tail [lindex $displayname end]]
+ }
+ bld {
+ set ek [lindex $displayname end]
+ }
+ fuzz {
+ set ek [lrange $displayname 1 2]
+ }
+ make {
+ set ek [lindex $displayname end]
+ }
+ }
+ if {[info exists estwork($ek)]} {
+ set ew $estwork($ek)
+ } else {
+ set ew $estwork($type)
+ }
trdb eval {
INSERT INTO jobs(
- displaytype, displayname, build, dirname, cmd, depid, priority, estwork,
- state
+ displaytype, displayname, build, dirname, cmd, depid, priority,
+ estwork, estkey, state
) VALUES (
$type,
$A(-displayname),
@@ -1000,6 +1080,7 @@ proc add_job {args} {
$A(-depid),
$A(-priority),
$ew,
+ $ek,
$state
)
}
@@ -1586,12 +1667,13 @@ proc progress_report {} {
}
}
set report "[elapsetime $tmms] [join $text { }]"
- if {$wdone>0} {
- set tmleft [expr {($tmms/$wdone)*($wtotal-$wdone)}]
- set etc " ETC [elapsetime $tmleft]"
+ if {$wdone>0 && [set pct [expr {int(($wdone*100.0)/$wtotal)}]]>=4} {
+ set tmleft [expr {($tmms/double($wdone))*($wtotal-$wdone)}]
+ set etc " ETC [elapsetime $tmleft]"
if {[string length $report]+[string length $etc]<80} {
append report $etc
}
+ # append report " $pct%"
}
puts -nonewline [format %-79.79s $report]\r
flush stdout
diff --git a/test/testrunner_estwork.tcl b/test/testrunner_estwork.tcl
new file mode 100644
index 000000000..c139394a5
--- /dev/null
+++ b/test/testrunner_estwork.tcl
@@ -0,0 +1,488 @@
+# Estimated relative cost of various jobs, based on the "estkey" field.
+# Computed by the "test/testrunner.tcl estwork" command.
+#
+set estwork((fuzzcheck)) 1291
+set estwork((fuzzcheck-asan)) 2427
+set estwork((fuzzcheck-ubsan)) 2749
+set estwork((sessionfuzz)) 1276
+set estwork((sqlite3)) 1281
+set estwork((testfixture)) 1546
+set estwork(aggerror.test) 5
+set estwork(alter.test) 20
+set estwork(alter3.test) 2
+set estwork(alterauth.test) 5
+set estwork(altercol.test) 5
+set estwork(alterdropcol.test) 17
+set estwork(alterlegacy.test) 2
+set estwork(altertab.test) 34
+set estwork(altertab2.test) 2
+set estwork(altertab3.test) 12
+set estwork(amatch1.test) 40
+set estwork(atof1.test) 146
+set estwork(atomic2.test) 2
+set estwork(auth.test) 2
+set estwork(autoindex1.test) 5
+set estwork(autoindex3.test) 5
+set estwork(autovacuum.test) 15
+set estwork(avfs.test) 16
+set estwork(avtrans.test) 285
+set estwork(backup2.test) 15
+set estwork(bestindex4.test) 12
+set estwork(bigrow.test) 5
+set estwork(bitvec.test) 94
+set estwork(bld) 99
+set estwork(blob.test) 2
+set estwork(boundary1.test) 8
+set estwork(boundary2.test) 16
+set estwork(boundary3.test) 14
+set estwork(btree01.test) 20
+set estwork(busy.test) 2
+set estwork(busy2.test) 288
+set estwork(capi3.test) 5
+set estwork(capi3b.test) 6
+set estwork(capi3c.test) 5
+set estwork(capi3d.test) 8
+set estwork(capi3e.test) 20
+set estwork(changes.test) 11
+set estwork(chunksize.test) 5
+set estwork(closure01.test) 63
+set estwork(collate5.test) 2
+set estwork(conflict.test) 8
+set estwork(conflict2.test) 4
+set estwork(conflict3.test) 8
+set estwork(corrupt2.test) 2
+set estwork(corrupt4.test) 91
+set estwork(corrupt7.test) 5
+set estwork(corrupt8.test) 3
+set estwork(corruptB.test) 4
+set estwork(corruptF.test) 6
+set estwork(count.test) 18
+set estwork(crash8.test) 14
+set estwork(createtab.test) 3
+set estwork(csv01.test) 7
+set estwork(cursorhint.test) 4
+set estwork(date.test) 17
+set estwork(date4.test) 64
+set estwork(date5.test) 3
+set estwork(dbdata.test) 77
+set estwork(dbfuzz001.test) 2
+set estwork(dbstatus.test) 4
+set estwork(decimal.test) 2
+set estwork(delete.test) 4
+set estwork(diskfull.test) 34
+set estwork(e_blobbytes.test) 11
+set estwork(e_createtable.test) 14
+set estwork(e_delete.test) 3
+set estwork(e_droptrigger.test) 6
+set estwork(e_dropview.test) 2
+set estwork(e_expr.test) 251
+set estwork(e_select.test) 5
+set estwork(e_select2.test) 5
+set estwork(e_vacuum.test) 6
+set estwork(e_walauto.test) 51
+set estwork(e_walckpt.test) 6
+set estwork(enc.test) 2
+set estwork(enc3.test) 11
+set estwork(enc4.test) 3
+set estwork(eval.test) 2
+set estwork(exists.test) 4
+set estwork(existsexpr.test) 44
+set estwork(expert1.test) 14
+set estwork(expr.test) 5
+set estwork(filectrl.test) 5
+set estwork(filefmt.test) 6
+set estwork(fkey2.test) 9
+set estwork(fpconv1.test) 40
+set estwork(fts3aa.test) 18
+set estwork(fts3ad.test) 10
+set estwork(fts3ag.test) 6
+set estwork(fts3aj.test) 8
+set estwork(fts3am.test) 5
+set estwork(fts3auto.test) 29
+set estwork(fts3b.test) 41
+set estwork(fts3c.test) 22
+set estwork(fts3conf.test) 3
+set estwork(fts3corrupt4.test) 7
+set estwork(fts3corrupt5.test) 8
+set estwork(fts3corrupt6.test) 13
+set estwork(fts3d.test) 2
+set estwork(fts3defer2.test) 2
+set estwork(fts3expr.test) 10
+set estwork(fts3expr2.test) 8
+set estwork(fts3expr3.test) 145
+set estwork(fts3f.test) 9
+set estwork(fts3first.test) 3
+set estwork(fts3matchinfo.test) 4
+set estwork(fts3misc.test) 54
+set estwork(fts3prefix.test) 4
+set estwork(fts3prefix2.test) 8
+set estwork(fts3query.test) 23
+set estwork(fts3varint.test) 2
+set estwork(fts4aa.test) 34
+set estwork(fts4content.test) 5
+set estwork(fts4incr.test) 19
+set estwork(fts4noti.test) 3
+set estwork(fts4opt.test) 129
+set estwork(fts4unicode.test) 45
+set estwork(fts5aa.test) 442
+set estwork(fts5ab.test) 54
+set estwork(fts5ad.test) 33
+set estwork(fts5ae.test) 3
+set estwork(fts5af.test) 13
+set estwork(fts5ag.test) 13
+set estwork(fts5ah.test) 265
+set estwork(fts5al.test) 2
+set estwork(fts5auto.test) 92
+set estwork(fts5connect.test) 5
+set estwork(fts5content.test) 9
+set estwork(fts5contentless.test) 23
+set estwork(fts5contentless2.test) 189
+set estwork(fts5contentless4.test) 234
+set estwork(fts5contentless5.test) 9
+set estwork(fts5delete.test) 62
+set estwork(fts5doclist.test) 11
+set estwork(fts5expr.test) 10
+set estwork(fts5full.test) 42
+set estwork(fts5hash.test) 17
+set estwork(fts5integrity.test) 84
+set estwork(fts5interrupt.test) 16
+set estwork(fts5locale.test) 5
+set estwork(fts5matchinfo.test) 11
+set estwork(fts5merge.test) 29
+set estwork(fts5merge2.test) 9
+set estwork(fts5misc.test) 8
+set estwork(fts5multiclient.test) 2
+set estwork(fts5optimize.test) 13
+set estwork(fts5optimize2.test) 737
+set estwork(fts5optimize3.test) 280
+set estwork(fts5origintext.test) 144
+set estwork(fts5origintext3.test) 8
+set estwork(fts5origintext4.test) 30
+set estwork(fts5origintext5.test) 462
+set estwork(fts5origintext6.test) 55
+set estwork(fts5porter.test) 57
+set estwork(fts5query.test) 8
+set estwork(fts5restart.test) 10
+set estwork(fts5rowid.test) 35
+set estwork(fts5secure.test) 61
+set estwork(fts5secure3.test) 796
+set estwork(fts5secure4.test) 141
+set estwork(fts5secure5.test) 29
+set estwork(fts5secure6.test) 33
+set estwork(fts5secure7.test) 680
+set estwork(fts5simple.test) 7
+set estwork(fts5simple2.test) 2
+set estwork(fts5synonym.test) 13
+set estwork(fts5synonym2.test) 384
+set estwork(fts5tok2.test) 92
+set estwork(fts5tokenizer.test) 2
+set estwork(fts5tokenizer3.test) 8
+set estwork(fts5trigram.test) 2
+set estwork(fts5unicode2.test) 28
+set estwork(fts5unicode3.test) 72
+set estwork(fts5unindexed.test) 7
+set estwork(fts5update.test) 161
+set estwork(fts5update2.test) 11
+set estwork(fts5vocab.test) 11
+set estwork(fts5vocab2.test) 15
+set estwork(func.test) 36
+set estwork(fuzz) 68
+set estwork(fuzz-oss1.test) 11
+set {estwork(fuzzcheck --slice)} 499
+set {estwork(fuzzcheck fuzzdata1.db)} 301
+set {estwork(fuzzcheck fuzzdata2.db)} 275
+set {estwork(fuzzcheck fuzzdata3.db)} 72
+set {estwork(fuzzcheck fuzzdata4.db)} 30
+set {estwork(fuzzcheck fuzzdata5.db)} 299
+set {estwork(fuzzcheck fuzzdata6.db)} 91
+set {estwork(fuzzcheck fuzzdata7.db)} 201
+set {estwork(fuzzcheck fuzzdata8.db)} 331
+set {estwork(fuzzcheck-asan --slice)} 2037
+set {estwork(fuzzcheck-asan fuzzdata1.db)} 3112
+set {estwork(fuzzcheck-asan fuzzdata2.db)} 8753
+set {estwork(fuzzcheck-asan fuzzdata3.db)} 459
+set {estwork(fuzzcheck-asan fuzzdata4.db)} 123
+set {estwork(fuzzcheck-asan fuzzdata5.db)} 1178
+set {estwork(fuzzcheck-asan fuzzdata6.db)} 1356
+set {estwork(fuzzcheck-asan fuzzdata7.db)} 938
+set {estwork(fuzzcheck-asan fuzzdata8.db)} 1451
+set {estwork(fuzzcheck-ubsan --slice)} 1729
+set {estwork(fuzzcheck-ubsan fuzzdata1.db)} 1180
+set {estwork(fuzzcheck-ubsan fuzzdata2.db)} 876
+set {estwork(fuzzcheck-ubsan fuzzdata3.db)} 306
+set {estwork(fuzzcheck-ubsan fuzzdata4.db)} 95
+set {estwork(fuzzcheck-ubsan fuzzdata5.db)} 1356
+set {estwork(fuzzcheck-ubsan fuzzdata6.db)} 333
+set {estwork(fuzzcheck-ubsan fuzzdata7.db)} 883
+set {estwork(fuzzcheck-ubsan fuzzdata8.db)} 1124
+set estwork(fuzzer1.test) 6
+set estwork(gencol1.test) 3
+set estwork(hook.test) 2
+set estwork(in4.test) 4
+set estwork(in7.test) 6
+set estwork(incrblob2.test) 2
+set estwork(incrblob3.test) 5
+set estwork(incrvacuum.test) 10
+set estwork(incrvacuum2.test) 17
+set estwork(incrvacuum3.test) 17
+set estwork(index.test) 3
+set estwork(index2.test) 8
+set estwork(index4.test) 33
+set estwork(index5.test) 99
+set estwork(index6.test) 2
+set estwork(indexexpr1.test) 2
+set estwork(insert3.test) 5
+set estwork(insert4.test) 2
+set estwork(intarray.test) 8
+set estwork(intck1.test) 34
+set estwork(intck2.test) 37
+set estwork(interrupt.test) 28
+set estwork(io.test) 3
+set estwork(join.test) 3
+set estwork(join3.test) 6
+set estwork(join5.test) 20
+set estwork(join7.test) 2
+set estwork(join8.test) 3
+set estwork(join9.test) 2
+set estwork(joinA.test) 11
+set estwork(joinB.test) 7
+set estwork(joinC.test) 6
+set estwork(joinD.test) 168
+set estwork(json103.test) 6
+set estwork(json106.test) 690
+set estwork(keyword1.test) 3
+set estwork(like2.test) 2
+set estwork(like3.test) 2
+set estwork(limit.test) 3
+set estwork(literal.test) 6
+set estwork(lock.test) 39
+set estwork(lock4.test) 2
+set estwork(lock5.test) 4
+set estwork(make) 102
+set estwork(manydb.test) 12
+set estwork(mem5.test) 2
+set estwork(memdb.test) 9
+set estwork(memdb1.test) 2
+set estwork(memjournal2.test) 164
+set estwork(memsubsys1.test) 8
+set estwork(misc1.test) 6
+set estwork(misc2.test) 6
+set estwork(misc5.test) 11
+set estwork(misc8.test) 5
+set estwork(mmap1.test) 8
+set estwork(mmap2.test) 10
+set estwork(mmapwarm.test) 2
+set estwork(multiplex.test) 30
+set estwork(multiplex2.test) 7
+set estwork(nan.test) 2
+set estwork(notify3.test) 5
+set estwork(orderby1.test) 11
+set estwork(orderby2.test) 2
+set estwork(orderby5.test) 11
+set estwork(orderby6.test) 6
+set estwork(orderby8.test) 20
+set estwork(orderbyA.test) 2
+set estwork(oserror.test) 7
+set estwork(ovfl.test) 11
+set estwork(pager1.test) 81
+set estwork(pager2.test) 129
+set estwork(pagesize.test) 3
+set estwork(percentile.test) 86
+set estwork(pragma.test) 4
+set estwork(pragma4.test) 18
+set estwork(printf.test) 21
+set estwork(printf2.test) 5
+set estwork(quota.test) 14
+set estwork(randexpr1.test) 35
+set estwork(rbu10.test) 16
+set estwork(rbu13.test) 5
+set estwork(rbuexlock.test) 5
+set estwork(rbumisc.test) 2
+set estwork(rbutemplimit.test) 2
+set estwork(readonly.test) 95
+set estwork(recover.test) 3
+set estwork(recover1.test) 7
+set estwork(recovercorrupt3.test) 5
+set estwork(recoverold.test) 7
+set estwork(recoverpgsz.test) 6
+set estwork(recoverrowid.test) 3
+set estwork(returning1.test) 6
+set estwork(rollback2.test) 2
+set estwork(round1.test) 261
+set estwork(rowhash.test) 85
+set estwork(rowid.test) 3
+set estwork(rowvalue.test) 2
+set estwork(rowvalue2.test) 38
+set estwork(rowvalue4.test) 2
+set estwork(rowvalueA.test) 2
+set estwork(rowvaluevtab.test) 2
+set estwork(rtree1.test) 4
+set estwork(rtree2.test) 758
+set estwork(rtree6.test) 6
+set estwork(rtree8.test) 15
+set estwork(rtree9.test) 15
+set estwork(rtreeA.test) 7
+set estwork(rtreeB.test) 7
+set estwork(rtreeE.test) 47
+set estwork(rtreeH.test) 24
+set estwork(rtreecheck.test) 2
+set estwork(rtreedoc.test) 8
+set estwork(rtreedoc3.test) 76
+set estwork(savepoint.test) 10
+set estwork(savepoint2.test) 57
+set estwork(schema2.test) 15
+set estwork(schema3.test) 2
+set estwork(schema5.test) 5
+set estwork(select1.test) 2
+set estwork(select2.test) 17
+set estwork(select3.test) 2
+set estwork(selectA.test) 2
+set estwork(selectB.test) 2
+set estwork(selectG.test) 30
+set estwork(session1.test) 5
+set estwork(session2.test) 33
+set estwork(session5.test) 63
+set estwork(session9.test) 3
+set estwork(sessionG.test) 60
+set estwork(sessionH.test) 18
+set estwork(sessionalter.test) 3
+set estwork(sessionat.test) 2
+set estwork(sessionblob.test) 3
+set {estwork(sessionfuzz sessionfuzz-data1.db)} 5
+set estwork(sessioninvert.test) 2
+set estwork(sessionnoop.test) 2
+set estwork(sessionnoop2.test) 8
+set estwork(sessionrebase.test) 8
+set estwork(shared.test) 7
+set estwork(sharedA.test) 48
+set estwork(shell1.test) 36
+set estwork(shell2.test) 11
+set estwork(shell3.test) 3
+set estwork(shell4.test) 2
+set estwork(shell5.test) 16
+set estwork(shell6.test) 3
+set estwork(shell8.test) 104
+set estwork(shell9.test) 3
+set estwork(shellA.test) 2
+set estwork(shmlock.test) 27
+set estwork(sidedelete.test) 10
+set estwork(skipscan1.test) 7
+set estwork(skipscan2.test) 5
+set estwork(sort.test) 38
+set estwork(sort2.test) 540
+set estwork(sort5.test) 16
+set estwork(spellfix.test) 5
+set estwork(spellfix2.test) 5
+set estwork(spellfix4.test) 11
+set estwork(starschema1.test) 2
+set estwork(strict1.test) 5
+set estwork(swarmvtab.test) 110
+set estwork(swarmvtab3.test) 14
+set estwork(syscall.test) 4
+set estwork(table.test) 62
+set estwork(tableapi.test) 8
+set estwork(tcl) 1
+set estwork(tclsqlite.test) 29
+set estwork(temptable2.test) 274
+set estwork(thread3.test) 21
+set estwork(timediff1.test) 5
+set estwork(tkt-2d1a5c67d.test) 6
+set estwork(tkt-38cb5df375.test) 2
+set estwork(tkt-4dd95f6943.test) 2
+set estwork(tkt-5e10420e8d.test) 5
+set estwork(tkt-6bfb98dfc0.test) 5
+set estwork(tkt-80e031a00f.test) 25
+set estwork(tkt-9d68c883.test) 3
+set estwork(tkt-9f2eb3abac.test) 5
+set estwork(tkt-b1d3a2e531.test) 5
+set estwork(tkt-b72787b1.test) 5
+set estwork(tkt-b75a9ca6b0.test) 8
+set estwork(tkt-d11f09d36e.test) 9
+set estwork(tkt-fc62af4523.test) 10
+set estwork(tkt1435.test) 7
+set estwork(tkt1644.test) 5
+set estwork(tkt1667.test) 20
+set estwork(tkt1873.test) 2
+set estwork(tkt2192.test) 3
+set estwork(tkt2285.test) 19
+set estwork(tkt2332.test) 2
+set estwork(tkt2409.test) 24
+set estwork(tkt3334.test) 5
+set estwork(tkt3357.test) 10
+set estwork(tkt3630.test) 2
+set estwork(tkt3832.test) 8
+set estwork(tkt3838.test) 5
+set estwork(tkt3918.test) 3
+set estwork(tkt4018.test) 48
+set estwork(tokenize.test) 9
+set estwork(tpch01.test) 6
+set estwork(trans.test) 258
+set estwork(trigger2.test) 15
+set estwork(trigger5.test) 2
+set estwork(trigger8.test) 30
+set estwork(triggerA.test) 36
+set estwork(triggerB.test) 4
+set estwork(triggerC.test) 67
+set estwork(triggerD.test) 3
+set estwork(types.test) 2
+set estwork(types2.test) 2
+set estwork(unionall2.test) 9
+set estwork(unionvtab.test) 2
+set estwork(update.test) 7
+set estwork(upsert3.test) 6
+set estwork(upsert5.test) 5
+set estwork(vacuum.test) 2
+set estwork(vacuum5.test) 3
+set estwork(vacuum6.test) 174
+set estwork(vacuummem.test) 132
+set estwork(varint.test) 8
+set estwork(view.test) 2
+set estwork(vtab1.test) 13
+set estwork(vtab6.test) 12
+set estwork(vtabC.test) 33
+set estwork(vtabD.test) 56
+set estwork(vtab_alter.test) 6
+set estwork(wal.test) 38
+set estwork(wal2.test) 7
+set estwork(wal3.test) 196
+set estwork(wal4.test) 70
+set estwork(wal5.test) 22
+set estwork(wal64k.test) 20
+set estwork(wal7.test) 3
+set estwork(wal9.test) 24
+set estwork(walbak.test) 2
+set estwork(walcksum.test) 3
+set estwork(walcrash4.test) 59
+set estwork(waloverwrite.test) 3
+set estwork(walpersist.test) 6
+set estwork(walprotocol2.test) 2
+set estwork(walro2.test) 11
+set estwork(walsetlk.test) 1610
+set estwork(walsetlk3.test) 3
+set estwork(walsetlk_recover.test) 193
+set estwork(walshared.test) 5
+set estwork(walvfs.test) 476
+set estwork(where.test) 24
+set estwork(where3.test) 4
+set estwork(where6.test) 2
+set estwork(where7.test) 20
+set estwork(where8.test) 95
+set estwork(where9.test) 16
+set estwork(whereB.test) 5
+set estwork(whereE.test) 6
+set estwork(whereN.test) 2
+set estwork(window1.test) 5
+set estwork(window2.test) 8
+set estwork(window3.test) 89
+set estwork(window4.test) 3
+set estwork(window5.test) 2
+set estwork(window8.test) 33
+set estwork(windowA.test) 5
+set estwork(windowD.test) 6
+set estwork(with1.test) 114
+set estwork(with2.test) 4
+set estwork(with5.test) 2
+set estwork(withM.test) 4
+set estwork(without_rowid1.test) 2
+set estwork(without_rowid3.test) 9
+set estwork(without_rowid4.test) 6