koffi 2.2.0 → 2.2.2-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/ChangeLog.md +6 -0
  2. package/package.json +2 -2
  3. package/src/koffi/build/2.2.2-beta.1/koffi_darwin_arm64.tar.gz +0 -0
  4. package/src/koffi/build/2.2.2-beta.1/koffi_darwin_x64.tar.gz +0 -0
  5. package/src/koffi/build/2.2.2-beta.1/koffi_freebsd_arm64.tar.gz +0 -0
  6. package/src/koffi/build/2.2.2-beta.1/koffi_freebsd_ia32.tar.gz +0 -0
  7. package/src/koffi/build/2.2.2-beta.1/koffi_freebsd_x64.tar.gz +0 -0
  8. package/src/koffi/build/2.2.2-beta.1/koffi_linux_arm32hf.tar.gz +0 -0
  9. package/src/koffi/build/2.2.2-beta.1/koffi_linux_arm64.tar.gz +0 -0
  10. package/src/koffi/build/2.2.2-beta.1/koffi_linux_ia32.tar.gz +0 -0
  11. package/src/koffi/build/2.2.2-beta.1/koffi_linux_riscv64hf64.tar.gz +0 -0
  12. package/src/koffi/build/2.2.2-beta.1/koffi_linux_x64.tar.gz +0 -0
  13. package/src/koffi/build/2.2.2-beta.1/koffi_openbsd_ia32.tar.gz +0 -0
  14. package/src/koffi/build/2.2.2-beta.1/koffi_openbsd_x64.tar.gz +0 -0
  15. package/src/koffi/build/2.2.2-beta.1/koffi_win32_arm64.tar.gz +0 -0
  16. package/src/koffi/build/2.2.2-beta.1/koffi_win32_ia32.tar.gz +0 -0
  17. package/src/koffi/build/2.2.2-beta.1/koffi_win32_x64.tar.gz +0 -0
  18. package/src/koffi/qemu/qemu.js +12 -10
  19. package/src/koffi/src/abi_arm32.cc +7 -11
  20. package/src/koffi/src/abi_arm64.cc +7 -11
  21. package/src/koffi/src/abi_riscv64.cc +7 -11
  22. package/src/koffi/src/abi_x64_sysv.cc +7 -11
  23. package/src/koffi/src/abi_x64_win.cc +7 -11
  24. package/src/koffi/src/abi_x86.cc +7 -11
  25. package/src/koffi/src/call.cc +53 -2
  26. package/src/koffi/src/call.hh +6 -1
  27. package/src/koffi/src/ffi.cc +66 -12
  28. package/src/koffi/src/ffi.hh +2 -0
  29. package/src/koffi/src/index.js +6 -2
  30. package/src/koffi/test/CMakeLists.txt +1 -1
  31. package/src/koffi/test/async.js +3 -0
  32. package/src/koffi/test/callbacks.js +30 -0
  33. package/src/koffi/test/misc.c +11 -0
  34. package/vendor/{sqlite3mc → sqlite3}/sqlite3.c +139 -43
  35. package/vendor/{sqlite3mc → sqlite3}/sqlite3.h +10 -3
  36. package/vendor/{sqlite3mc → sqlite3}/sqlite3ext.h +0 -0
  37. package/vendor/{sqlite3mc → sqlite3}/sqlite3mc.c +156 -53
  38. package/vendor/{sqlite3mc → sqlite3}/sqlite3mc.def +0 -0
  39. package/vendor/{sqlite3mc → sqlite3}/sqlite3mc.h +12 -5
  40. package/vendor/sqlite3/wasm/README.txt +23 -0
  41. package/vendor/sqlite3/wasm/common/SqliteTestUtil.js +236 -0
  42. package/vendor/sqlite3/wasm/common/emscripten.css +24 -0
  43. package/vendor/sqlite3/wasm/common/testing.css +63 -0
  44. package/vendor/sqlite3/wasm/demo-123-worker.html +44 -0
  45. package/vendor/sqlite3/wasm/demo-123.html +24 -0
  46. package/vendor/sqlite3/wasm/demo-123.js +289 -0
  47. package/vendor/sqlite3/wasm/demo-jsstorage.html +49 -0
  48. package/vendor/sqlite3/wasm/demo-jsstorage.js +114 -0
  49. package/vendor/sqlite3/wasm/demo-worker1-promiser.html +34 -0
  50. package/vendor/sqlite3/wasm/demo-worker1-promiser.js +270 -0
  51. package/vendor/sqlite3/wasm/demo-worker1.html +34 -0
  52. package/vendor/sqlite3/wasm/demo-worker1.js +345 -0
  53. package/vendor/sqlite3/wasm/index.html +90 -0
  54. package/vendor/sqlite3/wasm/jswasm/sqlite3-opfs-async-proxy.js +830 -0
  55. package/vendor/sqlite3/wasm/jswasm/sqlite3-worker1-promiser.js +259 -0
  56. package/vendor/sqlite3/wasm/jswasm/sqlite3-worker1.js +49 -0
  57. package/vendor/sqlite3/wasm/jswasm/sqlite3.js +10119 -0
  58. package/vendor/sqlite3/wasm/jswasm/sqlite3.wasm +0 -0
  59. package/vendor/sqlite3/wasm/tester1-worker.html +63 -0
  60. package/vendor/sqlite3/wasm/tester1.html +28 -0
  61. package/vendor/sqlite3/wasm/tester1.js +1864 -0
  62. package/src/koffi/build/2.2.0/koffi_darwin_arm64.tar.gz +0 -0
  63. package/src/koffi/build/2.2.0/koffi_darwin_x64.tar.gz +0 -0
  64. package/src/koffi/build/2.2.0/koffi_freebsd_arm64.tar.gz +0 -0
  65. package/src/koffi/build/2.2.0/koffi_freebsd_ia32.tar.gz +0 -0
  66. package/src/koffi/build/2.2.0/koffi_freebsd_x64.tar.gz +0 -0
  67. package/src/koffi/build/2.2.0/koffi_linux_arm32hf.tar.gz +0 -0
  68. package/src/koffi/build/2.2.0/koffi_linux_arm64.tar.gz +0 -0
  69. package/src/koffi/build/2.2.0/koffi_linux_ia32.tar.gz +0 -0
  70. package/src/koffi/build/2.2.0/koffi_linux_riscv64hf64.tar.gz +0 -0
  71. package/src/koffi/build/2.2.0/koffi_linux_x64.tar.gz +0 -0
  72. package/src/koffi/build/2.2.0/koffi_openbsd_ia32.tar.gz +0 -0
  73. package/src/koffi/build/2.2.0/koffi_openbsd_x64.tar.gz +0 -0
  74. package/src/koffi/build/2.2.0/koffi_win32_arm64.tar.gz +0 -0
  75. package/src/koffi/build/2.2.0/koffi_win32_ia32.tar.gz +0 -0
  76. package/src/koffi/build/2.2.0/koffi_win32_x64.tar.gz +0 -0
@@ -0,0 +1,236 @@
1
+ /*
2
+ 2022-05-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 bootstrapping code used by various test scripts
14
+ which live in this file's directory.
15
+ */
16
+ 'use strict';
17
+ (function(self){
18
+ /* querySelectorAll() proxy */
19
+ const EAll = function(/*[element=document,] cssSelector*/){
20
+ return (arguments.length>1 ? arguments[0] : document)
21
+ .querySelectorAll(arguments[arguments.length-1]);
22
+ };
23
+ /* querySelector() proxy */
24
+ const E = function(/*[element=document,] cssSelector*/){
25
+ return (arguments.length>1 ? arguments[0] : document)
26
+ .querySelector(arguments[arguments.length-1]);
27
+ };
28
+
29
+ /**
30
+ Helpers for writing sqlite3-specific tests.
31
+ */
32
+ self.SqliteTestUtil = {
33
+ /** Running total of the number of tests run via
34
+ this API. */
35
+ counter: 0,
36
+ /**
37
+ If expr is a function, it is called and its result
38
+ is returned, coerced to a bool, else expr, coerced to
39
+ a bool, is returned.
40
+ */
41
+ toBool: function(expr){
42
+ return (expr instanceof Function) ? !!expr() : !!expr;
43
+ },
44
+ /** abort() if expr is false. If expr is a function, it
45
+ is called and its result is evaluated.
46
+ */
47
+ assert: function f(expr, msg){
48
+ if(!f._){
49
+ f._ = ('undefined'===typeof abort
50
+ ? (msg)=>{throw new Error(msg)}
51
+ : abort);
52
+ }
53
+ ++this.counter;
54
+ if(!this.toBool(expr)){
55
+ f._(msg || "Assertion failed.");
56
+ }
57
+ return this;
58
+ },
59
+ /** Identical to assert() but throws instead of calling
60
+ abort(). */
61
+ affirm: function(expr, msg){
62
+ ++this.counter;
63
+ if(!this.toBool(expr)) throw new Error(msg || "Affirmation failed.");
64
+ return this;
65
+ },
66
+ /** Calls f() and squelches any exception it throws. If it
67
+ does not throw, this function throws. */
68
+ mustThrow: function(f, msg){
69
+ ++this.counter;
70
+ let err;
71
+ try{ f(); } catch(e){err=e;}
72
+ if(!err) throw new Error(msg || "Expected exception.");
73
+ return this;
74
+ },
75
+ /**
76
+ Works like mustThrow() but expects filter to be a regex,
77
+ function, or string to match/filter the resulting exception
78
+ against. If f() does not throw, this test fails and an Error is
79
+ thrown. If filter is a regex, the test passes if
80
+ filter.test(error.message) passes. If it's a function, the test
81
+ passes if filter(error) returns truthy. If it's a string, the
82
+ test passes if the filter matches the exception message
83
+ precisely. In all other cases the test fails, throwing an
84
+ Error.
85
+
86
+ If it throws, msg is used as the error report unless it's falsy,
87
+ in which case a default is used.
88
+ */
89
+ mustThrowMatching: function(f, filter, msg){
90
+ ++this.counter;
91
+ let err;
92
+ try{ f(); } catch(e){err=e;}
93
+ if(!err) throw new Error(msg || "Expected exception.");
94
+ let pass = false;
95
+ if(filter instanceof RegExp) pass = filter.test(err.message);
96
+ else if(filter instanceof Function) pass = filter(err);
97
+ else if('string' === typeof filter) pass = (err.message === filter);
98
+ if(!pass){
99
+ throw new Error(msg || ("Filter rejected this exception: "+err.message));
100
+ }
101
+ return this;
102
+ },
103
+ /** Throws if expr is truthy or expr is a function and expr()
104
+ returns truthy. */
105
+ throwIf: function(expr, msg){
106
+ ++this.counter;
107
+ if(this.toBool(expr)) throw new Error(msg || "throwIf() failed");
108
+ return this;
109
+ },
110
+ /** Throws if expr is falsy or expr is a function and expr()
111
+ returns falsy. */
112
+ throwUnless: function(expr, msg){
113
+ ++this.counter;
114
+ if(!this.toBool(expr)) throw new Error(msg || "throwUnless() failed");
115
+ return this;
116
+ },
117
+
118
+ /**
119
+ Parses window.location.search-style string into an object
120
+ containing key/value pairs of URL arguments (already
121
+ urldecoded). The object is created using Object.create(null),
122
+ so contains only parsed-out properties and has no prototype
123
+ (and thus no inherited properties).
124
+
125
+ If the str argument is not passed (arguments.length==0) then
126
+ window.location.search.substring(1) is used by default. If
127
+ neither str is passed in nor window exists then false is returned.
128
+
129
+ On success it returns an Object containing the key/value pairs
130
+ parsed from the string. Keys which have no value are treated
131
+ has having the boolean true value.
132
+
133
+ Pedantic licensing note: this code has appeared in other source
134
+ trees, but was originally written by the same person who pasted
135
+ it into those trees.
136
+ */
137
+ processUrlArgs: function(str) {
138
+ if( 0 === arguments.length ) {
139
+ if( ('undefined' === typeof window) ||
140
+ !window.location ||
141
+ !window.location.search ) return false;
142
+ else str = (''+window.location.search).substring(1);
143
+ }
144
+ if( ! str ) return false;
145
+ str = (''+str).split(/#/,2)[0]; // remove #... to avoid it being added as part of the last value.
146
+ const args = Object.create(null);
147
+ const sp = str.split(/&+/);
148
+ const rx = /^([^=]+)(=(.+))?/;
149
+ var i, m;
150
+ for( i in sp ) {
151
+ m = rx.exec( sp[i] );
152
+ if( ! m ) continue;
153
+ args[decodeURIComponent(m[1])] = (m[3] ? decodeURIComponent(m[3]) : true);
154
+ }
155
+ return args;
156
+ }
157
+ };
158
+
159
+
160
+ /**
161
+ This is a module object for use with the emscripten-installed
162
+ sqlite3InitModule() factory function.
163
+ */
164
+ self.sqlite3TestModule = {
165
+ /**
166
+ Array of functions to call after Emscripten has initialized the
167
+ wasm module. Each gets passed the Emscripten module object
168
+ (which is _this_ object).
169
+ */
170
+ postRun: [
171
+ /* function(theModule){...} */
172
+ ],
173
+ //onRuntimeInitialized: function(){},
174
+ /* Proxy for C-side stdout output. */
175
+ print: (...args)=>{console.log(...args)},
176
+ /* Proxy for C-side stderr output. */
177
+ printErr: (...args)=>{console.error(...args)},
178
+ /**
179
+ Called by the Emscripten module init bits to report loading
180
+ progress. It gets passed an empty argument when loading is done
181
+ (after onRuntimeInitialized() and any this.postRun callbacks
182
+ have been run).
183
+ */
184
+ setStatus: function f(text){
185
+ if(!f.last){
186
+ f.last = { text: '', step: 0 };
187
+ f.ui = {
188
+ status: E('#module-status'),
189
+ progress: E('#module-progress'),
190
+ spinner: E('#module-spinner')
191
+ };
192
+ }
193
+ if(text === f.last.text) return;
194
+ f.last.text = text;
195
+ if(f.ui.progress){
196
+ f.ui.progress.value = f.last.step;
197
+ f.ui.progress.max = f.last.step + 1;
198
+ }
199
+ ++f.last.step;
200
+ if(text) {
201
+ f.ui.status.classList.remove('hidden');
202
+ f.ui.status.innerText = text;
203
+ }else{
204
+ if(f.ui.progress){
205
+ f.ui.progress.remove();
206
+ f.ui.spinner.remove();
207
+ delete f.ui.progress;
208
+ delete f.ui.spinner;
209
+ }
210
+ f.ui.status.classList.add('hidden');
211
+ }
212
+ },
213
+ /**
214
+ Config options used by the Emscripten-dependent initialization
215
+ which happens via this.initSqlite3(). This object gets
216
+ (indirectly) passed to sqlite3ApiBootstrap() to configure the
217
+ sqlite3 API.
218
+ */
219
+ sqlite3ApiConfig: {
220
+ wasmfsOpfsDir: "/opfs"
221
+ },
222
+ /**
223
+ Intended to be called by apps which need to call the
224
+ Emscripten-installed sqlite3InitModule() routine. This function
225
+ temporarily installs this.sqlite3ApiConfig into the self
226
+ object, calls it sqlite3InitModule(), and removes
227
+ self.sqlite3ApiConfig after initialization is done. Returns the
228
+ promise from sqlite3InitModule(), and the next then() handler
229
+ will get the sqlite3 API object as its argument.
230
+ */
231
+ initSqlite3: function(){
232
+ self.sqlite3ApiConfig = this.sqlite3ApiConfig;
233
+ return self.sqlite3InitModule(this).finally(()=>delete self.sqlite3ApiConfig);
234
+ }
235
+ };
236
+ })(self/*window or worker*/);
@@ -0,0 +1,24 @@
1
+ /* emcscript-related styling, used during the module load/intialization processes... */
2
+ .emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
3
+ div.emscripten { text-align: center; }
4
+ div.emscripten_border { border: 1px solid black; }
5
+ #module-spinner { overflow: visible; }
6
+ #module-spinner > * {
7
+ margin-top: 1em;
8
+ }
9
+ .spinner {
10
+ height: 50px;
11
+ width: 50px;
12
+ margin: 0px auto;
13
+ animation: rotation 0.8s linear infinite;
14
+ border-left: 10px solid rgb(0,150,240);
15
+ border-right: 10px solid rgb(0,150,240);
16
+ border-bottom: 10px solid rgb(0,150,240);
17
+ border-top: 10px solid rgb(100,0,200);
18
+ border-radius: 100%;
19
+ background-color: rgb(200,100,250);
20
+ }
21
+ @keyframes rotation {
22
+ from {transform: rotate(0deg);}
23
+ to {transform: rotate(360deg);}
24
+ }
@@ -0,0 +1,63 @@
1
+ body {
2
+ display: flex;
3
+ flex-direction: column;
4
+ flex-wrap: wrap;
5
+ }
6
+ textarea {
7
+ font-family: monospace;
8
+ }
9
+ header {
10
+ font-size: 130%;
11
+ font-weight: bold;
12
+ }
13
+ .hidden, .initially-hidden {
14
+ position: absolute !important;
15
+ opacity: 0 !important;
16
+ pointer-events: none !important;
17
+ display: none !important;
18
+ }
19
+ fieldset.options {
20
+ font-size: 75%;
21
+ }
22
+ fieldset > legend {
23
+ padding: 0 0.5em;
24
+ }
25
+ span.labeled-input {
26
+ padding: 0.25em;
27
+ margin: 0.25em 0.5em;
28
+ border-radius: 0.25em;
29
+ white-space: nowrap;
30
+ background: #0002;
31
+ }
32
+ .center { text-align: center; }
33
+ .error {
34
+ color: red;
35
+ background-color: yellow;
36
+ }
37
+ .strong { font-weight: 700 }
38
+ .warning { color: firebrick; }
39
+ .green { color: darkgreen; }
40
+ .tests-pass { background-color: green; color: white }
41
+ .tests-fail { background-color: red; color: yellow }
42
+ .faded { opacity: 0.5; }
43
+ .group-start { color: blue; }
44
+ .group-end { color: blue; }
45
+ .input-wrapper {
46
+ white-space: nowrap;
47
+ display: flex;
48
+ align-items: center;
49
+ }
50
+ #test-output {
51
+ border: 1px inset;
52
+ border-radius: 0.25em;
53
+ padding: 0.25em;
54
+ /*max-height: 30em;*/
55
+ overflow: auto;
56
+ white-space: break-spaces;
57
+ display: flex; flex-direction: column;
58
+ font-family: monospace;
59
+ }
60
+ #test-output.reverse {
61
+ flex-direction: column-reverse;
62
+ }
63
+ label[for] { cursor: pointer }
@@ -0,0 +1,44 @@
1
+ <!doctype html>
2
+ <html lang="en-us">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
6
+ <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
7
+ <title>Hello, sqlite3</title>
8
+ <style>
9
+ .warning, .error {color: red}
10
+ .error {background-color: yellow}
11
+ body {
12
+ display: flex;
13
+ flex-direction: column;
14
+ font-family: monospace;
15
+ white-space: break-spaces;
16
+ }
17
+ </style>
18
+ </head>
19
+ <body>
20
+ <h1>1-2-sqlite3 worker demo</h1>
21
+ <script>(function(){
22
+ const logHtml = function(cssClass,...args){
23
+ const ln = document.createElement('div');
24
+ if(cssClass) ln.classList.add(cssClass);
25
+ ln.append(document.createTextNode(args.join(' ')));
26
+ document.body.append(ln);
27
+ };
28
+ const w = new Worker("demo-123.js?sqlite3.dir=jswasm"
29
+ /* Note the URL argument on that name. See
30
+ the notes in demo-123.js (search for
31
+ "importScripts") for why we need
32
+ that. */);
33
+ w.onmessage = function({data}){
34
+ switch(data.type){
35
+ case 'log':
36
+ logHtml(data.payload.cssClass, ...data.payload.args);
37
+ break;
38
+ default:
39
+ logHtml('error',"Unhandled message:",data.type);
40
+ };
41
+ };
42
+ })();</script>
43
+ </body>
44
+ </html>
@@ -0,0 +1,24 @@
1
+ <!doctype html>
2
+ <html lang="en-us">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
6
+ <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
7
+ <title>Hello, sqlite3</title>
8
+ <style>
9
+ .warning, .error {color: red}
10
+ .error {background-color: yellow}
11
+ body {
12
+ display: flex;
13
+ flex-direction: column;
14
+ font-family: monospace;
15
+ white-space: break-spaces;
16
+ }
17
+ </style>
18
+ </head>
19
+ <body>
20
+ <h1>1-2-sqlite3 demo</h1>
21
+ <script src="jswasm/sqlite3.js"></script>
22
+ <script src="demo-123.js"></script>
23
+ </body>
24
+ </html>
@@ -0,0 +1,289 @@
1
+ /*
2
+ 2022-09-19
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
+ A basic demonstration of the SQLite3 "OO#1" API.
14
+ */
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.
21
+ */
22
+ let logHtml;
23
+ if(self.window === self /* 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);
30
+ };
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
+ });
38
+ };
39
+ }
40
+ const log = (...args)=>logHtml('',...args);
41
+ const warn = (...args)=>logHtml('warning',...args);
42
+ const error = (...args)=>logHtml('error',...args);
43
+
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.
57
+ */
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).
70
+
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
+ });
84
+ }
85
+
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();
97
+ }
98
+ // Equivalent...
99
+ for( i = 103; i <= 105; ++i ){
100
+ q.bind(1, i).bind(2, i*2).stepReset();
101
+ }
102
+ }finally{
103
+ q.finalize();
104
+ }
105
+
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})
113
+ });
114
+
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})
122
+ });
123
+
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})
131
+ });
132
+
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})
140
+ });
141
+
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})
149
+ });
150
+
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
157
+ });
158
+ log("Result rows:",JSON.stringify(resultRows,undefined,2));
159
+
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;
165
+ }
166
+ });
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));
176
+ }
177
+ });
178
+ log("Result column names:",columnNames);
179
+
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);
186
+ }
187
+
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");
193
+ });
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;
200
+ }
201
+ }
202
+
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
214
+ });
215
+ log("In nested savepoint. Row count =",rows[0]);
216
+ throw new sqlite3.SQLite3Error("Demonstrating nested savepoint() rollback");
217
+ })
218
+ });
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;
225
+ }
226
+ }
227
+ }finally{
228
+ db.close();
229
+ }
230
+
231
+ log("That's all, folks!");
232
+
233
+ /**
234
+ Some of the features of the OO API not demonstrated above...
235
+
236
+ - get change count (total or statement-local, 32- or 64-bit)
237
+ - get a DB's file name
238
+
239
+ Misc. Stmt features:
240
+
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)
249
+ */
250
+ }/*demo1()*/;
251
+
252
+ log("Loading and initializing sqlite3 module...");
253
+ if(self.window!==self) /*worker thread*/{
254
+ /*
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.
263
+
264
+ URL arguments passed as part of the filename via importScripts()
265
+ are simply lost, and such scripts see the self.location of
266
+ _this_ script.
267
+ */
268
+ let sqlite3Js = 'sqlite3.js';
269
+ const urlParams = new URL(self.location.href).searchParams;
270
+ if(urlParams.has('sqlite3.dir')){
271
+ sqlite3Js = urlParams.get('sqlite3.dir') + '/' + sqlite3Js;
272
+ }
273
+ importScripts(sqlite3Js);
274
+ }
275
+ self.sqlite3InitModule({
276
+ // We can redirect any stdout/stderr from the module
277
+ // like so...
278
+ print: log,
279
+ printErr: error
280
+ }).then(function(sqlite3){
281
+ //console.log('sqlite3 =',sqlite3);
282
+ log("Done initializing. Running demo...");
283
+ try {
284
+ demo1(sqlite3);
285
+ }catch(e){
286
+ error("Exception:",e.message);
287
+ }
288
+ });
289
+ })();