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