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:
@ -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
|
||||||
|
@ -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.");
|
||||||
|
@ -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'
|
||||||
]){
|
]){
|
||||||
|
@ -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 */
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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>
|
||||||
|
@ -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);
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -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>
|
||||||
|
@ -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.");
|
||||||
|
@ -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);
|
||||||
|
32
manifest
32
manifest
@ -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.
|
||||||
|
@ -1 +1 @@
|
|||||||
333a45725d1708e0fefa559c33ce1c7eeb425cdb04f594b1f2b48166c1478c79
|
0d78961870ee9f22f1ba16d423377d28dcc36e04b1e31ffd57f3e2fd51f8f0f2
|
Reference in New Issue
Block a user