mirror of
https://github.com/sqlite/sqlite.git
synced 2026-01-06 08:01:16 +03:00
Export sqlite3_trace_v2() to wasm and use it to ensure that the new per-VFS post-open SQL support in the DB ctor works. Default opfs vfs to journal_mode=truncate, as it's faster in that mode. Add 't' DB open-mode flag to enable SQL tracing to console.log().
FossilOrigin-Name: 508f7f6d63e52f61fae5abe817579a4e130fa7fbd18733d741d521a5bdabb7ce
This commit is contained in:
@@ -74,6 +74,7 @@ _sqlite3_strglob
|
||||
_sqlite3_strlike
|
||||
_sqlite3_total_changes
|
||||
_sqlite3_total_changes64
|
||||
_sqlite3_trace_v2
|
||||
_sqlite3_uri_boolean
|
||||
_sqlite3_uri_int64
|
||||
_sqlite3_uri_key
|
||||
|
||||
@@ -621,7 +621,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
for(const t of ['access', 'blobFinalizers', 'dataTypes',
|
||||
'encodings', 'fcntl', 'flock', 'ioCap',
|
||||
'openFlags', 'prepareFlags', 'resultCodes',
|
||||
'serialize', 'syncFlags', 'udfFlags',
|
||||
'serialize', 'syncFlags', 'trace', 'udfFlags',
|
||||
'version'
|
||||
]){
|
||||
for(const e of Object.entries(wasm.ctype[t])){
|
||||
|
||||
@@ -61,6 +61,25 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
sqlite3_trace_v2() callback which gets installed by the DB ctor
|
||||
if its open-flags contain "t".
|
||||
*/
|
||||
const __dbTraceToConsole =
|
||||
wasm.installFunction('i(ippp)', function(t,c,p,x){
|
||||
if(capi.SQLITE_TRACE_STMT===t){
|
||||
// x == SQL, p == sqlite3_stmt*
|
||||
console.log("SQL TRACE #"+(++this.counter),
|
||||
wasm.cstringToJs(x));
|
||||
}
|
||||
}.bind({counter: 0}));
|
||||
|
||||
/**
|
||||
A map of sqlite3_vfs pointers to SQL code to run when the DB
|
||||
constructor opens a database with the given VFS.
|
||||
*/
|
||||
const __vfsPostOpenSql = Object.create(null);
|
||||
|
||||
/**
|
||||
A proxy for DB class constructors. It must be called with the
|
||||
being-construct DB object as its "this". See the DB constructor
|
||||
@@ -101,12 +120,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
? (n)=>toss3("The VFS for",n,"is only available in the main window thread.")
|
||||
: false;
|
||||
ctor._name2vfs[':localStorage:'] = {
|
||||
vfs: 'kvvfs',
|
||||
filename: isWorkerThread || (()=>'local')
|
||||
vfs: 'kvvfs', filename: isWorkerThread || (()=>'local')
|
||||
};
|
||||
ctor._name2vfs[':sessionStorage:'] = {
|
||||
vfs: 'kvvfs',
|
||||
filename: isWorkerThread || (()=>'session')
|
||||
vfs: 'kvvfs', filename: isWorkerThread || (()=>'session')
|
||||
};
|
||||
}
|
||||
const opt = ctor.normalizeArgs(...args);
|
||||
@@ -123,7 +140,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
vfsName = vfsCheck.vfs;
|
||||
fn = fnJs = vfsCheck.filename(fnJs);
|
||||
}
|
||||
let ptr, oflags = 0;
|
||||
let pDb, oflags = 0;
|
||||
if( flagsStr.indexOf('c')>=0 ){
|
||||
oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
|
||||
}
|
||||
@@ -132,24 +149,48 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
oflags |= capi.SQLITE_OPEN_EXRESCODE;
|
||||
const scope = wasm.scopedAllocPush();
|
||||
try {
|
||||
const ppDb = wasm.allocPtr() /* output (sqlite3**) arg */;
|
||||
const pPtr = wasm.allocPtr() /* output (sqlite3**) arg */;
|
||||
const pVfsName = vfsName ? (
|
||||
('number'===typeof vfsName ? vfsName : wasm.scopedAllocCString(vfsName))
|
||||
): 0;
|
||||
const rc = capi.sqlite3_open_v2(fn, ppDb, oflags, pVfsName);
|
||||
ptr = wasm.getPtrValue(ppDb);
|
||||
checkSqlite3Rc(ptr, rc);
|
||||
let rc = capi.sqlite3_open_v2(fn, pPtr, oflags, pVfsName);
|
||||
pDb = wasm.getPtrValue(pPtr);
|
||||
checkSqlite3Rc(pDb, rc);
|
||||
if(flagsStr.indexOf('t')>=0){
|
||||
capi.sqlite3_trace_v2(pDb, capi.SQLITE_TRACE_STMT,
|
||||
__dbTraceToConsole, 0);
|
||||
}
|
||||
// Check for per-VFS post-open SQL...
|
||||
wasm.setPtrValue(pPtr, 0);
|
||||
if(0===capi.sqlite3_file_control(
|
||||
pDb, "main", capi.SQLITE_FCNTL_VFS_POINTER, pPtr
|
||||
)){
|
||||
const postInitSql = __vfsPostOpenSql[wasm.getPtrValue(pPtr)];
|
||||
if(postInitSql){
|
||||
rc = capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0);
|
||||
checkSqlite3Rc(pDb, rc);
|
||||
}
|
||||
}
|
||||
}catch( e ){
|
||||
if( ptr ) capi.sqlite3_close_v2(ptr);
|
||||
if( pDb ) capi.sqlite3_close_v2(pDb);
|
||||
throw e;
|
||||
}finally{
|
||||
wasm.scopedAllocPop(scope);
|
||||
}
|
||||
this.filename = fnJs;
|
||||
__ptrMap.set(this, ptr);
|
||||
__ptrMap.set(this, pDb);
|
||||
__stmtMap.set(this, Object.create(null));
|
||||
};
|
||||
|
||||
/**
|
||||
Sets SQL which should be exec()'d on a DB instance after it is
|
||||
opened with the given VFS pointer. This is intended only for use
|
||||
by DB subclasses or sqlite3_vfs implementations.
|
||||
*/
|
||||
dbCtorHelper.setVfsPostOpenSql = function(pVfs, sql){
|
||||
__vfsPostOpenSql[pVfs] = sql;
|
||||
};
|
||||
|
||||
/**
|
||||
A helper for DB constructors. It accepts either a single
|
||||
config-style object or up to 3 arguments (filename, dbOpenFlags,
|
||||
@@ -175,7 +216,6 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
}
|
||||
return arg;
|
||||
};
|
||||
|
||||
/**
|
||||
The DB class provides a high-level OO wrapper around an sqlite3
|
||||
db handle.
|
||||
@@ -193,14 +233,18 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
database. It must be string containing a sequence of letters (in
|
||||
any order, but case sensitive) specifying the mode:
|
||||
|
||||
- "c" => create if it does not exist, else fail if it does not
|
||||
- "c": create if it does not exist, else fail if it does not
|
||||
exist. Implies the "w" flag.
|
||||
|
||||
- "w" => write. Implies "r": a db cannot be write-only.
|
||||
- "w": write. Implies "r": a db cannot be write-only.
|
||||
|
||||
- "r" => read-only if neither "w" nor "c" are provided, else it
|
||||
- "r": read-only if neither "w" nor "c" are provided, else it
|
||||
is ignored.
|
||||
|
||||
- "t": enable tracing of SQL executed on this database handle,
|
||||
sending it to `console.log()`. Once enabled, it cannot
|
||||
currently be easily switched off (TODO).
|
||||
|
||||
If "w" is not provided, the db is implicitly read-only, noting that
|
||||
"rc" is meaningless
|
||||
|
||||
@@ -229,16 +273,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
`sqlite3*` pointer value. That property can also be used to check
|
||||
whether this DB instance is still open.
|
||||
|
||||
|
||||
EXPERIMENTAL: in the main window thread, the filenames
|
||||
":localStorage:" and ":sessionStorage:" are special: they cause
|
||||
the db to use either localStorage or sessionStorage for storing
|
||||
the database. In this mode, only a single database is permitted
|
||||
in each storage object. This feature is experimental and subject
|
||||
to any number of changes (including outright removal). This
|
||||
support requires the kvvfs sqlite3 VFS, the existence of which
|
||||
can be determined at runtime by checking for a non-0 return value
|
||||
from sqlite3.capi.sqlite3_vfs_find("kvvfs").
|
||||
In the main window thread, the filenames ":localStorage:" and
|
||||
":sessionStorage:" are special: they cause the db to use either
|
||||
localStorage or sessionStorage for storing the database using
|
||||
the kvvfs.
|
||||
*/
|
||||
const DB = function(...args){
|
||||
dbCtorHelper.apply(this, args);
|
||||
|
||||
@@ -898,8 +898,14 @@ const installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri){
|
||||
sqlite3.oo1.dbCtorHelper.call(this, opt);
|
||||
};
|
||||
opfsUtil.OpfsDb.prototype = Object.create(sqlite3.oo1.DB.prototype);
|
||||
sqlite3.oo1.dbCtorHelper.setVfsPostOpenSql(
|
||||
opfsVfs.pointer,
|
||||
/* Truncate journal mode is faster than delete or wal for
|
||||
OPFS, per speedtest1. */
|
||||
"pragma journal_mode=truncate"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Potential TODOs:
|
||||
|
||||
@@ -907,7 +913,6 @@ const installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri){
|
||||
publish an interface for proxying the higher-level OPFS
|
||||
features like getting a directory listing.
|
||||
*/
|
||||
|
||||
const sanityCheck = function(){
|
||||
const scope = wasm.scopedAllocPush();
|
||||
const sq3File = new sqlite3_file();
|
||||
|
||||
@@ -815,6 +815,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
["sqlite3_step", "int", "sqlite3_stmt*"],
|
||||
["sqlite3_strglob", "int", "string","string"],
|
||||
["sqlite3_strlike", "int", "string","string","int"],
|
||||
["sqlite3_trace_v2", "int", "sqlite3*", "int", "*", "*"],
|
||||
["sqlite3_total_changes", "int", "sqlite3*"],
|
||||
["sqlite3_uri_boolean", "int", "string", "string", "int"],
|
||||
["sqlite3_uri_key", "string", "string", "int"],
|
||||
|
||||
@@ -527,6 +527,13 @@ const char * sqlite3_wasm_enum_json(void){
|
||||
DefInt(SQLITE_SYNC_DATAONLY);
|
||||
} _DefGroup;
|
||||
|
||||
DefGroup(trace) {
|
||||
DefInt(SQLITE_TRACE_STMT);
|
||||
DefInt(SQLITE_TRACE_PROFILE);
|
||||
DefInt(SQLITE_TRACE_ROW);
|
||||
DefInt(SQLITE_TRACE_CLOSE);
|
||||
} _DefGroup;
|
||||
|
||||
DefGroup(udfFlags) {
|
||||
DefInt(SQLITE_DETERMINISTIC);
|
||||
DefInt(SQLITE_DIRECTONLY);
|
||||
@@ -680,6 +687,28 @@ int sqlite3_wasm_vfs_unlink(const char * zName){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is NOT part of the sqlite3 public API. It is strictly
|
||||
** for use by the sqlite project's own JS/WASM bindings.
|
||||
**
|
||||
** This function resets the given db pointer's database as described at
|
||||
**
|
||||
** https://www.sqlite.org/c3ref/c_dbconfig_defensive.html#sqlitedbconfigresetdatabase
|
||||
**
|
||||
** Returns 0 on success, an SQLITE_xxx code on error. Returns
|
||||
** SQLITE_MISUSE if pDb is NULL.
|
||||
*/
|
||||
WASM_KEEP
|
||||
int sqlite3_wasm_db_reset(sqlite3*pDb){
|
||||
int rc = SQLITE_MISUSE;
|
||||
if( pDb ){
|
||||
rc = sqlite3_db_config(pDb, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);
|
||||
if( 0==rc ) rc = sqlite3_exec(pDb, "VACUUM", 0, 0, 0);
|
||||
sqlite3_db_config(pDb, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Uses the current database's VFS xRead to stream the db file's
|
||||
** contents out to the given callback. The callback gets a single
|
||||
|
||||
Reference in New Issue
Block a user