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