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