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