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