2022-08-10 11:26:08 +00:00
/ *
2022 - 07 - 22
The author disclaims copyright to this source code . In place of a
legal notice , here is a blessing :
* May you do good and not evil .
* May you find forgiveness for yourself and forgive others .
* May you share freely , never taking more than you give .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
This file contains the so - called OO # 1 API wrapper for the sqlite3
WASM build . It requires that sqlite3 - api - glue . js has already run
2023-03-07 19:12:06 +00:00
and it installs its deliverable as globalThis . sqlite3 . oo1 .
2022-08-10 11:26:08 +00:00
* /
2023-03-07 19:12:06 +00:00
globalThis . sqlite3ApiBootstrap . initializers . push ( function ( sqlite3 ) {
2022-08-10 11:26:08 +00:00
const toss = ( ... args ) => { throw new Error ( args . join ( ' ' ) ) } ;
2022-10-02 00:09:40 +00:00
const toss3 = ( ... args ) => { throw new sqlite3 . SQLite3Error ( ... args ) } ;
2022-08-10 11:26:08 +00:00
2022-10-29 07:54:10 +00:00
const capi = sqlite3 . capi , wasm = sqlite3 . wasm , util = sqlite3 . util ;
2022-08-10 11:26:08 +00:00
/ * W h a t f o l l o w s i s c o l l o q u i a l l y k n o w n a s " O O A P I # 1 " . I t i s a
binding of the sqlite3 API which is designed to be run within
the same thread ( main or worker ) as the one in which the
sqlite3 WASM binding was initialized . This wrapper cannot use
the sqlite3 binding if , e . g . , the wrapper is in the main thread
and the sqlite3 API is in a worker . * /
/ * *
In order to keep clients from manipulating , perhaps
inadvertently , the underlying pointer values of DB and Stmt
instances , we ' ll gate access to them via the ` pointer ` property
accessor and store their real values in this map . Keys = DB / Stmt
objects , values = pointer values . This also unifies how those are
accessed , for potential use downstream via custom
2022-10-02 03:11:13 +00:00
wasm . xWrap ( ) function signatures which know how to extract
2022-08-10 11:26:08 +00:00
it .
* /
const _ _ptrMap = new WeakMap ( ) ;
/ * *
Map of DB instances to objects , each object being a map of Stmt
wasm pointers to Stmt objects .
* /
const _ _stmtMap = new WeakMap ( ) ;
/ * * I f o b j e c t o p t s h a s _ i t s o w n _ p r o p e r t y n a m e d p t h e n t h a t
property ' s value is returned , else dflt is returned . * /
2022-10-16 18:50:55 +00:00
const getOwnOption = ( opts , p , dflt ) => {
const d = Object . getOwnPropertyDescriptor ( opts , p ) ;
return d ? d . value : dflt ;
} ;
2022-08-10 11:26:08 +00:00
2022-09-12 16:09:50 +00:00
// Documented in DB.checkRc()
const checkSqlite3Rc = function ( dbPtr , sqliteResultCode ) {
if ( sqliteResultCode ) {
if ( dbPtr instanceof DB ) dbPtr = dbPtr . pointer ;
2022-10-02 00:09:40 +00:00
toss3 (
2023-05-19 15:54:41 +00:00
sqliteResultCode ,
2022-11-24 02:35:03 +00:00
"sqlite3 result code" , sqliteResultCode + ":" ,
2022-09-12 16:09:50 +00:00
( dbPtr
? capi . sqlite3 _errmsg ( dbPtr )
: capi . sqlite3 _errstr ( sqliteResultCode ) )
) ;
}
2022-11-24 02:35:03 +00:00
return arguments [ 0 ] ;
2022-09-12 16:09:50 +00:00
} ;
2022-10-03 13:03:41 +00:00
/ * *
sqlite3 _trace _v2 ( ) callback which gets installed by the DB ctor
if its open - flags contain "t" .
* /
const _ _dbTraceToConsole =
wasm . installFunction ( 'i(ippp)' , function ( t , c , p , x ) {
if ( capi . SQLITE _TRACE _STMT === t ) {
// x == SQL, p == sqlite3_stmt*
2022-12-25 15:28:19 +00:00
console . log ( "SQL TRACE #" + ( ++ this . counter ) + ' via sqlite3@' + c + ':' ,
2022-12-06 08:46:39 +00:00
wasm . cstrToJs ( x ) ) ;
2022-10-03 13:03:41 +00:00
}
} . bind ( { counter : 0 } ) ) ;
/ * *
2022-12-03 01:59:03 +00:00
A map of sqlite3 _vfs pointers to SQL code or a callback function
to run when the DB constructor opens a database with the given
VFS . In the latter case , the call signature is ( theDbObject , sqlite3Namespace )
and the callback is expected to throw on error .
2022-10-03 13:03:41 +00:00
* /
const _ _vfsPostOpenSql = Object . create ( null ) ;
2022-09-12 16:09:50 +00:00
/ * *
A proxy for DB class constructors . It must be called with the
2022-09-18 17:32:35 +00:00
being - construct DB object as its "this" . See the DB constructor
for the argument docs . This is split into a separate function
in order to enable simple creation of special - case DB constructors ,
2022-10-21 06:58:27 +00:00
e . g . JsStorageDb and OpfsDb .
2022-09-18 17:32:35 +00:00
Expects to be passed a configuration object with the following
properties :
- ` .filename ` : the db filename . It may be a special name like ":memory:"
or "" .
- ` .flags ` : as documented in the DB constructor .
- ` .vfs ` : as documented in the DB constructor .
It also accepts those as the first 3 arguments .
2022-09-12 16:09:50 +00:00
* /
2022-09-18 17:32:35 +00:00
const dbCtorHelper = function ctor ( ... args ) {
2022-09-12 16:09:50 +00:00
if ( ! ctor . _name2vfs ) {
2022-09-20 16:10:39 +00:00
/ * *
Map special filenames which we handle here ( instead of in C )
to some helpful metadata ...
As of 2022 - 09 - 20 , the C API supports the names : localStorage :
and : sessionStorage : for kvvfs . However , C code cannot
determine ( without embedded JS code , e . g . via Emscripten ' s
EM _JS ( ) ) whether the kvvfs is legal in the current browser
context ( namely the main UI thread ) . In order to help client
code fail early on , instead of it being delayed until they
try to read or write a kvvfs - backed db , we ' ll check for those
names here and throw if they ' re not legal in the current
context .
* /
2022-09-12 16:09:50 +00:00
ctor . _name2vfs = Object . create ( null ) ;
2022-09-20 16:10:39 +00:00
const isWorkerThread = ( 'function' === typeof importScripts /*===running in worker thread*/ )
? ( n ) => toss3 ( "The VFS for" , n , "is only available in the main window thread." )
: false ;
2022-09-12 16:09:50 +00:00
ctor . _name2vfs [ ':localStorage:' ] = {
2022-10-03 13:03:41 +00:00
vfs : 'kvvfs' , filename : isWorkerThread || ( ( ) => 'local' )
2022-09-12 16:09:50 +00:00
} ;
ctor . _name2vfs [ ':sessionStorage:' ] = {
2022-10-03 13:03:41 +00:00
vfs : 'kvvfs' , filename : isWorkerThread || ( ( ) => 'session' )
2022-09-12 16:09:50 +00:00
} ;
}
2022-09-18 17:32:35 +00:00
const opt = ctor . normalizeArgs ( ... args ) ;
let fn = opt . filename , vfsName = opt . vfs , flagsStr = opt . flags ;
if ( ( 'string' !== typeof fn && 'number' !== typeof fn )
|| 'string' !== typeof flagsStr
|| ( vfsName && ( 'string' !== typeof vfsName && 'number' !== typeof vfsName ) ) ) {
2023-02-06 14:01:19 +00:00
sqlite3 . config . error ( "Invalid DB ctor args" , opt , arguments ) ;
2022-09-18 17:32:35 +00:00
toss3 ( "Invalid arguments for DB constructor." ) ;
2022-09-12 16:09:50 +00:00
}
2022-12-06 08:46:39 +00:00
let fnJs = ( 'number' === typeof fn ) ? wasm . cstrToJs ( fn ) : fn ;
2022-09-18 17:32:35 +00:00
const vfsCheck = ctor . _name2vfs [ fnJs ] ;
2022-09-12 16:09:50 +00:00
if ( vfsCheck ) {
vfsName = vfsCheck . vfs ;
2022-09-18 17:32:35 +00:00
fn = fnJs = vfsCheck . filename ( fnJs ) ;
2022-09-12 16:09:50 +00:00
}
2022-10-03 13:03:41 +00:00
let pDb , oflags = 0 ;
2022-09-18 17:32:35 +00:00
if ( flagsStr . indexOf ( 'c' ) >= 0 ) {
2022-09-12 16:09:50 +00:00
oflags |= capi . SQLITE _OPEN _CREATE | capi . SQLITE _OPEN _READWRITE ;
}
2022-09-18 17:32:35 +00:00
if ( flagsStr . indexOf ( 'w' ) >= 0 ) oflags |= capi . SQLITE _OPEN _READWRITE ;
2022-09-12 16:09:50 +00:00
if ( 0 === oflags ) oflags |= capi . SQLITE _OPEN _READONLY ;
oflags |= capi . SQLITE _OPEN _EXRESCODE ;
2022-10-20 21:28:31 +00:00
const stack = wasm . pstack . pointer ;
2022-09-12 16:09:50 +00:00
try {
2022-10-20 21:28:31 +00:00
const pPtr = wasm . pstack . allocPtr ( ) /* output (sqlite3**) arg */ ;
2022-10-21 06:58:27 +00:00
let rc = capi . sqlite3 _open _v2 ( fn , pPtr , oflags , vfsName || 0 ) ;
2022-12-09 09:23:27 +00:00
pDb = wasm . peekPtr ( pPtr ) ;
2022-10-03 13:03:41 +00:00
checkSqlite3Rc ( pDb , rc ) ;
2022-12-13 08:25:28 +00:00
capi . sqlite3 _extended _result _codes ( pDb , 1 ) ;
2022-10-03 13:03:41 +00:00
if ( flagsStr . indexOf ( 't' ) >= 0 ) {
capi . sqlite3 _trace _v2 ( pDb , capi . SQLITE _TRACE _STMT ,
2022-12-25 15:28:19 +00:00
_ _dbTraceToConsole , pDb ) ;
2022-10-03 13:03:41 +00:00
}
2022-09-12 16:09:50 +00:00
} catch ( e ) {
2022-10-03 13:03:41 +00:00
if ( pDb ) capi . sqlite3 _close _v2 ( pDb ) ;
2022-09-12 16:09:50 +00:00
throw e ;
} finally {
2022-10-20 21:28:31 +00:00
wasm . pstack . restore ( stack ) ;
2022-09-12 16:09:50 +00:00
}
2022-09-18 17:32:35 +00:00
this . filename = fnJs ;
2022-10-03 13:03:41 +00:00
_ _ptrMap . set ( this , pDb ) ;
2022-09-12 16:09:50 +00:00
_ _stmtMap . set ( this , Object . create ( null ) ) ;
2022-12-03 01:59:03 +00:00
try {
// Check for per-VFS post-open SQL/callback...
const pVfs = capi . sqlite3 _js _db _vfs ( pDb ) ;
if ( ! pVfs ) toss3 ( "Internal error: cannot get VFS for new db handle." ) ;
const postInitSql = _ _vfsPostOpenSql [ pVfs ] ;
if ( postInitSql instanceof Function ) {
postInitSql ( this , sqlite3 ) ;
} else if ( postInitSql ) {
checkSqlite3Rc (
pDb , capi . sqlite3 _exec ( pDb , postInitSql , 0 , 0 , 0 )
) ;
2023-01-27 19:56:40 +00:00
}
2022-12-03 01:59:03 +00:00
} catch ( e ) {
this . close ( ) ;
throw e ;
}
2022-09-12 16:09:50 +00:00
} ;
2022-09-18 17:32:35 +00:00
2022-10-03 13:03:41 +00:00
/ * *
Sets SQL which should be exec ( ) ' d on a DB instance after it is
2022-12-03 01:59:03 +00:00
opened with the given VFS pointer . The SQL may be any type
2022-12-05 13:12:48 +00:00
supported by the "string:flexible" function argument conversion .
Alternately , the 2 nd argument may be a function , in which case it
is called with ( theOo1DbObject , sqlite3Namespace ) at the end of
the DB ( ) constructor . The function must throw on error , in which
case the db is closed and the exception is propagated . This
function is intended only for use by DB subclasses or sqlite3 _vfs
implementations .
2022-10-03 13:03:41 +00:00
* /
dbCtorHelper . setVfsPostOpenSql = function ( pVfs , sql ) {
_ _vfsPostOpenSql [ pVfs ] = sql ;
} ;
2022-09-18 17:32:35 +00:00
/ * *
A helper for DB constructors . It accepts either a single
config - style object or up to 3 arguments ( filename , dbOpenFlags ,
dbVfsName ) . It returns a new object containing :
{ filename : ... , flags : ... , vfs : ... }
If passed an object , any additional properties it has are copied
as - is into the new object .
* /
2022-10-02 00:09:40 +00:00
dbCtorHelper . normalizeArgs = function ( filename = ':memory:' , flags = 'c' , vfs = null ) {
2022-09-18 17:32:35 +00:00
const arg = { } ;
2022-11-23 16:39:07 +00:00
if ( 1 === arguments . length && arguments [ 0 ] && 'object' === typeof arguments [ 0 ] ) {
Object . assign ( arg , arguments [ 0 ] ) ;
2022-09-18 17:32:35 +00:00
if ( undefined === arg . flags ) arg . flags = 'c' ;
if ( undefined === arg . vfs ) arg . vfs = null ;
2022-10-02 00:09:40 +00:00
if ( undefined === arg . filename ) arg . filename = ':memory:' ;
2022-09-18 17:32:35 +00:00
} else {
arg . filename = filename ;
arg . flags = flags ;
arg . vfs = vfs ;
}
return arg ;
} ;
2022-08-10 11:26:08 +00:00
/ * *
The DB class provides a high - level OO wrapper around an sqlite3
db handle .
The given db filename must be resolvable using whatever
filesystem layer ( virtual or otherwise ) is set up for the default
sqlite3 VFS .
Note that the special sqlite3 db names ":memory:" and ""
( temporary db ) have their normal special meanings here and need
not resolve to real filenames , but "" uses an on - storage
temporary database and requires that the VFS support that .
2022-08-16 16:36:19 +00:00
The second argument specifies the open / create mode for the
database . It must be string containing a sequence of letters ( in
any order , but case sensitive ) specifying the mode :
2022-10-03 13:03:41 +00:00
- "c" : create if it does not exist , else fail if it does not
2022-08-16 16:36:19 +00:00
exist . Implies the "w" flag .
2022-10-03 13:03:41 +00:00
- "w" : write . Implies "r" : a db cannot be write - only .
2022-08-16 16:36:19 +00:00
2022-10-03 13:03:41 +00:00
- "r" : read - only if neither "w" nor "c" are provided , else it
2022-08-16 16:36:19 +00:00
is ignored .
2022-10-03 13:03:41 +00:00
- "t" : enable tracing of SQL executed on this database handle ,
2022-10-03 13:46:20 +00:00
sending it to ` console.log() ` . To disable it later , call
` sqlite3.capi.sqlite3_trace_v2(thisDb.pointer, 0, 0, 0) ` .
2022-10-03 13:03:41 +00:00
2022-10-03 13:46:20 +00:00
If "w" is not provided , the db is implicitly read - only , noting
that "rc" is meaningless
2022-08-16 16:36:19 +00:00
Any other letters are currently ignored . The default is
"c" . These modes are ignored for the special ":memory:" and ""
2022-10-03 13:46:20 +00:00
names and _may _ be ignored altogether for certain VFSes .
2022-08-16 16:36:19 +00:00
2022-09-12 16:09:50 +00:00
The final argument is analogous to the final argument of
sqlite3 _open _v2 ( ) : the name of an sqlite3 VFS . Pass a falsy value ,
2022-10-02 00:09:40 +00:00
or none at all , to use the default . If passed a value , it must
2022-10-03 13:46:20 +00:00
be the string name of a VFS .
2022-08-10 11:26:08 +00:00
2022-09-18 17:32:35 +00:00
The constructor optionally ( and preferably ) takes its arguments
in the form of a single configuration object with the following
properties :
2022-11-01 07:49:49 +00:00
- ` filename ` : database file name
- ` flags ` : open - mode flags
- ` vfs ` : the VFS fname
2022-09-18 17:32:35 +00:00
The ` filename ` and ` vfs ` arguments may be either JS strings or
2022-10-03 13:46:20 +00:00
C - strings allocated via WASM . ` flags ` is required to be a JS
string ( because it ' s specific to this API , which is specific
to JS ) .
2022-09-18 17:32:35 +00:00
2022-08-10 11:26:08 +00:00
For purposes of passing a DB instance to C - style sqlite3
2022-08-16 16:36:19 +00:00
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 .
2022-09-12 16:09:50 +00:00
2022-10-03 13:46:20 +00:00
In the main window thread , the filenames ` ":localStorage:" ` and
` ":sessionStorage:" ` are special : they cause the db to use either
2022-10-03 13:03:41 +00:00
localStorage or sessionStorage for storing the database using
2022-10-03 13:46:20 +00:00
the kvvfs . If one of these names are used , they trump
any vfs name set in the arguments .
2022-08-10 11:26:08 +00:00
* /
2022-09-18 17:32:35 +00:00
const DB = function ( ... args ) {
dbCtorHelper . apply ( this , args ) ;
2022-08-10 11:26:08 +00:00
} ;
2022-10-28 10:36:18 +00:00
DB . dbCtorHelper = dbCtorHelper ;
2022-08-10 11:26:08 +00:00
/ * *
Internal - use enum for mapping JS types to DB - bindable types .
These do not ( and need not ) line up with the SQLITE _type
values . All values in this enum must be truthy and distinct
but they need not be numbers .
* /
const BindTypes = {
null : 1 ,
number : 2 ,
string : 3 ,
boolean : 4 ,
blob : 5
} ;
BindTypes [ 'undefined' ] == BindTypes . null ;
2022-10-02 03:11:13 +00:00
if ( wasm . bigIntEnabled ) {
2022-08-10 11:26:08 +00:00
BindTypes . bigint = BindTypes . number ;
}
/ * *
This class wraps sqlite3 _stmt . Calling this constructor
directly will trigger an exception . Use DB . prepare ( ) to create
new instances .
For purposes of passing a Stmt instance to C - style sqlite3
functions , its read - only ` pointer ` property holds its ` sqlite3_stmt* `
pointer value .
2022-09-05 13:24:08 +00:00
Other non - function properties include :
- ` db ` : the DB object which created the statement .
2023-05-10 21:06:02 +00:00
- ` columnCount ` : the number of result columns in the query , or 0
for queries which cannot return results . This property is a proxy
for sqlite3 _column _count ( ) and its use in loops should be avoided
because of the call overhead associated with that . The
` columnCount ` is not cached when the Stmt is created because a
schema change made via a separate db connection between this
statement ' s preparation and when it is stepped may invalidate it .
- ` parameterCount ` : the number of bindable parameters in the query .
2022-08-10 11:26:08 +00:00
* /
const Stmt = function ( ) {
if ( BindTypes !== arguments [ 2 ] ) {
2022-12-24 13:46:27 +00:00
toss3 ( capi . SQLITE _MISUSE , "Do not call the Stmt constructor directly. Use DB.prepare()." ) ;
2022-08-10 11:26:08 +00:00
}
this . db = arguments [ 0 ] ;
_ _ptrMap . set ( this , arguments [ 1 ] ) ;
this . parameterCount = capi . sqlite3 _bind _parameter _count ( this . pointer ) ;
} ;
/** Throws if the given DB has been closed, else it is returned. */
const affirmDbOpen = function ( db ) {
if ( ! db . pointer ) toss3 ( "DB has been closed." ) ;
return db ;
} ;
/ * * T h r o w s i f n d x i s n o t a n i n t e g e r o r i f i t i s o u t o f r a n g e
for stmt . columnCount , else returns stmt .
Reminder : this will also fail after the statement is finalized
but the resulting error will be about an out - of - bounds column
2022-09-06 16:35:54 +00:00
index rather than a statement - is - finalized error .
2022-08-10 11:26:08 +00:00
* /
const affirmColIndex = function ( stmt , ndx ) {
if ( ( ndx !== ( ndx | 0 ) ) || ndx < 0 || ndx >= stmt . columnCount ) {
toss3 ( "Column index" , ndx , "is out of range." ) ;
}
return stmt ;
} ;
/ * *
2022-08-25 13:27:52 +00:00
Expects to be passed the ` arguments ` object from DB . exec ( ) . Does
the argument processing / validation , throws on error , and returns
a new object on success :
2022-08-10 11:26:08 +00:00
{ sql : the SQL , opt : optionsObj , cbArg : function }
2022-09-06 16:35:54 +00:00
The opt object is a normalized copy of any passed to this
function . The sql will be converted to a string if it is provided
in one of the supported non - string formats .
cbArg is only set if the opt . callback or opt . resultRows are set ,
in which case it ' s a function which expects to be passed the
current Stmt and returns the callback argument of the type
indicated by the input arguments .
2022-08-10 11:26:08 +00:00
* /
2022-10-31 11:09:14 +00:00
const parseExecArgs = function ( db , args ) {
2022-08-10 11:26:08 +00:00
const out = Object . create ( null ) ;
out . opt = Object . create ( null ) ;
switch ( args . length ) {
case 1 :
if ( 'string' === typeof args [ 0 ] || util . isSQLableTypedArray ( args [ 0 ] ) ) {
out . sql = args [ 0 ] ;
2022-10-21 05:27:40 +00:00
} else if ( Array . isArray ( args [ 0 ] ) ) {
out . sql = args [ 0 ] ;
2022-08-10 11:26:08 +00:00
} else if ( args [ 0 ] && 'object' === typeof args [ 0 ] ) {
out . opt = args [ 0 ] ;
out . sql = out . opt . sql ;
}
break ;
case 2 :
out . sql = args [ 0 ] ;
out . opt = args [ 1 ] ;
break ;
default : toss3 ( "Invalid argument count for exec()." ) ;
} ;
2022-10-31 11:09:14 +00:00
out . sql = util . flexibleString ( out . sql ) ;
if ( 'string' !== typeof out . sql ) {
2022-10-21 05:27:40 +00:00
toss3 ( "Missing SQL argument or unsupported SQL value type." ) ;
2022-08-10 11:26:08 +00:00
}
2022-10-31 11:09:14 +00:00
const opt = out . opt ;
switch ( opt . returnValue ) {
case 'resultRows' :
if ( ! opt . resultRows ) opt . resultRows = [ ] ;
out . returnVal = ( ) => opt . resultRows ;
break ;
case 'saveSql' :
if ( ! opt . saveSql ) opt . saveSql = [ ] ;
out . returnVal = ( ) => opt . saveSql ;
break ;
case undefined :
case 'this' :
2022-11-01 11:09:34 +00:00
out . returnVal = ( ) => db ;
2022-10-31 11:09:14 +00:00
break ;
default :
toss3 ( "Invalid returnValue value:" , opt . returnValue ) ;
}
2023-01-28 05:09:26 +00:00
if ( ! opt . callback && ! opt . returnValue && undefined !== opt . rowMode ) {
if ( ! opt . resultRows ) opt . resultRows = [ ] ;
out . returnVal = ( ) => opt . resultRows ;
}
2022-10-31 11:09:14 +00:00
if ( opt . callback || opt . resultRows ) {
switch ( ( undefined === opt . rowMode )
? 'array' : opt . rowMode ) {
2022-08-25 13:27:52 +00:00
case 'object' : out . cbArg = ( stmt ) => stmt . get ( Object . create ( null ) ) ; break ;
2022-08-10 11:26:08 +00:00
case 'array' : out . cbArg = ( stmt ) => stmt . get ( [ ] ) ; break ;
case 'stmt' :
2022-10-31 11:09:14 +00:00
if ( Array . isArray ( opt . resultRows ) ) {
2022-08-25 13:27:52 +00:00
toss3 ( "exec(): invalid rowMode for a resultRows array: must" ,
2022-08-10 11:26:08 +00:00
"be one of 'array', 'object'," ,
2022-08-24 20:57:37 +00:00
"a result column number, or column name reference." ) ;
2022-08-10 11:26:08 +00:00
}
out . cbArg = ( stmt ) => stmt ;
break ;
default :
2022-10-31 11:09:14 +00:00
if ( util . isInt32 ( opt . rowMode ) ) {
out . cbArg = ( stmt ) => stmt . get ( opt . rowMode ) ;
2022-08-10 11:26:08 +00:00
break ;
2022-12-24 11:16:49 +00:00
} else if ( 'string' === typeof opt . rowMode
&& opt . rowMode . length > 1
&& '$' === opt . rowMode [ 0 ] ) {
2022-12-14 08:01:34 +00:00
/ * " $ X " : f e t c h c o l u m n n a m e d " X " ( c a s e - s e n s i t i v e ! ) . P r i o r
to 2022 - 12 - 14 ":X" and "@X" were also permitted , but
2022-12-14 14:28:54 +00:00
having so many options is unnecessary and likely to
cause confusion . * /
2022-12-24 11:16:49 +00:00
const $colName = opt . rowMode . substr ( 1 ) ;
out . cbArg = ( stmt ) => {
const rc = stmt . get ( Object . create ( null ) ) [ $colName ] ;
return ( undefined === rc )
? toss3 ( capi . SQLITE _NOTFOUND ,
"exec(): unknown result column:" , $colName )
: rc ;
} ;
break ;
2022-08-24 20:57:37 +00:00
}
2022-10-31 11:09:14 +00:00
toss3 ( "Invalid rowMode:" , opt . rowMode ) ;
2022-08-10 11:26:08 +00:00
}
}
return out ;
} ;
2022-10-30 11:39:47 +00:00
/ * *
2022-12-25 22:44:13 +00:00
Internal impl of the DB . selectValue ( ) , selectArray ( ) , and
2022-10-31 11:09:14 +00:00
selectObject ( ) methods .
2022-10-30 11:39:47 +00:00
* /
2022-12-25 22:44:13 +00:00
const _ _selectFirstRow = ( db , sql , bind , ... getArgs ) => {
const stmt = db . prepare ( sql ) ;
2022-10-30 11:39:47 +00:00
try {
2023-05-19 18:23:53 +00:00
const rc = stmt . bind ( bind ) . step ( ) ? stmt . get ( ... getArgs ) : undefined ;
stmt . reset ( /*for INSERT...RETURNING locking case*/ ) ;
return rc ;
2022-10-30 11:39:47 +00:00
} finally {
2022-12-25 22:44:13 +00:00
stmt . finalize ( ) ;
2022-10-30 11:39:47 +00:00
}
} ;
2022-12-06 06:09:03 +00:00
/ * *
2022-12-25 22:49:55 +00:00
Internal impl of the DB . selectArrays ( ) and selectObjects ( )
methods .
2022-12-06 06:09:03 +00:00
* /
const _ _selectAll =
( db , sql , bind , rowMode ) => db . exec ( {
sql , bind , rowMode , returnValue : 'resultRows'
} ) ;
2022-08-10 11:26:08 +00:00
/ * *
2022-09-05 13:24:08 +00:00
Expects to be given a DB instance or an ` sqlite3* ` pointer ( may
be null ) and an sqlite3 API result code . If the result code is
not falsy , this function throws an SQLite3Error with an error
2022-11-24 02:35:03 +00:00
message from sqlite3 _errmsg ( ) , using db ( or , if db is - a DB ,
db . pointer ) as the db handle , or sqlite3 _errstr ( ) if db is
falsy . Note that if it ' s passed a non - error code like SQLITE _ROW
or SQLITE _DONE , it will still throw but the error string might be
"Not an error." The various non - 0 non - error codes need to be
checked for in client code where they are expected .
2023-05-19 15:54:41 +00:00
The thrown exception ' s ` resultCode ` property will be the value of
the second argument to this function .
2022-11-24 02:35:03 +00:00
If it does not throw , it returns its first argument .
2022-08-10 11:26:08 +00:00
* /
2022-11-24 02:35:03 +00:00
DB . checkRc = ( db , resultCode ) => checkSqlite3Rc ( db , resultCode ) ;
2022-08-10 11:26:08 +00:00
DB . prototype = {
2022-09-30 15:46:08 +00:00
/** Returns true if this db handle is open, else false. */
isOpen : function ( ) {
return ! ! this . pointer ;
} ,
/** Throws if this given DB has been closed, else returns `this`. */
affirmOpen : function ( ) {
return affirmDbOpen ( this ) ;
} ,
2022-08-10 11:26:08 +00:00
/ * *
Finalizes all open statements and closes this database
connection . This is a no - op if the db has already been
closed . After calling close ( ) , ` this.pointer ` will resolve to
` undefined ` , so that can be used to check whether the db
instance is still opened .
2022-09-18 17:32:35 +00:00
If this . onclose . before is a function then it is called before
any close - related cleanup .
If this . onclose . after is a function then it is called after the
db is closed but before auxiliary state like this . filename is
cleared .
2022-12-08 09:06:20 +00:00
Both onclose handlers are passed this object , with the onclose
object as their "this," noting that the db will have been
closed when onclose . after is called . If this db is not opened
when close ( ) is called , neither of the handlers are called . Any
exceptions the handlers throw are ignored because " destructors
must not throw . "
2022-09-18 17:32:35 +00:00
Note that garbage collection of a db handle , if it happens at
all , will never trigger close ( ) , so onclose handlers are not a
reliable way to implement close - time cleanup or maintenance of
a db .
2022-08-10 11:26:08 +00:00
* /
close : function ( ) {
if ( this . pointer ) {
2022-09-18 17:32:35 +00:00
if ( this . onclose && ( this . onclose . before instanceof Function ) ) {
try { this . onclose . before ( this ) }
catch ( e ) { /*ignore*/ }
}
2022-08-10 11:26:08 +00:00
const pDb = this . pointer ;
Object . keys ( _ _stmtMap . get ( this ) ) . forEach ( ( k , s ) => {
2023-05-19 17:50:16 +00:00
if ( s && s . pointer ) {
try { s . finalize ( ) }
catch ( e ) { /*ignore*/ }
}
2022-08-10 11:26:08 +00:00
} ) ;
_ _ptrMap . delete ( this ) ;
_ _stmtMap . delete ( this ) ;
capi . sqlite3 _close _v2 ( pDb ) ;
2022-09-18 17:32:35 +00:00
if ( this . onclose && ( this . onclose . after instanceof Function ) ) {
try { this . onclose . after ( this ) }
catch ( e ) { /*ignore*/ }
}
2022-08-10 11:26:08 +00:00
delete this . filename ;
}
} ,
/ * *
Returns the number of changes , as per sqlite3 _changes ( )
( if the first argument is false ) or sqlite3 _total _changes ( )
( if it ' s true ) . If the 2 nd argument is true , it uses
sqlite3 _changes64 ( ) or sqlite3 _total _changes64 ( ) , which
will trigger an exception if this build does not have
BigInt support enabled .
* /
changes : function ( total = false , sixtyFour = false ) {
const p = affirmDbOpen ( this ) . pointer ;
if ( total ) {
return sixtyFour
? capi . sqlite3 _total _changes64 ( p )
: capi . sqlite3 _total _changes ( p ) ;
} else {
return sixtyFour
? capi . sqlite3 _changes64 ( p )
: capi . sqlite3 _changes ( p ) ;
}
} ,
2022-10-26 11:27:33 +00:00
/ * *
Similar to the this . filename but returns the
sqlite3 _db _filename ( ) value for the given database name ,
defaulting to "main" . The argument may be either a JS string
or a pointer to a WASM - allocated C - string .
* /
dbFilename : function ( dbName = 'main' ) {
return capi . sqlite3 _db _filename ( affirmDbOpen ( this ) . pointer , dbName ) ;
} ,
2022-08-10 11:26:08 +00:00
/ * *
Returns the name of the given 0 - based db number , as documented
for sqlite3 _db _name ( ) .
* /
dbName : function ( dbNumber = 0 ) {
return capi . sqlite3 _db _name ( affirmDbOpen ( this ) . pointer , dbNumber ) ;
} ,
2022-11-01 07:49:49 +00:00
/ * *
Returns the name of the sqlite3 _vfs used by the given database
of this connection ( defaulting to 'main' ) . The argument may be
either a JS string or a WASM C - string . Returns undefined if the
given db name is invalid . Throws if this object has been
close ( ) d .
* /
dbVfsName : function ( dbName = 0 ) {
let rc ;
const pVfs = capi . sqlite3 _js _db _vfs (
affirmDbOpen ( this ) . pointer , dbName
) ;
if ( pVfs ) {
const v = new capi . sqlite3 _vfs ( pVfs ) ;
2022-12-06 08:46:39 +00:00
try { rc = wasm . cstrToJs ( v . $zName ) }
2022-11-01 07:49:49 +00:00
finally { v . dispose ( ) }
}
2022-12-24 01:59:42 +00:00
return rc ;
2022-11-01 07:49:49 +00:00
} ,
2022-08-10 11:26:08 +00:00
/ * *
Compiles the given SQL and returns a prepared Stmt . This is
the only way to create new Stmt objects . Throws on error .
2022-09-27 09:17:37 +00:00
The given SQL must be a string , a Uint8Array holding SQL , a
WASM pointer to memory holding the NUL - terminated SQL string ,
or an array of strings . In the latter case , the array is
concatenated together , with no separators , to form the SQL
string ( arrays are often a convenient way to formulate long
statements ) . If the SQL contains no statements , an
SQLite3Error is thrown .
2022-08-10 11:26:08 +00:00
Design note : the C API permits empty SQL , reporting it as a 0
result code and a NULL stmt pointer . Supporting that case here
would cause extra work for all clients : any use of the Stmt API
on such a statement will necessarily throw , so clients would be
required to check ` stmt.pointer ` after calling ` prepare() ` in
order to determine whether the Stmt instance is empty or not .
Long - time practice ( with other sqlite3 script bindings )
2022-09-05 13:24:08 +00:00
suggests that the empty - prepare case is sufficiently rare that
supporting it here would simply hurt overall usability .
2022-08-10 11:26:08 +00:00
* /
prepare : function ( sql ) {
affirmDbOpen ( this ) ;
2022-10-02 03:11:13 +00:00
const stack = wasm . pstack . pointer ;
2022-08-10 11:26:08 +00:00
let ppStmt , pStmt ;
try {
2022-10-02 03:11:13 +00:00
ppStmt = wasm . pstack . alloc ( 8 ) /* output (sqlite3_stmt**) arg */ ;
2022-08-10 11:26:08 +00:00
DB . checkRc ( this , capi . sqlite3 _prepare _v2 ( this . pointer , sql , - 1 , ppStmt , null ) ) ;
2022-12-09 09:23:27 +00:00
pStmt = wasm . peekPtr ( ppStmt ) ;
2022-08-10 11:26:08 +00:00
}
2022-10-02 00:09:40 +00:00
finally {
2022-10-02 03:11:13 +00:00
wasm . pstack . restore ( stack ) ;
2022-10-02 00:09:40 +00:00
}
2022-08-10 11:26:08 +00:00
if ( ! pStmt ) toss3 ( "Cannot prepare empty SQL." ) ;
const stmt = new Stmt ( this , pStmt , BindTypes ) ;
_ _stmtMap . get ( this ) [ pStmt ] = stmt ;
return stmt ;
} ,
/ * *
Executes one or more SQL statements in the form of a single
string . Its arguments must be either ( sql , optionsObject ) or
2022-10-31 11:09:14 +00:00
( optionsObject ) . In the latter case , optionsObject . sql must
contain the SQL to execute . By default it returns this object
but that can be changed via the ` returnValue ` option as
described below . Throws on error .
2022-08-10 11:26:08 +00:00
If no SQL is provided , or a non - string is provided , an
exception is triggered . Empty SQL , on the other hand , is
simply a no - op .
The optional options object may contain any of the following
properties :
2022-10-31 11:09:14 +00:00
- ` sql ` = the SQL to run ( unless it ' s provided as the first
2022-08-25 13:27:52 +00:00
argument ) . This must be of type string , Uint8Array , or an array
of strings . In the latter case they ' re concatenated together
as - is , _with no separator _ between elements , before evaluation .
The array form is often simpler for long hand - written queries .
2022-08-10 11:26:08 +00:00
2022-10-31 11:09:14 +00:00
- ` bind ` = a single value valid as an argument for
2022-08-25 13:27:52 +00:00
Stmt . bind ( ) . This is _only _ applied to the _first _ non - empty
statement in the SQL which has any bindable parameters . ( Empty
statements are skipped entirely . )
2022-10-31 11:09:14 +00:00
- ` saveSql ` = an optional array . If set , the SQL of each
2022-08-25 13:27:52 +00:00
executed statement is appended to this array before the
2022-09-05 13:24:08 +00:00
statement is executed ( but after it is prepared - we don ' t have
2022-10-31 11:09:14 +00:00
the string until after that ) . Empty SQL statements are elided
but can have odd effects in the output . e . g . SQL of : ` "select
1 ; -- empty \ n ; select 2 " ` will result in an array containing
` ["select 1;", "--empty \n ; select 2"] ` . That ' s simply how
sqlite3 records the SQL for the 2 nd statement .
2022-08-25 13:27:52 +00:00
=== === === === === === === === === === === === === === === === === === === === === ===
The following options apply _only _ to the _first _ statement
which has a non - zero result column count , regardless of whether
the statement actually produces any result rows .
=== === === === === === === === === === === === === === === === === === === === === ===
2022-08-10 11:26:08 +00:00
2022-10-31 11:09:14 +00:00
- ` columnNames ` : if this is an array , the column names of the
2022-09-13 19:27:03 +00:00
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 .
2022-12-24 01:59:42 +00:00
- ` callback ` = a function which gets called for each row of the
2023-05-10 21:06:02 +00:00
result set , but only if that statement has any result rows . The
callback ' s "this" is the options object , noting that this
function synthesizes one if the caller does not pass one to
exec ( ) . The second argument passed to the callback is always
the current Stmt object , as it ' s needed if the caller wants to
fetch the column names or some such ( noting that they could
also be fetched via ` this.columnNames ` , if the client provides
the ` columnNames ` option ) . If the callback returns a literal
` false ` ( as opposed to any other falsy value , e . g . an implicit
` undefined ` return ) , any ongoing statement - ` step() ` iteration
stops without an error . The return value of the callback is
otherwise ignored .
2022-08-25 13:27:52 +00:00
ACHTUNG : The callback MUST NOT modify the Stmt object . Calling
any of the Stmt . get ( ) variants , Stmt . getColumnName ( ) , or
similar , is legal , but calling step ( ) or finalize ( ) is
2022-09-15 02:27:48 +00:00
not . Member methods which are illegal in this context will
2022-12-24 01:59:42 +00:00
trigger an exception , but clients must also refrain from using
any lower - level ( C - style ) APIs which might modify the
statement .
2022-08-25 13:27:52 +00:00
The first argument passed to the callback defaults to an array of
values from the current result row but may be changed with ...
2022-10-31 11:09:14 +00:00
- ` rowMode ` = specifies the type of he callback ' s first argument .
2022-08-25 13:27:52 +00:00
It may be any of ...
A ) A string describing what type of argument should be passed
2022-08-24 20:57:37 +00:00
as the first argument to the callback :
2022-09-05 13:24:08 +00:00
A . 1 ) ` 'array' ` ( the default ) causes the results of
2022-09-13 19:27:03 +00:00
` stmt.get([]) ` to be passed to the ` callback ` and / or appended
2023-05-10 21:06:02 +00:00
to ` resultRows ` .
2022-08-24 20:57:37 +00:00
2022-09-05 13:24:08 +00:00
A . 2 ) ` 'object' ` causes the results of
2022-08-25 13:27:52 +00:00
` stmt.get(Object.create(null)) ` to be passed to the
` callback ` and / or appended to ` resultRows ` . Achtung : an SQL
result may have multiple columns with identical names . In
that case , the right - most column will be the one set in this
object !
2022-08-24 20:57:37 +00:00
2022-09-05 13:24:08 +00:00
A . 3 ) ` 'stmt' ` causes the current Stmt to be passed to the
2022-08-24 20:57:37 +00:00
callback , but this mode will trigger an exception if
2023-05-10 21:06:02 +00:00
` resultRows ` is an array because appending the transient
statement to the array would be downright unhelpful .
2022-08-24 20:57:37 +00:00
2022-08-25 13:27:52 +00:00
B ) An integer , indicating a zero - based column in the result
row . Only that one single value will be passed on .
2022-08-24 20:57:37 +00:00
C ) A string with a minimum length of 2 and leading character of
2022-12-14 08:01:34 +00:00
'$' will fetch the row as an object , extract that one field ,
and pass that field ' s value to the callback . Note 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' `
would work but ` ' $ a' ` would not . A reference to a column not in
the result set will trigger an exception on the first 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 .
2022-08-24 20:57:37 +00:00
Any other ` rowMode ` value triggers an exception .
2022-08-10 11:26:08 +00:00
2022-10-31 11:09:14 +00:00
- ` resultRows ` : if this is an array , it functions similarly to
2022-08-25 13:27:52 +00:00
the ` callback ` option : each row of the result set ( if any ) ,
with the exception that the ` rowMode ` 'stmt' is not legal . It
is legal to use both ` resultRows ` and ` callback ` , but
` resultRows ` is likely much simpler to use for small data sets
and can be used over a WebWorker - style message interface .
exec ( ) throws if ` resultRows ` is set and ` rowMode ` is 'stmt' .
2022-10-31 11:09:14 +00:00
- ` returnValue ` : is a string specifying what this function
should return :
2023-01-28 05:09:26 +00:00
A ) The default value is ( usually ) ` "this" ` , meaning that the
2023-05-19 16:12:06 +00:00
DB object itself should be returned . The exception is if
2023-01-28 05:09:26 +00:00
the caller passes neither of ` callback ` nor ` returnValue `
but does pass an explicit ` rowMode ` then the default
` returnValue ` is ` "resultRows" ` , described below .
2022-10-31 11:09:14 +00:00
B ) ` "resultRows" ` means to return the value of the
` resultRows ` option . If ` resultRows ` is not set , this
function behaves as if it were set to an empty array .
C ) ` "saveSql" ` means to return the value of the
` saveSql ` option . If ` saveSql ` is not set , this
function behaves as if it were set to an empty array .
2022-09-13 19:27:03 +00:00
Potential TODOs :
2022-10-31 11:09:14 +00:00
- ` bind ` : permit an array of arrays / objects to bind . The first
2022-09-13 19:27:03 +00:00
sub - array would act on the first statement which has bindable
parameters ( as it does now ) . The 2 nd would act on the next such
statement , etc .
2022-10-31 11:09:14 +00:00
- ` callback ` and ` resultRows ` : permit an array entries with
semantics similar to those described for ` bind ` above .
2022-09-13 19:27:03 +00:00
2022-08-10 11:26:08 +00:00
* /
2022-08-25 13:27:52 +00:00
exec : function ( /*(sql [,obj]) || (obj)*/ ) {
2022-08-10 11:26:08 +00:00
affirmDbOpen ( this ) ;
2022-10-31 11:09:14 +00:00
const arg = parseExecArgs ( this , arguments ) ;
2022-08-25 13:27:52 +00:00
if ( ! arg . sql ) {
2022-11-01 11:09:34 +00:00
return toss3 ( "exec() requires an SQL string." ) ;
2022-08-25 13:27:52 +00:00
}
2022-08-10 11:26:08 +00:00
const opt = arg . opt ;
const callback = opt . callback ;
2022-11-01 11:09:34 +00:00
const resultRows =
Array . isArray ( opt . resultRows ) ? opt . resultRows : undefined ;
2022-08-10 11:26:08 +00:00
let stmt ;
let bind = opt . bind ;
2022-12-24 01:59:42 +00:00
let evalFirstResult = ! ! (
arg . cbArg || opt . columnNames || resultRows
) /* true to step through the first result-returning statement */ ;
2022-08-10 11:26:08 +00:00
const stack = wasm . scopedAllocPush ( ) ;
2022-12-14 08:01:34 +00:00
const saveSql = Array . isArray ( opt . saveSql ) ? opt . saveSql : undefined ;
2022-08-10 11:26:08 +00:00
try {
const isTA = util . isSQLableTypedArray ( arg . sql )
/ * O p t i m i z a t i o n : i f t h e S Q L i s a T y p e d A r r a y w e c a n s a v e s o m e s t r i n g
conversion costs . * / ;
/ * A l l o c a t e t h e t w o o u t p u t p o i n t e r s ( p p S t m t , p z T a i l ) a n d h e a p
space for the SQL ( pSql ) . When prepare _v2 ( ) returns , pzTail
will point to somewhere in pSql . * /
let sqlByteLen = isTA ? arg . sql . byteLength : wasm . jstrlen ( arg . sql ) ;
2022-12-24 01:59:42 +00:00
const ppStmt = wasm . scopedAlloc (
/* output (sqlite3_stmt**) arg and pzTail */
( 2 * wasm . ptrSizeof ) + ( sqlByteLen + 1 /* SQL + NUL */ )
) ;
2022-08-10 11:26:08 +00:00
const pzTail = ppStmt + wasm . ptrSizeof /* final arg to sqlite3_prepare_v2() */ ;
let pSql = pzTail + wasm . ptrSizeof ;
const pSqlEnd = pSql + sqlByteLen ;
if ( isTA ) wasm . heap8 ( ) . set ( arg . sql , pSql ) ;
else wasm . jstrcpy ( arg . sql , wasm . heap8 ( ) , pSql , sqlByteLen , false ) ;
2022-12-09 09:23:27 +00:00
wasm . poke ( pSql + sqlByteLen , 0 /*NUL terminator*/ ) ;
while ( pSql && wasm . peek ( pSql , 'i8' )
2022-08-24 20:57:37 +00:00
/ * M a i n t e n a n c e r e m i n d e r : ^ ^ ^ _ m u s t _ b e ' i 8 ' o r e l s e w e
2022-08-10 11:26:08 +00:00
will very likely cause an endless loop . What that ' s
doing is checking for a terminating NUL byte . If we
use i32 or similar then we read 4 bytes , read stuff
around the NUL terminator , and get stuck in and
endless loop at the end of the SQL , endlessly
re - preparing an empty statement . * / ) {
2022-12-09 09:23:27 +00:00
wasm . pokePtr ( [ ppStmt , pzTail ] , 0 ) ;
2022-08-25 13:27:52 +00:00
DB . checkRc ( this , capi . sqlite3 _prepare _v3 (
this . pointer , pSql , sqlByteLen , 0 , ppStmt , pzTail
2022-08-10 11:26:08 +00:00
) ) ;
2022-12-09 09:23:27 +00:00
const pStmt = wasm . peekPtr ( ppStmt ) ;
pSql = wasm . peekPtr ( pzTail ) ;
2022-08-10 11:26:08 +00:00
sqlByteLen = pSqlEnd - pSql ;
if ( ! pStmt ) continue ;
2022-12-14 08:01:34 +00:00
if ( saveSql ) saveSql . push ( capi . sqlite3 _sql ( pStmt ) . trim ( ) ) ;
2022-08-10 11:26:08 +00:00
stmt = new Stmt ( this , pStmt , BindTypes ) ;
if ( bind && stmt . parameterCount ) {
stmt . bind ( bind ) ;
bind = null ;
}
2022-09-05 13:24:08 +00:00
if ( evalFirstResult && stmt . columnCount ) {
2023-05-10 21:06:02 +00:00
/ * O n l y f o r w a r d S E L E C T - s t y l e r e s u l t s f o r t h e F I R S T q u e r y
2022-08-10 11:26:08 +00:00
in the SQL which potentially has them . * /
2023-05-10 21:06:02 +00:00
let gotColNames = Array . isArray (
opt . columnNames
/ * A s r e p o r t e d i n
https : //sqlite.org/forum/forumpost/7774b773937cbe0a
we need to delay fetching of the column names until
after the first step ( ) ( if we step ( ) at all ) because
a schema change between the prepare ( ) and step ( ) , via
another connection , may invalidate the column count
and names . * / ) ? 0 : 1 ;
2022-09-05 13:24:08 +00:00
evalFirstResult = false ;
2022-12-24 01:59:42 +00:00
if ( arg . cbArg || resultRows ) {
2023-05-19 17:50:16 +00:00
for ( ; stmt . step ( ) ; stmt . _lockedByExec = false ) {
2023-05-10 21:06:02 +00:00
if ( 0 === gotColNames ++ ) stmt . getColumnNames ( opt . columnNames ) ;
2023-05-19 17:50:16 +00:00
stmt . _lockedByExec = true ;
2022-12-24 01:59:42 +00:00
const row = arg . cbArg ( stmt ) ;
if ( resultRows ) resultRows . push ( row ) ;
if ( callback && false === callback . call ( opt , row , stmt ) ) {
break ;
}
}
2023-05-19 17:50:16 +00:00
stmt . _lockedByExec = false ;
2022-08-10 11:26:08 +00:00
}
2023-05-10 21:06:02 +00:00
if ( 0 === gotColNames ) {
/* opt.columnNames was provided but we visited no result rows */
stmt . getColumnNames ( opt . columnNames ) ;
}
2022-08-10 11:26:08 +00:00
} else {
stmt . step ( ) ;
}
2023-05-19 17:50:16 +00:00
stmt . reset (
/ * I n o r d e r t o t r i g g e r a n e x c e p t i o n i n t h e
INSERT ... RETURNING locking scenario :
https : //sqlite.org/forum/forumpost/36f7a2e7494897df
* / ) . f i n a l i z e ( ) ;
2022-08-10 11:26:08 +00:00
stmt = null ;
2023-05-19 17:50:16 +00:00
} /*prepare() loop*/
2022-08-25 13:27:52 +00:00
} / * catch ( e ) {
2023-02-06 14:01:19 +00:00
sqlite3 . config . warn ( "DB.exec() is propagating exception" , opt , e ) ;
2022-08-10 11:26:08 +00:00
throw e ;
2022-08-25 13:27:52 +00:00
} * / f i n a l l y {
2023-05-19 15:54:41 +00:00
wasm . scopedAllocPop ( stack ) ;
2022-08-10 11:26:08 +00:00
if ( stmt ) {
2023-05-19 17:50:16 +00:00
delete stmt . _lockedByExec ;
2022-08-10 11:26:08 +00:00
stmt . finalize ( ) ;
}
}
2022-10-31 11:09:14 +00:00
return arg . returnVal ( ) ;
2022-08-25 13:27:52 +00:00
} /*exec()*/ ,
2022-12-24 13:46:27 +00:00
2022-08-10 11:26:08 +00:00
/ * *
2022-12-24 13:46:27 +00:00
Creates a new UDF ( User - Defined Function ) which is accessible
via SQL code . This function may be called in any of the
following forms :
2022-08-10 11:26:08 +00:00
- ( name , function )
- ( name , function , optionsObject )
- ( name , optionsObject )
- ( optionsObject )
In the final two cases , the function must be defined as the
2022-10-13 16:48:35 +00:00
` callback ` property of the options object ( optionally called
` xFunc ` to align with the C API documentation ) . In the final
2022-08-10 11:26:08 +00:00
case , the function 's name must be the ' name ' property .
2022-10-16 18:50:55 +00:00
The first two call forms can only be used for creating scalar
2022-10-21 05:27:40 +00:00
functions . Creating an aggregate or window function requires
the options - object form ( see below for details ) .
2022-10-13 16:48:35 +00:00
2022-12-24 13:46:27 +00:00
UDFs can be removed as documented for
sqlite3 _create _function _v2 ( ) and
sqlite3 _create _window _function ( ) , but doing so will "leak" the
JS - created WASM binding of those functions ( meaning that their
entries in the WASM indirect function table still
exist ) . Eliminating that potential leak is a pending TODO .
2022-08-10 11:26:08 +00:00
On success , returns this object . Throws on error .
2022-10-02 18:47:39 +00:00
When called from SQL arguments to the UDF , and its result ,
will be converted between JS and SQL with as much fidelity as
is feasible , triggering an exception if a type conversion
cannot be determined . The docs for sqlite3 _create _function _v2 ( )
describe the conversions in more detail .
2022-08-10 11:26:08 +00:00
2022-10-16 18:50:55 +00:00
The values set in the options object differ for scalar and
aggregate functions :
- Scalar : set the ` xFunc ` function - type property to the UDF
function .
- Aggregate : set the ` xStep ` and ` xFinal ` function - type
properties to the "step" and "final" callbacks for the
aggregate . Do not set the ` xFunc ` property .
2022-10-21 05:27:40 +00:00
- Window : set the ` xStep ` , ` xFinal ` , ` xValue ` , and ` xInverse `
function - type properties . Do not set the ` xFunc ` property .
2022-10-16 18:50:55 +00:00
2022-10-21 05:27:40 +00:00
The options object may optionally have an ` xDestroy `
function - type property , as per sqlite3 _create _function _v2 ( ) .
Its argument will be the WASM - pointer - type value of the ` pApp `
property , and this function will throw if ` pApp ` is defined but
is not null , undefined , or a numeric ( WASM pointer )
value . i . e . ` pApp ` , if set , must be value suitable for use as a
WASM pointer argument , noting that ` null ` or ` undefined ` will
translate to 0 for that purpose .
The options object may contain flags to modify how
2022-08-10 11:26:08 +00:00
the function is defined :
2022-10-16 18:50:55 +00:00
- ` arity ` : the number of arguments which SQL calls to this
function expect or require . The default value is ` xFunc.length `
or ` xStep.length ` ( i . e . the number of declared parameters it
has ) * * MINUS 1 * * ( see below for why ) . As a special case , if the
` length ` is 0 , its arity is also 0 instead of - 1. A negative
arity value means that the function is variadic and may accept
any number of arguments , up to sqlite3 ' s compile - time
limits . sqlite3 will enforce the argument count if is zero or
2022-10-21 05:27:40 +00:00
greater . The callback always receives a pointer to an
` sqlite3_context ` object as its first argument . Any arguments
after that are from SQL code . The leading context argument does
_not _ count towards the function ' s arity . See the docs for
2022-10-02 22:50:04 +00:00
sqlite3 . capi . sqlite3 _create _function _v2 ( ) for why that argument
is needed in the interface .
2022-08-10 11:26:08 +00:00
2022-10-21 05:27:40 +00:00
The following options - object properties correspond to flags
documented at :
2022-08-10 11:26:08 +00:00
https : //sqlite.org/c3ref/create_function.html
2022-10-21 05:27:40 +00:00
- ` deterministic ` = sqlite3 . capi . SQLITE _DETERMINISTIC
- ` directOnly ` = sqlite3 . capi . SQLITE _DIRECTONLY
- ` innocuous ` = sqlite3 . capi . SQLITE _INNOCUOUS
Sidebar : the ability to add new WASM - accessible functions to
the runtime requires that the WASM build is compiled with the
equivalent functionality as that provided by Emscripten ' s
` -sALLOW_TABLE_GROWTH ` flag .
2022-08-10 11:26:08 +00:00
* /
2022-10-16 18:50:55 +00:00
createFunction : function f ( name , xFunc , opt ) {
const isFunc = ( f ) => ( f instanceof Function ) ;
2022-08-10 11:26:08 +00:00
switch ( arguments . length ) {
case 1 : /* (optionsObject) */
opt = name ;
name = opt . name ;
2022-10-21 05:27:40 +00:00
xFunc = opt . xFunc || 0 ;
2022-08-10 11:26:08 +00:00
break ;
case 2 : /* (name, callback|optionsObject) */
2022-10-16 18:50:55 +00:00
if ( ! isFunc ( xFunc ) ) {
opt = xFunc ;
2022-10-21 05:27:40 +00:00
xFunc = opt . xFunc || 0 ;
2022-08-10 11:26:08 +00:00
}
break ;
2022-10-16 18:50:55 +00:00
case 3 : /* name, xFunc, opt */
break ;
2022-08-10 11:26:08 +00:00
default : break ;
}
if ( ! opt ) opt = { } ;
2022-10-16 18:50:55 +00:00
if ( 'string' !== typeof name ) {
2022-08-10 11:26:08 +00:00
toss3 ( "Invalid arguments: missing function name." ) ;
}
2022-10-21 05:27:40 +00:00
let xStep = opt . xStep || 0 ;
let xFinal = opt . xFinal || 0 ;
const xValue = opt . xValue || 0 ;
const xInverse = opt . xInverse || 0 ;
let isWindow = undefined ;
2022-10-16 18:50:55 +00:00
if ( isFunc ( xFunc ) ) {
2022-10-21 05:27:40 +00:00
isWindow = false ;
2022-10-16 18:50:55 +00:00
if ( isFunc ( xStep ) || isFunc ( xFinal ) ) {
toss3 ( "Ambiguous arguments: scalar or aggregate?" ) ;
}
xStep = xFinal = null ;
} else if ( isFunc ( xStep ) ) {
if ( ! isFunc ( xFinal ) ) {
2022-10-21 05:27:40 +00:00
toss3 ( "Missing xFinal() callback for aggregate or window UDF." ) ;
2022-10-16 18:50:55 +00:00
}
xFunc = null ;
} else if ( isFunc ( xFinal ) ) {
2022-10-21 05:27:40 +00:00
toss3 ( "Missing xStep() callback for aggregate or window UDF." ) ;
2022-10-16 18:50:55 +00:00
} else {
toss3 ( "Missing function-type properties." ) ;
}
2022-10-21 05:27:40 +00:00
if ( false === isWindow ) {
if ( isFunc ( xValue ) || isFunc ( xInverse ) ) {
toss3 ( "xValue and xInverse are not permitted for non-window UDFs." ) ;
}
} else if ( isFunc ( xValue ) ) {
if ( ! isFunc ( xInverse ) ) {
toss3 ( "xInverse must be provided if xValue is." ) ;
}
isWindow = true ;
} else if ( isFunc ( xInverse ) ) {
toss3 ( "xValue must be provided if xInverse is." ) ;
}
2022-10-16 18:50:55 +00:00
const pApp = opt . pApp ;
2022-10-16 18:57:15 +00:00
if ( undefined !== pApp &&
null !== pApp &&
2022-10-29 07:54:10 +00:00
( ( 'number' !== typeof pApp ) || ! util . isInt32 ( pApp ) ) ) {
2022-10-16 18:50:55 +00:00
toss3 ( "Invalid value for pApp property. Must be a legal WASM pointer value." ) ;
}
2022-10-21 05:27:40 +00:00
const xDestroy = opt . xDestroy || 0 ;
2022-10-16 18:50:55 +00:00
if ( xDestroy && ! isFunc ( xDestroy ) ) {
toss3 ( "xDestroy property must be a function." ) ;
}
2022-08-10 11:26:08 +00:00
let fFlags = 0 /*flags for sqlite3_create_function_v2()*/ ;
if ( getOwnOption ( opt , 'deterministic' ) ) fFlags |= capi . SQLITE _DETERMINISTIC ;
if ( getOwnOption ( opt , 'directOnly' ) ) fFlags |= capi . SQLITE _DIRECTONLY ;
if ( getOwnOption ( opt , 'innocuous' ) ) fFlags |= capi . SQLITE _INNOCUOUS ;
name = name . toLowerCase ( ) ;
2022-10-16 18:50:55 +00:00
const xArity = xFunc || xStep ;
const arity = getOwnOption ( opt , 'arity' ) ;
2022-10-21 05:27:40 +00:00
const arityArg = ( 'number' === typeof arity
? arity
: ( xArity . length ? xArity . length - 1 /*for pCtx arg*/ : 0 ) ) ;
let rc ;
if ( isWindow ) {
rc = capi . sqlite3 _create _window _function (
this . pointer , name , arityArg ,
capi . SQLITE _UTF8 | fFlags , pApp || 0 ,
xStep , xFinal , xValue , xInverse , xDestroy ) ;
} else {
rc = capi . sqlite3 _create _function _v2 (
this . pointer , name , arityArg ,
capi . SQLITE _UTF8 | fFlags , pApp || 0 ,
xFunc , xStep , xFinal , xDestroy ) ;
}
DB . checkRc ( this , rc ) ;
2022-08-10 11:26:08 +00:00
return this ;
} /*createFunction()*/ ,
/ * *
Prepares the given SQL , step ( ) s it one time , and returns
the value of the first result column . If it has no results ,
undefined is returned .
If passed a second argument , it is treated like an argument
to Stmt . bind ( ) , so may be any type supported by that
function . Passing the undefined value is the same as passing
no value , which is useful when ...
If passed a 3 rd argument , it is expected to be one of the
SQLITE _ { typename } constants . Passing the undefined value is
the same as not passing a value .
2022-10-02 00:09:40 +00:00
Throws on error ( e . g . malformed SQL ) .
2022-08-10 11:26:08 +00:00
* /
selectValue : function ( sql , bind , asType ) {
2022-12-25 22:44:13 +00:00
return _ _selectFirstRow ( this , sql , bind , 0 , asType ) ;
} ,
/ * *
Runs the given query and returns an array of the values from
the first result column of each row of the result set . The 2 nd
argument is an optional value for use in a single - argument call
to Stmt . bind ( ) . The 3 rd argument may be any value suitable for
use as the 2 nd argument to Stmt . get ( ) . If a 3 rd argument is
desired but no bind data are needed , pass ` undefined ` for the 2 nd
argument .
If there are no result rows , an empty array is returned .
* /
selectValues : function ( sql , bind , asType ) {
const stmt = this . prepare ( sql ) , rc = [ ] ;
2022-08-10 11:26:08 +00:00
try {
2022-12-25 22:44:13 +00:00
stmt . bind ( bind ) ;
while ( stmt . step ( ) ) rc . push ( stmt . get ( 0 , asType ) ) ;
2023-05-19 18:23:53 +00:00
stmt . reset ( /*for INSERT...RETURNING locking case*/ ) ;
2022-08-10 11:26:08 +00:00
} finally {
2022-12-25 22:44:13 +00:00
stmt . finalize ( ) ;
2022-08-10 11:26:08 +00:00
}
return rc ;
} ,
2022-12-25 22:44:13 +00:00
2022-10-30 11:39:47 +00:00
/ * *
Prepares the given SQL , step ( ) s it one time , and returns an
array containing the values of the first result row . If it has
no results , ` undefined ` is returned .
If passed a second argument other than ` undefined ` , it is
treated like an argument to Stmt . bind ( ) , so may be any type
supported by that function .
Throws on error ( e . g . malformed SQL ) .
* /
selectArray : function ( sql , bind ) {
return _ _selectFirstRow ( this , sql , bind , [ ] ) ;
} ,
/ * *
Prepares the given SQL , step ( ) s it one time , and returns an
object containing the key / value pairs of the first result
row . If it has no results , ` undefined ` is returned .
Note that the order of returned object ' s keys is not guaranteed
to be the same as the order of the fields in the query string .
If passed a second argument other than ` undefined ` , it is
treated like an argument to Stmt . bind ( ) , so may be any type
supported by that function .
Throws on error ( e . g . malformed SQL ) .
* /
selectObject : function ( sql , bind ) {
return _ _selectFirstRow ( this , sql , bind , { } ) ;
} ,
2022-08-10 11:26:08 +00:00
2022-12-06 06:09:03 +00:00
/ * *
Runs the given SQL and returns an array of all results , with
each row represented as an array , as per the 'array' ` rowMode `
option to ` exec() ` . An empty result set resolves
to an empty array . The second argument , if any , is treated as
the 'bind' option to a call to exec ( ) .
* /
selectArrays : function ( sql , bind ) {
return _ _selectAll ( this , sql , bind , 'array' ) ;
} ,
/ * *
Works identically to selectArrays ( ) except that each value
in the returned array is an object , as per the 'object' ` rowMode `
option to ` exec() ` .
* /
selectObjects : function ( sql , bind ) {
return _ _selectAll ( this , sql , bind , 'object' ) ;
} ,
2022-08-10 11:26:08 +00:00
/ * *
Returns the number of currently - opened Stmt handles for this db
2022-12-25 22:44:13 +00:00
handle , or 0 if this DB instance is closed . Note that only
handles prepared via this . prepare ( ) are counted , and not
handles prepared using capi . sqlite3 _prepare _v3 ( ) ( or
equivalent ) .
2022-08-10 11:26:08 +00:00
* /
openStatementCount : function ( ) {
return this . pointer ? Object . keys ( _ _stmtMap . get ( this ) ) . length : 0 ;
} ,
2022-08-13 13:46:19 +00:00
/ * *
Starts a transaction , calls the given callback , and then either
2022-08-18 12:21:58 +00:00
rolls back or commits the savepoint , depending on whether the
callback throws . The callback is passed this db object as its
only argument . On success , returns the result of the
callback . Throws on error .
Note that transactions may not be nested , so this will throw if
it is called recursively . For nested transactions , use the
savepoint ( ) method or manually manage SAVEPOINTs using exec ( ) .
2022-12-27 11:40:05 +00:00
If called with 2 arguments , the first must be a keyword which
is legal immediately after a BEGIN statement , e . g . one of
"DEFERRED" , "IMMEDIATE" , or "EXCLUSIVE" . Though the exact list
of supported keywords is not hard - coded here , in order to be
future - compatible , if the argument does not look like a single
keyword then an exception is triggered with a description of
the problem .
2022-08-13 13:46:19 +00:00
* /
2022-12-27 11:40:05 +00:00
transaction : function ( /* [beginQualifier,] */ callback ) {
let opener = 'BEGIN' ;
if ( arguments . length > 1 ) {
if ( /[^a-zA-Z]/ . test ( arguments [ 0 ] ) ) {
toss3 ( capi . SQLITE _MISUSE , "Invalid argument for BEGIN qualifier." ) ;
}
opener += ' ' + arguments [ 0 ] ;
callback = arguments [ 1 ] ;
}
affirmDbOpen ( this ) . exec ( opener ) ;
2022-08-18 12:21:58 +00:00
try {
const rc = callback ( this ) ;
this . exec ( "COMMIT" ) ;
return rc ;
} catch ( e ) {
this . exec ( "ROLLBACK" ) ;
2022-08-13 13:46:19 +00:00
throw e ;
}
} ,
2022-08-18 12:21:58 +00:00
/ * *
This works similarly to transaction ( ) but uses sqlite3 ' s SAVEPOINT
feature . This function starts a savepoint ( with an unspecified name )
and calls the given callback function , passing it this db object .
If the callback returns , the savepoint is released ( committed ) . If
the callback throws , the savepoint is rolled back . If it does not
throw , it returns the result of the callback .
* /
savepoint : function ( callback ) {
affirmDbOpen ( this ) . exec ( "SAVEPOINT oo1" ) ;
try {
const rc = callback ( this ) ;
this . exec ( "RELEASE oo1" ) ;
return rc ;
} catch ( e ) {
2022-08-25 13:27:52 +00:00
this . exec ( "ROLLBACK to SAVEPOINT oo1; RELEASE SAVEPOINT oo1" ) ;
2022-08-18 12:21:58 +00:00
throw e ;
}
2022-11-24 02:35:03 +00:00
} ,
/ * *
A convenience form of DB . checkRc ( this , resultCode ) . If it does
not throw , it returns this object .
* /
checkRc : function ( resultCode ) {
2023-05-19 15:54:41 +00:00
return checkSqlite3Rc ( this , resultCode ) ;
2024-01-11 11:15:03 +02:00
} ,
getAutocommit : function ( ) {
return capi . sqlite3 _get _autocommit ( this . pointer ) ;
2024-01-15 12:53:53 +02:00
} ,
lastInsertRowid : function ( ) {
return capi . sqlite3 _last _insert _rowid ( this . pointer ) ;
2022-08-10 11:26:08 +00:00
}
} /*DB.prototype*/ ;
/ * * T h r o w s i f t h e g i v e n S t m t h a s b e e n f i n a l i z e d , e l s e s t m t i s
returned . * /
const affirmStmtOpen = function ( stmt ) {
if ( ! stmt . pointer ) toss3 ( "Stmt has been closed." ) ;
return stmt ;
} ;
/ * * R e t u r n s a n o p a q u e t r u t h y v a l u e f r o m t h e B i n d T y p e s
enum if v ' s type is a valid bindable type , else
returns a falsy value . As a special case , a value of
undefined is treated as a bind type of null . * /
const isSupportedBindType = function ( v ) {
let t = BindTypes [ ( null === v || undefined === v ) ? 'null' : typeof v ] ;
switch ( t ) {
case BindTypes . boolean :
case BindTypes . null :
case BindTypes . number :
case BindTypes . string :
return t ;
case BindTypes . bigint :
2022-10-02 03:11:13 +00:00
if ( wasm . bigIntEnabled ) return t ;
2022-08-10 11:26:08 +00:00
/* else fall through */
default :
2022-12-26 14:55:00 +00:00
return util . isBindableTypedArray ( v ) ? BindTypes . blob : undefined ;
2022-08-10 11:26:08 +00:00
}
} ;
/ * *
If isSupportedBindType ( v ) returns a truthy value , this
function returns that value , else it throws .
* /
const affirmSupportedBindType = function ( v ) {
2023-02-06 14:01:19 +00:00
//sqlite3.config.log('affirmSupportedBindType',v);
2022-08-10 11:26:08 +00:00
return isSupportedBindType ( v ) || toss3 ( "Unsupported bind() argument type:" , typeof v ) ;
} ;
/ * *
If key is a number and within range of stmt ' s bound parameter
count , key is returned .
If key is not a number then it is checked against named
parameters . If a match is found , its index is returned .
Else it throws .
* /
const affirmParamIndex = function ( stmt , key ) {
const n = ( 'number' === typeof key )
? key : capi . sqlite3 _bind _parameter _index ( stmt . pointer , key ) ;
if ( 0 === n || ! util . isInt32 ( n ) ) {
toss3 ( "Invalid bind() parameter name: " + key ) ;
}
else if ( n < 1 || n > stmt . parameterCount ) toss3 ( "Bind index" , key , "is out of range." ) ;
return n ;
} ;
/ * *
2023-05-19 17:50:16 +00:00
If stmt . _lockedByExec is truthy , this throws an exception
2022-08-10 11:26:08 +00:00
complaining that the 2 nd argument ( an operation name ,
e . g . "bind()" ) is not legal while the statement is "locked" .
Locking happens before an exec ( ) - like callback is passed a
statement , to ensure that the callback does not mutate or
finalize the statement . If it does not throw , it returns stmt .
* /
2023-05-19 17:50:16 +00:00
const affirmNotLockedByExec = function ( stmt , currentOpName ) {
if ( stmt . _lockedByExec ) {
2022-08-10 11:26:08 +00:00
toss3 ( "Operation is illegal when statement is locked:" , currentOpName ) ;
}
return stmt ;
} ;
/ * *
Binds a single bound parameter value on the given stmt at the
given index ( numeric or named ) using the given bindType ( see
the BindTypes enum ) and value . Throws on error . Returns stmt on
success .
* /
const bindOne = function f ( stmt , ndx , bindType , val ) {
2023-05-19 17:50:16 +00:00
affirmNotLockedByExec ( affirmStmtOpen ( stmt ) , 'bind()' ) ;
2022-08-10 11:26:08 +00:00
if ( ! f . _ ) {
2022-10-02 22:50:04 +00:00
f . _tooBigInt = ( v ) => toss3 (
"BigInt value is too big to store without precision loss:" , v
) ;
2022-08-10 11:26:08 +00:00
f . _ = {
string : function ( stmt , ndx , val , asBlob ) {
2022-12-24 15:28:45 +00:00
const [ pStr , n ] = wasm . allocCString ( val , true ) ;
const f = asBlob ? capi . sqlite3 _bind _blob : capi . sqlite3 _bind _text ;
return f ( stmt . pointer , ndx , pStr , n , capi . SQLITE _WASM _DEALLOC ) ;
2022-08-10 11:26:08 +00:00
}
} ;
2022-10-02 00:09:40 +00:00
} /* static init */
2022-08-10 11:26:08 +00:00
affirmSupportedBindType ( val ) ;
ndx = affirmParamIndex ( stmt , ndx ) ;
let rc = 0 ;
switch ( ( null === val || undefined === val ) ? BindTypes . null : bindType ) {
case BindTypes . null :
rc = capi . sqlite3 _bind _null ( stmt . pointer , ndx ) ;
break ;
case BindTypes . string :
rc = f . _ . string ( stmt , ndx , val , false ) ;
break ;
case BindTypes . number : {
let m ;
if ( util . isInt32 ( val ) ) m = capi . sqlite3 _bind _int ;
2022-10-02 00:09:40 +00:00
else if ( 'bigint' === typeof val ) {
2022-10-02 22:50:04 +00:00
if ( ! util . bigIntFits64 ( val ) ) {
f . _tooBigInt ( val ) ;
2022-10-02 03:11:13 +00:00
} else if ( wasm . bigIntEnabled ) {
2022-10-02 00:09:40 +00:00
m = capi . sqlite3 _bind _int64 ;
2022-10-02 22:50:04 +00:00
} else if ( util . bigIntFitsDouble ( val ) ) {
2022-10-02 00:09:40 +00:00
val = Number ( val ) ;
m = capi . sqlite3 _bind _double ;
} else {
2022-10-02 22:50:04 +00:00
f . _tooBigInt ( val ) ;
2022-10-02 00:09:40 +00:00
}
} else { // !int32, !bigint
val = Number ( val ) ;
2022-10-02 03:11:13 +00:00
if ( wasm . bigIntEnabled && Number . isInteger ( val ) ) {
2022-10-02 00:09:40 +00:00
m = capi . sqlite3 _bind _int64 ;
} else {
m = capi . sqlite3 _bind _double ;
2022-08-10 11:26:08 +00:00
}
}
rc = m ( stmt . pointer , ndx , val ) ;
break ;
}
case BindTypes . boolean :
rc = capi . sqlite3 _bind _int ( stmt . pointer , ndx , val ? 1 : 0 ) ;
break ;
case BindTypes . blob : {
if ( 'string' === typeof val ) {
rc = f . _ . string ( stmt , ndx , val , true ) ;
2022-12-24 14:16:02 +00:00
break ;
} else if ( val instanceof ArrayBuffer ) {
val = new Uint8Array ( val ) ;
2022-08-10 11:26:08 +00:00
} else if ( ! util . isBindableTypedArray ( val ) ) {
toss3 ( "Binding a value as a blob requires" ,
2022-12-24 14:16:02 +00:00
"that it be a string, Uint8Array, Int8Array, or ArrayBuffer." ) ;
}
2022-12-24 15:28:45 +00:00
const pBlob = wasm . alloc ( val . byteLength || 1 ) ;
wasm . heap8 ( ) . set ( val . byteLength ? val : [ 0 ] , pBlob )
rc = capi . sqlite3 _bind _blob ( stmt . pointer , ndx , pBlob , val . byteLength ,
capi . SQLITE _WASM _DEALLOC ) ;
2022-08-10 11:26:08 +00:00
break ;
}
default :
2023-02-06 14:01:19 +00:00
sqlite3 . config . warn ( "Unsupported bind() argument type:" , val ) ;
2022-08-10 11:26:08 +00:00
toss3 ( "Unsupported bind() argument type: " + ( typeof val ) ) ;
}
2022-08-13 13:46:19 +00:00
if ( rc ) DB . checkRc ( stmt . db . pointer , rc ) ;
2022-12-24 14:16:02 +00:00
stmt . _mayGet = false ;
2022-08-10 11:26:08 +00:00
return stmt ;
} ;
Stmt . prototype = {
/ * *
2023-05-19 17:50:16 +00:00
"Finalizes" this statement . This is a no - op if the statement
has already been finalized . Returns the result of
sqlite3 _finalize ( ) ( 0 on success , non - 0 on error ) , or the
undefined value if the statement has already been
finalized . Regardless of success or failure , most methods in
this class will throw if called after this is .
2023-05-19 15:54:41 +00:00
This method always throws if called when it is illegal to do
2023-05-19 17:50:16 +00:00
so . Namely , when triggered via a per - row callback handler of a
DB . exec ( ) call .
2022-08-10 11:26:08 +00:00
* /
finalize : function ( ) {
if ( this . pointer ) {
2023-05-19 17:50:16 +00:00
affirmNotLockedByExec ( this , 'finalize()' ) ;
const rc = capi . sqlite3 _finalize ( this . pointer ) ;
delete _ _stmtMap . get ( this . db ) [ this . pointer ] ;
2022-08-10 11:26:08 +00:00
_ _ptrMap . delete ( this ) ;
2022-08-16 16:36:19 +00:00
delete this . _mayGet ;
2022-08-10 11:26:08 +00:00
delete this . parameterCount ;
2023-05-19 17:50:16 +00:00
delete this . _lockedByExec ;
2023-05-19 15:54:41 +00:00
delete this . db ;
2023-05-19 17:50:16 +00:00
return rc ;
2022-08-10 11:26:08 +00:00
}
} ,
2023-05-19 15:54:41 +00:00
/ * *
Clears all bound values . Returns this object . Throws if this
statement has been finalized or if modification of the
statement is currently illegal ( e . g . in the per - row callback of
a DB . exec ( ) call ) .
* /
2022-08-10 11:26:08 +00:00
clearBindings : function ( ) {
2023-05-19 17:50:16 +00:00
affirmNotLockedByExec ( affirmStmtOpen ( this ) , 'clearBindings()' )
2022-08-10 11:26:08 +00:00
capi . sqlite3 _clear _bindings ( this . pointer ) ;
this . _mayGet = false ;
return this ;
} ,
/ * *
2023-05-19 16:34:56 +00:00
Resets this statement so that it may be step ( ) ed again from the
beginning . Returns this object . Throws if this statement has
2023-05-19 17:50:16 +00:00
been finalized , if it may not legally be reset because it is
currently being used from a DB . exec ( ) callback , or if the
underlying call to sqlite3 _reset ( ) returns non - 0.
2022-08-10 11:26:08 +00:00
If passed a truthy argument then this . clearBindings ( ) is
also called , otherwise any existing bindings , along with
any memory allocated for them , are retained .
2023-05-19 16:34:56 +00:00
2023-05-19 17:59:21 +00:00
In versions 3.42 . 0 and earlier , this function did not throw if
2023-05-19 17:50:16 +00:00
sqlite3 _reset ( ) returns non - 0 , but it was discovered that
throwing ( or significant extra client - side code ) is necessary
in order to avoid certain silent failure scenarios , as
discussed at :
https : //sqlite.org/forum/forumpost/36f7a2e7494897df
2022-08-10 11:26:08 +00:00
* /
reset : function ( alsoClearBinds ) {
2023-05-19 17:50:16 +00:00
affirmNotLockedByExec ( this , 'reset()' ) ;
2022-08-10 11:26:08 +00:00
if ( alsoClearBinds ) this . clearBindings ( ) ;
2023-05-19 16:34:56 +00:00
const rc = capi . sqlite3 _reset ( affirmStmtOpen ( this ) . pointer ) ;
2022-08-10 11:26:08 +00:00
this . _mayGet = false ;
2023-05-19 16:34:56 +00:00
checkSqlite3Rc ( this . db , rc ) ;
2022-08-10 11:26:08 +00:00
return this ;
} ,
/ * *
Binds one or more values to its bindable parameters . It
accepts 1 or 2 arguments :
If passed a single argument , it must be either an array , an
object , or a value of a bindable type ( see below ) .
If passed 2 arguments , the first one is the 1 - based bind
index or bindable parameter name and the second one must be
a value of a bindable type .
Bindable value types :
- null is bound as NULL .
- undefined as a standalone value is a no - op intended to
2022-10-02 00:09:40 +00:00
simplify certain client - side use cases : passing undefined as
a value to this function will not actually bind anything and
this function will skip confirmation that binding is even
legal . ( Those semantics simplify certain client - side uses . )
Conversely , a value of undefined as an array or object
property when binding an array / object ( see below ) is treated
the same as null .
- Numbers are bound as either doubles or integers : doubles if
they are larger than 32 bits , else double or int32 , depending
on whether they have a fractional part . Booleans are bound as
integer 0 or 1. It is not expected the distinction of binding
doubles which have no fractional parts is integers is
significant for the majority of clients due to sqlite3 ' s data
typing model . If [ BigInt ] support is enabled then this
routine will bind BigInt values as 64 - bit integers if they ' ll
fit in 64 bits . If that support disabled , it will store the
BigInt as an int32 or a double if it can do so without loss
of precision . If the BigInt is _too BigInt _ then it will
throw .
2022-08-10 11:26:08 +00:00
- Strings are bound as strings ( use bindAsBlob ( ) to force
2022-10-02 00:09:40 +00:00
blob binding ) .
2022-08-10 11:26:08 +00:00
2022-12-24 14:16:02 +00:00
- Uint8Array , Int8Array , and ArrayBuffer instances are bound as
2022-12-26 14:55:00 +00:00
blobs .
2022-08-10 11:26:08 +00:00
If passed an array , each element of the array is bound at
the parameter index equal to the array index plus 1
( because arrays are 0 - based but binding is 1 - based ) .
If passed an object , each object key is treated as a
bindable parameter name . The object keys _must _ match any
bindable parameter names , including any ` $ ` , ` @ ` , or ` : `
prefix . Because ` $ ` is a legal identifier chararacter in
JavaScript , that is the suggested prefix for bindable
parameters : ` stmt.bind({ $ a: 1, $ b: 2}) ` .
It returns this object on success and throws on
error . Errors include :
- Any bind index is out of range , a named bind parameter
does not match , or this statement has no bindable
parameters .
- Any value to bind is of an unsupported type .
- Passed no arguments or more than two .
- The statement has been finalized .
* /
bind : function ( /*[ndx,] arg*/ ) {
affirmStmtOpen ( this ) ;
let ndx , arg ;
switch ( arguments . length ) {
case 1 : ndx = 1 ; arg = arguments [ 0 ] ; break ;
case 2 : ndx = arguments [ 0 ] ; arg = arguments [ 1 ] ; break ;
default : toss3 ( "Invalid bind() arguments." ) ;
}
if ( undefined === arg ) {
/ * I t m i g h t s e e m i n t u i t i v e t o b i n d u n d e f i n e d a s N U L L
but this approach simplifies certain client - side
uses when passing on arguments between 2 + levels of
functions . * /
return this ;
} else if ( ! this . parameterCount ) {
toss3 ( "This statement has no bindable parameters." ) ;
}
this . _mayGet = false ;
if ( null === arg ) {
/* bind NULL */
return bindOne ( this , ndx , BindTypes . null , arg ) ;
}
else if ( Array . isArray ( arg ) ) {
/* bind each entry by index */
if ( 1 !== arguments . length ) {
toss3 ( "When binding an array, an index argument is not permitted." ) ;
}
arg . forEach ( ( v , i ) => bindOne ( this , i + 1 , affirmSupportedBindType ( v ) , v ) ) ;
return this ;
2022-12-24 14:16:02 +00:00
} else if ( arg instanceof ArrayBuffer ) {
arg = new Uint8Array ( arg ) ;
2022-08-10 11:26:08 +00:00
}
2022-12-24 14:16:02 +00:00
if ( 'object' === typeof arg /*null was checked above*/
2022-08-10 11:26:08 +00:00
&& ! util . isBindableTypedArray ( arg ) ) {
/* Treat each property of arg as a named bound parameter. */
if ( 1 !== arguments . length ) {
toss3 ( "When binding an object, an index argument is not permitted." ) ;
}
Object . keys ( arg )
. forEach ( k => bindOne ( this , k ,
affirmSupportedBindType ( arg [ k ] ) ,
arg [ k ] ) ) ;
return this ;
} else {
return bindOne ( this , ndx , affirmSupportedBindType ( arg ) , arg ) ;
}
toss3 ( "Should not reach this point." ) ;
} ,
/ * *
Special case of bind ( ) which binds the given value using the
BLOB binding mechanism instead of the default selected one for
the value . The ndx may be a numbered or named bind index . The
value must be of type string , null / undefined ( both get treated
as null ) , or a TypedArray of a type supported by the bind ( )
2022-12-24 14:16:02 +00:00
API . This API cannot bind numbers as blobs .
2022-08-10 11:26:08 +00:00
If passed a single argument , a bind index of 1 is assumed and
the first argument is the value .
* /
bindAsBlob : function ( ndx , arg ) {
affirmStmtOpen ( this ) ;
if ( 1 === arguments . length ) {
arg = ndx ;
ndx = 1 ;
}
const t = affirmSupportedBindType ( arg ) ;
if ( BindTypes . string !== t && BindTypes . blob !== t
&& BindTypes . null !== t ) {
toss3 ( "Invalid value type for bindAsBlob()" ) ;
}
2022-12-24 14:16:02 +00:00
return bindOne ( this , ndx , BindTypes . blob , arg ) ;
2022-08-10 11:26:08 +00:00
} ,
/ * *
2022-08-13 13:46:19 +00:00
Steps the statement one time . If the result indicates that a
row of data is available , a truthy value is returned .
If no row of data is available , a falsy
value is returned . Throws on error .
2022-08-10 11:26:08 +00:00
* /
step : function ( ) {
2023-05-19 17:50:16 +00:00
affirmNotLockedByExec ( this , 'step()' ) ;
2022-08-10 11:26:08 +00:00
const rc = capi . sqlite3 _step ( affirmStmtOpen ( this ) . pointer ) ;
switch ( rc ) {
case capi . SQLITE _DONE : return this . _mayGet = false ;
case capi . SQLITE _ROW : return this . _mayGet = true ;
default :
this . _mayGet = false ;
2023-02-06 14:01:19 +00:00
sqlite3 . config . warn ( "sqlite3_step() rc=" , rc ,
2022-10-20 18:31:32 +00:00
capi . sqlite3 _js _rc _str ( rc ) ,
2022-10-02 22:50:04 +00:00
"SQL =" , capi . sqlite3 _sql ( this . pointer ) ) ;
2022-08-13 13:46:19 +00:00
DB . checkRc ( this . db . pointer , rc ) ;
}
} ,
2022-08-16 16:36:19 +00:00
/ * *
Functions exactly like step ( ) except that ...
1 ) On success , it calls this . reset ( ) and returns this object .
2 ) On error , it throws and does not call reset ( ) .
This is intended to simplify constructs like :
` ` `
for ( ... ) {
stmt . bind ( ... ) . stepReset ( ) ;
}
` ` `
Note that the reset ( ) call makes it illegal to call this . get ( )
after the step .
* /
stepReset : function ( ) {
this . step ( ) ;
return this . reset ( ) ;
} ,
2022-08-13 13:46:19 +00:00
/ * *
2023-05-19 16:34:56 +00:00
Functions like step ( ) except that it calls finalize ( ) on this
statement immediately after stepping , even if the step ( ) call
throws .
2022-08-13 13:46:19 +00:00
On success , it returns true if the step indicated that a row of
data was available , else it returns false .
This is intended to simplify use cases such as :
` ` `
2022-10-02 00:09:40 +00:00
aDb . prepare ( "insert into foo(a) values(?)" ) . bind ( 123 ) . stepFinalize ( ) ;
2022-08-13 13:46:19 +00:00
` ` `
* /
stepFinalize : function ( ) {
2023-05-19 16:34:56 +00:00
try {
2023-05-19 18:23:53 +00:00
const rc = this . step ( ) ;
this . reset ( /*for INSERT...RETURNING locking case*/ ) ;
return rc ;
2023-05-19 17:50:16 +00:00
} finally {
2023-05-19 16:34:56 +00:00
try { this . finalize ( ) }
2023-05-19 17:50:16 +00:00
catch ( e ) { /*ignored*/ }
2023-05-19 16:34:56 +00:00
}
2022-08-10 11:26:08 +00:00
} ,
/ * *
Fetches the value from the given 0 - based column index of
2022-12-25 22:44:13 +00:00
the current data row , throwing if index is out of range .
2022-08-10 11:26:08 +00:00
Requires that step ( ) has just returned a truthy value , else
an exception is thrown .
By default it will determine the data type of the result
automatically . If passed a second arugment , it must be one
of the enumeration values for sqlite3 types , which are
defined as members of the sqlite3 module : SQLITE _INTEGER ,
SQLITE _FLOAT , SQLITE _TEXT , SQLITE _BLOB . Any other value ,
except for undefined , will trigger an exception . Passing
undefined is the same as not passing a value . It is legal
to , e . g . , fetch an integer value as a string , in which case
sqlite3 will convert the value to a string .
If ndx is an array , this function behaves a differently : it
assigns the indexes of the array , from 0 to the number of
result columns , to the values of the corresponding column ,
and returns that array .
If ndx is a plain object , this function behaves even
differentlier : it assigns the properties of the object to
the values of their corresponding result columns .
Blobs are returned as Uint8Array instances .
Potential TODO : add type ID SQLITE _JSON , which fetches the
result as a string and passes it ( if it ' s not null ) to
JSON . parse ( ) , returning the result of that . Until then ,
getJSON ( ) can be used for that .
* /
get : function ( ndx , asType ) {
if ( ! affirmStmtOpen ( this ) . _mayGet ) {
toss3 ( "Stmt.step() has not (recently) returned true." ) ;
}
if ( Array . isArray ( ndx ) ) {
let i = 0 ;
2023-05-10 21:06:02 +00:00
const n = this . columnCount ;
while ( i < n ) {
2022-08-10 11:26:08 +00:00
ndx [ i ] = this . get ( i ++ ) ;
}
return ndx ;
} else if ( ndx && 'object' === typeof ndx ) {
let i = 0 ;
2023-05-10 21:06:02 +00:00
const n = this . columnCount ;
while ( i < n ) {
2022-08-10 11:26:08 +00:00
ndx [ capi . sqlite3 _column _name ( this . pointer , i ) ] = this . get ( i ++ ) ;
}
return ndx ;
}
affirmColIndex ( this , ndx ) ;
switch ( undefined === asType
? capi . sqlite3 _column _type ( this . pointer , ndx )
: asType ) {
case capi . SQLITE _NULL : return null ;
case capi . SQLITE _INTEGER : {
2022-10-02 03:11:13 +00:00
if ( wasm . bigIntEnabled ) {
2022-08-10 11:26:08 +00:00
const rc = capi . sqlite3 _column _int64 ( this . pointer , ndx ) ;
if ( rc >= Number . MIN _SAFE _INTEGER && rc <= Number . MAX _SAFE _INTEGER ) {
/ * C o e r c e " n o r m a l " n u m b e r r a n g e s t o n o r m a l n u m b e r v a l u e s ,
and only return BigInt - type values for numbers out of this
range . * /
return Number ( rc ) . valueOf ( ) ;
}
return rc ;
} else {
const rc = capi . sqlite3 _column _double ( this . pointer , ndx ) ;
if ( rc > Number . MAX _SAFE _INTEGER || rc < Number . MIN _SAFE _INTEGER ) {
/ * T h r o w i n g h e r e i s a r g u a b l e b u t , s i n c e w e ' r e e x p l i c i t l y
extracting an SQLITE _INTEGER - type value , it seems fair to throw
if the extracted number is out of range for that type .
This policy may be laxened to simply pass on the number and
hope for the best , as the C API would do . * /
toss3 ( "Integer is out of range for JS integer range: " + rc ) ;
}
2023-02-06 14:01:19 +00:00
//sqlite3.config.log("get integer rc=",rc,isInt32(rc));
2022-08-10 11:26:08 +00:00
return util . isInt32 ( rc ) ? ( rc | 0 ) : rc ;
}
}
case capi . SQLITE _FLOAT :
return capi . sqlite3 _column _double ( this . pointer , ndx ) ;
case capi . SQLITE _TEXT :
return capi . sqlite3 _column _text ( this . pointer , ndx ) ;
case capi . SQLITE _BLOB : {
const n = capi . sqlite3 _column _bytes ( this . pointer , ndx ) ,
ptr = capi . sqlite3 _column _blob ( this . pointer , ndx ) ,
rc = new Uint8Array ( n ) ;
2022-10-02 03:11:13 +00:00
//heap = n ? wasm.heap8() : false;
if ( n ) rc . set ( wasm . heap8u ( ) . slice ( ptr , ptr + n ) , 0 ) ;
2022-08-10 11:26:08 +00:00
//for(let i = 0; i < n; ++i) rc[i] = heap[ptr + i];
if ( n && this . db . _blobXfer instanceof Array ) {
/ * T h i s i s a n o p t i m i z a t i o n s o l e y f o r t h e
Worker - based API . These values will be
transfered to the main thread directly
instead of being copied . * /
this . db . _blobXfer . push ( rc . buffer ) ;
}
return rc ;
}
default : toss3 ( "Don't know how to translate" ,
"type of result column #" + ndx + "." ) ;
}
2022-08-16 16:36:19 +00:00
toss3 ( "Not reached." ) ;
2022-08-10 11:26:08 +00:00
} ,
/ * * E q u i v a l e n t t o g e t ( n d x ) b u t c o e r c e s t h e r e s u l t t o a n
integer . * /
getInt : function ( ndx ) { return this . get ( ndx , capi . SQLITE _INTEGER ) } ,
/ * * E q u i v a l e n t t o g e t ( n d x ) b u t c o e r c e s t h e r e s u l t t o a
float . * /
getFloat : function ( ndx ) { return this . get ( ndx , capi . SQLITE _FLOAT ) } ,
/ * * E q u i v a l e n t t o g e t ( n d x ) b u t c o e r c e s t h e r e s u l t t o a
string . * /
getString : function ( ndx ) { return this . get ( ndx , capi . SQLITE _TEXT ) } ,
/ * * E q u i v a l e n t t o g e t ( n d x ) b u t c o e r c e s t h e r e s u l t t o a
Uint8Array . * /
getBlob : function ( ndx ) { return this . get ( ndx , capi . SQLITE _BLOB ) } ,
/ * *
A convenience wrapper around get ( ) which fetches the value
as a string and then , if it is not null , passes it to
JSON . parse ( ) , returning that result . Throws if parsing
fails . If the result is null , null is returned . An empty
string , on the other hand , will trigger an exception .
* /
getJSON : function ( ndx ) {
const s = this . get ( ndx , capi . SQLITE _STRING ) ;
return null === s ? s : JSON . parse ( s ) ;
} ,
// Design note: the only reason most of these getters have a 'get'
// prefix is for consistency with getVALUE_TYPE(). The latter
2022-10-02 00:09:40 +00:00
// arguably really need that prefix for API readability and the
2022-08-10 11:26:08 +00:00
// rest arguably don't, but consistency is a powerful thing.
/ * *
Returns the result column name of the given index , or
throws if index is out of bounds or this statement has been
finalized . This can be used without having run step ( )
first .
* /
getColumnName : function ( ndx ) {
return capi . sqlite3 _column _name (
affirmColIndex ( affirmStmtOpen ( this ) , ndx ) . pointer , ndx
) ;
} ,
/ * *
2023-05-10 21:06:02 +00:00
If this statement potentially has result columns , this function
returns an array of all such names . If passed an array , it is
used as the target and all names are appended to it . Returns
the target array . Throws if this statement cannot have result
columns . This object ' s columnCount property holds the number of
columns .
2022-08-10 11:26:08 +00:00
* /
2022-10-02 00:09:40 +00:00
getColumnNames : function ( tgt = [ ] ) {
2022-08-10 11:26:08 +00:00
affirmColIndex ( affirmStmtOpen ( this ) , 0 ) ;
2023-05-10 21:06:02 +00:00
const n = this . columnCount ;
for ( let i = 0 ; i < n ; ++ i ) {
2022-08-10 11:26:08 +00:00
tgt . push ( capi . sqlite3 _column _name ( this . pointer , i ) ) ;
}
return tgt ;
} ,
/ * *
If this statement has named bindable parameters and the
given name matches one , its 1 - based bind index is
returned . If no match is found , 0 is returned . If it has no
bindable parameters , the undefined value is returned .
* /
getParamIndex : function ( name ) {
return ( affirmStmtOpen ( this ) . parameterCount
? capi . sqlite3 _bind _parameter _index ( this . pointer , name )
: undefined ) ;
}
} /*Stmt.prototype*/ ;
{ /* Add the `pointer` property to DB and Stmt. */
const prop = {
enumerable : true ,
get : function ( ) { return _ _ptrMap . get ( this ) } ,
set : ( ) => toss3 ( "The pointer property is read-only." )
}
Object . defineProperty ( Stmt . prototype , 'pointer' , prop ) ;
Object . defineProperty ( DB . prototype , 'pointer' , prop ) ;
}
2023-05-10 21:06:02 +00:00
/ * *
2023-05-10 21:08:01 +00:00
Stmt . columnCount is an interceptor for sqlite3 _column _count ( ) .
2023-05-10 21:06:02 +00:00
This requires an unfortunate performance hit compared to caching
columnCount when the Stmt is created / prepared ( as was done in
SQLite <= 3.42 . 0 ) , but is necessary in order to handle certain
corner cases , as described in
https : //sqlite.org/forum/forumpost/7774b773937cbe0a.
* /
Object . defineProperty ( Stmt . prototype , 'columnCount' , {
enumerable : false ,
get : function ( ) { return capi . sqlite3 _column _count ( this . pointer ) } ,
set : ( ) => toss3 ( "The columnCount property is read-only." )
} ) ;
2022-09-30 11:01:44 +00:00
2022-08-10 11:26:08 +00:00
/** The OO API's public namespace. */
sqlite3 . oo1 = {
DB ,
2022-10-28 10:36:18 +00:00
Stmt
2022-08-22 13:34:13 +00:00
} /*oo1 object*/ ;
2022-09-12 16:09:50 +00:00
2022-10-21 05:27:40 +00:00
if ( util . isUIThread ( ) ) {
2022-09-30 11:01:44 +00:00
/ * *
Functionally equivalent to DB ( storageName , 'c' , 'kvvfs' ) except
that it throws if the given storage name is not one of 'local'
or 'session' .
* /
sqlite3 . oo1 . JsStorageDb = function ( storageName = 'session' ) {
if ( 'session' !== storageName && 'local' !== storageName ) {
toss3 ( "JsStorageDb db name must be one of 'session' or 'local'." ) ;
}
dbCtorHelper . call ( this , {
filename : storageName ,
flags : 'c' ,
vfs : "kvvfs"
} ) ;
} ;
2022-09-30 15:46:08 +00:00
const jdb = sqlite3 . oo1 . JsStorageDb ;
jdb . prototype = Object . create ( DB . prototype ) ;
2022-10-20 18:31:32 +00:00
/** Equivalent to sqlite3_js_kvvfs_clear(). */
jdb . clearStorage = capi . sqlite3 _js _kvvfs _clear ;
2022-09-30 15:46:08 +00:00
/ * *
Clears this database instance ' s storage or throws if this
instance has been closed . Returns the number of
database blocks which were cleaned up .
* /
jdb . prototype . clearStorage = function ( ) {
return jdb . clearStorage ( affirmDbOpen ( this ) . filename ) ;
} ;
2022-10-20 18:31:32 +00:00
/** Equivalent to sqlite3_js_kvvfs_size(). */
jdb . storageSize = capi . sqlite3 _js _kvvfs _size ;
2022-09-30 15:46:08 +00:00
/ * *
Returns the _approximate _ number of bytes this database takes
up in its storage or throws if this instance has been closed .
* /
jdb . prototype . storageSize = function ( ) {
return jdb . storageSize ( affirmDbOpen ( this ) . filename ) ;
} ;
} /*main-window-only bits*/
2022-09-30 11:01:44 +00:00
2022-08-22 13:34:13 +00:00
} ) ;