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