not resolve to real filenames, but "" uses an on-storage
temporary database and requires that the VFS support that.
- The db is currently opened with a fixed set of flags:
- (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
- SQLITE_OPEN_EXRESCODE). This API will change in the future
- permit the caller to provide those flags via an additional
- argument.
+ The second argument specifies the open/create mode for the
+ database. It must be string containing a sequence of letters (in
+ any order, but case sensitive) specifying the mode:
+
+ - "c" => create if it does not exist, else fail if it does not
+ exist. Implies the "w" flag.
+
+ - "w" => write. Implies "r": a db cannot be write-only.
+
+ - "r" => read-only if neither "w" nor "c" are provided, else it
+ is ignored.
+
+ If "w" is not provided, the db is implicitly read-only, noting that
+ "rc" is meaningless
+
+ Any other letters are currently ignored. The default is
+ "c". These modes are ignored for the special ":memory:" and ""
+ names.
+
+ The final argument is currently unimplemented but will eventually
+ be used to specify an optional sqlite3 VFS implementation name,
+ as for the final argument to sqlite3_open_v2().
For purposes of passing a DB instance to C-style sqlite3
- functions, its read-only `pointer` property holds its `sqlite3*`
- pointer value. That property can also be used to check whether
- this DB instance is still open.
+ functions, the DB object's read-only `pointer` property holds its
+ `sqlite3*` pointer value. That property can also be used to check
+ whether this DB instance is still open.
*/
- const DB = function ctor(fn=':memory:'){
+ const DB = function ctor(fn=':memory:', flags='c', vtab="not yet implemented"){
if('string'!==typeof fn){
toss3("Invalid filename for DB constructor.");
}
+ let ptr, oflags = 0;
+ if( flags.indexOf('c')>=0 ){
+ oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
+ }
+ if( flags.indexOf('w')>=0 ) oflags |= capi.SQLITE_OPEN_READWRITE;
+ if( 0===oflags ) oflags |= capi.SQLITE_OPEN_READONLY;
+ oflags |= capi.SQLITE_OPEN_EXRESCODE;
const stack = capi.wasm.scopedAllocPush();
- let ptr;
try {
const ppDb = capi.wasm.scopedAllocPtr() /* output (sqlite3**) arg */;
- const rc = capi.sqlite3_open_v2(fn, ppDb, capi.SQLITE_OPEN_READWRITE
- | capi.SQLITE_OPEN_CREATE
- | capi.SQLITE_OPEN_EXRESCODE, null);
+ const rc = capi.sqlite3_open_v2(fn, ppDb, oflags, null);
ptr = capi.wasm.getMemValue(ppDb, '*');
ctor.checkRc(ptr, rc);
- }catch(e){
- if(ptr) capi.sqlite3_close_v2(ptr);
+ }catch( e ){
+ if( ptr ) capi.sqlite3_close_v2(ptr);
throw e;
+ }finally{
+ capi.wasm.scopedAllocPop(stack);
}
- finally{capi.wasm.scopedAllocPop(stack);}
this.filename = fn;
__ptrMap.set(this, ptr);
__stmtMap.set(this, Object.create(null));
file. If the name is "" or ":memory:", it resolves to false.
Note that it is not aware of the peculiarities of URI-style
names and a URI-style name for a ":memory:" db will fool it.
+ Returns false if this db is closed.
*/
hasFilename: function(){
- const fn = this.filename;
- if(!fn || ':memory'===fn) return false;
- return true;
+ return this.filename && ':memory'!==this.filename;
},
/**
Returns the name of the given 0-based db number, as documented
statement in the SQL which has any bindable
parameters. (Empty statements are skipped entirely.)
- - .callback = a function which gets called for each row of
- the FIRST statement in the SQL which has result
- _columns_, but only if that statement has any result
- _rows_. The second argument passed to the callback is
- always the current Stmt object (so that the caller may
- collect column names, or similar). The first argument
- passed to the callback defaults to the current Stmt
- object but may be changed with ...
+ - .callback = a function which gets called for each row of the
+ FIRST statement in the SQL which has result _columns_, but only
+ if that statement has any result _rows_. The callback's "this"
+ is the options object. The second argument passed to the
+ callback is always the current Stmt object (so that the caller
+ may collect column names, or similar). The first argument
+ passed to the callback defaults to the current Stmt object but
+ may be changed with ...
- .rowMode = either a string describing what type of argument
should be passed as the first argument to the callback or an
the FIRST first statement which has result _columns_ is
appended to the array in the format specified for the `rowMode`
option, with the exception that the only legal values for
- `rowMode` in this case are 'array' or 'object', neither of
- which is the default. It is legal to use both `resultRows` and
- `callback`, but `resultRows` is likely much simpler to use for
- small data sets and can be used over a WebWorker-style message
- interface. execMulti() throws if `resultRows` is set and
- `rowMode` is 'stmt' (which is the default!).
+ `rowMode` in this case are 'array', 'object', or an integer,
+ none of which are the default for `rowMode`. It is legal to use
+ both `resultRows` and `callback`, but `resultRows` is likely
+ much simpler to use for small data sets and can be used over a
+ WebWorker-style message interface. execMulti() throws if
+ `resultRows` is set and `rowMode` is 'stmt' (which is the
+ default!).
- saveSql = an optional array. If set, the SQL of each
executed statement is appended to this array before the
delete __stmtMap.get(this.db)[this.pointer];
capi.sqlite3_finalize(this.pointer);
__ptrMap.delete(this);
+ delete this._mayGet;
delete this.columnCount;
delete this.parameterCount;
delete this.db;
DB.checkRc(this.db.pointer, rc);
}
},
+ /**
+ Functions exactly like step() except that...
+
+ 1) On success, it calls this.reset() and returns this object.
+ 2) On error, it throws and does not call reset().
+
+ This is intended to simplify constructs like:
+
+ ```
+ for(...) {
+ stmt.bind(...).stepReset();
+ }
+ ```
+
+ Note that the reset() call makes it illegal to call this.get()
+ after the step.
+ */
+ stepReset: function(){
+ this.step();
+ return this.reset();
+ },
/**
Functions like step() except that
it finalizes this statement immediately after stepping unless
```
*/
stepFinalize: function(){
- affirmUnlocked(this, 'step()');
- const rc = capi.sqlite3_step(affirmStmtOpen(this).pointer);
- switch(rc){
- case capi.SQLITE_DONE: this.finalize(); return false;
- case capi.SQLITE_ROW: this.finalize(); return true;
- default:
- this.finalize();
- console.warn("sqlite3_step() rc=",rc,"SQL =",
- capi.sqlite3_sql(this.pointer));
- DB.checkRc(this.db.pointer, rc);
- }
+ const rc = this.step();
+ this.finalize();
+ return rc;
},
/**
Fetches the value from the given 0-based column index of
default: toss3("Don't know how to translate",
"type of result column #"+ndx+".");
}
- abort("Not reached.");
+ toss3("Not reached.");
},
/** Equivalent to get(ndx) but coerces the result to an
integer. */
--- /dev/null
+<!doctype html>
+<html lang="en-us">
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
+ <link rel="stylesheet" href="common/emscripten.css"/>
+ <link rel="stylesheet" href="common/testing.css"/>
+ <title>sqlite3-api OO #1 Demo</title>
+ </head>
+ <body>
+ <header id='titlebar'><span>sqlite3-api OO #1 Demo</span></header>
+ <!-- emscripten bits -->
+ <figure id="module-spinner">
+ <div class="spinner"></div>
+ <div class='center'><strong>Initializing app...</strong></div>
+ <div class='center'>
+ On a slow internet connection this may take a moment. If this
+ message displays for "a long time", intialization may have
+ failed and the JavaScript console may contain clues as to why.
+ </div>
+ </figure>
+ <div class="emscripten" id="module-status">Downloading...</div>
+ <div class="emscripten">
+ <progress value="0" max="100" id="module-progress" hidden='1'></progress>
+ </div><!-- /emscripten bits -->
+ <div>Most stuff on this page happens in the dev console.</div>
+ <hr>
+ <div id='test-output'></div>
+ <script src="sqlite3.js"></script>
+ <script src="common/SqliteTestUtil.js"></script>
+ <script src="demo-oo1.js"></script>
+ </body>
+</html>
--- /dev/null
+/*
+ 2022-08-16
+
+ The author disclaims copyright to this source code. In place of a
+ legal notice, here is a blessing:
+
+ * May you do good and not evil.
+ * May you find forgiveness for yourself and forgive others.
+ * May you share freely, never taking more than you give.
+
+ ***********************************************************************
+
+ A basic demonstration of the SQLite3 OO API #1, shorn of assertions
+ and the like to improve readability.
+*/
+'use strict';
+(function(){
+ const T = self.SqliteTestUtil;
+ const toss = function(...args){throw new Error(args.join(' '))};
+ const debug = console.debug.bind(console),
+ log = console.log.bind(console),
+ warn = console.warn.bind(console),
+ error = console.error.bind(console);
+
+ const demo1 = function(sqlite3,EmModule){
+ const capi = sqlite3.capi,
+ oo = sqlite3.oo1,
+ wasm = capi.wasm;
+
+ // If we have persistent storage, maybe init and mount it:
+ const dbDir = true
+ ? "" // this demo works better without persistent storage.
+ : capi.sqlite3_web_persistent_dir();
+ // ^^^ returns name of persistent mount point or "" if we have none
+
+ const db = new oo.DB(dbDir+"/mydb.sqlite3");
+ /**
+ Never(!) rely on garbage collection to clean up DBs and
+ (especially) statements. Always wrap their lifetimes in
+ try/finally construct...
+ */
+ try {
+ log("Create a table...");
+ db.exec("CREATE TABLE IF NOT EXISTS t(a,b)");
+ //Equivalent:
+ db.exec({
+ sql:"CREATE TABLE IF NOT EXISTS t(a,b)"
+ // ... numerous other options ...
+ });
+ // SQL can be either a string or a byte array
+
+ log("Insert some data using exec()...");
+ let i;
+ for( i = 1; i <= 5; ++i ){
+ db.exec({
+ sql: "insert into t(a,b) values (?,?)",
+ // bind by parameter index...
+ bind: [i, i*2]
+ });
+ db.exec({
+ sql: "insert into t(a,b) values ($a,$b)",
+ // bind by parameter name...
+ bind: {$a: i * 3, $b: i * 4}
+ });
+ }
+
+ log("Insert using a prepared statement...");
+ let q = db.prepare("insert into t(a,b) values(?,?)");
+ try {
+ for( i = 100; i < 103; ++i ){
+ q.bind( [i, i*2] ).step();
+ q.reset();
+ }
+ // Equivalent...
+ for( i = 103; i <= 105; ++i ){
+ q.bind(1, i).bind(2, i*2).stepReset();
+ }
+ }finally{
+ q.finalize();
+ }
+
+ log("Query data with exec() using rowMode 'array'...");
+ db.exec({
+ sql: "select a from t order by a limit 3",
+ rowMode: 'array', // 'array', 'object', or 'stmt' (default)
+ callback: function(row){
+ log("row ",++this.counter,"=",row);
+ }.bind({counter: 0})
+ });
+
+ log("Query data with exec() using rowMode 'object'...");
+ db.exec({
+ sql: "select a as aa, b as bb from t order by aa limit 3",
+ rowMode: 'object',
+ callback: function(row){
+ log("row ",++this.counter,"=",row);
+ }.bind({counter: 0})
+ });
+
+ log("Query data with exec() using rowMode 'stmt'...");
+ db.exec({
+ sql: "select a from t order by a limit 3",
+ rowMode: 'stmt', // stmt === the default
+ callback: function(row){
+ log("row ",++this.counter,"get(0) =",row.get(0));
+ }.bind({counter: 0})
+ });
+
+ log("Query data with exec() using rowMode INTEGER (result column index)...");
+ db.exec({
+ sql: "select a, b from t order by a limit 3",
+ rowMode: 1, // === result column 1
+ callback: function(row){
+ log("row ",++this.counter,"b =",row);
+ }.bind({counter: 0})
+ });
+
+ log("Query data with exec() without a callback...");
+ let resultRows = [];
+ db.exec({
+ sql: "select a, b from t order by a limit 3",
+ rowMode: 'object',
+ resultRows: resultRows
+ });
+ log("Result rows:",resultRows);
+
+ log("Create a scalar UDF...");
+ db.createFunction({
+ name: 'twice',
+ callback: function(arg){ // note the call arg count
+ return arg + arg;
+ }
+ });
+ log("Run scalar UDF and collect result column names...");
+ let columnNames = [];
+ db.exec({
+ sql: "select a, twice(a), twice(''||a) from t order by a desc limit 3",
+ columnNames: columnNames,
+ callback: function(row){
+ log("a =",row.get(0), "twice(a) =", row.get(1), "twice(''||a) =",row.get(2));
+ }
+ });
+ log("Result column names:",columnNames);
+
+ /**
+ Main differences between exec() and execMulti():
+
+ - execMulti() traverses all statements in the input SQL
+
+ - exec() supports a couple options not supported by execMulti(),
+ and vice versa.
+
+ - execMulti() result callback/array only activates for the
+ first statement which has result columns. It is arguable
+ whether it should support a callback at all, and that
+ feature may be removed.
+
+ - execMulti() column-bind data only activates for the first statement
+ with bindable columns. This feature is arguable and may be removed.
+ */
+
+ if(0){
+ warn("UDF will throw because of incorrect arg count...");
+ db.exec("select twice(1,2,3)");
+ }
+
+ try {
+ db.callInTransaction( function(D) {
+ D.exec("delete from t");
+ log("In transaction: count(*) from t =",db.selectValue("select count(*) from t"));
+ throw new sqlite3.SQLite3Error("Demonstrating callInTransaction() rollback");
+ });
+ }catch(e){
+ log("Got expected exception:",e.message);
+ log("count(*) from t =",db.selectValue("select count(*) from t"));
+ }
+
+ }finally{
+ db.close();
+ }
+
+ /**
+ Misc. DB features:
+
+ - get change count (total or statement-local, 32- or 64-bit)
+ - get its file name
+ - selectValue() takes SQL and returns first column of first row.
+
+ Misc. Stmt features:
+
+ - Various forms of bind()
+ - clearBindings()
+ - reset()
+ - Various forms of step()
+ - Variants of get() for explicit type treatment/conversion,
+ e.g. getInt(), getFloat(), getBlob(), getJSON()
+ - getColumnName(ndx), getColumnNames()
+ - getParamIndex(name)
+ */
+ }/*demo1()*/;
+
+ const runDemos = function(Module){
+ //log("Module",Module);
+ const sqlite3 = Module.sqlite3,
+ capi = sqlite3.capi,
+ oo = sqlite3.oo1,
+ wasm = capi.wasm;
+ log("Loaded module:",capi.sqlite3_libversion(), capi.sqlite3_sourceid());
+ try {
+ [ demo1 ].forEach((f)=>f(sqlite3, Module))
+ }catch(e){
+ error("Exception:",e.message);
+ throw e;
+ }
+ };
+
+ sqlite3InitModule(self.sqlite3TestModule).then(runDemos);
+})();
<div>Most stuff on this page happens in the dev console.</div>
<hr>
<div id='test-output'></div>
- <script src="api/sqlite3.js"></script>
+ <script src="sqlite3.js"></script>
<script src="common/SqliteTestUtil.js"></script>
<script src="testing1.js"></script>
</body>
-C wasm:\smove\sanother\sfile\sand\supdate\stesting1/testing2\sto\saccount\sfor\s[e38d00c2b82d].\sDisable\swasmfs\sby\sdefault\sas\sit\sbreaks\sthe\sworker-based\smodule\sloader\s(reason\sas\syet\sunknown).
-D 2022-08-16T16:16:25.326
+C wasm:\sadd\sa\ssmall\sdemo/presentation\sapp\sfor\sJS\sOO\sAPI\s#1\sand\smake\sa\sfew\sminor\sadditions\sto\sthat\sAPI.
+D 2022-08-16T16:36:19.533
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F ext/wasm/api/post-js-header.js 0e853b78db83cb1c06b01663549e0e8b4f377f12f5a2d9a4a06cb776c003880b
F ext/wasm/api/sqlite3-api-cleanup.js 149fd63a0400cd1d69548887ffde2ed89c13283384a63c2e9fcfc695e38a9e11
F ext/wasm/api/sqlite3-api-glue.js 82c09f49c69984009ba5af2b628e67cc26c5dd203d383cd3091d40dab4e6514b
-F ext/wasm/api/sqlite3-api-oo1.js a3469bbb217b9787ba9aa6216423ec55cf9457fecefb9698e433d0e1cc4cc918
+F ext/wasm/api/sqlite3-api-oo1.js 1d63e7e453e38ff2ad0c5e8bf68345f6fc5fe99fbc4a893cc982b4c50d904ca0
F ext/wasm/api/sqlite3-api-opfs.js c93cdd14f81a26b3a64990515ee05c7e29827fbc8fba4e4c2fef3a37a984db89
F ext/wasm/api/sqlite3-api-prologue.js c0f335bf8b44071da0204b8fa95ce78fd737033b155e7bcfdaee6ae64600802f
F ext/wasm/api/sqlite3-api-worker.js 1124f404ecdf3c14d9f829425cef778cd683911a9883f0809a463c3c7773c9fd
F ext/wasm/common/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f
F ext/wasm/common/testing.css 572cf1ffae0b6eb7ca63684d3392bf350217a07b90e7a896e4fa850700c989b0
F ext/wasm/common/whwasmutil.js 41b8e097e0a9cb07c24c0ede3c81b72470a63f4a4efb07f75586dc131569f5ae
+F ext/wasm/demo-oo1.html 75646855b38405d82781246fd08c852a2b3bee05dd9f0fe10ab655a8cffb79aa
+F ext/wasm/demo-oo1.js 0b1f85ee622b8f0ffe133ed88584bfc6b1ef1dcbe5b605278073e4694ebd0a2f
F ext/wasm/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f
F ext/wasm/fiddle/fiddle-worker.js bccf46045be8824752876f3eec01c223be0616ccac184bffd0024cfe7a3262b8
F ext/wasm/fiddle/fiddle.html 550c5aafce40bd218de9bf26192749f69f9b10bc379423ecd2e162bcef885c08
F ext/wasm/scratchpad-opfs-worker.html 66c1d15d678f3bd306373d76b61c6c8aef988f61f4a8dd40185d452f9c6d2bf5
F ext/wasm/scratchpad-opfs-worker.js 3ec2868c669713145c76eb5877c64a1b20741f741817b87c907a154b676283a9
F ext/wasm/scratchpad-opfs-worker2.js de3ea77548243a638c8426b7e43cc1dbfc511013228ab98436eb102923ed6689
-F ext/wasm/sqlite3-worker.js 1325ca8d40129a82531902a3a077b795db2eeaee81746e5a0c811a04b415fa7f w ext/wasm/api/sqlite3-worker.js
-F ext/wasm/testing1.html 0bf3ff224628c1f1e3ed22a2dc1837c6c73722ad8c0ad9c8e6fb9e6047667231
+F ext/wasm/sqlite3-worker.js 1325ca8d40129a82531902a3a077b795db2eeaee81746e5a0c811a04b415fa7f
+F ext/wasm/testing1.html 528001c7e32ee567abc195aa071fd9820cc3c8ffc9c8a39a75e680db05f0c409
F ext/wasm/testing1.js a25069e20d5f8dc548cc98bcf7002cec812084421a1f7f70ffae2c706d1167b2
F ext/wasm/testing2.html 73e5048e666fd6fb28b6e635677a9810e1e139c599ddcf28d687c982134b92b8
F ext/wasm/testing2.js dbb825174878716fab42c340962c0c1b32bfbe26dd16c7b082d30d35f510466c
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 41762f9518bb51b8b23ae6507628d6d3256044e1f2aca6e7251dc57722062c42
-R 8ceb5e9180bc147ed0af56485cecdca6
+P 6dad5e0573ee866657ee10b43e55b86fc9caac7a66c13bdbd35c3625a4783f14
+R 21ffe0bceeaf14b3e3d3b64b375f9eb8
U stephan
-Z 7a0a645037fbcb33d5a75b781a0d284d
+Z cfe198e466da02226e0ffe831d5c4056
# Remove this line to create a well-formed Fossil manifest.
-6dad5e0573ee866657ee10b43e55b86fc9caac7a66c13bdbd35c3625a4783f14
\ No newline at end of file
+d6d79b661a1c6137d4693393e02416da4858d58dc84d144081a48d523655b483
\ No newline at end of file