Snapshot of upstream SQLite 3.46.1
[sqlcipher.git] / ext / wasm / demo-123.js
blob9f90ca7568d094bb52f86dafc7a51226bc34d214
1 /*
2 2022-09-19
4 The author disclaims copyright to this source code. In place of a
5 legal notice, here is a blessing:
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.
11 ***********************************************************************
13 A basic demonstration of the SQLite3 "OO#1" API.
15 'use strict';
16 (function(){
17 /**
18 Set up our output channel differently depending
19 on whether we are running in a worker thread or
20 the main (UI) thread.
22 let logHtml;
23 if(globalThis.window === globalThis /* UI thread */){
24 console.log("Running demo from main UI thread.");
25 logHtml = function(cssClass,...args){
26 const ln = document.createElement('div');
27 if(cssClass) ln.classList.add(cssClass);
28 ln.append(document.createTextNode(args.join(' ')));
29 document.body.append(ln);
31 }else{ /* Worker thread */
32 console.log("Running demo from Worker thread.");
33 logHtml = function(cssClass,...args){
34 postMessage({
35 type:'log',
36 payload:{cssClass, args}
37 });
40 const log = (...args)=>logHtml('',...args);
41 const warn = (...args)=>logHtml('warning',...args);
42 const error = (...args)=>logHtml('error',...args);
44 const demo1 = function(sqlite3){
45 const capi = sqlite3.capi/*C-style API*/,
46 oo = sqlite3.oo1/*high-level OO API*/;
47 log("sqlite3 version",capi.sqlite3_libversion(), capi.sqlite3_sourceid());
48 const db = new oo.DB("/mydb.sqlite3",'ct');
49 log("transient db =",db.filename);
50 /**
51 Never(!) rely on garbage collection to clean up DBs and
52 (especially) prepared statements. Always wrap their lifetimes
53 in a try/finally construct, as demonstrated below. By and
54 large, client code can entirely avoid lifetime-related
55 complications of prepared statement objects by using the
56 DB.exec() method for SQL execution.
58 try {
59 log("Create a table...");
60 db.exec("CREATE TABLE IF NOT EXISTS t(a,b)");
61 //Equivalent:
62 db.exec({
63 sql:"CREATE TABLE IF NOT EXISTS t(a,b)"
64 // ... numerous other options ...
65 });
66 // SQL can be either a string or a byte array
67 // or an array of strings which get concatenated
68 // together as-is (so be sure to end each statement
69 // with a semicolon).
71 log("Insert some data using exec()...");
72 let i;
73 for( i = 20; i <= 25; ++i ){
74 db.exec({
75 sql: "insert into t(a,b) values (?,?)",
76 // bind by parameter index...
77 bind: [i, i*2]
78 });
79 db.exec({
80 sql: "insert into t(a,b) values ($a,$b)",
81 // bind by parameter name...
82 bind: {$a: i * 10, $b: i * 20}
83 });
86 log("Insert using a prepared statement...");
87 let q = db.prepare([
88 // SQL may be a string or array of strings
89 // (concatenated w/o separators).
90 "insert into t(a,b) ",
91 "values(?,?)"
92 ]);
93 try {
94 for( i = 100; i < 103; ++i ){
95 q.bind( [i, i*2] ).step();
96 q.reset();
98 // Equivalent...
99 for( i = 103; i <= 105; ++i ){
100 q.bind(1, i).bind(2, i*2).stepReset();
102 }finally{
103 q.finalize();
106 log("Query data with exec() using rowMode 'array'...");
107 db.exec({
108 sql: "select a from t order by a limit 3",
109 rowMode: 'array', // 'array' (default), 'object', or 'stmt'
110 callback: function(row){
111 log("row ",++this.counter,"=",row);
112 }.bind({counter: 0})
115 log("Query data with exec() using rowMode 'object'...");
116 db.exec({
117 sql: "select a as aa, b as bb from t order by aa limit 3",
118 rowMode: 'object',
119 callback: function(row){
120 log("row ",++this.counter,"=",JSON.stringify(row));
121 }.bind({counter: 0})
124 log("Query data with exec() using rowMode 'stmt'...");
125 db.exec({
126 sql: "select a from t order by a limit 3",
127 rowMode: 'stmt',
128 callback: function(row){
129 log("row ",++this.counter,"get(0) =",row.get(0));
130 }.bind({counter: 0})
133 log("Query data with exec() using rowMode INTEGER (result column index)...");
134 db.exec({
135 sql: "select a, b from t order by a limit 3",
136 rowMode: 1, // === result column 1
137 callback: function(row){
138 log("row ",++this.counter,"b =",row);
139 }.bind({counter: 0})
142 log("Query data with exec() using rowMode $COLNAME (result column name)...");
143 db.exec({
144 sql: "select a a, b from t order by a limit 3",
145 rowMode: '$a',
146 callback: function(value){
147 log("row ",++this.counter,"a =",value);
148 }.bind({counter: 0})
151 log("Query data with exec() without a callback...");
152 let resultRows = [];
153 db.exec({
154 sql: "select a, b from t order by a limit 3",
155 rowMode: 'object',
156 resultRows: resultRows
158 log("Result rows:",JSON.stringify(resultRows,undefined,2));
160 log("Create a scalar UDF...");
161 db.createFunction({
162 name: 'twice',
163 xFunc: function(pCx, arg){ // note the call arg count
164 return arg + arg;
167 log("Run scalar UDF and collect result column names...");
168 let columnNames = [];
169 db.exec({
170 sql: "select a, twice(a), twice(''||a) from t order by a desc limit 3",
171 columnNames: columnNames,
172 rowMode: 'stmt',
173 callback: function(row){
174 log("a =",row.get(0), "twice(a) =", row.get(1),
175 "twice(''||a) =",row.get(2));
178 log("Result column names:",columnNames);
180 try{
181 log("The following use of the twice() UDF will",
182 "fail because of incorrect arg count...");
183 db.exec("select twice(1,2,3)");
184 }catch(e){
185 warn("Got expected exception:",e.message);
188 try {
189 db.transaction( function(D) {
190 D.exec("delete from t");
191 log("In transaction: count(*) from t =",db.selectValue("select count(*) from t"));
192 throw new sqlite3.SQLite3Error("Demonstrating transaction() rollback");
194 }catch(e){
195 if(e instanceof sqlite3.SQLite3Error){
196 log("Got expected exception from db.transaction():",e.message);
197 log("count(*) from t =",db.selectValue("select count(*) from t"));
198 }else{
199 throw e;
203 try {
204 db.savepoint( function(D) {
205 D.exec("delete from t");
206 log("In savepoint: count(*) from t =",db.selectValue("select count(*) from t"));
207 D.savepoint(function(DD){
208 const rows = [];
209 DD.exec({
210 sql: ["insert into t(a,b) values(99,100);",
211 "select count(*) from t"],
212 rowMode: 0,
213 resultRows: rows
215 log("In nested savepoint. Row count =",rows[0]);
216 throw new sqlite3.SQLite3Error("Demonstrating nested savepoint() rollback");
219 }catch(e){
220 if(e instanceof sqlite3.SQLite3Error){
221 log("Got expected exception from nested db.savepoint():",e.message);
222 log("count(*) from t =",db.selectValue("select count(*) from t"));
223 }else{
224 throw e;
227 }finally{
228 db.close();
231 log("That's all, folks!");
234 Some of the features of the OO API not demonstrated above...
236 - get change count (total or statement-local, 32- or 64-bit)
237 - get a DB's file name
239 Misc. Stmt features:
241 - Various forms of bind()
242 - clearBindings()
243 - reset()
244 - Various forms of step()
245 - Variants of get() for explicit type treatment/conversion,
246 e.g. getInt(), getFloat(), getBlob(), getJSON()
247 - getColumnName(ndx), getColumnNames()
248 - getParamIndex(name)
250 }/*demo1()*/;
252 log("Loading and initializing sqlite3 module...");
253 if(globalThis.window!==globalThis) /*worker thread*/{
255 If sqlite3.js is in a directory other than this script, in order
256 to get sqlite3.js to resolve sqlite3.wasm properly, we have to
257 explicitly tell it where sqlite3.js is being loaded from. We do
258 that by passing the `sqlite3.dir=theDirName` URL argument to
259 _this_ script. That URL argument will be seen by the JS/WASM
260 loader and it will adjust the sqlite3.wasm path accordingly. If
261 sqlite3.js/.wasm are in the same directory as this script then
262 that's not needed.
264 URL arguments passed as part of the filename via importScripts()
265 are simply lost, and such scripts see the globalThis.location of
266 _this_ script.
268 let sqlite3Js = 'sqlite3.js';
269 const urlParams = new URL(globalThis.location.href).searchParams;
270 if(urlParams.has('sqlite3.dir')){
271 sqlite3Js = urlParams.get('sqlite3.dir') + '/' + sqlite3Js;
273 importScripts(sqlite3Js);
275 globalThis.sqlite3InitModule({
276 /* We can redirect any stdout/stderr from the module like so, but
277 note that doing so makes use of Emscripten-isms, not
278 well-defined sqlite APIs. */
279 print: log,
280 printErr: error
281 }).then(function(sqlite3){
282 //console.log('sqlite3 =',sqlite3);
283 log("Done initializing. Running demo...");
284 try {
285 demo1(sqlite3);
286 }catch(e){
287 error("Exception:",e.message);
290 })();