mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-27 20:41:58 +03:00
Merge kv-vfs branch into fiddle-opfs branch to add kvvfs-based wasm build and demo.
FossilOrigin-Name: a7d8b26acd3c1ae344369e4d70804c0cab45272c0983cfd32d616a0a7b28acb9
This commit is contained in:
@ -70,6 +70,74 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
const toss3 = (...args)=>{throw new SQLite3Error(...args)};
|
||||
sqlite3.SQLite3Error = SQLite3Error;
|
||||
|
||||
// Documented in DB.checkRc()
|
||||
const checkSqlite3Rc = function(dbPtr, sqliteResultCode){
|
||||
if(sqliteResultCode){
|
||||
if(dbPtr instanceof DB) dbPtr = dbPtr.pointer;
|
||||
throw new SQLite3Error(
|
||||
"sqlite result code",sqliteResultCode+":",
|
||||
(dbPtr
|
||||
? capi.sqlite3_errmsg(dbPtr)
|
||||
: capi.sqlite3_errstr(sqliteResultCode))
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
A proxy for DB class constructors. It must be called with the
|
||||
being-construct DB object as its "this".
|
||||
*/
|
||||
const dbCtorHelper = function ctor(fn=':memory:', flags='c', vfsName){
|
||||
if(!ctor._name2vfs){
|
||||
// Map special filenames which we handle here (instead of in C)
|
||||
// to some helpful metadata...
|
||||
ctor._name2vfs = Object.create(null);
|
||||
const isWorkerThread = (self.window===self /*===running in main window*/)
|
||||
? false
|
||||
: (n)=>toss3("The VFS for",n,"is only available in the main window thread.")
|
||||
ctor._name2vfs[':localStorage:'] = {
|
||||
vfs: 'kvvfs',
|
||||
filename: isWorkerThread || (()=>'local')
|
||||
};
|
||||
ctor._name2vfs[':sessionStorage:'] = {
|
||||
vfs: 'kvvfs',
|
||||
filename: isWorkerThread || (()=>'session')
|
||||
};
|
||||
}
|
||||
if('string'!==typeof fn){
|
||||
toss3("Invalid filename for DB constructor.");
|
||||
}
|
||||
const vfsCheck = ctor._name2vfs[fn];
|
||||
if(vfsCheck){
|
||||
vfsName = vfsCheck.vfs;
|
||||
fn = vfsCheck.filename(fn);
|
||||
}
|
||||
let ptr, oflags = 0;
|
||||
if( flags.indexOf('c')>=0 ){
|
||||
oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
|
||||
}
|
||||
if( flags.indexOf('w')>=0 ) oflags |= capi.SQLITE_OPEN_READWRITE;
|
||||
if( 0===oflags ) oflags |= capi.SQLITE_OPEN_READONLY;
|
||||
oflags |= capi.SQLITE_OPEN_EXRESCODE;
|
||||
const stack = capi.wasm.scopedAllocPush();
|
||||
try {
|
||||
const ppDb = capi.wasm.scopedAllocPtr() /* output (sqlite3**) arg */;
|
||||
const pVfsName = vfsName ? capi.wasm.scopedAllocCString(vfsName) : 0;
|
||||
const rc = capi.sqlite3_open_v2(fn, ppDb, oflags, pVfsName);
|
||||
ptr = capi.wasm.getPtrValue(ppDb);
|
||||
checkSqlite3Rc(ptr, rc);
|
||||
}catch( e ){
|
||||
if( ptr ) capi.sqlite3_close_v2(ptr);
|
||||
throw e;
|
||||
}finally{
|
||||
capi.wasm.scopedAllocPop(stack);
|
||||
}
|
||||
this.filename = fn;
|
||||
__ptrMap.set(this, ptr);
|
||||
__stmtMap.set(this, Object.create(null));
|
||||
__udfMap.set(this, Object.create(null));
|
||||
};
|
||||
|
||||
/**
|
||||
The DB class provides a high-level OO wrapper around an sqlite3
|
||||
db handle.
|
||||
@ -102,42 +170,29 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
"c". These modes are ignored for the special ":memory:" and ""
|
||||
names.
|
||||
|
||||
The final argument is currently unimplemented but will eventually
|
||||
be used to specify an optional sqlite3 VFS implementation name,
|
||||
as for the final argument to sqlite3_open_v2().
|
||||
The final argument is analogous to the final argument of
|
||||
sqlite3_open_v2(): the name of an sqlite3 VFS. Pass a falsy value,
|
||||
or not at all, to use the default. If passed a value, it must
|
||||
be the string name of a VFS
|
||||
|
||||
For purposes of passing a DB instance to C-style sqlite3
|
||||
functions, the DB object's read-only `pointer` property holds its
|
||||
`sqlite3*` pointer value. That property can also be used to check
|
||||
whether this DB instance is still open.
|
||||
|
||||
|
||||
EXPERIMENTAL: in the main window thread, the filenames
|
||||
":localStorage:" and ":sessionStorage:" are special: they cause
|
||||
the db to use either localStorage or sessionStorage for storing
|
||||
the database. In this mode, only a single database is permitted
|
||||
in each storage object. This feature is experimental and subject
|
||||
to any number of changes (including outright removal). This
|
||||
support requires a specific build of sqlite3, the existence of
|
||||
which can be determined at runtime by checking for a non-0 return
|
||||
value from sqlite3.capi.sqlite3_vfs_find("kvvfs").
|
||||
*/
|
||||
const DB = function ctor(fn=':memory:', flags='c', vtab="not yet implemented"){
|
||||
if('string'!==typeof fn){
|
||||
toss3("Invalid filename for DB constructor.");
|
||||
}
|
||||
let ptr, oflags = 0;
|
||||
if( flags.indexOf('c')>=0 ){
|
||||
oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
|
||||
}
|
||||
if( flags.indexOf('w')>=0 ) oflags |= capi.SQLITE_OPEN_READWRITE;
|
||||
if( 0===oflags ) oflags |= capi.SQLITE_OPEN_READONLY;
|
||||
oflags |= capi.SQLITE_OPEN_EXRESCODE;
|
||||
const stack = capi.wasm.scopedAllocPush();
|
||||
try {
|
||||
const ppDb = capi.wasm.scopedAllocPtr() /* output (sqlite3**) arg */;
|
||||
const rc = capi.sqlite3_open_v2(fn, ppDb, oflags, null);
|
||||
ptr = capi.wasm.getPtrValue(ppDb);
|
||||
ctor.checkRc(ptr, rc);
|
||||
}catch( e ){
|
||||
if( ptr ) capi.sqlite3_close_v2(ptr);
|
||||
throw e;
|
||||
}finally{
|
||||
capi.wasm.scopedAllocPop(stack);
|
||||
}
|
||||
this.filename = fn;
|
||||
__ptrMap.set(this, ptr);
|
||||
__stmtMap.set(this, Object.create(null));
|
||||
__udfMap.set(this, Object.create(null));
|
||||
const DB = function ctor(fn=':memory:', flags='c', vfsName){
|
||||
dbCtorHelper.apply(this, Array.prototype.slice.call(arguments));
|
||||
};
|
||||
|
||||
/**
|
||||
@ -232,6 +287,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
}else if(args[0] && 'object'===typeof args[0]){
|
||||
out.opt = args[0];
|
||||
out.sql = out.opt.sql;
|
||||
}else if(Array.isArray(args[0])){
|
||||
out.sql = args[0];
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
@ -295,17 +352,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
non-0 non-error codes need to be checked for in
|
||||
client code where they are expected.
|
||||
*/
|
||||
DB.checkRc = function(dbPtr, sqliteResultCode){
|
||||
if(sqliteResultCode){
|
||||
if(dbPtr instanceof DB) dbPtr = dbPtr.pointer;
|
||||
throw new SQLite3Error(
|
||||
"sqlite result code",sqliteResultCode+":",
|
||||
(dbPtr
|
||||
? capi.sqlite3_errmsg(dbPtr)
|
||||
: capi.sqlite3_errstr(sqliteResultCode))
|
||||
);
|
||||
}
|
||||
};
|
||||
DB.checkRc = checkSqlite3Rc;
|
||||
|
||||
DB.prototype = {
|
||||
/**
|
||||
@ -1532,5 +1579,19 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
DB,
|
||||
Stmt
|
||||
}/*oo1 object*/;
|
||||
|
||||
if( self.window===self && 0!==capi.sqlite3_vfs_find('kvvfs') ){
|
||||
/* In the main window thread, add a couple of convenience proxies
|
||||
for localStorage and sessionStorage DBs... */
|
||||
let klass = sqlite3.oo1.LocalStorageDb = function(){
|
||||
dbCtorHelper.call(this, 'local', 'c', 'kvvfs');
|
||||
};
|
||||
klass.prototype = DB.prototype;
|
||||
|
||||
klass = sqlite3.oo1.SessionStorageDb = function(){
|
||||
dbCtorHelper.call(this, 'session', 'c', 'kvvfs');
|
||||
};
|
||||
klass.prototype = DB.prototype;
|
||||
}
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user