mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
wasm: introduce the sqlite3.oo1.DB.wrapHandle() and Stmt.wrapHandle() APIs, which enable clients to wrap (sqlite3*) resp. (sqlite3_stmt*) pointers in their oo1 API counterparts, optionally with or without taking over ownership of the pointer.
FossilOrigin-Name: e5d079549594ca44852773b8919894866394e47ad725dadc7f65242413a219d3
This commit is contained in:
@ -429,7 +429,7 @@ define SQLITE.CALL.C-PP.FILTER
|
|||||||
$(2): $(1) $$(MAKEFILE_LIST) $$(bin.c-pp)
|
$(2): $(1) $$(MAKEFILE_LIST) $$(bin.c-pp)
|
||||||
@mkdir -p $$(dir $$@)
|
@mkdir -p $$(dir $$@)
|
||||||
$$(bin.c-pp) -f $(1) -o $$@ $(3) $(SQLITE.CALL.C-PP.FILTER.global)
|
$$(bin.c-pp) -f $(1) -o $$@ $(3) $(SQLITE.CALL.C-PP.FILTER.global)
|
||||||
#CLEAN_FILES += $(2)
|
CLEAN_FILES += $(2)
|
||||||
endef
|
endef
|
||||||
# /end SQLITE.CALL.C-PP.FILTER
|
# /end SQLITE.CALL.C-PP.FILTER
|
||||||
########################################################################
|
########################################################################
|
||||||
|
@ -37,6 +37,21 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
it.
|
it.
|
||||||
*/
|
*/
|
||||||
const __ptrMap = new WeakMap();
|
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
|
Map of DB instances to objects, each object being a map of Stmt
|
||||||
wasm pointers to Stmt objects.
|
wasm pointers to Stmt objects.
|
||||||
@ -234,73 +249,89 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
const opt = ctor.normalizeArgs(...args);
|
const opt = ctor.normalizeArgs(...args);
|
||||||
let fn = opt.filename, vfsName = opt.vfs, flagsStr = opt.flags;
|
//sqlite3.config.debug("DB ctor",opt);
|
||||||
if(('string'!==typeof fn && 'number'!==typeof fn)
|
let pDb;
|
||||||
|| 'string'!==typeof flagsStr
|
if( (pDb = opt['sqlite3*']) ){
|
||||||
|| (vfsName && ('string'!==typeof vfsName && 'number'!==typeof vfsName))){
|
/* This property ^^^^^ is very specifically NOT DOCUMENTED and
|
||||||
sqlite3.config.error("Invalid DB ctor args",opt,arguments);
|
NOT part of the public API. This is a back door for functions
|
||||||
toss3("Invalid arguments for DB constructor.");
|
like DB.wrapDbHandle(). */
|
||||||
}
|
//sqlite3.config.debug("creating proxy db from",opt);
|
||||||
let fnJs = ('number'===typeof fn) ? wasm.cstrToJs(fn) : fn;
|
if( !opt['sqlite3*:takeOwnership'] ){
|
||||||
const vfsCheck = ctor._name2vfs[fnJs];
|
/* This is object does not own its handle. */
|
||||||
if(vfsCheck){
|
__doesNotOwnHandle.add(this);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}catch( e ){
|
this.filename = capi.sqlite3_db_filename(pDb,'main');
|
||||||
if( pDb ) capi.sqlite3_close_v2(pDb);
|
}else{
|
||||||
throw e;
|
let fn = opt.filename, vfsName = opt.vfs, flagsStr = opt.flags;
|
||||||
}finally{
|
if(('string'!==typeof fn && 'number'!==typeof fn)
|
||||||
wasm.pstack.restore(stack);
|
|| '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);
|
__ptrMap.set(this, pDb);
|
||||||
__stmtMap.set(this, Object.create(null));
|
__stmtMap.set(this, Object.create(null));
|
||||||
try{
|
if( !opt['sqlite3*'] ){
|
||||||
|
try{
|
||||||
//#if enable-see
|
//#if enable-see
|
||||||
dbCtorApplySEEKey(this,opt);
|
dbCtorApplySEEKey(this,opt);
|
||||||
//#endif
|
//#endif
|
||||||
// Check for per-VFS post-open SQL/callback...
|
// Check for per-VFS post-open SQL/callback...
|
||||||
const pVfs = capi.sqlite3_js_db_vfs(pDb)
|
const pVfs = capi.sqlite3_js_db_vfs(pDb)
|
||||||
|| toss3("Internal error: cannot get VFS for new db handle.");
|
|| toss3("Internal error: cannot get VFS for new db handle.");
|
||||||
const postInitSql = __vfsPostOpenCallback[pVfs];
|
const postInitSql = __vfsPostOpenCallback[pVfs];
|
||||||
if(postInitSql){
|
if(postInitSql){
|
||||||
/**
|
/**
|
||||||
Reminder: if this db is encrypted and the client did _not_ pass
|
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.
|
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
|
We don't actually know whether the db is encrypted, so we cannot
|
||||||
sensibly apply any heuristics which skip the init code only for
|
sensibly apply any heuristics which skip the init code only for
|
||||||
encrypted databases for which no key has yet been supplied.
|
encrypted databases for which no key has yet been supplied.
|
||||||
*/
|
*/
|
||||||
if(postInitSql instanceof Function){
|
if(postInitSql instanceof Function){
|
||||||
postInitSql(this, sqlite3);
|
postInitSql(this, sqlite3);
|
||||||
}else{
|
}else{
|
||||||
checkSqlite3Rc(
|
checkSqlite3Rc(
|
||||||
pDb, capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0)
|
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
|
- `vfs`: the VFS fname
|
||||||
|
|
||||||
//#if enable-see
|
//#if enable-see
|
||||||
|
|
||||||
SEE-capable builds optionally support ONE of the following
|
SEE-capable builds optionally support ONE of the following
|
||||||
additional options:
|
additional options:
|
||||||
|
|
||||||
@ -429,7 +459,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
is supplied and the database is encrypted, execution of the
|
is supplied and the database is encrypted, execution of the
|
||||||
post-initialization SQL will fail, causing the constructor to
|
post-initialization SQL will fail, causing the constructor to
|
||||||
throw.
|
throw.
|
||||||
|
|
||||||
//#endif enable-see
|
//#endif enable-see
|
||||||
|
|
||||||
The `filename` and `vfs` arguments may be either JS strings or
|
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.
|
Internal-use enum for mapping JS types to DB-bindable types.
|
||||||
These do not (and need not) line up with the SQLITE_type
|
These do not (and need not) line up with the SQLITE_type
|
||||||
values. All values in this enum must be truthy and distinct
|
values. All values in this enum must be truthy and (mostly)
|
||||||
but they need not be numbers.
|
distinct but they need not be numbers.
|
||||||
*/
|
*/
|
||||||
const BindTypes = {
|
const BindTypes = {
|
||||||
null: 1,
|
null: 1,
|
||||||
@ -467,7 +496,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
boolean: 4,
|
boolean: 4,
|
||||||
blob: 5
|
blob: 5
|
||||||
};
|
};
|
||||||
BindTypes['undefined'] == BindTypes.null;
|
|
||||||
if(wasm.bigIntEnabled){
|
if(wasm.bigIntEnabled){
|
||||||
BindTypes.bigint = BindTypes.number;
|
BindTypes.bigint = BindTypes.number;
|
||||||
}
|
}
|
||||||
@ -486,26 +514,30 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
- `db`: the DB object which created the statement.
|
- `db`: the DB object which created the statement.
|
||||||
|
|
||||||
- `columnCount`: the number of result columns in the query, or 0
|
- `columnCount`: the number of result columns in the query, or 0
|
||||||
for queries which cannot return results. This property is a proxy
|
for queries which cannot return results. This property is a
|
||||||
for sqlite3_column_count() and its use in loops should be avoided
|
read-only proxy for sqlite3_column_count() and its use in loops
|
||||||
because of the call overhead associated with that. The
|
should be avoided because of the call overhead associated with
|
||||||
`columnCount` is not cached when the Stmt is created because a
|
that. The `columnCount` is not cached when the Stmt is created
|
||||||
schema change made via a separate db connection between this
|
because a schema change made between this statement's preparation
|
||||||
statement's preparation and when it is stepped may invalidate it.
|
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
|
As a general rule, most methods of this class will throw if
|
||||||
called on an instance which has been finalized. For brevity's
|
called on an instance which has been finalized. For brevity's
|
||||||
sake, the method docs do not all repeat this warning.
|
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]){
|
if(BindTypes!==arguments[2]){
|
||||||
toss3(capi.SQLITE_MISUSE, "Do not call the Stmt constructor directly. Use DB.prepare().");
|
toss3(capi.SQLITE_MISUSE, "Do not call the Stmt constructor directly. Use DB.prepare().");
|
||||||
}
|
}
|
||||||
this.db = arguments[0];
|
this.db = arguments[0];
|
||||||
__ptrMap.set(this, arguments[1]);
|
__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. */
|
/** 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
|
Finalizes all open statements and closes this database
|
||||||
connection. This is a no-op if the db has already been
|
connection (with one exception noted below). This is a no-op if
|
||||||
closed. After calling close(), `this.pointer` will resolve to
|
the db has already been closed. After calling close(),
|
||||||
`undefined`, so that can be used to check whether the db
|
`this.pointer` will resolve to `undefined`, and that can be
|
||||||
instance is still opened.
|
used to check whether the db instance is still opened.
|
||||||
|
|
||||||
If this.onclose.before is a function then it is called before
|
If this.onclose.before is a function then it is called before
|
||||||
any close-related cleanup.
|
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
|
all, will never trigger close(), so onclose handlers are not a
|
||||||
reliable way to implement close-time cleanup or maintenance of
|
reliable way to implement close-time cleanup or maintenance of
|
||||||
a db.
|
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(){
|
close: function(){
|
||||||
if(this.pointer){
|
const pDb = this.pointer;
|
||||||
|
if(pDb){
|
||||||
if(this.onclose && (this.onclose.before instanceof Function)){
|
if(this.onclose && (this.onclose.before instanceof Function)){
|
||||||
try{this.onclose.before(this)}
|
try{this.onclose.before(this)}
|
||||||
catch(e){/*ignore*/}
|
catch(e){/*ignore*/}
|
||||||
}
|
}
|
||||||
const pDb = this.pointer;
|
|
||||||
Object.keys(__stmtMap.get(this)).forEach((k,s)=>{
|
Object.keys(__stmtMap.get(this)).forEach((k,s)=>{
|
||||||
if(s && s.pointer){
|
if(s && s.pointer){
|
||||||
try{s.finalize()}
|
try{s.finalize()}
|
||||||
@ -737,7 +774,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
});
|
});
|
||||||
__ptrMap.delete(this);
|
__ptrMap.delete(this);
|
||||||
__stmtMap.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)){
|
if(this.onclose && (this.onclose.after instanceof Function)){
|
||||||
try{this.onclose.after(this)}
|
try{this.onclose.after(this)}
|
||||||
catch(e){/*ignore*/}
|
catch(e){/*ignore*/}
|
||||||
@ -1450,9 +1489,63 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
*/
|
*/
|
||||||
checkRc: function(resultCode){
|
checkRc: function(resultCode){
|
||||||
return checkSqlite3Rc(this, resultCode);
|
return checkSqlite3Rc(this, resultCode);
|
||||||
}
|
},
|
||||||
}/*DB.prototype*/;
|
}/*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
|
/** Throws if the given Stmt has been finalized, else stmt is
|
||||||
returned. */
|
returned. */
|
||||||
@ -1474,8 +1567,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
case BindTypes.string:
|
case BindTypes.string:
|
||||||
return t;
|
return t;
|
||||||
case BindTypes.bigint:
|
case BindTypes.bigint:
|
||||||
if(wasm.bigIntEnabled) return t;
|
return wasm.bigIntEnabled ? t : undefined;
|
||||||
/* else fall through */
|
|
||||||
default:
|
default:
|
||||||
return util.isBindableTypedArray(v) ? BindTypes.blob : undefined;
|
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
|
This method always throws if called when it is illegal to do
|
||||||
so. Namely, when triggered via a per-row callback handler of a
|
so. Namely, when triggered via a per-row callback handler of a
|
||||||
DB.exec() call.
|
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(){
|
finalize: function(){
|
||||||
if(this.pointer){
|
const ptr = this.pointer;
|
||||||
|
if(ptr){
|
||||||
affirmNotLockedByExec(this,'finalize()');
|
affirmNotLockedByExec(this,'finalize()');
|
||||||
const rc = capi.sqlite3_finalize(this.pointer);
|
const rc = (__doesNotOwnHandle.delete(this)
|
||||||
delete __stmtMap.get(this.db)[this.pointer];
|
? 0
|
||||||
|
: capi.sqlite3_finalize(ptr));
|
||||||
|
delete __stmtMap.get(this.db)[ptr];
|
||||||
__ptrMap.delete(this);
|
__ptrMap.delete(this);
|
||||||
__execLock.delete(this);
|
__execLock.delete(this);
|
||||||
__stmtMayGet.delete(this);
|
__stmtMayGet.delete(this);
|
||||||
@ -2134,6 +2233,64 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
set: ()=>toss3("The columnCount property is read-only.")
|
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. */
|
/** The OO API's public namespace. */
|
||||||
sqlite3.oo1 = {
|
sqlite3.oo1 = {
|
||||||
DB,
|
DB,
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
ES6 worker module build:
|
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
|
//#if target=es6-module
|
||||||
import {default as sqlite3InitModule} from './jswasm/sqlite3.mjs';
|
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(filter instanceof Function) pass = filter(err);
|
||||||
else if('string' === typeof filter) pass = (err.message === filter);
|
else if('string' === typeof filter) pass = (err.message === filter);
|
||||||
if(!pass){
|
if(!pass){
|
||||||
throw new Error(msg || ("Filter rejected this exception: "+err.message));
|
throw new Error(msg || ("Filter rejected this exception: <<"+err.message+">>"));
|
||||||
}
|
}
|
||||||
return this;
|
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){
|
.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);
|
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/)
|
/columnCount property is read-only/)
|
||||||
.assert(1===st.columnCount)
|
.assert(1===st.columnCount)
|
||||||
.assert(0===st.parameterCount)
|
.assert(0===st.parameterCount)
|
||||||
|
.assert(0===capi.sqlite3_bind_parameter_count(st))
|
||||||
.mustThrow(()=>st.bind(1,null))
|
.mustThrow(()=>st.bind(1,null))
|
||||||
.assert(true===st.step())
|
.assert(true===st.step())
|
||||||
.assert(3 === st.get(0))
|
.assert(3 === st.get(0))
|
||||||
@ -1490,6 +1589,8 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
|||||||
let st = db.prepare("update t set b=:b where a='blob'");
|
let st = db.prepare("update t set b=:b where a='blob'");
|
||||||
try {
|
try {
|
||||||
T.assert(0===st.columnCount)
|
T.assert(0===st.columnCount)
|
||||||
|
.assert(1===st.parameterCount)
|
||||||
|
.assert(1===capi.sqlite3_bind_parameter_count(st))
|
||||||
.assert( false===st.isReadOnly() );
|
.assert( false===st.isReadOnly() );
|
||||||
const ndx = st.getParamIndex(':b');
|
const ndx = st.getParamIndex(':b');
|
||||||
T.assert(1===ndx);
|
T.assert(1===ndx);
|
||||||
@ -3329,6 +3430,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
|||||||
db.exec("create table t(a)");
|
db.exec("create table t(a)");
|
||||||
const stmt = db.prepare("insert into t(a) values($a)");
|
const stmt = db.prepare("insert into t(a) values($a)");
|
||||||
T.assert( 1===capi.sqlite3_bind_parameter_count(stmt) )
|
T.assert( 1===capi.sqlite3_bind_parameter_count(stmt) )
|
||||||
|
.assert( 1===stmt.parameterCount )
|
||||||
.assert( 1===capi.sqlite3_bind_parameter_index(stmt, "$a") )
|
.assert( 1===capi.sqlite3_bind_parameter_index(stmt, "$a") )
|
||||||
.assert( 0===capi.sqlite3_bind_parameter_index(stmt, ":a") )
|
.assert( 0===capi.sqlite3_bind_parameter_index(stmt, ":a") )
|
||||||
.assert( 1===stmt.getParamIndex("$a") )
|
.assert( 1===stmt.getParamIndex("$a") )
|
||||||
|
19
manifest
19
manifest
@ -1,5 +1,5 @@
|
|||||||
C Additional\sheader\scomment\sdocumentation\sin\sthe\sext/misc/vtablog.c\stest\sextension.
|
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-11T17:02:11.169
|
D 2025-07-11T19:52:36.729
|
||||||
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
|
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
|
||||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||||
@ -621,7 +621,7 @@ F ext/session/sqlite3session.c 6b0877fe1ab832aa4b85eaca72606dfd1630a1363a1be7af1
|
|||||||
F ext/session/sqlite3session.h 9bb1a6687b467764b35178dc29bbd2c57ab8cd3acdc8a62f088c34ad17e4fe2b
|
F ext/session/sqlite3session.h 9bb1a6687b467764b35178dc29bbd2c57ab8cd3acdc8a62f088c34ad17e4fe2b
|
||||||
F ext/session/test_session.c 2ddff73ea368d827028c32851b291416e1008845832feb27b751d15e57e13cc3
|
F ext/session/test_session.c 2ddff73ea368d827028c32851b291416e1008845832feb27b751d15e57e13cc3
|
||||||
F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c
|
F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c
|
||||||
F ext/wasm/GNUmakefile fa694fe78fc0acfd4406a36133ce4aff8820e086f4dd5f1473d2fafce590ab64
|
F ext/wasm/GNUmakefile d62af1b0914eb2e03fa6e4e75e93acadc8f4faeb2d56335da25d61b9ea144c53
|
||||||
F ext/wasm/README-dist.txt f01081a850ce38a56706af6b481e3a7878e24e42b314cfcd4b129f0f8427066a
|
F ext/wasm/README-dist.txt f01081a850ce38a56706af6b481e3a7878e24e42b314cfcd4b129f0f8427066a
|
||||||
F ext/wasm/README.md b89605f65661cf35bf034ff6d43e448cc169b8017fc105d498e33b81218b482c
|
F ext/wasm/README.md b89605f65661cf35bf034ff6d43e448cc169b8017fc105d498e33b81218b482c
|
||||||
F ext/wasm/SQLTester/GNUmakefile e0794f676d55819951bbfae45cc5e8d7818dc460492dc317ce7f0d2eca15caff
|
F ext/wasm/SQLTester/GNUmakefile e0794f676d55819951bbfae45cc5e8d7818dc460492dc317ce7f0d2eca15caff
|
||||||
@ -641,7 +641,7 @@ F ext/wasm/api/post-js-header.js 53740d824e5d9027eb1e6fd59e216abbd2136740ce260ea
|
|||||||
F ext/wasm/api/pre-js.c-pp.js a614a2c82b12c4d96d8e3ba77330329efc53c4d56a8a7e60ade900f341866cfb
|
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-cleanup.js 3ac1786e461ada63033143be8c3b00b26b939540661f3e839515bb92f2e35359
|
||||||
F ext/wasm/api/sqlite3-api-glue.c-pp.js 0b76510f3650053bac67ca8947cb6ab9d050ad2218118a2e7796dd37be832ffa
|
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-oo1.c-pp.js f59e59f0d94ba5835c6b7fc9b800a4aa5084e1224721a07e3cd6cc7fef1789c2
|
||||||
F ext/wasm/api/sqlite3-api-prologue.js 4f1c2a9dc9caf631907766e9872c27d11b255ccae779e8af01c7f8b932817214
|
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-api-worker1.c-pp.js f646a65257973b8c4481f8a6a216370b85644f23e64b126e7ae113570587c0ab
|
||||||
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
|
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
|
||||||
@ -698,7 +698,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
|
|||||||
F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f809baaaca1a00c
|
F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f809baaaca1a00c
|
||||||
F ext/wasm/tester1-worker.html ebc4b820a128963afce328ecf63ab200bd923309eb939f4110510ab449e9814c
|
F ext/wasm/tester1-worker.html ebc4b820a128963afce328ecf63ab200bd923309eb939f4110510ab449e9814c
|
||||||
F ext/wasm/tester1.c-pp.html 1c1bc78b858af2019e663b1a31e76657b73dc24bede28ca92fbe917c3a972af2
|
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/index.html 657578a6e9ce1e9b8be951549ed93a6a471f4520a99e5b545928668f4285fb5e
|
||||||
F ext/wasm/tests/opfs/concurrency/test.js d08889a5bb6e61937d0b8cbb78c9efbefbf65ad09f510589c779b7cc6a803a88
|
F ext/wasm/tests/opfs/concurrency/test.js d08889a5bb6e61937d0b8cbb78c9efbefbf65ad09f510589c779b7cc6a803a88
|
||||||
F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2
|
F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2
|
||||||
@ -2212,8 +2212,9 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350
|
|||||||
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
|
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
|
||||||
F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
|
F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
|
||||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||||
P 9d68971c58261bce72b49c574cf07ad31add62bee814c58840b927fed7eb87b1
|
P 3656acfaa3011321a6e17fb81e5bdedcfffeab6035f133ab89ae9589bf5bef72 53401b5435e30c4b47b6e203976b714d616246d734b5876a34f53f6388f872f8
|
||||||
R 5643c35e4f11fb6cf54743a0885fc1f7
|
R 6e106d1cb56322541040e2b7c468c9ad
|
||||||
U drh
|
T +closed 53401b5435e30c4b47b6e203976b714d616246d734b5876a34f53f6388f872f8 Closed\sby\sintegrate-merge.
|
||||||
Z b5fe84fd8bb20fd9110a384dcfcde9c2
|
U stephan
|
||||||
|
Z f91aebcbb3981855ba9f714a42d1af4f
|
||||||
# Remove this line to create a well-formed Fossil manifest.
|
# Remove this line to create a well-formed Fossil manifest.
|
||||||
|
@ -1 +1 @@
|
|||||||
3656acfaa3011321a6e17fb81e5bdedcfffeab6035f133ab89ae9589bf5bef72
|
e5d079549594ca44852773b8919894866394e47ad725dadc7f65242413a219d3
|
||||||
|
Reference in New Issue
Block a user