1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-29 08:01:23 +03:00

Add/apply various kvvfs-specific utility APIs to the JS layer to assist in testing and analysis. Correct a backwards default arg check for sqlite3ApiBootstrap(). Add exports for sqlite3_db_handle(), sqlite3_file_control(), and the SQLITE_FCNTL_xxx enum.

FossilOrigin-Name: 0d78961870ee9f22f1ba16d423377d28dcc36e04b1e31ffd57f3e2fd51f8f0f2
This commit is contained in:
stephan
2022-09-13 19:27:03 +00:00
parent 23d39ce54d
commit 5b91500796
13 changed files with 340 additions and 126 deletions

View File

@ -25,6 +25,7 @@ _sqlite3_compileoption_used
_sqlite3_create_function_v2 _sqlite3_create_function_v2
_sqlite3_data_count _sqlite3_data_count
_sqlite3_db_filename _sqlite3_db_filename
_sqlite3_db_handle
_sqlite3_db_name _sqlite3_db_name
_sqlite3_errmsg _sqlite3_errmsg
_sqlite3_error_offset _sqlite3_error_offset
@ -33,6 +34,7 @@ _sqlite3_exec
_sqlite3_expanded_sql _sqlite3_expanded_sql
_sqlite3_extended_errcode _sqlite3_extended_errcode
_sqlite3_extended_result_codes _sqlite3_extended_result_codes
_sqlite3_file_control
_sqlite3_finalize _sqlite3_finalize
_sqlite3_initialize _sqlite3_initialize
_sqlite3_interrupt _sqlite3_interrupt

View File

@ -20,11 +20,17 @@ if('undefined' !== typeof Module){ // presumably an Emscripten build
/** /**
Install a suitable default configuration for sqlite3ApiBootstrap(). Install a suitable default configuration for sqlite3ApiBootstrap().
*/ */
const SABC = self.sqlite3ApiBootstrap.defaultConfig; const SABC = self.sqlite3ApiConfig || Object.create(null);
SABC.Module = Module /* ==> Currently needs to be exposed here for test code. NOT part if(undefined===SABC.Module){
of the public API. */; SABC.Module = Module /* ==> Currently needs to be exposed here for
SABC.exports = Module['asm']; test code. NOT part of the public API. */;
SABC.memory = Module.wasmMemory /* gets set if built with -sIMPORT_MEMORY */; }
if(undefined===SABC.exports){
SABC.exports = Module['asm'];
}
if(undefined===SABC.memory){
SABC.memory = Module.wasmMemory /* gets set if built with -sIMPORT_MEMORY */;
}
/** /**
For current (2022-08-22) purposes, automatically call For current (2022-08-22) purposes, automatically call
@ -35,8 +41,15 @@ if('undefined' !== typeof Module){ // presumably an Emscripten build
configuration used by a no-args call to sqlite3ApiBootstrap(). configuration used by a no-args call to sqlite3ApiBootstrap().
*/ */
//console.warn("self.sqlite3ApiConfig = ",self.sqlite3ApiConfig); //console.warn("self.sqlite3ApiConfig = ",self.sqlite3ApiConfig);
const sqlite3 = self.sqlite3ApiBootstrap(); const rmApiConfig = (SABC !== self.sqlite3ApiConfig);
delete self.sqlite3ApiBootstrap; self.sqlite3ApiConfig = SABC;
let sqlite3;
try{
sqlite3 = self.sqlite3ApiBootstrap();
}finally{
delete self.sqlite3ApiBootstrap;
if(rmApiConfig) delete self.sqlite3ApiConfig;
}
if(self.location && +self.location.port > 1024){ if(self.location && +self.location.port > 1024){
console.warn("Installing sqlite3 bits as global S for local dev/test purposes."); console.warn("Installing sqlite3 bits as global S for local dev/test purposes.");

View File

@ -55,6 +55,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
*/ */
const aPtr = wasm.xWrap.argAdapter('*'); const aPtr = wasm.xWrap.argAdapter('*');
wasm.xWrap.argAdapter('sqlite3*', aPtr)('sqlite3_stmt*', aPtr); wasm.xWrap.argAdapter('sqlite3*', aPtr)('sqlite3_stmt*', aPtr);
wasm.xWrap.resultAdapter('sqlite3*', aPtr)('sqlite3_stmt*', aPtr);
/** /**
Populate api object with sqlite3_...() by binding the "raw" wasm Populate api object with sqlite3_...() by binding the "raw" wasm
@ -174,7 +175,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
wasm.ctype = JSON.parse(wasm.cstringToJs(cJson)); wasm.ctype = JSON.parse(wasm.cstringToJs(cJson));
//console.debug('wasm.ctype length =',wasm.cstrlen(cJson)); //console.debug('wasm.ctype length =',wasm.cstrlen(cJson));
for(const t of ['access', 'blobFinalizers', 'dataTypes', for(const t of ['access', 'blobFinalizers', 'dataTypes',
'encodings', 'flock', 'ioCap', 'encodings', 'fcntl', 'flock', 'ioCap',
'openFlags', 'prepareFlags', 'resultCodes', 'openFlags', 'prepareFlags', 'resultCodes',
'syncFlags', 'udfFlags', 'version' 'syncFlags', 'udfFlags', 'version'
]){ ]){

View File

@ -496,6 +496,13 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
the statement actually produces any result rows. the statement actually produces any result rows.
================================================================== ==================================================================
- `.columnNames`: if this is an array, the column names of the
result set are stored in this array before the callback (if
any) is triggered (regardless of whether the query produces any
result rows). If no statement has result columns, this value is
unchanged. Achtung: an SQL result may have multiple columns
with identical names.
- `.callback` = a function which gets called for each row of - `.callback` = a function which gets called for each row of
the result set, but only if that statement has any result the result set, but only if that statement has any result
_rows_. The callback's "this" is the options object. The second _rows_. The callback's "this" is the options object. The second
@ -523,8 +530,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
as the first argument to the callback: as the first argument to the callback:
A.1) `'array'` (the default) causes the results of A.1) `'array'` (the default) causes the results of
`stmt.get([])` to be passed to passed on and/or appended to `stmt.get([])` to be passed to the `callback` and/or appended
`resultRows`. to `resultRows`.
A.2) `'object'` causes the results of A.2) `'object'` causes the results of
`stmt.get(Object.create(null))` to be passed to the `stmt.get(Object.create(null))` to be passed to the
@ -536,7 +543,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
A.3) `'stmt'` causes the current Stmt to be passed to the A.3) `'stmt'` causes the current Stmt to be passed to the
callback, but this mode will trigger an exception if callback, but this mode will trigger an exception if
`resultRows` is an array because appending the statement to `resultRows` is an array because appending the statement to
the array would be unhelpful. the array would be downright unhelpful.
B) An integer, indicating a zero-based column in the result B) An integer, indicating a zero-based column in the result
row. Only that one single value will be passed on. row. Only that one single value will be passed on.
@ -545,10 +552,14 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
':', '$', or '@' will fetch the row as an object, extract that ':', '$', or '@' will fetch the row as an object, extract that
one field, and pass that field's value to the callback. Note one field, and pass that field's value to the callback. Note
that these keys are case-sensitive so must match the case used that these keys are case-sensitive so must match the case used
in the SQL. e.g. `"select a A from t"` with a `rowMode` of '$A' in the SQL. e.g. `"select a A from t"` with a `rowMode` of
would work but '$a' would not. A reference to a column not in `'$A'` would work but `'$a'` would not. A reference to a column
the result set will trigger an exception on the first row (as not in the result set will trigger an exception on the first
the check is not performed until rows are fetched). row (as the check is not performed until rows are fetched).
Note also that `$` is a legal identifier character in JS so
need not be quoted. (Design note: those 3 characters were
chosen because they are the characters support for naming bound
parameters.)
Any other `rowMode` value triggers an exception. Any other `rowMode` value triggers an exception.
@ -560,12 +571,17 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
and can be used over a WebWorker-style message interface. and can be used over a WebWorker-style message interface.
exec() throws if `resultRows` is set and `rowMode` is 'stmt'. exec() throws if `resultRows` is set and `rowMode` is 'stmt'.
- `.columnNames`: if this is an array, the column names of the
result set are stored in this array before the callback (if Potential TODOs:
any) is triggered (regardless of whether the query produces any
result rows). If no statement has result columns, this value is - `.bind`: permit an array of arrays/objects to bind. The first
unchanged. Achtung: an SQL result may have multiple columns sub-array would act on the first statement which has bindable
with identical names. parameters (as it does now). The 2nd would act on the next such
statement, etc.
- `.callback` and `.resultRows`: permit an array entries with
semantics similar to those described for `.bind` above.
*/ */
exec: function(/*(sql [,obj]) || (obj)*/){ exec: function(/*(sql [,obj]) || (obj)*/){
affirmDbOpen(this); affirmDbOpen(this);
@ -1580,31 +1596,5 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
Stmt Stmt
}/*oo1 object*/; }/*oo1 object*/;
if( self.window===self && 0!==capi.sqlite3_vfs_find('kvvfs') ){
/* Features specific to kvvfs... */
/**
Clears all storage used by the kvvfs DB backend, deleting any
DB(s) stored there. Its argument must be either 'session',
'local', or ''. In the first two cases, only sessionStorage
resp. localStorage is cleared. If it's an empty string (the
default) then both are cleared. Only storage keys which match
the pattern used by kvvfs are cleared: any other client-side
data are retained.
*/
DB.clearKvvfsStorage = function(which=''){
const prefix = 'kvvfs-'+which;
const stores = [];
if('session'===which || ''===which) stores.push(sessionStorage);
if('local'===which || ''===which) stores.push(localStorage);
stores.forEach(function(s){
const toRm = [];
let i = 0, k;
for( i = 0; (k = s.key(i)); ++i ){
if(k.startsWith(prefix)) toRm.push(k);
}
toRm.forEach((kk)=>s.removeItem(kk));
});
};
}/* main-window-only bits */
}); });

View File

@ -43,10 +43,7 @@
- Insofar as possible, support client-side storage using JS - Insofar as possible, support client-side storage using JS
filesystem APIs. As of this writing, such things are still very filesystem APIs. As of this writing, such things are still very
much TODO. Initial testing with using IndexedDB as backing storage much under development.
showed it to work reasonably well, but it's also too easy to
corrupt by using a web page in two browser tabs because IndexedDB
lacks the locking features needed to support that.
Specific non-goals of this project: Specific non-goals of this project:
@ -54,8 +51,10 @@
Encodings in that realm, there are no currently plans to support Encodings in that realm, there are no currently plans to support
the UTF16-related sqlite3 APIs. They would add a complication to the UTF16-related sqlite3 APIs. They would add a complication to
the bindings for no appreciable benefit. Though web-related the bindings for no appreciable benefit. Though web-related
implementation details take priority, the lower-level WASM module implementation details take priority, and the JavaScript
"should" work in non-web WASM environments. components of the API specifically focus on browser clients, the
lower-level WASM module "should" work in non-web WASM
environments.
- Supporting old or niche-market platforms. WASM is built for a - Supporting old or niche-market platforms. WASM is built for a
modern web and requires modern platforms. modern web and requires modern platforms.
@ -78,17 +77,18 @@
*/ */
/** /**
sqlite3ApiBootstrap() is the only global symbol exposed by this sqlite3ApiBootstrap() is the only global symbol persistently
API. It is intended to be called one time at the end of the API exposed by this API. It is intended to be called one time at the
amalgamation process, passed configuration details for the current end of the API amalgamation process, passed configuration details
environment, and then optionally be removed from the global object for the current environment, and then optionally be removed from
using `delete self.sqlite3ApiBootstrap`. the global object using `delete self.sqlite3ApiBootstrap`.
This function expects a configuration object, intended to abstract This function expects a configuration object, intended to abstract
away details specific to any given WASM environment, primarily so away details specific to any given WASM environment, primarily so
that it can be used without any _direct_ dependency on that it can be used without any _direct_ dependency on
Emscripten. The config object is only honored the first time this Emscripten. (Note the default values for the config object!) The
is called. Subsequent calls ignore the argument and return the same config object is only honored the first time this is
called. Subsequent calls ignore the argument and return the same
(configured) object which gets initialized by the first call. (configured) object which gets initialized by the first call.
The config object properties include: The config object properties include:
@ -133,7 +133,7 @@
*/ */
'use strict'; 'use strict';
self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
apiConfig = (sqlite3ApiBootstrap.defaultConfig || self.sqlite3ApiConfig) apiConfig = (self.sqlite3ApiConfig || sqlite3ApiBootstrap.defaultConfig)
){ ){
if(sqlite3ApiBootstrap.sqlite3){ /* already initalized */ if(sqlite3ApiBootstrap.sqlite3){ /* already initalized */
console.warn("sqlite3ApiBootstrap() called multiple times.", console.warn("sqlite3ApiBootstrap() called multiple times.",
@ -567,18 +567,22 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
) ? !!capi.sqlite3_compileoption_used(optName) : false; ) ? !!capi.sqlite3_compileoption_used(optName) : false;
}/*compileOptionUsed()*/; }/*compileOptionUsed()*/;
capi.wasm.bindingSignatures = [ /**
/** Signatures for the WASM-exported C-side functions. Each entry
Signatures for the WASM-exported C-side functions. Each entry is an array with 2+ elements:
is an array with 2+ elements:
["c-side name", [ "c-side name",
"result type" (capi.wasm.xWrap() syntax), "result type" (capi.wasm.xWrap() syntax),
[arg types in xWrap() syntax] [arg types in xWrap() syntax]
// ^^^ this needn't strictly be an array: it can be subsequent // ^^^ this needn't strictly be an array: it can be subsequent
// elements instead: [x,y,z] is equivalent to x,y,z // elements instead: [x,y,z] is equivalent to x,y,z
] ]
*/
Note that support for the API-specific data types in the
result/argument type strings gets plugged in at a later phase in
the API initialization process.
*/
capi.wasm.bindingSignatures = [
// Please keep these sorted by function name! // Please keep these sorted by function name!
["sqlite3_bind_blob","int", "sqlite3_stmt*", "int", "*", "int", "*"], ["sqlite3_bind_blob","int", "sqlite3_stmt*", "int", "*", "int", "*"],
["sqlite3_bind_double","int", "sqlite3_stmt*", "int", "f64"], ["sqlite3_bind_double","int", "sqlite3_stmt*", "int", "f64"],
@ -604,6 +608,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
"sqlite3*", "string", "int", "int", "*", "*", "*", "*", "*"], "sqlite3*", "string", "int", "int", "*", "*", "*", "*", "*"],
["sqlite3_data_count", "int", "sqlite3_stmt*"], ["sqlite3_data_count", "int", "sqlite3_stmt*"],
["sqlite3_db_filename", "string", "sqlite3*", "string"], ["sqlite3_db_filename", "string", "sqlite3*", "string"],
["sqlite3_db_handle", "sqlite3*", "sqlite3_stmt*"],
["sqlite3_db_name", "string", "sqlite3*", "int"], ["sqlite3_db_name", "string", "sqlite3*", "int"],
["sqlite3_errmsg", "string", "sqlite3*"], ["sqlite3_errmsg", "string", "sqlite3*"],
["sqlite3_error_offset", "int", "sqlite3*"], ["sqlite3_error_offset", "int", "sqlite3*"],
@ -614,6 +619,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
["sqlite3_expanded_sql", "string", "sqlite3_stmt*"], ["sqlite3_expanded_sql", "string", "sqlite3_stmt*"],
["sqlite3_extended_errcode", "int", "sqlite3*"], ["sqlite3_extended_errcode", "int", "sqlite3*"],
["sqlite3_extended_result_codes", "int", "sqlite3*", "int"], ["sqlite3_extended_result_codes", "int", "sqlite3*", "int"],
["sqlite3_file_control", "int", "sqlite3*", "string", "int", "*"],
["sqlite3_finalize", "int", "sqlite3_stmt*"], ["sqlite3_finalize", "int", "sqlite3_stmt*"],
["sqlite3_initialize", undefined], ["sqlite3_initialize", undefined],
["sqlite3_interrupt", undefined, "sqlite3*" ["sqlite3_interrupt", undefined, "sqlite3*"
@ -740,20 +746,132 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
/** /**
Returns true if sqlite3.capi.sqlite3_web_persistent_dir() is a Returns true if sqlite3.capi.sqlite3_web_persistent_dir() is a
non-empty string and the given name has that string as its non-empty string and the given name starts with (that string +
prefix, else returns false. '/'), else returns false.
Potential (but arguable) TODO: return true if the name is one of
(":localStorage:", "local", ":sessionStorage:", "session") and
kvvfs is available.
*/ */
capi.sqlite3_web_filename_is_persistent = function(name){ capi.sqlite3_web_filename_is_persistent = function(name){
const p = capi.sqlite3_web_persistent_dir(); const p = capi.sqlite3_web_persistent_dir();
return (p && name) ? name.startsWith(p) : false; return (p && name) ? name.startsWith(p+'/') : false;
}; };
if(0===capi.wasm.exports.sqlite3_vfs_find(0)){ if(0===capi.wasm.exports.sqlite3_vfs_find(0)){
/* Assume that sqlite3_initialize() has not yet been called. /* Assume that sqlite3_initialize() has not yet been called.
This will be the case in an SQLITE_OS_KV build. */ This will be the case in an SQLITE_OS_KV build. */
capi.wasm.exports.sqlite3_initialize(); capi.wasm.exports.sqlite3_initialize();
} }
if( self.window===self ){
/* Features specific to the main window thread... */
/**
Internal helper for sqlite3_web_kvvfs_clear() and friends.
Its argument should be one of ('local','session','').
*/
const __kvvfsInfo = function(which){
const rc = Object.create(null);
rc.prefix = 'kvvfs-'+which;
rc.stores = [];
if('session'===which || ''===which) rc.stores.push(self.sessionStorage);
if('local'===which || ''===which) rc.stores.push(self.localStorage);
return rc;
};
/**
Clears all storage used by the kvvfs DB backend, deleting any
DB(s) stored there. Its argument must be either 'session',
'local', or ''. In the first two cases, only sessionStorage
resp. localStorage is cleared. If it's an empty string (the
default) then both are cleared. Only storage keys which match
the pattern used by kvvfs are cleared: any other client-side
data are retained.
This function is only available in the main window thread.
Returns the number of entries cleared.
*/
capi.sqlite3_web_kvvfs_clear = function(which=''){
let rc = 0;
const kvinfo = __kvvfsInfo(which);
kvinfo.stores.forEach((s)=>{
const toRm = [] /* keys to remove */;
let i;
for( i = 0; i < s.length; ++i ){
const k = s.key(i);
if(k.startsWith(kvinfo.prefix)) toRm.push(k);
}
toRm.forEach((kk)=>s.removeItem(kk));
rc += toRm.length;
});
return rc;
};
/**
This routine guesses the approximate amount of
window.localStorage and/or window.sessionStorage in use by the
kvvfs database backend. Its argument must be one of
('session', 'local', ''). In the first two cases, only
sessionStorage resp. localStorage is counted. If it's an empty
string (the default) then both are counted. Only storage keys
which match the pattern used by kvvfs are counted. The returned
value is the "length" value of every matching key and value,
noting that the kvvf uses only ASCII keys and values.
Note that the returned size is not authoritative from the
perspective of how much data can fit into localStorage and
sessionStorage, as the precise algorithms for determining
those limits are unspecified and may include per-entry
overhead invisible to clients.
*/
capi.sqlite3_web_kvvfs_size = function(which=''){
let sz = 0;
const kvinfo = __kvvfsInfo(which);
kvinfo.stores.forEach((s)=>{
let i;
for(i = 0; i < s.length; ++i){
const k = s.key(i);
if(k.startsWith(kvinfo.prefix)){
sz += k.length;
sz += s.getItem(k).length;
}
}
});
return sz;
};
/**
Given an `sqlite3*`, returns a truthy value (see below) if that
db handle uses the "kvvfs" VFS, else returns false. If pDb is
NULL then this function returns true if the default VFS is
"kvvfs". Results are undefined if pDb is truthy but refers to
an invalid pointer.
The truthy value it returns is a pointer to the kvvfs
`sqlite3_vfs` object.
*/
capi.sqlite3_web_db_is_kvvfs = function(pDb){
const pK = capi.sqlite3_vfs_find("kvvfs");
if(!pK) return false;
else if(!pDb){
return capi.sqlite3_vfs_find(0) && pK;
}
const scope = capi.wasm.scopedAllocPush();
try{
const ppVfs = capi.wasm.scopedAllocPtr();
return (
(0===capi.sqlite3_file_control(
pDb, "main", capi.SQLITE_FCNTL_VFS_POINTER, ppVfs
)) && (capi.wasm.getPtrValue(ppVfs) === pK)
) ? pK : false;
}finally{
capi.wasm.scopedAllocPop(scope);
}
};
}/* main-window-only bits */
/* The remainder of the API will be set up in later steps. */ /* The remainder of the API will be set up in later steps. */
const sqlite3 = { const sqlite3 = {
WasmAllocError: WasmAllocError, WasmAllocError: WasmAllocError,
@ -790,6 +908,11 @@ self.sqlite3ApiBootstrap.initializers = [];
global-scope symbol. global-scope symbol.
*/ */
self.sqlite3ApiBootstrap.defaultConfig = Object.create(null); self.sqlite3ApiBootstrap.defaultConfig = Object.create(null);
/** Placeholder: gets installed by the first call to /**
self.sqlite3ApiBootstrap(). */ Placeholder: gets installed by the first call to
self.sqlite3ApiBootstrap(). However, it is recommended that the
caller of sqlite3ApiBootstrap() capture its return value and delete
self.sqlite3ApiBootstrap after calling it. It returns the same
value which will be stored here.
*/
self.sqlite3ApiBootstrap.sqlite3 = undefined; self.sqlite3ApiBootstrap.sqlite3 = undefined;

View File

@ -76,7 +76,7 @@ int sqlite3_wasm_db_error(sqlite3*db, int err_code, const char *zMsg){
*/ */
WASM_KEEP WASM_KEEP
const char * sqlite3_wasm_enum_json(void){ const char * sqlite3_wasm_enum_json(void){
static char strBuf[1024 * 8] = {0} /* where the JSON goes */; static char strBuf[1024 * 12] = {0} /* where the JSON goes */;
int n = 0, childCount = 0, structCount = 0 int n = 0, childCount = 0, structCount = 0
/* output counters for figuring out where commas go */; /* output counters for figuring out where commas go */;
char * pos = &strBuf[1] /* skip first byte for now to help protect char * pos = &strBuf[1] /* skip first byte for now to help protect
@ -259,7 +259,8 @@ const char * sqlite3_wasm_enum_json(void){
} _DefGroup; } _DefGroup;
DefGroup(openFlags) { DefGroup(openFlags) {
/* Noting that not all of these will have any effect in WASM-space. */ /* Noting that not all of these will have any effect in
** WASM-space. */
DefInt(SQLITE_OPEN_READONLY); DefInt(SQLITE_OPEN_READONLY);
DefInt(SQLITE_OPEN_READWRITE); DefInt(SQLITE_OPEN_READWRITE);
DefInt(SQLITE_OPEN_CREATE); DefInt(SQLITE_OPEN_CREATE);
@ -322,6 +323,49 @@ const char * sqlite3_wasm_enum_json(void){
DefInt(SQLITE_IOCAP_BATCH_ATOMIC); DefInt(SQLITE_IOCAP_BATCH_ATOMIC);
} _DefGroup; } _DefGroup;
DefGroup(fcntl) {
DefInt(SQLITE_FCNTL_LOCKSTATE);
DefInt(SQLITE_FCNTL_GET_LOCKPROXYFILE);
DefInt(SQLITE_FCNTL_SET_LOCKPROXYFILE);
DefInt(SQLITE_FCNTL_LAST_ERRNO);
DefInt(SQLITE_FCNTL_SIZE_HINT);
DefInt(SQLITE_FCNTL_CHUNK_SIZE);
DefInt(SQLITE_FCNTL_FILE_POINTER);
DefInt(SQLITE_FCNTL_SYNC_OMITTED);
DefInt(SQLITE_FCNTL_WIN32_AV_RETRY);
DefInt(SQLITE_FCNTL_PERSIST_WAL);
DefInt(SQLITE_FCNTL_OVERWRITE);
DefInt(SQLITE_FCNTL_VFSNAME);
DefInt(SQLITE_FCNTL_POWERSAFE_OVERWRITE);
DefInt(SQLITE_FCNTL_PRAGMA);
DefInt(SQLITE_FCNTL_BUSYHANDLER);
DefInt(SQLITE_FCNTL_TEMPFILENAME);
DefInt(SQLITE_FCNTL_MMAP_SIZE);
DefInt(SQLITE_FCNTL_TRACE);
DefInt(SQLITE_FCNTL_HAS_MOVED);
DefInt(SQLITE_FCNTL_SYNC);
DefInt(SQLITE_FCNTL_COMMIT_PHASETWO);
DefInt(SQLITE_FCNTL_WIN32_SET_HANDLE);
DefInt(SQLITE_FCNTL_WAL_BLOCK);
DefInt(SQLITE_FCNTL_ZIPVFS);
DefInt(SQLITE_FCNTL_RBU);
DefInt(SQLITE_FCNTL_VFS_POINTER);
DefInt(SQLITE_FCNTL_JOURNAL_POINTER);
DefInt(SQLITE_FCNTL_WIN32_GET_HANDLE);
DefInt(SQLITE_FCNTL_PDB);
DefInt(SQLITE_FCNTL_BEGIN_ATOMIC_WRITE);
DefInt(SQLITE_FCNTL_COMMIT_ATOMIC_WRITE);
DefInt(SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE);
DefInt(SQLITE_FCNTL_LOCK_TIMEOUT);
DefInt(SQLITE_FCNTL_DATA_VERSION);
DefInt(SQLITE_FCNTL_SIZE_LIMIT);
DefInt(SQLITE_FCNTL_CKPT_DONE);
DefInt(SQLITE_FCNTL_RESERVE_BYTES);
DefInt(SQLITE_FCNTL_CKPT_START);
DefInt(SQLITE_FCNTL_EXTERNAL_READER);
DefInt(SQLITE_FCNTL_CKSM_FILE);
} _DefGroup;
DefGroup(access){ DefGroup(access){
DefInt(SQLITE_ACCESS_EXISTS); DefInt(SQLITE_ACCESS_EXISTS);
DefInt(SQLITE_ACCESS_READWRITE); DefInt(SQLITE_ACCESS_READWRITE);

View File

@ -55,7 +55,9 @@
<hr> <hr>
<div id='reverse-log-notice' class='hidden'>(Log output is in reverse order, newest first!)</div> <div id='reverse-log-notice' class='hidden'>(Log output is in reverse order, newest first!)</div>
<div id='test-output'></div> <div id='test-output'></div>
<!-- batch-runner.js "should" work with sqlite3-kvvfs so long as
its data sets don't violate the the storage limits. -->
<!--script src="sqlite3-kvvfs.js"></script-->
<script src="sqlite3.js"></script> <script src="sqlite3.js"></script>
<script src="common/SqliteTestUtil.js"></script> <script src="common/SqliteTestUtil.js"></script>
<script src="batch-runner.js"></script> <script src="batch-runner.js"></script>

View File

@ -17,6 +17,7 @@
(function(){ (function(){
const toss = function(...args){throw new Error(args.join(' '))}; const toss = function(...args){throw new Error(args.join(' '))};
const warn = console.warn.bind(console); const warn = console.warn.bind(console);
let sqlite3;
const App = { const App = {
e: { e: {
@ -30,6 +31,7 @@
btnReset: document.querySelector('#db-reset'), btnReset: document.querySelector('#db-reset'),
cbReverseLog: document.querySelector('#cb-reverse-log-order') cbReverseLog: document.querySelector('#cb-reverse-log-order')
}, },
db: Object.create(null),
cache:{}, cache:{},
metrics:{ metrics:{
/** /**
@ -61,15 +63,16 @@
}, },
openDb: function(fn, unlinkFirst=true){ openDb: function(fn, unlinkFirst=true){
if(this.db && this.db.ptr){ if(this.db.ptr){
toss("Already have an opened db."); toss("Already have an opened db.");
} }
const capi = this.sqlite3.capi, wasm = capi.wasm; const capi = this.sqlite3.capi, wasm = capi.wasm;
const stack = wasm.scopedAllocPush(); const stack = wasm.scopedAllocPush();
let pDb = 0; let pDb = 0;
try{ try{
if(unlinkFirst && fn && ':memory:'!==fn){ if(unlinkFirst && fn){
capi.wasm.sqlite3_wasm_vfs_unlink(fn); if(':'!==fn[0]) capi.wasm.sqlite3_wasm_vfs_unlink(fn);
this.clearStorage();
} }
const oFlags = capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE; const oFlags = capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
const ppDb = wasm.scopedAllocPtr(); const ppDb = wasm.scopedAllocPtr();
@ -82,7 +85,6 @@
}finally{ }finally{
wasm.scopedAllocPop(stack); wasm.scopedAllocPop(stack);
} }
this.db = Object.create(null);
this.db.filename = fn; this.db.filename = fn;
this.db.ptr = pDb; this.db.ptr = pDb;
this.logHtml("Opened db:",fn); this.logHtml("Opened db:",fn);
@ -90,10 +92,13 @@
}, },
closeDb: function(unlink=false){ closeDb: function(unlink=false){
if(this.db && this.db.ptr){ if(this.db.ptr){
this.sqlite3.capi.sqlite3_close_v2(this.db.ptr); this.sqlite3.capi.sqlite3_close_v2(this.db.ptr);
this.logHtml("Closed db",this.db.filename); this.logHtml("Closed db",this.db.filename);
if(unlink) capi.wasm.sqlite3_wasm_vfs_unlink(this.db.filename); if(unlink){
capi.wasm.sqlite3_wasm_vfs_unlink(this.db.filename);
this.clearStorage();
}
this.db.ptr = this.db.filename = undefined; this.db.ptr = this.db.filename = undefined;
} }
}, },
@ -329,6 +334,21 @@
return p.catch((e)=>this.logErr("Error via evalFile("+fn+"):",e.message)); return p.catch((e)=>this.logErr("Error via evalFile("+fn+"):",e.message));
}/*evalFile()*/, }/*evalFile()*/,
clearStorage: function(){
const sz = sqlite3.capi.sqlite3_web_kvvfs_size();
const n = sqlite3.capi.sqlite3_web_kvvfs_clear(this.db.filename || '');
this.logHtml("Cleared kvvfs local/sessionStorage:",
n,"entries totaling approximately",sz,"bytes.");
},
resetDb: function(){
if(this.db.ptr){
const fn = this.db.filename;
this.closeDb(true);
this.openDb(fn,false);
}
},
run: function(sqlite3){ run: function(sqlite3){
delete this.run; delete this.run;
this.sqlite3 = sqlite3; this.sqlite3 = sqlite3;
@ -336,9 +356,14 @@
this.logHtml("Loaded module:",capi.sqlite3_libversion(), capi.sqlite3_sourceid()); this.logHtml("Loaded module:",capi.sqlite3_libversion(), capi.sqlite3_sourceid());
this.logHtml("WASM heap size =",wasm.heap8().length); this.logHtml("WASM heap size =",wasm.heap8().length);
this.loadSqlList(); this.loadSqlList();
const pDir = capi.sqlite3_web_persistent_dir(); const pDir = 1 ? '' : capi.sqlite3_web_persistent_dir();
const dbFile = pDir ? pDir+"/speedtest.db" : ":memory:"; const dbFile = pDir ? pDir+"/speedtest.db" : (
if(!pDir){ sqlite3.capi.sqlite3_vfs_find('kvvfs') ? 'local' : ':memory:'
);
this.clearStorage();
if(pDir){
logHtml("Using persistent storage:",dbFile);
}else{
document.querySelector('#warn-opfs').remove(); document.querySelector('#warn-opfs').remove();
} }
this.openDb(dbFile, !!pDir); this.openDb(dbFile, !!pDir);
@ -368,11 +393,7 @@
who.evalFile(who.e.selSql.value); who.evalFile(who.e.selSql.value);
}, false); }, false);
this.e.btnReset.addEventListener('click', function(){ this.e.btnReset.addEventListener('click', function(){
const fn = who.db.filename; who.resetDb();
if(fn){
who.closeDb(true);
who.openDb(fn,true);
}
}, false); }, false);
this.e.btnExportMetrics.addEventListener('click', function(){ this.e.btnExportMetrics.addEventListener('click', function(){
who.logHtml2('warning',"Triggering download of metrics CSV. Check your downloads folder."); who.logHtml2('warning',"Triggering download of metrics CSV. Check your downloads folder.");
@ -394,12 +415,14 @@
} }
const timeTotal = performance.now() - timeStart; const timeTotal = performance.now() - timeStart;
who.logHtml("Run-remaining time:",timeTotal,"ms ("+(timeTotal/1000/60)+" minute(s))"); who.logHtml("Run-remaining time:",timeTotal,"ms ("+(timeTotal/1000/60)+" minute(s))");
who.clearStorage();
}, false); }, false);
}/*run()*/ }/*run()*/
}/*App*/; }/*App*/;
self.sqlite3TestModule.initSqlite3().then(function(theEmccModule){ self.sqlite3TestModule.initSqlite3().then(function(theEmccModule){
self._MODULE = theEmccModule /* this is only to facilitate testing from the console */; self._MODULE = theEmccModule /* this is only to facilitate testing from the console */;
sqlite3 = theEmccModule.sqlite3;
App.run(theEmccModule.sqlite3); App.run(theEmccModule.sqlite3);
}); });
})(); })();

View File

@ -31,6 +31,7 @@
<button id='btn-clear-storage'>Clear storage</button> <button id='btn-clear-storage'>Clear storage</button>
<button id='btn-init-db'>(Re)init db</button> <button id='btn-init-db'>(Re)init db</button>
<button id='btn-select1'>Select db rows</button> <button id='btn-select1'>Select db rows</button>
<button id='btn-storage-size'>Approx. storage size</button>
</div> </div>
</fieldset> </fieldset>
<div id='test-output'></div> <div id='test-output'></div>

View File

@ -48,35 +48,35 @@
wasm = capi.wasm; wasm = capi.wasm;
log("Loaded module:",capi.sqlite3_libversion(), capi.sqlite3_sourceid()); log("Loaded module:",capi.sqlite3_libversion(), capi.sqlite3_sourceid());
T.assert( 0 !== capi.sqlite3_vfs_find(null) ); T.assert( 0 !== capi.sqlite3_vfs_find(null) );
if(!oo.DB.clearKvvfsStorage){ if(!capi.sqlite3_vfs_find('kvvfs')){
warn("This build is not kvvfs-capable."); warn("This build is not kvvfs-capable.");
return; return;
} }
const dbStorage = 1 ? ':sessionStorage:' : ':localStorage:'; const dbStorage = 1 ? 'session' : 'local';
const theStore = 's'===dbStorage[1] ? sessionStorage : localStorage; const theStore = 's'===dbStorage[0] ? sessionStorage : localStorage;
/** /**
The names ':sessionStorage:' and ':localStorage:' are handled The names ':sessionStorage:' and ':localStorage:' are handled
via the DB class constructor, not the C level. In the C API, via the DB class constructor, not the C level. In the C API,
the names "local" and "session" are the current (2022-09-12) the names "local" and "session" are the current (2022-09-12)
names for those keys, but that is subject to change. names for those keys, but that is subject to change.
*/ */
const db = new oo.DB( dbStorage ); const db = new oo.DB( dbStorage, 'c', 'kvvfs' );
document.querySelector('#btn-clear-storage').addEventListener('click',function(){ document.querySelector('#btn-clear-storage').addEventListener('click',function(){
oo.DB.clearKvvfsStorage(); const sz = capi.sqlite3_web_kvvfs_clear();
log("kvvfs localStorage and sessionStorage cleared."); log("kvvfs localStorage and sessionStorage cleared:",sz,"entries.");
}); });
document.querySelector('#btn-clear-log').addEventListener('click',function(){ document.querySelector('#btn-clear-log').addEventListener('click',function(){
eOutput.innerText = ''; eOutput.innerText = '';
}); });
document.querySelector('#btn-init-db').addEventListener('click',function(){ document.querySelector('#btn-init-db').addEventListener('click',function(){
const saveSql = [];
try{ try{
const saveSql = [];
db.exec({ db.exec({
sql:["drop table if exists t;", sql: ["drop table if exists t;",
"create table if not exists t(a);", "create table if not exists t(a);",
"insert into t(a) values(?),(?),(?)"], "insert into t(a) values(?),(?),(?)"],
bind: [performance.now() >> 0, bind: [performance.now() >> 0,
(performance.now() * 2) >> 0, (performance.now() * 2) >> 0,
(performance.now() / 2) >> 0], (performance.now() / 2) >> 0],
@ -101,6 +101,10 @@
error(e.message); error(e.message);
} }
}); });
document.querySelector('#btn-storage-size').addEventListener('click',function(){
log("sqlite3_web_kvvfs_size(",dbStorage,") says", capi.sqlite3_web_kvvfs_size(dbStorage),
"bytes");
});
log("Storage backend:",db.filename /* note that the name was internally translated */); log("Storage backend:",db.filename /* note that the name was internally translated */);
if(0===db.selectValue('select count(*) from sqlite_master')){ if(0===db.selectValue('select count(*) from sqlite_master')){
log("DB is empty. Use the init button to populate it."); log("DB is empty. Use the init button to populate it.");

View File

@ -33,6 +33,8 @@
return v1>=(v2-factor) && v1<=(v2+factor); return v1>=(v2-factor) && v1<=(v2+factor);
}; };
let sqlite3;
const testBasicSanity = function(db,sqlite3){ const testBasicSanity = function(db,sqlite3){
const capi = sqlite3.capi; const capi = sqlite3.capi;
log("Basic sanity tests..."); log("Basic sanity tests...");
@ -1005,10 +1007,17 @@
} }
}/*testWasmUtil()*/; }/*testWasmUtil()*/;
const clearKvvfs = function(){
const sz = sqlite3.capi.sqlite3_web_kvvfs_size();
const n = sqlite3.capi.sqlite3_web_kvvfs_clear('');
log("Cleared kvvfs local/sessionStorage:",
n,"entries totaling approximately",sz,"bytes.");
};
const runTests = function(Module){ const runTests = function(Module){
//log("Module",Module); //log("Module",Module);
const sqlite3 = Module.sqlite3, sqlite3 = Module.sqlite3;
capi = sqlite3.capi, const capi = sqlite3.capi,
oo = sqlite3.oo1, oo = sqlite3.oo1,
wasm = capi.wasm; wasm = capi.wasm;
log("Loaded module:",capi.sqlite3_libversion(), capi.sqlite3_sourceid()); log("Loaded module:",capi.sqlite3_libversion(), capi.sqlite3_sourceid());
@ -1048,14 +1057,15 @@
let dbName = "/testing1.sqlite3"; let dbName = "/testing1.sqlite3";
let vfsName = undefined; let vfsName = undefined;
if(oo.DB.clearKvvfsStorage){ if(capi.sqlite3_web_db_is_kvvfs()){
dbName = "local"; dbName = "local";
vfsName = 'kvvfs'; vfsName = 'kvvfs';
logHtml("Found kvvfs. Clearing db(s) from sessionStorage and localStorage", logHtml("Found kvvfs. Clearing db(s) from sessionStorage and localStorage",
"and selecting kvvfs-friendly db name:",dbName); "and selecting kvvfs-friendly db name:",dbName);
oo.DB.clearKvvfsStorage(); clearKvvfs();
} }
const db = new oo.DB(dbName,'c',vfsName), startTime = performance.now(); const db = new oo.DB(dbName,'c',vfsName), startTime = performance.now();
log("capi.sqlite3_web_db_is_kvvfs() ==",capi.sqlite3_web_db_is_kvvfs(db.pointer));
try { try {
log("db.filename =",db.filename,"db.fileName() =",db.fileName()); log("db.filename =",db.filename,"db.fileName() =",db.fileName());
const banner1 = '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>', const banner1 = '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>',
@ -1072,6 +1082,7 @@
}); });
}finally{ }finally{
db.close(); db.close();
if('kvvfs'===vfsName) clearKvvfs();
} }
logHtml("Total Test count:",T.counter,"in",(performance.now() - startTime),"ms"); logHtml("Total Test count:",T.counter,"in",(performance.now() - startTime),"ms");
log('capi.wasm.exports',capi.wasm.exports); log('capi.wasm.exports',capi.wasm.exports);

View File

@ -1,5 +1,5 @@
C Get\stesting1.js\sworking\swith\sa\skvvfs\sbuild. C Add/apply\svarious\skvvfs-specific\sutility\sAPIs\sto\sthe\sJS\slayer\sto\sassist\sin\stesting\sand\sanalysis.\sCorrect\sa\sbackwards\sdefault\sarg\scheck\sfor\ssqlite3ApiBootstrap().\sAdd\sexports\sfor\ssqlite3_db_handle(),\ssqlite3_file_control(),\sand\sthe\sSQLITE_FCNTL_xxx\senum.
D 2022-09-12T22:27:00.037 D 2022-09-13T19:27:03.599
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -476,21 +476,21 @@ F ext/wasm/EXPORTED_FUNCTIONS.fiddle db7a4602f043cf4a5e4135be3609a487f9f1c83f057
F ext/wasm/EXPORTED_RUNTIME_METHODS.fiddle a004bd5eeeda6d3b28d16779b7f1a80305bfe009dfc7f0721b042967f0d39d02 F ext/wasm/EXPORTED_RUNTIME_METHODS.fiddle a004bd5eeeda6d3b28d16779b7f1a80305bfe009dfc7f0721b042967f0d39d02
F ext/wasm/GNUmakefile b175a00599c976fe9e7bc02bbc1337b5e3b81d042320c3a0be1621d2c7a21b21 F ext/wasm/GNUmakefile b175a00599c976fe9e7bc02bbc1337b5e3b81d042320c3a0be1621d2c7a21b21
F ext/wasm/README.md e1ee1e7c321c6a250bf78a84ca6f5882890a237a450ba5a0649c7a8399194c52 F ext/wasm/README.md e1ee1e7c321c6a250bf78a84ca6f5882890a237a450ba5a0649c7a8399194c52
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api 1dfd067b3cbd9a49cb204097367cf2f8fe71b5a3b245d9d82a24779fd4ac2394 F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api 150a793a47205b8009ac934f3b6d6ebf67b965c072339aaa25ce808a19e116cc
F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287 F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287
F ext/wasm/api/README.md d876597edd2b9542b6ea031adaaff1c042076fde7b670b1dc6d8a87b28a6631b F ext/wasm/api/README.md d876597edd2b9542b6ea031adaaff1c042076fde7b670b1dc6d8a87b28a6631b
F ext/wasm/api/post-js-footer.js b64319261d920211b8700004d08b956a6c285f3b0bba81456260a713ed04900c F ext/wasm/api/post-js-footer.js b64319261d920211b8700004d08b956a6c285f3b0bba81456260a713ed04900c
F ext/wasm/api/post-js-header.js 0e853b78db83cb1c06b01663549e0e8b4f377f12f5a2d9a4a06cb776c003880b F ext/wasm/api/post-js-header.js 0e853b78db83cb1c06b01663549e0e8b4f377f12f5a2d9a4a06cb776c003880b
F ext/wasm/api/sqlite3-api-cleanup.js 101919ec261644e2f6f0a59952fd9612127b69ea99b493277b2789ea478f9b6b F ext/wasm/api/sqlite3-api-cleanup.js 8564a6077cdcaea9a9f428a019af8a05887f0131e6a2a1e72a7ff1145fadfe77
F ext/wasm/api/sqlite3-api-glue.js 2bf536a38cde324cf352bc2c575f8e22c6d204d667c0eda5a254ba45318914bc F ext/wasm/api/sqlite3-api-glue.js 366d580c8e5bf7fcf4c6dee6f646c31f5549bd417ea03a59a0acca00e8ecce30
F ext/wasm/api/sqlite3-api-oo1.js b498662748918c132aa59433ea2bd2ebb7e026549fd68506a1ae1ea94736f4f6 F ext/wasm/api/sqlite3-api-oo1.js 4925f4736eb28fd3a6d4dbbd2c078c38be651aa5996041e7f0b81be36506608e
F ext/wasm/api/sqlite3-api-opfs.js 011799db398157cbd254264b6ebae00d7234b93d0e9e810345f213a5774993c0 F ext/wasm/api/sqlite3-api-opfs.js 011799db398157cbd254264b6ebae00d7234b93d0e9e810345f213a5774993c0
F ext/wasm/api/sqlite3-api-prologue.js 9e37ce4dfd74926d0df80dd7e72e33085db4bcee48e2c21236039be416a7dff2 F ext/wasm/api/sqlite3-api-prologue.js c496adc0cf2ae427ee900aad01c09db97850bd8b6737f2849cab207c8415b839
F ext/wasm/api/sqlite3-api-worker1.js d33062afa045fd4be01ba4abc266801807472558b862b30056211b00c9c347b4 F ext/wasm/api/sqlite3-api-worker1.js d33062afa045fd4be01ba4abc266801807472558b862b30056211b00c9c347b4
F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9 F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9
F ext/wasm/api/sqlite3-wasm.c bf4637cf28463cada4b25f09651943c7ece004b253ef39b7ab68eaa60662aa09 F ext/wasm/api/sqlite3-wasm.c 7d1760f3a864a9ae16cfb71543829d946a54384bd07af99a3adf9ef32913705f
F ext/wasm/batch-runner.html 23209ade7981acce7ecd79d6eff9f4c5a4e8b14ae867ac27cd89b230be640fa6 F ext/wasm/batch-runner.html 2857a6db7292ac83d1581af865d643fd34235db2df830d10b43b01388c599e04
F ext/wasm/batch-runner.js 2abd146d3e3a66128ac0a2cc39bfd01e9811c9511fa10ec927d6649795f1ee50 F ext/wasm/batch-runner.js fb6a338aeef509f181f499700a8595bc578bbc54ef832e0cda7e7e7c10b90a18
F ext/wasm/common/SqliteTestUtil.js 529161a624265ba84271a52db58da022649832fa1c71309fb1e02cc037327a2b F ext/wasm/common/SqliteTestUtil.js 529161a624265ba84271a52db58da022649832fa1c71309fb1e02cc037327a2b
F ext/wasm/common/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f F ext/wasm/common/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f
F ext/wasm/common/testing.css 3a5143699c2b73a85b962271e1a9b3241b30d90e30d895e4f55665e648572962 F ext/wasm/common/testing.css 3a5143699c2b73a85b962271e1a9b3241b30d90e30d895e4f55665e648572962
@ -507,8 +507,8 @@ F ext/wasm/jaccwabyt/jaccwabyt.md 447cc02b598f7792edaa8ae6853a7847b8178a18ed356a
F ext/wasm/jaccwabyt/jaccwabyt_test.c 39e4b865a33548f943e2eb9dd0dc8d619a80de05d5300668e9960fff30d0d36f F ext/wasm/jaccwabyt/jaccwabyt_test.c 39e4b865a33548f943e2eb9dd0dc8d619a80de05d5300668e9960fff30d0d36f
F ext/wasm/jaccwabyt/jaccwabyt_test.exports 5ff001ef975c426ffe88d7d8a6e96ec725e568d2c2307c416902059339c06f19 F ext/wasm/jaccwabyt/jaccwabyt_test.exports 5ff001ef975c426ffe88d7d8a6e96ec725e568d2c2307c416902059339c06f19
F ext/wasm/kvvfs.make bfa0aaac384d9f200d2c8e31efb3536b40d139667b88e6eba9c0a71e23da6a5c F ext/wasm/kvvfs.make bfa0aaac384d9f200d2c8e31efb3536b40d139667b88e6eba9c0a71e23da6a5c
F ext/wasm/kvvfs1.html 83bac238d1e93ed102a461672fc58fe74e611e426708e9a5c66002c01eadb942 F ext/wasm/kvvfs1.html 13bb24190bfb276a57b228499519badcc1bf39ed07e4b37bc2a425ce6418fed1
F ext/wasm/kvvfs1.js 53721a42e0ec45f6978cc723e5de47f882517867d0fcff4c6ff05f4c422e27c4 F ext/wasm/kvvfs1.js a23ee98a78b9da379eab7a20d7ddf5283a684dd7a91685a84686c05216f96689
F ext/wasm/scratchpad-opfs-main.html 4565cf194e66188190d35f70e82553e2e2d72b9809b73c94ab67b8cfd14d2e0c F ext/wasm/scratchpad-opfs-main.html 4565cf194e66188190d35f70e82553e2e2d72b9809b73c94ab67b8cfd14d2e0c
F ext/wasm/scratchpad-opfs-main.js 69e960e9161f6412fd0c30f355d4112f1894d6609eb431e2d16d207d1380518e F ext/wasm/scratchpad-opfs-main.js 69e960e9161f6412fd0c30f355d4112f1894d6609eb431e2d16d207d1380518e
F ext/wasm/scratchpad-opfs-worker.html 66c1d15d678f3bd306373d76b61c6c8aef988f61f4a8dd40185d452f9c6d2bf5 F ext/wasm/scratchpad-opfs-worker.html 66c1d15d678f3bd306373d76b61c6c8aef988f61f4a8dd40185d452f9c6d2bf5
@ -526,7 +526,7 @@ F ext/wasm/sqlite3-worker1.js 0c1e7626304543969c3846573e080c082bf43bcaa47e87d416
F ext/wasm/testing-worker1-promiser.html 6eaec6e04a56cf24cf4fa8ef49d78ce8905dde1354235c9125dca6885f7ce893 F ext/wasm/testing-worker1-promiser.html 6eaec6e04a56cf24cf4fa8ef49d78ce8905dde1354235c9125dca6885f7ce893
F ext/wasm/testing-worker1-promiser.js c62b5879339eef0b21aebd9d75bc125c86530edc17470afff18077f931cb704a F ext/wasm/testing-worker1-promiser.js c62b5879339eef0b21aebd9d75bc125c86530edc17470afff18077f931cb704a
F ext/wasm/testing1.html 50575755e43232dbe4c2f97c9086b3118eb91ec2ee1fae931e6d7669fb17fcae F ext/wasm/testing1.html 50575755e43232dbe4c2f97c9086b3118eb91ec2ee1fae931e6d7669fb17fcae
F ext/wasm/testing1.js 735120231d6e55b92964924fcb54a66484d8b2e30fe5a18c71081b3590344a5f F ext/wasm/testing1.js 7cd8ab255c238b030d928755ae8e91e7d90a12f2ae601b1b8f7827aaa4fb258e
F ext/wasm/testing2.html a66951c38137ff1d687df79466351f3c734fa9c6d9cce71d3cf97c291b2167e3 F ext/wasm/testing2.html a66951c38137ff1d687df79466351f3c734fa9c6d9cce71d3cf97c291b2167e3
F ext/wasm/testing2.js 25584bcc30f19673ce13a6f301f89f8820a59dfe044e0c4f2913941f4097fe3c F ext/wasm/testing2.js 25584bcc30f19673ce13a6f301f89f8820a59dfe044e0c4f2913941f4097fe3c
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
@ -2024,8 +2024,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 8b1608a9a37131121cb3a0cb1e8dbad5e39dc1fc2a341d056f09537f179b2e7a P 333a45725d1708e0fefa559c33ce1c7eeb425cdb04f594b1f2b48166c1478c79
R 77095a41dfb9b784dcab0078822e6eff R fff963b52d5c3a76677d96f35303ab67
U stephan U stephan
Z c624cb9efadffe8972e3df15b8dc9939 Z e8c548c1774e1a39daa4183bad155966
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
333a45725d1708e0fefa559c33ce1c7eeb425cdb04f594b1f2b48166c1478c79 0d78961870ee9f22f1ba16d423377d28dcc36e04b1e31ffd57f3e2fd51f8f0f2