1/* 2 2022-07-22 3 4 The author disclaims copyright to this source code. In place of a 5 legal notice, here is a blessing: 6 7 * May you do good and not evil. 8 * May you find forgiveness for yourself and forgive others. 9 * May you share freely, never taking more than you give. 10 11 *********************************************************************** 12 13 This file contains the so-called OO #1 API wrapper for the sqlite3 14 WASM build. It requires that sqlite3-api-glue.js has already run 15 and it installs its deliverable as self.sqlite3.oo1. 16*/ 17self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ 18 const toss = (...args)=>{throw new Error(args.join(' '))}; 19 const toss3 = (...args)=>{throw new sqlite3.SQLite3Error(...args)}; 20 21 const capi = sqlite3.capi, wasm = sqlite3.wasm, util = sqlite3.util; 22 /* What follows is colloquially known as "OO API #1". It is a 23 binding of the sqlite3 API which is designed to be run within 24 the same thread (main or worker) as the one in which the 25 sqlite3 WASM binding was initialized. This wrapper cannot use 26 the sqlite3 binding if, e.g., the wrapper is in the main thread 27 and the sqlite3 API is in a worker. */ 28 29 /** 30 In order to keep clients from manipulating, perhaps 31 inadvertently, the underlying pointer values of DB and Stmt 32 instances, we'll gate access to them via the `pointer` property 33 accessor and store their real values in this map. Keys = DB/Stmt 34 objects, values = pointer values. This also unifies how those are 35 accessed, for potential use downstream via custom 36 wasm.xWrap() function signatures which know how to extract 37 it. 38 */ 39 const __ptrMap = new WeakMap(); 40 /** 41 Map of DB instances to objects, each object being a map of Stmt 42 wasm pointers to Stmt objects. 43 */ 44 const __stmtMap = new WeakMap(); 45 46 /** If object opts has _its own_ property named p then that 47 property's value is returned, else dflt is returned. */ 48 const getOwnOption = (opts, p, dflt)=>{ 49 const d = Object.getOwnPropertyDescriptor(opts,p); 50 return d ? d.value : dflt; 51 }; 52 53 // Documented in DB.checkRc() 54 const checkSqlite3Rc = function(dbPtr, sqliteResultCode){ 55 if(sqliteResultCode){ 56 if(dbPtr instanceof DB) dbPtr = dbPtr.pointer; 57 toss3( 58 "sqlite result code",sqliteResultCode+":", 59 (dbPtr 60 ? capi.sqlite3_errmsg(dbPtr) 61 : capi.sqlite3_errstr(sqliteResultCode)) 62 ); 63 } 64 }; 65 66 /** 67 sqlite3_trace_v2() callback which gets installed by the DB ctor 68 if its open-flags contain "t". 69 */ 70 const __dbTraceToConsole = 71 wasm.installFunction('i(ippp)', function(t,c,p,x){ 72 if(capi.SQLITE_TRACE_STMT===t){ 73 // x == SQL, p == sqlite3_stmt* 74 console.log("SQL TRACE #"+(++this.counter), 75 wasm.cstringToJs(x)); 76 } 77 }.bind({counter: 0})); 78 79 /** 80 A map of sqlite3_vfs pointers to SQL code to run when the DB 81 constructor opens a database with the given VFS. 82 */ 83 const __vfsPostOpenSql = Object.create(null); 84 85 /** 86 A proxy for DB class constructors. It must be called with the 87 being-construct DB object as its "this". See the DB constructor 88 for the argument docs. This is split into a separate function 89 in order to enable simple creation of special-case DB constructors, 90 e.g. JsStorageDb and OpfsDb. 91 92 Expects to be passed a configuration object with the following 93 properties: 94 95 - `.filename`: the db filename. It may be a special name like ":memory:" 96 or "". 97 98 - `.flags`: as documented in the DB constructor. 99 100 - `.vfs`: as documented in the DB constructor. 101 102 It also accepts those as the first 3 arguments. 103 */ 104 const dbCtorHelper = function ctor(...args){ 105 if(!ctor._name2vfs){ 106 /** 107 Map special filenames which we handle here (instead of in C) 108 to some helpful metadata... 109 110 As of 2022-09-20, the C API supports the names :localStorage: 111 and :sessionStorage: for kvvfs. However, C code cannot 112 determine (without embedded JS code, e.g. via Emscripten's 113 EM_JS()) whether the kvvfs is legal in the current browser 114 context (namely the main UI thread). In order to help client 115 code fail early on, instead of it being delayed until they 116 try to read or write a kvvfs-backed db, we'll check for those 117 names here and throw if they're not legal in the current 118 context. 119 */ 120 ctor._name2vfs = Object.create(null); 121 const isWorkerThread = ('function'===typeof importScripts/*===running in worker thread*/) 122 ? (n)=>toss3("The VFS for",n,"is only available in the main window thread.") 123 : false; 124 ctor._name2vfs[':localStorage:'] = { 125 vfs: 'kvvfs', filename: isWorkerThread || (()=>'local') 126 }; 127 ctor._name2vfs[':sessionStorage:'] = { 128 vfs: 'kvvfs', filename: isWorkerThread || (()=>'session') 129 }; 130 } 131 const opt = ctor.normalizeArgs(...args); 132 let fn = opt.filename, vfsName = opt.vfs, flagsStr = opt.flags; 133 if(('string'!==typeof fn && 'number'!==typeof fn) 134 || 'string'!==typeof flagsStr 135 || (vfsName && ('string'!==typeof vfsName && 'number'!==typeof vfsName))){ 136 console.error("Invalid DB ctor args",opt,arguments); 137 toss3("Invalid arguments for DB constructor."); 138 } 139 let fnJs = ('number'===typeof fn) ? wasm.cstringToJs(fn) : fn; 140 const vfsCheck = ctor._name2vfs[fnJs]; 141 if(vfsCheck){ 142 vfsName = vfsCheck.vfs; 143 fn = fnJs = vfsCheck.filename(fnJs); 144 } 145 let pDb, oflags = 0; 146 if( flagsStr.indexOf('c')>=0 ){ 147 oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE; 148 } 149 if( flagsStr.indexOf('w')>=0 ) oflags |= capi.SQLITE_OPEN_READWRITE; 150 if( 0===oflags ) oflags |= capi.SQLITE_OPEN_READONLY; 151 oflags |= capi.SQLITE_OPEN_EXRESCODE; 152 const stack = wasm.pstack.pointer; 153 try { 154 const pPtr = wasm.pstack.allocPtr() /* output (sqlite3**) arg */; 155 let rc = capi.sqlite3_open_v2(fn, pPtr, oflags, vfsName || 0); 156 pDb = wasm.getPtrValue(pPtr); 157 checkSqlite3Rc(pDb, rc); 158 if(flagsStr.indexOf('t')>=0){ 159 capi.sqlite3_trace_v2(pDb, capi.SQLITE_TRACE_STMT, 160 __dbTraceToConsole, 0); 161 } 162 // Check for per-VFS post-open SQL... 163 const pVfs = capi.sqlite3_js_db_vfs(pDb); 164 //console.warn("Opened db",fn,"with vfs",vfsName,pVfs); 165 if(!pVfs) toss3("Internal error: cannot get VFS for new db handle."); 166 const postInitSql = __vfsPostOpenSql[pVfs]; 167 if(postInitSql){ 168 rc = capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0); 169 checkSqlite3Rc(pDb, rc); 170 } 171 }catch( e ){ 172 if( pDb ) capi.sqlite3_close_v2(pDb); 173 throw e; 174 }finally{ 175 wasm.pstack.restore(stack); 176 } 177 this.filename = fnJs; 178 __ptrMap.set(this, pDb); 179 __stmtMap.set(this, Object.create(null)); 180 }; 181 182 /** 183 Sets SQL which should be exec()'d on a DB instance after it is 184 opened with the given VFS pointer. This is intended only for use 185 by DB subclasses or sqlite3_vfs implementations. 186 */ 187 dbCtorHelper.setVfsPostOpenSql = function(pVfs, sql){ 188 __vfsPostOpenSql[pVfs] = sql; 189 }; 190 191 /** 192 A helper for DB constructors. It accepts either a single 193 config-style object or up to 3 arguments (filename, dbOpenFlags, 194 dbVfsName). It returns a new object containing: 195 196 { filename: ..., flags: ..., vfs: ... } 197 198 If passed an object, any additional properties it has are copied 199 as-is into the new object. 200 */ 201 dbCtorHelper.normalizeArgs = function(filename=':memory:',flags = 'c',vfs = null){ 202 const arg = {}; 203 if(1===arguments.length && 'object'===typeof arguments[0]){ 204 const x = arguments[0]; 205 Object.keys(x).forEach((k)=>arg[k] = x[k]); 206 if(undefined===arg.flags) arg.flags = 'c'; 207 if(undefined===arg.vfs) arg.vfs = null; 208 if(undefined===arg.filename) arg.filename = ':memory:'; 209 }else{ 210 arg.filename = filename; 211 arg.flags = flags; 212 arg.vfs = vfs; 213 } 214 return arg; 215 }; 216 /** 217 The DB class provides a high-level OO wrapper around an sqlite3 218 db handle. 219 220 The given db filename must be resolvable using whatever 221 filesystem layer (virtual or otherwise) is set up for the default 222 sqlite3 VFS. 223 224 Note that the special sqlite3 db names ":memory:" and "" 225 (temporary db) have their normal special meanings here and need 226 not resolve to real filenames, but "" uses an on-storage 227 temporary database and requires that the VFS support that. 228 229 The second argument specifies the open/create mode for the 230 database. It must be string containing a sequence of letters (in 231 any order, but case sensitive) specifying the mode: 232 233 - "c": create if it does not exist, else fail if it does not 234 exist. Implies the "w" flag. 235 236 - "w": write. Implies "r": a db cannot be write-only. 237 238 - "r": read-only if neither "w" nor "c" are provided, else it 239 is ignored. 240 241 - "t": enable tracing of SQL executed on this database handle, 242 sending it to `console.log()`. To disable it later, call 243 `sqlite3.capi.sqlite3_trace_v2(thisDb.pointer, 0, 0, 0)`. 244 245 If "w" is not provided, the db is implicitly read-only, noting 246 that "rc" is meaningless 247 248 Any other letters are currently ignored. The default is 249 "c". These modes are ignored for the special ":memory:" and "" 250 names and _may_ be ignored altogether for certain VFSes. 251 252 The final argument is analogous to the final argument of 253 sqlite3_open_v2(): the name of an sqlite3 VFS. Pass a falsy value, 254 or none at all, to use the default. If passed a value, it must 255 be the string name of a VFS. 256 257 The constructor optionally (and preferably) takes its arguments 258 in the form of a single configuration object with the following 259 properties: 260 261 - `.filename`: database file name 262 - `.flags`: open-mode flags 263 - `.vfs`: the VFS fname 264 265 The `filename` and `vfs` arguments may be either JS strings or 266 C-strings allocated via WASM. `flags` is required to be a JS 267 string (because it's specific to this API, which is specific 268 to JS). 269 270 For purposes of passing a DB instance to C-style sqlite3 271 functions, the DB object's read-only `pointer` property holds its 272 `sqlite3*` pointer value. That property can also be used to check 273 whether this DB instance is still open. 274 275 In the main window thread, the filenames `":localStorage:"` and 276 `":sessionStorage:"` are special: they cause the db to use either 277 localStorage or sessionStorage for storing the database using 278 the kvvfs. If one of these names are used, they trump 279 any vfs name set in the arguments. 280 */ 281 const DB = function(...args){ 282 dbCtorHelper.apply(this, args); 283 }; 284 DB.dbCtorHelper = dbCtorHelper; 285 286 /** 287 Internal-use enum for mapping JS types to DB-bindable types. 288 These do not (and need not) line up with the SQLITE_type 289 values. All values in this enum must be truthy and distinct 290 but they need not be numbers. 291 */ 292 const BindTypes = { 293 null: 1, 294 number: 2, 295 string: 3, 296 boolean: 4, 297 blob: 5 298 }; 299 BindTypes['undefined'] == BindTypes.null; 300 if(wasm.bigIntEnabled){ 301 BindTypes.bigint = BindTypes.number; 302 } 303 304 /** 305 This class wraps sqlite3_stmt. Calling this constructor 306 directly will trigger an exception. Use DB.prepare() to create 307 new instances. 308 309 For purposes of passing a Stmt instance to C-style sqlite3 310 functions, its read-only `pointer` property holds its `sqlite3_stmt*` 311 pointer value. 312 313 Other non-function properties include: 314 315 - `db`: the DB object which created the statement. 316 317 - `columnCount`: the number of result columns in the query, or 0 for 318 queries which cannot return results. 319 320 - `parameterCount`: the number of bindable paramters in the query. 321 */ 322 const Stmt = function(){ 323 if(BindTypes!==arguments[2]){ 324 toss3("Do not call the Stmt constructor directly. Use DB.prepare()."); 325 } 326 this.db = arguments[0]; 327 __ptrMap.set(this, arguments[1]); 328 this.columnCount = capi.sqlite3_column_count(this.pointer); 329 this.parameterCount = capi.sqlite3_bind_parameter_count(this.pointer); 330 }; 331 332 /** Throws if the given DB has been closed, else it is returned. */ 333 const affirmDbOpen = function(db){ 334 if(!db.pointer) toss3("DB has been closed."); 335 return db; 336 }; 337 338 /** Throws if ndx is not an integer or if it is out of range 339 for stmt.columnCount, else returns stmt. 340 341 Reminder: this will also fail after the statement is finalized 342 but the resulting error will be about an out-of-bounds column 343 index rather than a statement-is-finalized error. 344 */ 345 const affirmColIndex = function(stmt,ndx){ 346 if((ndx !== (ndx|0)) || ndx<0 || ndx>=stmt.columnCount){ 347 toss3("Column index",ndx,"is out of range."); 348 } 349 return stmt; 350 }; 351 352 /** 353 Expects to be passed the `arguments` object from DB.exec(). Does 354 the argument processing/validation, throws on error, and returns 355 a new object on success: 356 357 { sql: the SQL, opt: optionsObj, cbArg: function} 358 359 The opt object is a normalized copy of any passed to this 360 function. The sql will be converted to a string if it is provided 361 in one of the supported non-string formats. 362 363 cbArg is only set if the opt.callback or opt.resultRows are set, 364 in which case it's a function which expects to be passed the 365 current Stmt and returns the callback argument of the type 366 indicated by the input arguments. 367 */ 368 const parseExecArgs = function(args){ 369 const out = Object.create(null); 370 out.opt = Object.create(null); 371 switch(args.length){ 372 case 1: 373 if('string'===typeof args[0] || util.isSQLableTypedArray(args[0])){ 374 out.sql = args[0]; 375 }else if(Array.isArray(args[0])){ 376 out.sql = args[0]; 377 }else if(args[0] && 'object'===typeof args[0]){ 378 out.opt = args[0]; 379 out.sql = out.opt.sql; 380 } 381 break; 382 case 2: 383 out.sql = args[0]; 384 out.opt = args[1]; 385 break; 386 default: toss3("Invalid argument count for exec()."); 387 }; 388 if(util.isSQLableTypedArray(out.sql)){ 389 out.sql = util.typedArrayToString(out.sql); 390 }else if(Array.isArray(out.sql)){ 391 out.sql = out.sql.join(''); 392 }else if('string'!==typeof out.sql){ 393 toss3("Missing SQL argument or unsupported SQL value type."); 394 } 395 if(out.opt.callback || out.opt.resultRows){ 396 switch((undefined===out.opt.rowMode) 397 ? 'array' : out.opt.rowMode) { 398 case 'object': out.cbArg = (stmt)=>stmt.get(Object.create(null)); break; 399 case 'array': out.cbArg = (stmt)=>stmt.get([]); break; 400 case 'stmt': 401 if(Array.isArray(out.opt.resultRows)){ 402 toss3("exec(): invalid rowMode for a resultRows array: must", 403 "be one of 'array', 'object',", 404 "a result column number, or column name reference."); 405 } 406 out.cbArg = (stmt)=>stmt; 407 break; 408 default: 409 if(util.isInt32(out.opt.rowMode)){ 410 out.cbArg = (stmt)=>stmt.get(out.opt.rowMode); 411 break; 412 }else if('string'===typeof out.opt.rowMode && out.opt.rowMode.length>1){ 413 /* "$X", ":X", and "@X" fetch column named "X" (case-sensitive!) */ 414 const prefix = out.opt.rowMode[0]; 415 if(':'===prefix || '@'===prefix || '$'===prefix){ 416 out.cbArg = function(stmt){ 417 const rc = stmt.get(this.obj)[this.colName]; 418 return (undefined===rc) ? toss3("exec(): unknown result column:",this.colName) : rc; 419 }.bind({ 420 obj:Object.create(null), 421 colName: out.opt.rowMode.substr(1) 422 }); 423 break; 424 } 425 } 426 toss3("Invalid rowMode:",out.opt.rowMode); 427 } 428 } 429 return out; 430 }; 431 432 /** 433 Expects to be given a DB instance or an `sqlite3*` pointer (may 434 be null) and an sqlite3 API result code. If the result code is 435 not falsy, this function throws an SQLite3Error with an error 436 message from sqlite3_errmsg(), using dbPtr as the db handle, or 437 sqlite3_errstr() if dbPtr is falsy. Note that if it's passed a 438 non-error code like SQLITE_ROW or SQLITE_DONE, it will still 439 throw but the error string might be "Not an error." The various 440 non-0 non-error codes need to be checked for in 441 client code where they are expected. 442 */ 443 DB.checkRc = checkSqlite3Rc; 444 445 DB.prototype = { 446 /** Returns true if this db handle is open, else false. */ 447 isOpen: function(){ 448 return !!this.pointer; 449 }, 450 /** Throws if this given DB has been closed, else returns `this`. */ 451 affirmOpen: function(){ 452 return affirmDbOpen(this); 453 }, 454 /** 455 Finalizes all open statements and closes this database 456 connection. This is a no-op if the db has already been 457 closed. After calling close(), `this.pointer` will resolve to 458 `undefined`, so that can be used to check whether the db 459 instance is still opened. 460 461 If this.onclose.before is a function then it is called before 462 any close-related cleanup. 463 464 If this.onclose.after is a function then it is called after the 465 db is closed but before auxiliary state like this.filename is 466 cleared. 467 468 Both onclose handlers are passed this object. If this db is not 469 opened, neither of the handlers are called. Any exceptions the 470 handlers throw are ignored because "destructors must not 471 throw." 472 473 Note that garbage collection of a db handle, if it happens at 474 all, will never trigger close(), so onclose handlers are not a 475 reliable way to implement close-time cleanup or maintenance of 476 a db. 477 */ 478 close: function(){ 479 if(this.pointer){ 480 if(this.onclose && (this.onclose.before instanceof Function)){ 481 try{this.onclose.before(this)} 482 catch(e){/*ignore*/} 483 } 484 const pDb = this.pointer; 485 Object.keys(__stmtMap.get(this)).forEach((k,s)=>{ 486 if(s && s.pointer) s.finalize(); 487 }); 488 __ptrMap.delete(this); 489 __stmtMap.delete(this); 490 capi.sqlite3_close_v2(pDb); 491 if(this.onclose && (this.onclose.after instanceof Function)){ 492 try{this.onclose.after(this)} 493 catch(e){/*ignore*/} 494 } 495 delete this.filename; 496 } 497 }, 498 /** 499 Returns the number of changes, as per sqlite3_changes() 500 (if the first argument is false) or sqlite3_total_changes() 501 (if it's true). If the 2nd argument is true, it uses 502 sqlite3_changes64() or sqlite3_total_changes64(), which 503 will trigger an exception if this build does not have 504 BigInt support enabled. 505 */ 506 changes: function(total=false,sixtyFour=false){ 507 const p = affirmDbOpen(this).pointer; 508 if(total){ 509 return sixtyFour 510 ? capi.sqlite3_total_changes64(p) 511 : capi.sqlite3_total_changes(p); 512 }else{ 513 return sixtyFour 514 ? capi.sqlite3_changes64(p) 515 : capi.sqlite3_changes(p); 516 } 517 }, 518 /** 519 Similar to the this.filename but returns the 520 sqlite3_db_filename() value for the given database name, 521 defaulting to "main". The argument may be either a JS string 522 or a pointer to a WASM-allocated C-string. 523 */ 524 dbFilename: function(dbName='main'){ 525 return capi.sqlite3_db_filename(affirmDbOpen(this).pointer, dbName); 526 }, 527 /** 528 Returns the name of the given 0-based db number, as documented 529 for sqlite3_db_name(). 530 */ 531 dbName: function(dbNumber=0){ 532 return capi.sqlite3_db_name(affirmDbOpen(this).pointer, dbNumber); 533 }, 534 /** 535 Compiles the given SQL and returns a prepared Stmt. This is 536 the only way to create new Stmt objects. Throws on error. 537 538 The given SQL must be a string, a Uint8Array holding SQL, a 539 WASM pointer to memory holding the NUL-terminated SQL string, 540 or an array of strings. In the latter case, the array is 541 concatenated together, with no separators, to form the SQL 542 string (arrays are often a convenient way to formulate long 543 statements). If the SQL contains no statements, an 544 SQLite3Error is thrown. 545 546 Design note: the C API permits empty SQL, reporting it as a 0 547 result code and a NULL stmt pointer. Supporting that case here 548 would cause extra work for all clients: any use of the Stmt API 549 on such a statement will necessarily throw, so clients would be 550 required to check `stmt.pointer` after calling `prepare()` in 551 order to determine whether the Stmt instance is empty or not. 552 Long-time practice (with other sqlite3 script bindings) 553 suggests that the empty-prepare case is sufficiently rare that 554 supporting it here would simply hurt overall usability. 555 */ 556 prepare: function(sql){ 557 affirmDbOpen(this); 558 const stack = wasm.pstack.pointer; 559 let ppStmt, pStmt; 560 try{ 561 ppStmt = wasm.pstack.alloc(8)/* output (sqlite3_stmt**) arg */; 562 DB.checkRc(this, capi.sqlite3_prepare_v2(this.pointer, sql, -1, ppStmt, null)); 563 pStmt = wasm.getPtrValue(ppStmt); 564 } 565 finally { 566 wasm.pstack.restore(stack); 567 } 568 if(!pStmt) toss3("Cannot prepare empty SQL."); 569 const stmt = new Stmt(this, pStmt, BindTypes); 570 __stmtMap.get(this)[pStmt] = stmt; 571 return stmt; 572 }, 573 /** 574 Executes one or more SQL statements in the form of a single 575 string. Its arguments must be either (sql,optionsObject) or 576 (optionsObject). In the latter case, optionsObject.sql 577 must contain the SQL to execute. Returns this 578 object. Throws on error. 579 580 If no SQL is provided, or a non-string is provided, an 581 exception is triggered. Empty SQL, on the other hand, is 582 simply a no-op. 583 584 The optional options object may contain any of the following 585 properties: 586 587 - `.sql` = the SQL to run (unless it's provided as the first 588 argument). This must be of type string, Uint8Array, or an array 589 of strings. In the latter case they're concatenated together 590 as-is, _with no separator_ between elements, before evaluation. 591 The array form is often simpler for long hand-written queries. 592 593 - `.bind` = a single value valid as an argument for 594 Stmt.bind(). This is _only_ applied to the _first_ non-empty 595 statement in the SQL which has any bindable parameters. (Empty 596 statements are skipped entirely.) 597 598 - `.saveSql` = an optional array. If set, the SQL of each 599 executed statement is appended to this array before the 600 statement is executed (but after it is prepared - we don't have 601 the string until after that). Empty SQL statements are elided. 602 603 ================================================================== 604 The following options apply _only_ to the _first_ statement 605 which has a non-zero result column count, regardless of whether 606 the statement actually produces any result rows. 607 ================================================================== 608 609 - `.columnNames`: if this is an array, the column names of the 610 result set are stored in this array before the callback (if 611 any) is triggered (regardless of whether the query produces any 612 result rows). If no statement has result columns, this value is 613 unchanged. Achtung: an SQL result may have multiple columns 614 with identical names. 615 616 - `.callback` = a function which gets called for each row of 617 the result set, but only if that statement has any result 618 _rows_. The callback's "this" is the options object, noting 619 that this function synthesizes one if the caller does not pass 620 one to exec(). The second argument passed to the callback is 621 always the current Stmt object, as it's needed if the caller 622 wants to fetch the column names or some such (noting that they 623 could also be fetched via `this.columnNames`, if the client 624 provides the `columnNames` option). 625 626 ACHTUNG: The callback MUST NOT modify the Stmt object. Calling 627 any of the Stmt.get() variants, Stmt.getColumnName(), or 628 similar, is legal, but calling step() or finalize() is 629 not. Member methods which are illegal in this context will 630 trigger an exception. 631 632 The first argument passed to the callback defaults to an array of 633 values from the current result row but may be changed with ... 634 635 - `.rowMode` = specifies the type of he callback's first argument. 636 It may be any of... 637 638 A) A string describing what type of argument should be passed 639 as the first argument to the callback: 640 641 A.1) `'array'` (the default) causes the results of 642 `stmt.get([])` to be passed to the `callback` and/or appended 643 to `resultRows`. 644 645 A.2) `'object'` causes the results of 646 `stmt.get(Object.create(null))` to be passed to the 647 `callback` and/or appended to `resultRows`. Achtung: an SQL 648 result may have multiple columns with identical names. In 649 that case, the right-most column will be the one set in this 650 object! 651 652 A.3) `'stmt'` causes the current Stmt to be passed to the 653 callback, but this mode will trigger an exception if 654 `resultRows` is an array because appending the statement to 655 the array would be downright unhelpful. 656 657 B) An integer, indicating a zero-based column in the result 658 row. Only that one single value will be passed on. 659 660 C) A string with a minimum length of 2 and leading character of 661 ':', '$', or '@' will fetch the row as an object, extract that 662 one field, and pass that field's value to the callback. Note 663 that these keys are case-sensitive so must match the case used 664 in the SQL. e.g. `"select a A from t"` with a `rowMode` of 665 `'$A'` would work but `'$a'` would not. A reference to a column 666 not in the result set will trigger an exception on the first 667 row (as the check is not performed until rows are fetched). 668 Note also that `$` is a legal identifier character in JS so 669 need not be quoted. (Design note: those 3 characters were 670 chosen because they are the characters support for naming bound 671 parameters.) 672 673 Any other `rowMode` value triggers an exception. 674 675 - `.resultRows`: if this is an array, it functions similarly to 676 the `callback` option: each row of the result set (if any), 677 with the exception that the `rowMode` 'stmt' is not legal. It 678 is legal to use both `resultRows` and `callback`, but 679 `resultRows` is likely much simpler to use for small data sets 680 and can be used over a WebWorker-style message interface. 681 exec() throws if `resultRows` is set and `rowMode` is 'stmt'. 682 683 684 Potential TODOs: 685 686 - `.bind`: permit an array of arrays/objects to bind. The first 687 sub-array would act on the first statement which has bindable 688 parameters (as it does now). The 2nd would act on the next such 689 statement, etc. 690 691 - `.callback` and `.resultRows`: permit an array entries with 692 semantics similar to those described for `.bind` above. 693 694 */ 695 exec: function(/*(sql [,obj]) || (obj)*/){ 696 affirmDbOpen(this); 697 const arg = parseExecArgs(arguments); 698 if(!arg.sql){ 699 return (''===arg.sql) ? this : toss3("exec() requires an SQL string."); 700 } 701 const opt = arg.opt; 702 const callback = opt.callback; 703 let resultRows = (Array.isArray(opt.resultRows) 704 ? opt.resultRows : undefined); 705 let stmt; 706 let bind = opt.bind; 707 let evalFirstResult = !!(arg.cbArg || opt.columnNames) /* true to evaluate the first result-returning query */; 708 const stack = wasm.scopedAllocPush(); 709 try{ 710 const isTA = util.isSQLableTypedArray(arg.sql) 711 /* Optimization: if the SQL is a TypedArray we can save some string 712 conversion costs. */; 713 /* Allocate the two output pointers (ppStmt, pzTail) and heap 714 space for the SQL (pSql). When prepare_v2() returns, pzTail 715 will point to somewhere in pSql. */ 716 let sqlByteLen = isTA ? arg.sql.byteLength : wasm.jstrlen(arg.sql); 717 const ppStmt = wasm.scopedAlloc(/* output (sqlite3_stmt**) arg and pzTail */ 718 (2 * wasm.ptrSizeof) 719 + (sqlByteLen + 1/* SQL + NUL */)); 720 const pzTail = ppStmt + wasm.ptrSizeof /* final arg to sqlite3_prepare_v2() */; 721 let pSql = pzTail + wasm.ptrSizeof; 722 const pSqlEnd = pSql + sqlByteLen; 723 if(isTA) wasm.heap8().set(arg.sql, pSql); 724 else wasm.jstrcpy(arg.sql, wasm.heap8(), pSql, sqlByteLen, false); 725 wasm.setMemValue(pSql + sqlByteLen, 0/*NUL terminator*/); 726 while(pSql && wasm.getMemValue(pSql, 'i8') 727 /* Maintenance reminder:^^^ _must_ be 'i8' or else we 728 will very likely cause an endless loop. What that's 729 doing is checking for a terminating NUL byte. If we 730 use i32 or similar then we read 4 bytes, read stuff 731 around the NUL terminator, and get stuck in and 732 endless loop at the end of the SQL, endlessly 733 re-preparing an empty statement. */ ){ 734 wasm.setPtrValue(ppStmt, 0); 735 wasm.setPtrValue(pzTail, 0); 736 DB.checkRc(this, capi.sqlite3_prepare_v3( 737 this.pointer, pSql, sqlByteLen, 0, ppStmt, pzTail 738 )); 739 const pStmt = wasm.getPtrValue(ppStmt); 740 pSql = wasm.getPtrValue(pzTail); 741 sqlByteLen = pSqlEnd - pSql; 742 if(!pStmt) continue; 743 if(Array.isArray(opt.saveSql)){ 744 opt.saveSql.push(capi.sqlite3_sql(pStmt).trim()); 745 } 746 stmt = new Stmt(this, pStmt, BindTypes); 747 if(bind && stmt.parameterCount){ 748 stmt.bind(bind); 749 bind = null; 750 } 751 if(evalFirstResult && stmt.columnCount){ 752 /* Only forward SELECT results for the FIRST query 753 in the SQL which potentially has them. */ 754 evalFirstResult = false; 755 if(Array.isArray(opt.columnNames)){ 756 stmt.getColumnNames(opt.columnNames); 757 } 758 while(!!arg.cbArg && stmt.step()){ 759 stmt._isLocked = true; 760 const row = arg.cbArg(stmt); 761 if(resultRows) resultRows.push(row); 762 if(callback) callback.apply(opt,[row,stmt]); 763 stmt._isLocked = false; 764 } 765 }else{ 766 stmt.step(); 767 } 768 stmt.finalize(); 769 stmt = null; 770 } 771 }/*catch(e){ 772 console.warn("DB.exec() is propagating exception",opt,e); 773 throw e; 774 }*/finally{ 775 if(stmt){ 776 delete stmt._isLocked; 777 stmt.finalize(); 778 } 779 wasm.scopedAllocPop(stack); 780 } 781 return this; 782 }/*exec()*/, 783 /** 784 Creates a new scalar UDF (User-Defined Function) which is 785 accessible via SQL code. This function may be called in any 786 of the following forms: 787 788 - (name, function) 789 - (name, function, optionsObject) 790 - (name, optionsObject) 791 - (optionsObject) 792 793 In the final two cases, the function must be defined as the 794 `callback` property of the options object (optionally called 795 `xFunc` to align with the C API documentation). In the final 796 case, the function's name must be the 'name' property. 797 798 The first two call forms can only be used for creating scalar 799 functions. Creating an aggregate or window function requires 800 the options-object form (see below for details). 801 802 UDFs cannot currently be removed from a DB handle after they're 803 added. More correctly, they can be removed as documented for 804 sqlite3_create_function_v2(), but doing so will "leak" the 805 JS-created WASM binding of those functions. 806 807 On success, returns this object. Throws on error. 808 809 When called from SQL arguments to the UDF, and its result, 810 will be converted between JS and SQL with as much fidelity as 811 is feasible, triggering an exception if a type conversion 812 cannot be determined. The docs for sqlite3_create_function_v2() 813 describe the conversions in more detail. 814 815 The values set in the options object differ for scalar and 816 aggregate functions: 817 818 - Scalar: set the `xFunc` function-type property to the UDF 819 function. 820 821 - Aggregate: set the `xStep` and `xFinal` function-type 822 properties to the "step" and "final" callbacks for the 823 aggregate. Do not set the `xFunc` property. 824 825 - Window: set the `xStep`, `xFinal`, `xValue`, and `xInverse` 826 function-type properties. Do not set the `xFunc` property. 827 828 The options object may optionally have an `xDestroy` 829 function-type property, as per sqlite3_create_function_v2(). 830 Its argument will be the WASM-pointer-type value of the `pApp` 831 property, and this function will throw if `pApp` is defined but 832 is not null, undefined, or a numeric (WASM pointer) 833 value. i.e. `pApp`, if set, must be value suitable for use as a 834 WASM pointer argument, noting that `null` or `undefined` will 835 translate to 0 for that purpose. 836 837 The options object may contain flags to modify how 838 the function is defined: 839 840 - `arity`: the number of arguments which SQL calls to this 841 function expect or require. The default value is `xFunc.length` 842 or `xStep.length` (i.e. the number of declared parameters it 843 has) **MINUS 1** (see below for why). As a special case, if the 844 `length` is 0, its arity is also 0 instead of -1. A negative 845 arity value means that the function is variadic and may accept 846 any number of arguments, up to sqlite3's compile-time 847 limits. sqlite3 will enforce the argument count if is zero or 848 greater. The callback always receives a pointer to an 849 `sqlite3_context` object as its first argument. Any arguments 850 after that are from SQL code. The leading context argument does 851 _not_ count towards the function's arity. See the docs for 852 sqlite3.capi.sqlite3_create_function_v2() for why that argument 853 is needed in the interface. 854 855 The following options-object properties correspond to flags 856 documented at: 857 858 https://sqlite.org/c3ref/create_function.html 859 860 - `deterministic` = sqlite3.capi.SQLITE_DETERMINISTIC 861 - `directOnly` = sqlite3.capi.SQLITE_DIRECTONLY 862 - `innocuous` = sqlite3.capi.SQLITE_INNOCUOUS 863 864 Sidebar: the ability to add new WASM-accessible functions to 865 the runtime requires that the WASM build is compiled with the 866 equivalent functionality as that provided by Emscripten's 867 `-sALLOW_TABLE_GROWTH` flag. 868 */ 869 createFunction: function f(name, xFunc, opt){ 870 const isFunc = (f)=>(f instanceof Function); 871 switch(arguments.length){ 872 case 1: /* (optionsObject) */ 873 opt = name; 874 name = opt.name; 875 xFunc = opt.xFunc || 0; 876 break; 877 case 2: /* (name, callback|optionsObject) */ 878 if(!isFunc(xFunc)){ 879 opt = xFunc; 880 xFunc = opt.xFunc || 0; 881 } 882 break; 883 case 3: /* name, xFunc, opt */ 884 break; 885 default: break; 886 } 887 if(!opt) opt = {}; 888 if('string' !== typeof name){ 889 toss3("Invalid arguments: missing function name."); 890 } 891 let xStep = opt.xStep || 0; 892 let xFinal = opt.xFinal || 0; 893 const xValue = opt.xValue || 0; 894 const xInverse = opt.xInverse || 0; 895 let isWindow = undefined; 896 if(isFunc(xFunc)){ 897 isWindow = false; 898 if(isFunc(xStep) || isFunc(xFinal)){ 899 toss3("Ambiguous arguments: scalar or aggregate?"); 900 } 901 xStep = xFinal = null; 902 }else if(isFunc(xStep)){ 903 if(!isFunc(xFinal)){ 904 toss3("Missing xFinal() callback for aggregate or window UDF."); 905 } 906 xFunc = null; 907 }else if(isFunc(xFinal)){ 908 toss3("Missing xStep() callback for aggregate or window UDF."); 909 }else{ 910 toss3("Missing function-type properties."); 911 } 912 if(false === isWindow){ 913 if(isFunc(xValue) || isFunc(xInverse)){ 914 toss3("xValue and xInverse are not permitted for non-window UDFs."); 915 } 916 }else if(isFunc(xValue)){ 917 if(!isFunc(xInverse)){ 918 toss3("xInverse must be provided if xValue is."); 919 } 920 isWindow = true; 921 }else if(isFunc(xInverse)){ 922 toss3("xValue must be provided if xInverse is."); 923 } 924 const pApp = opt.pApp; 925 if(undefined!==pApp && 926 null!==pApp && 927 (('number'!==typeof pApp) || !util.isInt32(pApp))){ 928 toss3("Invalid value for pApp property. Must be a legal WASM pointer value."); 929 } 930 const xDestroy = opt.xDestroy || 0; 931 if(xDestroy && !isFunc(xDestroy)){ 932 toss3("xDestroy property must be a function."); 933 } 934 let fFlags = 0 /*flags for sqlite3_create_function_v2()*/; 935 if(getOwnOption(opt, 'deterministic')) fFlags |= capi.SQLITE_DETERMINISTIC; 936 if(getOwnOption(opt, 'directOnly')) fFlags |= capi.SQLITE_DIRECTONLY; 937 if(getOwnOption(opt, 'innocuous')) fFlags |= capi.SQLITE_INNOCUOUS; 938 name = name.toLowerCase(); 939 const xArity = xFunc || xStep; 940 const arity = getOwnOption(opt, 'arity'); 941 const arityArg = ('number'===typeof arity 942 ? arity 943 : (xArity.length ? xArity.length-1/*for pCtx arg*/ : 0)); 944 let rc; 945 if( isWindow ){ 946 rc = capi.sqlite3_create_window_function( 947 this.pointer, name, arityArg, 948 capi.SQLITE_UTF8 | fFlags, pApp || 0, 949 xStep, xFinal, xValue, xInverse, xDestroy); 950 }else{ 951 rc = capi.sqlite3_create_function_v2( 952 this.pointer, name, arityArg, 953 capi.SQLITE_UTF8 | fFlags, pApp || 0, 954 xFunc, xStep, xFinal, xDestroy); 955 } 956 DB.checkRc(this, rc); 957 return this; 958 }/*createFunction()*/, 959 /** 960 Prepares the given SQL, step()s it one time, and returns 961 the value of the first result column. If it has no results, 962 undefined is returned. 963 964 If passed a second argument, it is treated like an argument 965 to Stmt.bind(), so may be any type supported by that 966 function. Passing the undefined value is the same as passing 967 no value, which is useful when... 968 969 If passed a 3rd argument, it is expected to be one of the 970 SQLITE_{typename} constants. Passing the undefined value is 971 the same as not passing a value. 972 973 Throws on error (e.g. malformed SQL). 974 */ 975 selectValue: function(sql,bind,asType){ 976 let stmt, rc; 977 try { 978 stmt = this.prepare(sql).bind(bind); 979 if(stmt.step()) rc = stmt.get(0,asType); 980 }finally{ 981 if(stmt) stmt.finalize(); 982 } 983 return rc; 984 }, 985 986 /** 987 Returns the number of currently-opened Stmt handles for this db 988 handle, or 0 if this DB instance is closed. 989 */ 990 openStatementCount: function(){ 991 return this.pointer ? Object.keys(__stmtMap.get(this)).length : 0; 992 }, 993 994 /** 995 Starts a transaction, calls the given callback, and then either 996 rolls back or commits the savepoint, depending on whether the 997 callback throws. The callback is passed this db object as its 998 only argument. On success, returns the result of the 999 callback. Throws on error. 1000 1001 Note that transactions may not be nested, so this will throw if 1002 it is called recursively. For nested transactions, use the 1003 savepoint() method or manually manage SAVEPOINTs using exec(). 1004 */ 1005 transaction: function(callback){ 1006 affirmDbOpen(this).exec("BEGIN"); 1007 try { 1008 const rc = callback(this); 1009 this.exec("COMMIT"); 1010 return rc; 1011 }catch(e){ 1012 this.exec("ROLLBACK"); 1013 throw e; 1014 } 1015 }, 1016 1017 /** 1018 This works similarly to transaction() but uses sqlite3's SAVEPOINT 1019 feature. This function starts a savepoint (with an unspecified name) 1020 and calls the given callback function, passing it this db object. 1021 If the callback returns, the savepoint is released (committed). If 1022 the callback throws, the savepoint is rolled back. If it does not 1023 throw, it returns the result of the callback. 1024 */ 1025 savepoint: function(callback){ 1026 affirmDbOpen(this).exec("SAVEPOINT oo1"); 1027 try { 1028 const rc = callback(this); 1029 this.exec("RELEASE oo1"); 1030 return rc; 1031 }catch(e){ 1032 this.exec("ROLLBACK to SAVEPOINT oo1; RELEASE SAVEPOINT oo1"); 1033 throw e; 1034 } 1035 } 1036 }/*DB.prototype*/; 1037 1038 1039 /** Throws if the given Stmt has been finalized, else stmt is 1040 returned. */ 1041 const affirmStmtOpen = function(stmt){ 1042 if(!stmt.pointer) toss3("Stmt has been closed."); 1043 return stmt; 1044 }; 1045 1046 /** Returns an opaque truthy value from the BindTypes 1047 enum if v's type is a valid bindable type, else 1048 returns a falsy value. As a special case, a value of 1049 undefined is treated as a bind type of null. */ 1050 const isSupportedBindType = function(v){ 1051 let t = BindTypes[(null===v||undefined===v) ? 'null' : typeof v]; 1052 switch(t){ 1053 case BindTypes.boolean: 1054 case BindTypes.null: 1055 case BindTypes.number: 1056 case BindTypes.string: 1057 return t; 1058 case BindTypes.bigint: 1059 if(wasm.bigIntEnabled) return t; 1060 /* else fall through */ 1061 default: 1062 //console.log("isSupportedBindType",t,v); 1063 return util.isBindableTypedArray(v) ? BindTypes.blob : undefined; 1064 } 1065 }; 1066 1067 /** 1068 If isSupportedBindType(v) returns a truthy value, this 1069 function returns that value, else it throws. 1070 */ 1071 const affirmSupportedBindType = function(v){ 1072 //console.log('affirmSupportedBindType',v); 1073 return isSupportedBindType(v) || toss3("Unsupported bind() argument type:",typeof v); 1074 }; 1075 1076 /** 1077 If key is a number and within range of stmt's bound parameter 1078 count, key is returned. 1079 1080 If key is not a number then it is checked against named 1081 parameters. If a match is found, its index is returned. 1082 1083 Else it throws. 1084 */ 1085 const affirmParamIndex = function(stmt,key){ 1086 const n = ('number'===typeof key) 1087 ? key : capi.sqlite3_bind_parameter_index(stmt.pointer, key); 1088 if(0===n || !util.isInt32(n)){ 1089 toss3("Invalid bind() parameter name: "+key); 1090 } 1091 else if(n<1 || n>stmt.parameterCount) toss3("Bind index",key,"is out of range."); 1092 return n; 1093 }; 1094 1095 /** 1096 If stmt._isLocked is truthy, this throws an exception 1097 complaining that the 2nd argument (an operation name, 1098 e.g. "bind()") is not legal while the statement is "locked". 1099 Locking happens before an exec()-like callback is passed a 1100 statement, to ensure that the callback does not mutate or 1101 finalize the statement. If it does not throw, it returns stmt. 1102 */ 1103 const affirmUnlocked = function(stmt,currentOpName){ 1104 if(stmt._isLocked){ 1105 toss3("Operation is illegal when statement is locked:",currentOpName); 1106 } 1107 return stmt; 1108 }; 1109 1110 /** 1111 Binds a single bound parameter value on the given stmt at the 1112 given index (numeric or named) using the given bindType (see 1113 the BindTypes enum) and value. Throws on error. Returns stmt on 1114 success. 1115 */ 1116 const bindOne = function f(stmt,ndx,bindType,val){ 1117 affirmUnlocked(stmt, 'bind()'); 1118 if(!f._){ 1119 f._tooBigInt = (v)=>toss3( 1120 "BigInt value is too big to store without precision loss:", v 1121 ); 1122 /* Reminder: when not in BigInt mode, it's impossible for 1123 JS to represent a number out of the range we can bind, 1124 so we have no range checking. */ 1125 f._ = { 1126 string: function(stmt, ndx, val, asBlob){ 1127 if(1){ 1128 /* _Hypothetically_ more efficient than the impl in the 'else' block. */ 1129 const stack = wasm.scopedAllocPush(); 1130 try{ 1131 const n = wasm.jstrlen(val); 1132 const pStr = wasm.scopedAlloc(n); 1133 wasm.jstrcpy(val, wasm.heap8u(), pStr, n, false); 1134 const f = asBlob ? capi.sqlite3_bind_blob : capi.sqlite3_bind_text; 1135 return f(stmt.pointer, ndx, pStr, n, capi.SQLITE_TRANSIENT); 1136 }finally{ 1137 wasm.scopedAllocPop(stack); 1138 } 1139 }else{ 1140 const bytes = wasm.jstrToUintArray(val,false); 1141 const pStr = wasm.alloc(bytes.length || 1); 1142 wasm.heap8u().set(bytes.length ? bytes : [0], pStr); 1143 try{ 1144 const f = asBlob ? capi.sqlite3_bind_blob : capi.sqlite3_bind_text; 1145 return f(stmt.pointer, ndx, pStr, bytes.length, capi.SQLITE_TRANSIENT); 1146 }finally{ 1147 wasm.dealloc(pStr); 1148 } 1149 } 1150 } 1151 }; 1152 }/* static init */ 1153 affirmSupportedBindType(val); 1154 ndx = affirmParamIndex(stmt,ndx); 1155 let rc = 0; 1156 switch((null===val || undefined===val) ? BindTypes.null : bindType){ 1157 case BindTypes.null: 1158 rc = capi.sqlite3_bind_null(stmt.pointer, ndx); 1159 break; 1160 case BindTypes.string: 1161 rc = f._.string(stmt, ndx, val, false); 1162 break; 1163 case BindTypes.number: { 1164 let m; 1165 if(util.isInt32(val)) m = capi.sqlite3_bind_int; 1166 else if('bigint'===typeof val){ 1167 if(!util.bigIntFits64(val)){ 1168 f._tooBigInt(val); 1169 }else if(wasm.bigIntEnabled){ 1170 m = capi.sqlite3_bind_int64; 1171 }else if(util.bigIntFitsDouble(val)){ 1172 val = Number(val); 1173 m = capi.sqlite3_bind_double; 1174 }else{ 1175 f._tooBigInt(val); 1176 } 1177 }else{ // !int32, !bigint 1178 val = Number(val); 1179 if(wasm.bigIntEnabled && Number.isInteger(val)){ 1180 m = capi.sqlite3_bind_int64; 1181 }else{ 1182 m = capi.sqlite3_bind_double; 1183 } 1184 } 1185 rc = m(stmt.pointer, ndx, val); 1186 break; 1187 } 1188 case BindTypes.boolean: 1189 rc = capi.sqlite3_bind_int(stmt.pointer, ndx, val ? 1 : 0); 1190 break; 1191 case BindTypes.blob: { 1192 if('string'===typeof val){ 1193 rc = f._.string(stmt, ndx, val, true); 1194 }else if(!util.isBindableTypedArray(val)){ 1195 toss3("Binding a value as a blob requires", 1196 "that it be a string, Uint8Array, or Int8Array."); 1197 }else if(1){ 1198 /* _Hypothetically_ more efficient than the impl in the 'else' block. */ 1199 const stack = wasm.scopedAllocPush(); 1200 try{ 1201 const pBlob = wasm.scopedAlloc(val.byteLength || 1); 1202 wasm.heap8().set(val.byteLength ? val : [0], pBlob) 1203 rc = capi.sqlite3_bind_blob(stmt.pointer, ndx, pBlob, val.byteLength, 1204 capi.SQLITE_TRANSIENT); 1205 }finally{ 1206 wasm.scopedAllocPop(stack); 1207 } 1208 }else{ 1209 const pBlob = wasm.allocFromTypedArray(val); 1210 try{ 1211 rc = capi.sqlite3_bind_blob(stmt.pointer, ndx, pBlob, val.byteLength, 1212 capi.SQLITE_TRANSIENT); 1213 }finally{ 1214 wasm.dealloc(pBlob); 1215 } 1216 } 1217 break; 1218 } 1219 default: 1220 console.warn("Unsupported bind() argument type:",val); 1221 toss3("Unsupported bind() argument type: "+(typeof val)); 1222 } 1223 if(rc) DB.checkRc(stmt.db.pointer, rc); 1224 return stmt; 1225 }; 1226 1227 Stmt.prototype = { 1228 /** 1229 "Finalizes" this statement. This is a no-op if the 1230 statement has already been finalizes. Returns 1231 undefined. Most methods in this class will throw if called 1232 after this is. 1233 */ 1234 finalize: function(){ 1235 if(this.pointer){ 1236 affirmUnlocked(this,'finalize()'); 1237 delete __stmtMap.get(this.db)[this.pointer]; 1238 capi.sqlite3_finalize(this.pointer); 1239 __ptrMap.delete(this); 1240 delete this._mayGet; 1241 delete this.columnCount; 1242 delete this.parameterCount; 1243 delete this.db; 1244 delete this._isLocked; 1245 } 1246 }, 1247 /** Clears all bound values. Returns this object. 1248 Throws if this statement has been finalized. */ 1249 clearBindings: function(){ 1250 affirmUnlocked(affirmStmtOpen(this), 'clearBindings()') 1251 capi.sqlite3_clear_bindings(this.pointer); 1252 this._mayGet = false; 1253 return this; 1254 }, 1255 /** 1256 Resets this statement so that it may be step()ed again 1257 from the beginning. Returns this object. Throws if this 1258 statement has been finalized. 1259 1260 If passed a truthy argument then this.clearBindings() is 1261 also called, otherwise any existing bindings, along with 1262 any memory allocated for them, are retained. 1263 */ 1264 reset: function(alsoClearBinds){ 1265 affirmUnlocked(this,'reset()'); 1266 if(alsoClearBinds) this.clearBindings(); 1267 capi.sqlite3_reset(affirmStmtOpen(this).pointer); 1268 this._mayGet = false; 1269 return this; 1270 }, 1271 /** 1272 Binds one or more values to its bindable parameters. It 1273 accepts 1 or 2 arguments: 1274 1275 If passed a single argument, it must be either an array, an 1276 object, or a value of a bindable type (see below). 1277 1278 If passed 2 arguments, the first one is the 1-based bind 1279 index or bindable parameter name and the second one must be 1280 a value of a bindable type. 1281 1282 Bindable value types: 1283 1284 - null is bound as NULL. 1285 1286 - undefined as a standalone value is a no-op intended to 1287 simplify certain client-side use cases: passing undefined as 1288 a value to this function will not actually bind anything and 1289 this function will skip confirmation that binding is even 1290 legal. (Those semantics simplify certain client-side uses.) 1291 Conversely, a value of undefined as an array or object 1292 property when binding an array/object (see below) is treated 1293 the same as null. 1294 1295 - Numbers are bound as either doubles or integers: doubles if 1296 they are larger than 32 bits, else double or int32, depending 1297 on whether they have a fractional part. Booleans are bound as 1298 integer 0 or 1. It is not expected the distinction of binding 1299 doubles which have no fractional parts is integers is 1300 significant for the majority of clients due to sqlite3's data 1301 typing model. If [BigInt] support is enabled then this 1302 routine will bind BigInt values as 64-bit integers if they'll 1303 fit in 64 bits. If that support disabled, it will store the 1304 BigInt as an int32 or a double if it can do so without loss 1305 of precision. If the BigInt is _too BigInt_ then it will 1306 throw. 1307 1308 - Strings are bound as strings (use bindAsBlob() to force 1309 blob binding). 1310 1311 - Uint8Array and Int8Array instances are bound as blobs. 1312 (TODO: binding the other TypedArray types.) 1313 1314 If passed an array, each element of the array is bound at 1315 the parameter index equal to the array index plus 1 1316 (because arrays are 0-based but binding is 1-based). 1317 1318 If passed an object, each object key is treated as a 1319 bindable parameter name. The object keys _must_ match any 1320 bindable parameter names, including any `$`, `@`, or `:` 1321 prefix. Because `$` is a legal identifier chararacter in 1322 JavaScript, that is the suggested prefix for bindable 1323 parameters: `stmt.bind({$a: 1, $b: 2})`. 1324 1325 It returns this object on success and throws on 1326 error. Errors include: 1327 1328 - Any bind index is out of range, a named bind parameter 1329 does not match, or this statement has no bindable 1330 parameters. 1331 1332 - Any value to bind is of an unsupported type. 1333 1334 - Passed no arguments or more than two. 1335 1336 - The statement has been finalized. 1337 */ 1338 bind: function(/*[ndx,] arg*/){ 1339 affirmStmtOpen(this); 1340 let ndx, arg; 1341 switch(arguments.length){ 1342 case 1: ndx = 1; arg = arguments[0]; break; 1343 case 2: ndx = arguments[0]; arg = arguments[1]; break; 1344 default: toss3("Invalid bind() arguments."); 1345 } 1346 if(undefined===arg){ 1347 /* It might seem intuitive to bind undefined as NULL 1348 but this approach simplifies certain client-side 1349 uses when passing on arguments between 2+ levels of 1350 functions. */ 1351 return this; 1352 }else if(!this.parameterCount){ 1353 toss3("This statement has no bindable parameters."); 1354 } 1355 this._mayGet = false; 1356 if(null===arg){ 1357 /* bind NULL */ 1358 return bindOne(this, ndx, BindTypes.null, arg); 1359 } 1360 else if(Array.isArray(arg)){ 1361 /* bind each entry by index */ 1362 if(1!==arguments.length){ 1363 toss3("When binding an array, an index argument is not permitted."); 1364 } 1365 arg.forEach((v,i)=>bindOne(this, i+1, affirmSupportedBindType(v), v)); 1366 return this; 1367 } 1368 else if('object'===typeof arg/*null was checked above*/ 1369 && !util.isBindableTypedArray(arg)){ 1370 /* Treat each property of arg as a named bound parameter. */ 1371 if(1!==arguments.length){ 1372 toss3("When binding an object, an index argument is not permitted."); 1373 } 1374 Object.keys(arg) 1375 .forEach(k=>bindOne(this, k, 1376 affirmSupportedBindType(arg[k]), 1377 arg[k])); 1378 return this; 1379 }else{ 1380 return bindOne(this, ndx, affirmSupportedBindType(arg), arg); 1381 } 1382 toss3("Should not reach this point."); 1383 }, 1384 /** 1385 Special case of bind() which binds the given value using the 1386 BLOB binding mechanism instead of the default selected one for 1387 the value. The ndx may be a numbered or named bind index. The 1388 value must be of type string, null/undefined (both get treated 1389 as null), or a TypedArray of a type supported by the bind() 1390 API. 1391 1392 If passed a single argument, a bind index of 1 is assumed and 1393 the first argument is the value. 1394 */ 1395 bindAsBlob: function(ndx,arg){ 1396 affirmStmtOpen(this); 1397 if(1===arguments.length){ 1398 arg = ndx; 1399 ndx = 1; 1400 } 1401 const t = affirmSupportedBindType(arg); 1402 if(BindTypes.string !== t && BindTypes.blob !== t 1403 && BindTypes.null !== t){ 1404 toss3("Invalid value type for bindAsBlob()"); 1405 } 1406 bindOne(this, ndx, BindTypes.blob, arg); 1407 this._mayGet = false; 1408 return this; 1409 }, 1410 /** 1411 Steps the statement one time. If the result indicates that a 1412 row of data is available, a truthy value is returned. 1413 If no row of data is available, a falsy 1414 value is returned. Throws on error. 1415 */ 1416 step: function(){ 1417 affirmUnlocked(this, 'step()'); 1418 const rc = capi.sqlite3_step(affirmStmtOpen(this).pointer); 1419 switch(rc){ 1420 case capi.SQLITE_DONE: return this._mayGet = false; 1421 case capi.SQLITE_ROW: return this._mayGet = true; 1422 default: 1423 this._mayGet = false; 1424 console.warn("sqlite3_step() rc=",rc, 1425 capi.sqlite3_js_rc_str(rc), 1426 "SQL =", capi.sqlite3_sql(this.pointer)); 1427 DB.checkRc(this.db.pointer, rc); 1428 } 1429 }, 1430 /** 1431 Functions exactly like step() except that... 1432 1433 1) On success, it calls this.reset() and returns this object. 1434 2) On error, it throws and does not call reset(). 1435 1436 This is intended to simplify constructs like: 1437 1438 ``` 1439 for(...) { 1440 stmt.bind(...).stepReset(); 1441 } 1442 ``` 1443 1444 Note that the reset() call makes it illegal to call this.get() 1445 after the step. 1446 */ 1447 stepReset: function(){ 1448 this.step(); 1449 return this.reset(); 1450 }, 1451 /** 1452 Functions like step() except that it finalizes this statement 1453 immediately after stepping unless the step cannot be performed 1454 because the statement is locked. Throws on error, but any error 1455 other than the statement-is-locked case will also trigger 1456 finalization of this statement. 1457 1458 On success, it returns true if the step indicated that a row of 1459 data was available, else it returns false. 1460 1461 This is intended to simplify use cases such as: 1462 1463 ``` 1464 aDb.prepare("insert into foo(a) values(?)").bind(123).stepFinalize(); 1465 ``` 1466 */ 1467 stepFinalize: function(){ 1468 const rc = this.step(); 1469 this.finalize(); 1470 return rc; 1471 }, 1472 /** 1473 Fetches the value from the given 0-based column index of 1474 the current data row, throwing if index is out of range. 1475 1476 Requires that step() has just returned a truthy value, else 1477 an exception is thrown. 1478 1479 By default it will determine the data type of the result 1480 automatically. If passed a second arugment, it must be one 1481 of the enumeration values for sqlite3 types, which are 1482 defined as members of the sqlite3 module: SQLITE_INTEGER, 1483 SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB. Any other value, 1484 except for undefined, will trigger an exception. Passing 1485 undefined is the same as not passing a value. It is legal 1486 to, e.g., fetch an integer value as a string, in which case 1487 sqlite3 will convert the value to a string. 1488 1489 If ndx is an array, this function behaves a differently: it 1490 assigns the indexes of the array, from 0 to the number of 1491 result columns, to the values of the corresponding column, 1492 and returns that array. 1493 1494 If ndx is a plain object, this function behaves even 1495 differentlier: it assigns the properties of the object to 1496 the values of their corresponding result columns. 1497 1498 Blobs are returned as Uint8Array instances. 1499 1500 Potential TODO: add type ID SQLITE_JSON, which fetches the 1501 result as a string and passes it (if it's not null) to 1502 JSON.parse(), returning the result of that. Until then, 1503 getJSON() can be used for that. 1504 */ 1505 get: function(ndx,asType){ 1506 if(!affirmStmtOpen(this)._mayGet){ 1507 toss3("Stmt.step() has not (recently) returned true."); 1508 } 1509 if(Array.isArray(ndx)){ 1510 let i = 0; 1511 while(i<this.columnCount){ 1512 ndx[i] = this.get(i++); 1513 } 1514 return ndx; 1515 }else if(ndx && 'object'===typeof ndx){ 1516 let i = 0; 1517 while(i<this.columnCount){ 1518 ndx[capi.sqlite3_column_name(this.pointer,i)] = this.get(i++); 1519 } 1520 return ndx; 1521 } 1522 affirmColIndex(this, ndx); 1523 switch(undefined===asType 1524 ? capi.sqlite3_column_type(this.pointer, ndx) 1525 : asType){ 1526 case capi.SQLITE_NULL: return null; 1527 case capi.SQLITE_INTEGER:{ 1528 if(wasm.bigIntEnabled){ 1529 const rc = capi.sqlite3_column_int64(this.pointer, ndx); 1530 if(rc>=Number.MIN_SAFE_INTEGER && rc<=Number.MAX_SAFE_INTEGER){ 1531 /* Coerce "normal" number ranges to normal number values, 1532 and only return BigInt-type values for numbers out of this 1533 range. */ 1534 return Number(rc).valueOf(); 1535 } 1536 return rc; 1537 }else{ 1538 const rc = capi.sqlite3_column_double(this.pointer, ndx); 1539 if(rc>Number.MAX_SAFE_INTEGER || rc<Number.MIN_SAFE_INTEGER){ 1540 /* Throwing here is arguable but, since we're explicitly 1541 extracting an SQLITE_INTEGER-type value, it seems fair to throw 1542 if the extracted number is out of range for that type. 1543 This policy may be laxened to simply pass on the number and 1544 hope for the best, as the C API would do. */ 1545 toss3("Integer is out of range for JS integer range: "+rc); 1546 } 1547 //console.log("get integer rc=",rc,isInt32(rc)); 1548 return util.isInt32(rc) ? (rc | 0) : rc; 1549 } 1550 } 1551 case capi.SQLITE_FLOAT: 1552 return capi.sqlite3_column_double(this.pointer, ndx); 1553 case capi.SQLITE_TEXT: 1554 return capi.sqlite3_column_text(this.pointer, ndx); 1555 case capi.SQLITE_BLOB: { 1556 const n = capi.sqlite3_column_bytes(this.pointer, ndx), 1557 ptr = capi.sqlite3_column_blob(this.pointer, ndx), 1558 rc = new Uint8Array(n); 1559 //heap = n ? wasm.heap8() : false; 1560 if(n) rc.set(wasm.heap8u().slice(ptr, ptr+n), 0); 1561 //for(let i = 0; i < n; ++i) rc[i] = heap[ptr + i]; 1562 if(n && this.db._blobXfer instanceof Array){ 1563 /* This is an optimization soley for the 1564 Worker-based API. These values will be 1565 transfered to the main thread directly 1566 instead of being copied. */ 1567 this.db._blobXfer.push(rc.buffer); 1568 } 1569 return rc; 1570 } 1571 default: toss3("Don't know how to translate", 1572 "type of result column #"+ndx+"."); 1573 } 1574 toss3("Not reached."); 1575 }, 1576 /** Equivalent to get(ndx) but coerces the result to an 1577 integer. */ 1578 getInt: function(ndx){return this.get(ndx,capi.SQLITE_INTEGER)}, 1579 /** Equivalent to get(ndx) but coerces the result to a 1580 float. */ 1581 getFloat: function(ndx){return this.get(ndx,capi.SQLITE_FLOAT)}, 1582 /** Equivalent to get(ndx) but coerces the result to a 1583 string. */ 1584 getString: function(ndx){return this.get(ndx,capi.SQLITE_TEXT)}, 1585 /** Equivalent to get(ndx) but coerces the result to a 1586 Uint8Array. */ 1587 getBlob: function(ndx){return this.get(ndx,capi.SQLITE_BLOB)}, 1588 /** 1589 A convenience wrapper around get() which fetches the value 1590 as a string and then, if it is not null, passes it to 1591 JSON.parse(), returning that result. Throws if parsing 1592 fails. If the result is null, null is returned. An empty 1593 string, on the other hand, will trigger an exception. 1594 */ 1595 getJSON: function(ndx){ 1596 const s = this.get(ndx, capi.SQLITE_STRING); 1597 return null===s ? s : JSON.parse(s); 1598 }, 1599 // Design note: the only reason most of these getters have a 'get' 1600 // prefix is for consistency with getVALUE_TYPE(). The latter 1601 // arguably really need that prefix for API readability and the 1602 // rest arguably don't, but consistency is a powerful thing. 1603 /** 1604 Returns the result column name of the given index, or 1605 throws if index is out of bounds or this statement has been 1606 finalized. This can be used without having run step() 1607 first. 1608 */ 1609 getColumnName: function(ndx){ 1610 return capi.sqlite3_column_name( 1611 affirmColIndex(affirmStmtOpen(this),ndx).pointer, ndx 1612 ); 1613 }, 1614 /** 1615 If this statement potentially has result columns, this 1616 function returns an array of all such names. If passed an 1617 array, it is used as the target and all names are appended 1618 to it. Returns the target array. Throws if this statement 1619 cannot have result columns. This object's columnCount member 1620 holds the number of columns. 1621 */ 1622 getColumnNames: function(tgt=[]){ 1623 affirmColIndex(affirmStmtOpen(this),0); 1624 for(let i = 0; i < this.columnCount; ++i){ 1625 tgt.push(capi.sqlite3_column_name(this.pointer, i)); 1626 } 1627 return tgt; 1628 }, 1629 /** 1630 If this statement has named bindable parameters and the 1631 given name matches one, its 1-based bind index is 1632 returned. If no match is found, 0 is returned. If it has no 1633 bindable parameters, the undefined value is returned. 1634 */ 1635 getParamIndex: function(name){ 1636 return (affirmStmtOpen(this).parameterCount 1637 ? capi.sqlite3_bind_parameter_index(this.pointer, name) 1638 : undefined); 1639 } 1640 }/*Stmt.prototype*/; 1641 1642 {/* Add the `pointer` property to DB and Stmt. */ 1643 const prop = { 1644 enumerable: true, 1645 get: function(){return __ptrMap.get(this)}, 1646 set: ()=>toss3("The pointer property is read-only.") 1647 } 1648 Object.defineProperty(Stmt.prototype, 'pointer', prop); 1649 Object.defineProperty(DB.prototype, 'pointer', prop); 1650 } 1651 1652 /** The OO API's public namespace. */ 1653 sqlite3.oo1 = { 1654 version: { 1655 lib: capi.sqlite3_libversion(), 1656 ooApi: "0.1" 1657 }, 1658 DB, 1659 Stmt 1660 }/*oo1 object*/; 1661 1662 if(util.isUIThread()){ 1663 /** 1664 Functionally equivalent to DB(storageName,'c','kvvfs') except 1665 that it throws if the given storage name is not one of 'local' 1666 or 'session'. 1667 */ 1668 sqlite3.oo1.JsStorageDb = function(storageName='session'){ 1669 if('session'!==storageName && 'local'!==storageName){ 1670 toss3("JsStorageDb db name must be one of 'session' or 'local'."); 1671 } 1672 dbCtorHelper.call(this, { 1673 filename: storageName, 1674 flags: 'c', 1675 vfs: "kvvfs" 1676 }); 1677 }; 1678 const jdb = sqlite3.oo1.JsStorageDb; 1679 jdb.prototype = Object.create(DB.prototype); 1680 /** Equivalent to sqlite3_js_kvvfs_clear(). */ 1681 jdb.clearStorage = capi.sqlite3_js_kvvfs_clear; 1682 /** 1683 Clears this database instance's storage or throws if this 1684 instance has been closed. Returns the number of 1685 database blocks which were cleaned up. 1686 */ 1687 jdb.prototype.clearStorage = function(){ 1688 return jdb.clearStorage(affirmDbOpen(this).filename); 1689 }; 1690 /** Equivalent to sqlite3_js_kvvfs_size(). */ 1691 jdb.storageSize = capi.sqlite3_js_kvvfs_size; 1692 /** 1693 Returns the _approximate_ number of bytes this database takes 1694 up in its storage or throws if this instance has been closed. 1695 */ 1696 jdb.prototype.storageSize = function(){ 1697 return jdb.storageSize(affirmDbOpen(this).filename); 1698 }; 1699 }/*main-window-only bits*/ 1700 1701}); 1702 1703