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