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