SQLite

Check-in [d6f6ee5cbc]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Merge the latest trunk enhancements into the begin-concurrent branch.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | begin-concurrent
Files: files | file ages | folders
SHA3-256: d6f6ee5cbcd9b263bc2423ce90700ec238deea212d32888fa9302fa2479b7d99
User & Date: drh 2022-05-28 14:25:10.801
Context
2022-06-16
13:37
Merge the latest trunk enhancements into the begin-concurrent branch. (check-in: 221e07ed78 user: drh tags: begin-concurrent)
2022-05-28
14:32
Merge the latest trunk enhancements into the begin-concurrent-report branch. (check-in: 034d2c511a user: drh tags: begin-concurrent-report)
14:25
Merge the latest trunk enhancements into the begin-concurrent branch. (check-in: d6f6ee5cbc user: drh tags: begin-concurrent)
14:03
Apply the UPDATE-FROM file from check-in [98b3816bbaf539ea] to update-delete-limit builds. (check-in: 7e87892c24 user: drh tags: trunk)
2022-05-10
12:00
Merge recent trunk enhancements into the begin-concurrent branch. (check-in: f65bd76760 user: drh tags: begin-concurrent)
Changes
Unified Diff Ignore Whitespace Patch
Changes to Makefile.in.
1510
1511
1512
1513
1514
1515
1516
































































































	echo 'EXPORTS' >sqlite3.def
	nm $(REAL_LIBOBJ) | grep ' T ' | grep ' _sqlite3_' \
		| sed 's/^.* _//' >>sqlite3.def

sqlite3.dll: $(REAL_LIBOBJ) sqlite3.def
	$(TCC) -shared -o $@ sqlite3.def \
		-Wl,"--strip-all" $(REAL_LIBOBJ)







































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
	echo 'EXPORTS' >sqlite3.def
	nm $(REAL_LIBOBJ) | grep ' T ' | grep ' _sqlite3_' \
		| sed 's/^.* _//' >>sqlite3.def

sqlite3.dll: $(REAL_LIBOBJ) sqlite3.def
	$(TCC) -shared -o $@ sqlite3.def \
		-Wl,"--strip-all" $(REAL_LIBOBJ)


#
# fiddle/wasm section
#
fiddle_dir = ext/fiddle
fiddle_dir_abs = $(TOP)/$(fiddle_dir)
# ^^^ some emcc opts require absolute paths
fiddle_html = $(fiddle_dir)/fiddle.html
fiddle_module_js = $(fiddle_dir)/fiddle-module.js
fiddle_generated = $(fiddle_module_js) \
                   $(fiddle_dir)/fiddle-module.wasm
sqlite3_wasm_js = $(fiddle_dir)/sqlite3.js
sqlite3_wasm = $(fiddle_dir)/sqlite3.wasm
sqlite3_wasm_generated = $(sqlite3_wasm) $(sqlite3_wasm_js)
clean-wasm:
	rm -f $(fiddle_generated) $(sqlite3_wasm_generated)
clean: clean-wasm
#emcc_opt = -O0
#emcc_opt = -O1
#emcc_opt = -O2
#emcc_opt = -O3
emcc_opt = -Oz
emcc_flags = $(emcc_opt) -sALLOW_TABLE_GROWTH -I. $(SHELL_OPT)
$(fiddle_module_js): Makefile sqlite3.c shell.c \
    $(fiddle_dir)/EXPORTED_RUNTIME_METHODS \
    $(fiddle_dir)/EXPORTED_FUNCTIONS.fiddle
	emcc -o $@ $(emcc_flags) \
        -sENVIRONMENT=web \
        -sMODULARIZE \
        -sEXPORT_NAME=initFiddleModule \
        -sEXPORTED_RUNTIME_METHODS=@$(fiddle_dir_abs)/EXPORTED_RUNTIME_METHODS \
        -sEXPORTED_FUNCTIONS=@$(fiddle_dir_abs)/EXPORTED_FUNCTIONS.fiddle \
        sqlite3.c shell.c
$(sqlite3_wasm_js): Makefile sqlite3.c \
    $(fiddle_dir)/sqlite3-api.js \
    $(fiddle_dir)/EXPORTED_RUNTIME_METHODS \
    $(fiddle_dir)/EXPORTED_FUNCTIONS.sqlite3-api
	emcc -o $@ $(emcc_flags) \
        -sENVIRONMENT=web \
        -sMODULARIZE \
        -sEXPORT_NAME=initSqlite3Module \
        -sEXPORTED_RUNTIME_METHODS=@$(fiddle_dir_abs)/EXPORTED_RUNTIME_METHODS \
        -sEXPORTED_FUNCTIONS=@$(fiddle_dir_abs)/EXPORTED_FUNCTIONS.sqlite3-api \
        --post-js=$(fiddle_dir)/sqlite3-api.js \
        --no-entry \
        sqlite3.c
fiddle: $(fiddle_module_js)
sqlite3-wasm: $(sqlite3_wasm_js)
wasm: fiddle sqlite3-wasm
########################################################################
# Explanation of the emcc build flags:
#
# -sENVIRONMENT=web: elides bootstrap code related to non-web JS
#  environments like node.js. Removing this makes the output a tiny
#  tick larger but hypothetically makes it more portable to
#  non-browser JS environments.
#
# -sMODULARIZE: changes how the generated code is structured to avoid
#  declaring a global Module object and instead installing a function
#  which loads and initialized the module. The function is named...
#
# -sEXPORT_NAME=jsFunctionName (see -sMODULARIZE)
#
# -sEXPORTED_RUNTIME_METHODS=@/absolute/path/to/file: a file
#  containing a list of emscripten-supplied APIs, one per line, which
#  must be exported into the generated JS. Must be an absolute path!
#
# -sEXPORTED_FUNCTIONS=@/absolute/path/to/file: a file containing a
#  list of C functions, one per line, which must be exported via wasm
#  so they're visible to JS. C symbols names in that file must all
#  start with an underscore for reasons known only to the emcc
#  developers. e.g., _sqlite3_open_v2 and _sqlite3_finalize. Must be
#  an absolute path!
#
# --no-entry: for compiling library code with no main(). If this is
#  not supplied and the code has a main(), it is called as part of the
#  module init process. Note that main() is #if'd out of shell.c
#  (renamed) when building in wasm mode.
#
# --pre-js/--post-js=FILE relative or absolute paths to JS files to
#  prepend/append to the emcc-generated bootstrapping JS. It's
#  easier/faster to develop with separate JS files (reduces rebuilding
#  requirements) but certain configurations, namely -sMODULARIZE, may
#  require using at least a --pre-js file. They can be used
#  individually and need not be paired.
#
# -O0..-O3 and -Oz: optimization levels affect not only C-style
#  optimization but whether or not the resulting generated JS code
#  gets minified. -O0 compiles _much_ more quickly than -O3 or -Oz,
#  and doesn't minimize any JS code, so is recommended for
#  development. -O3 or -Oz are recommended for deployment, but
#  primarily because -Oz will shrink the wasm file notably. JS-side
#  minification makes little difference in terms of overall
#  distributable size.
########################################################################
Added ext/fiddle/EXPORTED_FUNCTIONS.fiddle.














>
>
>
>
>
>
>
1
2
3
4
5
6
7
_fiddle_exec
_fiddle_interrupt
_fiddle_experiment
_fiddle_the_db
_fiddle_db_arg
_fiddle_db_filename
_fiddle_reset_db
Added ext/fiddle/EXPORTED_FUNCTIONS.sqlite3-api.






































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
_sqlite3_bind_blob
_sqlite3_bind_double
_sqlite3_bind_int
_sqlite3_bind_int64
_sqlite3_bind_null
_sqlite3_bind_parameter_count
_sqlite3_bind_parameter_index
_sqlite3_bind_text
_sqlite3_changes
_sqlite3_clear_bindings
_sqlite3_close_v2
_sqlite3_column_blob
_sqlite3_column_bytes
_sqlite3_column_count
_sqlite3_column_count
_sqlite3_column_double
_sqlite3_column_int
_sqlite3_column_int64
_sqlite3_column_name
_sqlite3_column_text
_sqlite3_column_type
_sqlite3_compileoption_get
_sqlite3_compileoption_used
_sqlite3_create_function_v2
_sqlite3_data_count
_sqlite3_db_filename
_sqlite3_errmsg
_sqlite3_exec
_sqlite3_finalize
_sqlite3_interrupt
_sqlite3_libversion
_sqlite3_open
_sqlite3_open_v2
_sqlite3_prepare_v2
_sqlite3_prepare_v2
_sqlite3_reset
_sqlite3_result_blob
_sqlite3_result_double
_sqlite3_result_error
_sqlite3_result_int
_sqlite3_result_null
_sqlite3_result_text
_sqlite3_sourceid
_sqlite3_sql
_sqlite3_step
_sqlite3_value_blob
_sqlite3_value_bytes
_sqlite3_value_double
_sqlite3_value_text
_sqlite3_value_type
_free
Added ext/fiddle/EXPORTED_RUNTIME_METHODS.




























>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
ALLOC_NORMAL
FS
UTF8ToString
addFunction
allocate
allocateUTF8OnStack
ccall
cwrap
getValue
removeFunction
setValue
stackAlloc
stackRestore
stackSave
Added ext/fiddle/Makefile.


































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# This GNU makefile exists primarily to simplify/speed up development
# from emacs. It is not part of the canonical build process.
default:
	$(MAKE) -C ../.. wasm -e emcc_opt=-O0

clean:
	$(MAKE) -C ../../ clean-wasm

fiddle_files = emscripten.css fiddle.html \
             fiddle.js fiddle-module.js \
             fiddle-module.wasm fiddle-worker.js

# fiddle_remote is the remote destination for the fiddle app. It
# must be a [user@]HOST:/path for rsync.
# Note that the target "should probably" contain a symlink of
# index.html -> fiddle.html.
fiddle_remote ?=
ifeq (,$(fiddle_remote))
ifneq (,$(wildcard /home/stephan))
  fiddle_remote = wh2:www/wh/sqlite3/.
else ifneq (,$(wildcard /home/drh))
  #fiddle_remote = if appropriate, add that user@host:/path here
endif
endif

$(fiddle_files): default

push-fiddle: $(fiddle_files)
	@if [ x = "x$(fiddle_remote)" ]; then \
		echo "fiddle_remote must be a [user@]HOST:/path for rsync"; \
		exit 1; \
	fi
	rsync -va $(fiddle_files) $(fiddle_remote)
Added ext/fiddle/SqliteTestUtil.js.
































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*
  2022-05-22

  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.

  ***********************************************************************

  This file contains bootstrapping code used by various test scripts
  which live in this file's directory.
*/
(function(){
    /* querySelectorAll() proxy */
    const EAll = function(/*[element=document,] cssSelector*/){
        return (arguments.length>1 ? arguments[0] : document)
            .querySelectorAll(arguments[arguments.length-1]);
    };
    /* querySelector() proxy */
    const E = function(/*[element=document,] cssSelector*/){
        return (arguments.length>1 ? arguments[0] : document)
            .querySelector(arguments[arguments.length-1]);
    };

    /**
       Helpers for writing sqlite3-specific tests.
    */
    self/*window or worker*/.SqliteTestUtil = {
        /** Running total of the number of tests run via
            this API. */
        counter: 0,
        /**
           If expr is a function, it is called and its result
           is returned, coerced to a bool, else expr, coerced to
           a bool, is returned.
        */
        toBool: function(expr){
            return (expr instanceof Function) ? !!expr() : !!expr;
        },
        /** abort() if expr is false. If expr is a function, it
            is called and its result is evaluated.
        */
        assert: function f(expr, msg){
            if(!f._){
                f._ = ('undefined'===typeof abort
                       ? (msg)=>{throw new Error(msg)}
                       : abort);
            }
            ++this.counter;
            if(!this.toBool(expr)){
                f._(msg || "Assertion failed.");
            }
            return this;
        },
        /** Identical to assert() but throws instead of calling
            abort(). */
        affirm: function(expr, msg){
            ++this.counter;
            if(!this.toBool(expr)) throw new Error(msg || "Affirmation failed.");
            return this;
        },
        /** Calls f() and squelches any exception it throws. If it
            does not throw, this function throws. */
        mustThrow: function(f, msg){
            ++this.counter;
            let err;
            try{ f(); } catch(e){err=e;}
            if(!err) throw new Error(msg || "Expected exception.");
            return this;
        },
        /** Throws if expr is truthy or expr is a function and expr()
            returns truthy. */
        throwIf: function(expr, msg){
            ++this.counter;
            if(this.toBool(expr)) throw new Error(msg || "throwIf() failed");
            return this;
        },
        /** Throws if expr is falsy or expr is a function and expr()
            returns falsy. */
        throwUnless: function(expr, msg){
            ++this.counter;
            if(!this.toBool(expr)) throw new Error(msg || "throwUnless() failed");
            return this;
        }
    };

    
    /**
       This is a module object for use with the emscripten-installed
       initSqlite3Module() factory function.
    */
    self.sqlite3TestModule = {
        postRun: [
            /* function(theModule){...} */
        ],
        //onRuntimeInitialized: function(){},
        /* Proxy for C-side stdout output. */
        print: function(){
            console.log.apply(console, Array.prototype.slice.call(arguments));
        },
        /* Proxy for C-side stderr output. */
        printErr: function(){
            console.error.apply(console, Array.prototype.slice.call(arguments));
        },
        /**
           Called by the module init bits to report loading
           progress. It gets passed an empty argument when loading is
           done (after onRuntimeInitialized() and any this.postRun
           callbacks have been run).
        */
        setStatus: function f(text){
            if(!f.last){
                f.last = { text: '', step: 0 };
                f.ui = {
                    status: E('#module-status'),
                    progress: E('#module-progress'),
                    spinner: E('#module-spinner')
                };
            }
            if(text === f.last.text) return;
            f.last.text = text;
            if(f.ui.progress){
                f.ui.progress.value = f.last.step;
                f.ui.progress.max = f.last.step + 1;
            }
            ++f.last.step;
            if(text) {
                f.ui.status.classList.remove('hidden');
                f.ui.status.innerText = text;
            }else{
                if(f.ui.progress){
                    f.ui.progress.remove();
                    f.ui.spinner.remove();
                    delete f.ui.progress;
                    delete f.ui.spinner;
                }
                f.ui.status.classList.add('hidden');
            }
        }
    };
})(self/*window or worker*/);
Added ext/fiddle/emscripten.css.
















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* emcscript-related styling, used during the module load/intialization processes... */
.emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
div.emscripten { text-align: center; }
div.emscripten_border { border: 1px solid black; }
#module-spinner { overflow: visible; }
#module-spinner > * {
    margin-top: 1em;
}
.spinner {
    height: 50px;
    width: 50px;
    margin: 0px auto;
    animation: rotation 0.8s linear infinite;
    border-left: 10px solid rgb(0,150,240);
    border-right: 10px solid rgb(0,150,240);
    border-bottom: 10px solid rgb(0,150,240);
    border-top: 10px solid rgb(100,0,200);
    border-radius: 100%;
    background-color: rgb(200,100,250);
}
@keyframes rotation {
    from {transform: rotate(0deg);}
    to {transform: rotate(360deg);}
}
Added ext/fiddle/fiddle-worker.js.
























































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
/*
  2022-05-20

  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.

  ***********************************************************************

  This is the JS Worker file for the sqlite3 fiddle app. It loads the
  sqlite3 wasm module and offers access to the db via the Worker
  message-passing interface.

  Forewarning: this API is still very much Under Construction and
  subject to any number of changes as experience reveals what those
  need to be.

  Because we can have only a single message handler, as opposed to an
  arbitrary number of discrete event listeners like with DOM elements,
  we have to define a lower-level message API. Messages abstractly
  look like:

  { type: string, data: type-specific value }

  Where 'type' is used for dispatching and 'data' is a
  'type'-dependent value.

  The 'type' values expected by each side of the main/worker
  connection vary. The types are described below but subject to
  change at any time as this experiment evolves.

  Workers-to-Main types

  - stdout, stderr: indicate stdout/stderr output from the wasm
    layer. The data property is the string of the output, noting
    that the emscripten binding emits these one line at a time. Thus,
    if a C-side puts() emits multiple lines in a single call, the JS
    side will see that as multiple calls. Example:

    {type:'stdout', data: 'Hi, world.'}

  - module: Status text. This is intended to alert the main thread
    about module loading status so that, e.g., the main thread can
    update a progress widget and DTRT when the module is finished
    loading and available for work. Status messages come in the form
    
    {type:'module', data:{
        type:'status',
        data: {text:string|null, step:1-based-integer}
    }

    with an incrementing step value for each subsequent message. When
    the module loading is complete, a message with a text value of
    null is posted.

  - working: data='start'|'end'. Indicates that work is about to be
    sent to the module or has just completed. This can be used, e.g.,
    to disable UI elements which should not be activated while work
    is pending. Example:

    {type:'working', data:'start'}

  Main-to-Worker types:

  - shellExec: data=text to execute as if it had been entered in the
    sqlite3 CLI shell app (as opposed to sqlite3_exec()). This event
    causes the worker to emit a 'working' event (data='start') before
    it starts and a 'working' event (data='end') when it finished. If
    called while work is currently being executed it emits stderr
    message instead of doing actual work, as the underlying db cannot
    handle concurrent tasks. Example:

    {type:'shellExec', data: 'select * from sqlite_master'}

  - More TBD as the higher-level db layer develops.
*/

/*
  Apparent browser(s) bug: console messages emitted may be duplicated
  in the console, even though they're provably only run once. See:

  https://stackoverflow.com/questions/49659464

  Noting that it happens in Firefox as well as Chrome. Harmless but
  annoying.
*/
"use strict";
(function(){
    /**
       Posts a message in the form {type,data} unless passed more than 2
       args, in which case it posts {type, data:[arg1...argN]}.
    */
    const wMsg = function(type,data){
        postMessage({
            type,
            data: arguments.length<3
                ? data
                : Array.prototype.slice.call(arguments,1)
        });
    };

    const stdout = function(){wMsg('stdout', Array.prototype.slice.call(arguments));};
    const stderr = function(){wMsg('stderr', Array.prototype.slice.call(arguments));};

    self.onerror = function(/*message, source, lineno, colno, error*/) {
        const err = arguments[4];
        if(err && 'ExitStatus'==err.name){
            /* This is relevant for the sqlite3 shell binding but not the
               lower-level binding. */
            fiddleModule.isDead = true;
            stderr("FATAL ERROR:", err.message);
            stderr("Restarting the app requires reloading the page.");
            wMsg('error', err);
        }
        console.error(err);
        fiddleModule.setStatus('Exception thrown, see JavaScript console: '+err);
    };

    const Sqlite3Shell = {
        /** Returns the name of the currently-opened db. */
        dbFilename: function f(){
            if(!f._) f._ = fiddleModule.cwrap('fiddle_db_filename', "string", ['string']);
            return f._();
        },
        /**
           Runs the given text through the shell as if it had been typed
           in by a user. Fires a working/start event before it starts and
           working/end event when it finishes.
        */
        exec: function f(sql){
            if(!f._) f._ = fiddleModule.cwrap('fiddle_exec', null, ['string']);
            if(fiddleModule.isDead){
                stderr("shell module has exit()ed. Cannot run SQL.");
                return;
            }
            wMsg('working','start');
            try {
                if(f._running){
                    stderr('Cannot run multiple commands concurrently.');
                }else{
                    f._running = true;
                    f._(sql);
                }
            } finally {
                delete f._running;
                wMsg('working','end');
            }
        },
        resetDb: function f(){
            if(!f._) f._ = fiddleModule.cwrap('fiddle_reset_db', null);
            stdout("Resetting database.");
            f._();
            stdout("Reset",this.dbFilename());
        },
        /* Interrupt can't work: this Worker is tied up working, so won't get the
           interrupt event which would be needed to perform the interrupt. */
        interrupt: function f(){
            if(!f._) f._ = fiddleModule.cwrap('fiddle_interrupt', null);
            stdout("Requesting interrupt.");
            f._();
        }
    };

    self.onmessage = function f(ev){
        ev = ev.data;
        if(!f.cache){
            f.cache = {
                prevFilename: null
            };
        }
        //console.debug("worker: onmessage.data",ev);
        switch(ev.type){
            case 'shellExec': Sqlite3Shell.exec(ev.data); return;
            case 'db-reset': Sqlite3Shell.resetDb(); return;
            case 'interrupt': Sqlite3Shell.interrupt(); return;
                /** Triggers the export of the current db. Fires an
                    event in the form:

                    {type:'db-export',
                    data:{
                    filename: name of db,
                    buffer: contents of the db file (Uint8Array),
                    error: on error, a message string and no buffer property.
                    }
                    }
                */
            case 'db-export': {
                const fn = Sqlite3Shell.dbFilename();
                stdout("Exporting",fn+".");
                const fn2 = fn ? fn.split(/[/\\]/).pop() : null;
                try{
                    if(!fn2) throw new Error("DB appears to be closed.");
                    wMsg('db-export',{
                        filename: fn2,
                        buffer: fiddleModule.FS.readFile(fn, {encoding:"binary"})
                    });
                }catch(e){
                    /* Post a failure message so that UI elements disabled
                       during the export can be re-enabled. */
                    wMsg('db-export',{
                        filename: fn,
                        error: e.message
                    });
                }
                return;
            }
            case 'open': {
                /* Expects: {
                   buffer: ArrayBuffer | Uint8Array,
                   filename: for logging/informational purposes only
                   } */
                const opt = ev.data;
                let buffer = opt.buffer;
                if(buffer instanceof Uint8Array){
                }else if(buffer instanceof ArrayBuffer){
                    buffer = new Uint8Array(buffer);
                }else{
                    stderr("'open' expects {buffer:Uint8Array} containing an uploaded db.");
                    return;
                }
                const fn = (
                    opt.filename
                        ? opt.filename.split(/[/\\]/).pop().replace('"','_')
                        : ("db-"+((Math.random() * 10000000) | 0)+
                           "-"+((Math.random() * 10000000) | 0)+".sqlite3")
                );
                /* We cannot delete the existing db file until the new one
                   is installed, which means that we risk overflowing our
                   quota (if any) by having both the previous and current
                   db briefly installed in the virtual filesystem. */
                fiddleModule.FS.createDataFile("/", fn, buffer, true, true);
                const oldName = Sqlite3Shell.dbFilename();
                Sqlite3Shell.exec('.open "/'+fn+'"');
                if(oldName !== fn){
                    fiddleModule.FS.unlink(oldName);
                }
                stdout("Replaced DB with",fn+".");
                return;
            }
        };
        console.warn("Unknown fiddle-worker message type:",ev);
    };
   
    /**
       emscripten module for use with build mode -sMODULARIZE.
    */
    const fiddleModule = {
        print: stdout,
        printErr: stderr,
        /**
           Intercepts status updates from the emscripting module init
           and fires worker events with a type of 'status' and a
           payload of:

           {
           text: string | null, // null at end of load process
           step: integer // starts at 1, increments 1 per call
           }

           We have no way of knowing in advance how many steps will
           be processed/posted, so creating a "percentage done" view is
           not really practical. One can be approximated by giving it a
           current value of message.step and max value of message.step+1,
           though.

           When work is finished, a message with a text value of null is
           submitted.

           After a message with text==null is posted, the module may later
           post messages about fatal problems, e.g. an exit() being
           triggered, so it is recommended that UI elements for posting
           status messages not be outright removed from the DOM when
           text==null, and that they instead be hidden until/unless
           text!=null.
        */
        setStatus: function f(text){
            if(!f.last) f.last = { step: 0, text: '' };
            else if(text === f.last.text) return;
            f.last.text = text;
            wMsg('module',{
                type:'status',
                data:{step: ++f.last.step, text: text||null}
            });
        }
    };

    importScripts('fiddle-module.js');
    /**
       initFiddleModule() is installed via fiddle-module.js due to
       building with:

       emcc ... -sMODULARIZE=1 -sEXPORT_NAME=initFiddleModule
    */
    initFiddleModule(fiddleModule).then(function(thisModule){
        wMsg('fiddle-ready');
    });
})();
Added ext/fiddle/fiddle.html.
















































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
<!doctype html>
<html lang="en-us">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>sqlite3 fiddle</title>
    <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
    <!-- to add a togglable terminal-style view, uncomment the following
         two lines and ensure that these files are on the web server. -->
    <!--script src="jqterm/jqterm-bundle.min.js"></script>
    <link rel="stylesheet" href="jqterm/jquery.terminal.min.css"/-->
    <link rel="stylesheet" href="emscripten.css"/>
    <style>
      /* The following styles are for app-level use. */
      textarea {
          font-family: monospace;
          flex: 1 1 auto;
      }
      header {
          font-size: 130%;
          font-weight: bold;
      }
      #main-wrapper {
          display: flex;
          flex-direction: column-reverse;
          flex: 20 1 auto;
      }
      #main-wrapper.side-by-side {
          flex-direction: row-reverse;
      }
      #main-wrapper.swapio {
          flex-direction: column;
      }
      #main-wrapper.side-by-side.swapio {
          flex-direction: row;
      }
      .ta-wrapper{
          display: flex;
          flex-direction: column;
          align-items: stretch;
          margin: 0 0.25em;
          flex: 1 1 auto;
      }
      .ta-wrapper.input { flex: 10 1 auto; }
      .ta-wrapper.output { flex: 20 1 auto; }
      .ta-wrapper textarea {
          font-size: 110%;
          filter: invert(100%);
          flex: 10 1 auto;
      }
      .button-bar {
          display: flex;
          justify-content: center;
          flex: 0 1 auto;
          flex-wrap: wrap;
      }
      .button-bar button {
          margin: 0.25em 1em;
      }
      label[for] {
          cursor: pointer;
      }
      .error {
          color: red;
          background-color: yellow;
      }
      .hidden, .initially-hidden {
          position: absolute !important;
          opacity: 0 !important;
          pointer-events: none !important;
          display: none !important;
      }
      /* Safari supports neither styling of nor event handling on a
         fieldset legend, so we emulate a fieldset-like widget. */
      .fieldset {
          border-radius: 0.5em;
          border: 1px inset;
          display: flex;
          flex-direction: column;
      }
      .fieldset > .legend {
          position: relative;
          top: -1.5ex;
          padding: 0 0.5em;
          font-size: 85%;
          margin-left: 0.5em;
          flex: 0 1 auto;
          align-self: self-start;
          cursor: pointer;
      }
      .fieldset.options > div {
          display: flex;
          flex-wrap: wrap;
          font-size: 70%;
          margin: 0 0.5em 0.5em 0.5em;
      }
      .fieldset > .legend > span {
          position: relative;
      }
      .fieldset > .legend::before {
          /* Hide the parent element's top border where this
             element intersects it. */
          content: ' '; 
          width: 100%; 
          height: 100%; 
          background-color: white
           /* REALLY want to 'inherit' the color from the fieldset's
              parent, but inherit leads to a transparent bg, which is
              exactly what we're trying to avoid here. */;
          opacity: 1;
          position: absolute; 
          top: 0; 
          left: 0; 
      }
      .fieldset > .legend::after {
          content: " [hide]";
          position: relative;
      }
      .fieldset.collapsed > .legend::after {
          content: " [show]";
          position: relative;
      }
      span.labeled-input {
          padding: 0.25em;
          margin: 0.25em 0.5em;
          border-radius: 0.25em;
          white-space: nowrap;
          background: #0002;
      }
      #notes-caveats {
          border-top: 1px dotted;
          padding-top: 0.25em;
          margin-top: 0.5em;
      }
      .center { text-align: center; }

      body.terminal-mode {
          max-height: calc(100% - 2em);
          display: flex;
          flex-direction: column;
          align-items: stretch;
      }
      #view-terminal {
      }
      .app-view {
          flex: 20 1 auto;
      }
      #titlebar {
          display: flex;
          justify-content: space-between;
          margin-bottom: 0.5em;
      }
      #view-split {
          display: flex;
          flex-direction: column-reverse;
      }
      #view-split > .fieldset.options {
          margin-top: 0.5em;
      }
    </style>
  </head>
  <body>
    <header id='titlebar'><span>sqlite3 fiddle</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 id='view-terminal' class='app-view hidden initially-hidden'>
      This is a placeholder for a terminal-like view.
    </div>

    <div id='view-split' class='app-view initially-hidden'>
      <div class='fieldset options collapsible'>
        <span class='legend'><span>Options</span></span>
        <div class=''>
          <span class='labeled-input'>
            <input type='checkbox' id='opt-cb-sbs'
                   data-csstgt='#main-wrapper'
                   data-cssclass='side-by-side'
                   data-config='sideBySide'>
            <label for='opt-cb-sbs'>Side-by-side</label>
          </span>
          <span class='labeled-input'>
            <input type='checkbox' id='opt-cb-swapio'
                   data-csstgt='#main-wrapper'
                   data-cssclass='swapio'
                   data-config='swapInOut'>
            <label for='opt-cb-swapio'>Swap in/out</label>
          </span>
          <span class='labeled-input'>
            <input type='checkbox' id='opt-cb-autoscroll'
                   data-config='autoScrollOutput'>
            <label for='opt-cb-autoscroll'>Auto-scroll output</label>
          </span>
          <span class='labeled-input'>
            <input type='checkbox' id='opt-cb-autoclear'
                   data-config='autoClearOutput'>
            <label for='opt-cb-autoclear'>Auto-clear output</label>
          </span>
          <span class='labeled-input'>
            <input type='file' id='load-db'/>
            <label>Load DB</label>
          </span>
          <span class='labeled-input'>
            <button id='btn-export'>Download DB</button>
          </span>
          <span class='labeled-input'>
            <button id='btn-reset'>Reset DB</button>
          </span>
          <span class='labeled-input'>
            <select id='select-examples'></select>
          </span>
        </div>
      </div><!-- .fieldset -->
      <div id='main-wrapper' class=''>
        <div class='ta-wrapper input'>
          <textarea id="input"
                    placeholder="Shell input. Ctrl-enter/shift-enter runs it.">
-- Use ctrl-enter or shift-enter to execute SQL. If only a subset
-- is currently selected, only that part is executed.
.nullvalue NULL
.mode box
CREATE TABLE t(a,b);
INSERT INTO t(a,b) VALUES('abc',123),('def',456),(NULL,789),('ghi',012);
SELECT * FROM t;</textarea>        
          <div class='button-bar'>
            <button id='btn-shell-exec'>Run</button>
            <button id='btn-clear'>Clear Input</button>
            <button data-cmd='.help'>Help</button>
          </div>
        </div>
        <div class='ta-wrapper output'>
          <textarea id="output" readonly
                    placeholder="Shell output."></textarea>
          <div class='button-bar'>
            <button id='btn-clear-output'>Clear Output</button>
            <button id='btn-interrupt' class='hidden' disabled>Interrupt</button>
            <!-- interruption cannot work in the current configuration
                 because we cannot send an interrupt message when work
                 is currently underway. At that point the Worker is
                 tied up and will not receive the message. -->
          </div>
        </div>
      </div>
    </div> <!-- #view-split -->
    <!-- Maintenance notes:

        ... TODO... currently being refactored...

    -->
    <script src="fiddle.js"></script>
  </body>
</html>
Added ext/fiddle/fiddle.js.






























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
/*
  2022-05-20

  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.

  ***********************************************************************

  This is the main entry point for the sqlite3 fiddle app. It sets up the
  various UI bits, loads a Worker for the db connection, and manages the
  communication between the UI and worker.
*/
(function(){
    'use strict';
    /* Recall that the 'self' symbol, except where locally
       overwritten, refers to the global window or worker object. */

    const storage = (function(NS/*namespace object in which to store this module*/){
        /* Pedantic licensing note: this code originated in the Fossil SCM
           source tree, where it has a different license, but the person who
           ported it into sqlite is the same one who wrote it for fossil. */
        'use strict';
        NS = NS||{};

        /**
           This module provides a basic wrapper around localStorage
           or sessionStorage or a dummy proxy object if neither
           of those are available.
        */
        const tryStorage = function f(obj){
            if(!f.key) f.key = 'storage.access.check';
            try{
                obj.setItem(f.key, 'f');
                const x = obj.getItem(f.key);
                obj.removeItem(f.key);
                if(x!=='f') throw new Error(f.key+" failed")
                return obj;
            }catch(e){
                return undefined;
            }
        };

        /** Internal storage impl for this module. */
        const $storage =
              tryStorage(window.localStorage)
              || tryStorage(window.sessionStorage)
              || tryStorage({
                  // A basic dummy xyzStorage stand-in
                  $$$:{},
                  setItem: function(k,v){this.$$$[k]=v},
                  getItem: function(k){
                      return this.$$$.hasOwnProperty(k) ? this.$$$[k] : undefined;
                  },
                  removeItem: function(k){delete this.$$$[k]},
                  clear: function(){this.$$$={}}
              });

        /**
           For the dummy storage we need to differentiate between
           $storage and its real property storage for hasOwnProperty()
           to work properly...
        */
        const $storageHolder = $storage.hasOwnProperty('$$$') ? $storage.$$$ : $storage;

        /**
           A prefix which gets internally applied to all storage module
           property keys so that localStorage and sessionStorage across the
           same browser profile instance do not "leak" across multiple apps
           being hosted by the same origin server. Such cross-polination is
           still there but, with this key prefix applied, it won't be
           immediately visible via the storage API.

           With this in place we can justify using localStorage instead of
           sessionStorage.

           One implication of using localStorage and sessionStorage is that
           their scope (the same "origin" and client application/profile)
           allows multiple apps on the same origin to use the same
           storage. Thus /appA/foo could then see changes made via
           /appB/foo. The data do not cross user- or browser boundaries,
           though, so it "might" arguably be called a
           feature. storageKeyPrefix was added so that we can sandbox that
           state for each separate app which shares an origin.

           See: https://fossil-scm.org/forum/forumpost/4afc4d34de

           Sidebar: it might seem odd to provide a key prefix and stick all
           properties in the topmost level of the storage object. We do that
           because adding a layer of object to sandbox each app would mean
           (de)serializing that whole tree on every storage property change.
           e.g. instead of storageObject.projectName.foo we have
           storageObject[storageKeyPrefix+'foo']. That's soley for
           efficiency's sake (in terms of battery life and
           environment-internal storage-level effort).
        */
        const storageKeyPrefix = (
            $storageHolder===$storage/*localStorage or sessionStorage*/
                ? (
                    (NS.config ?
                     (NS.config.projectCode || NS.config.projectName
                      || NS.config.shortProjectName)
                     : false)
                        || window.location.pathname
                )+'::' : (
                    '' /* transient storage */
                )
        );

        /**
           A proxy for localStorage or sessionStorage or a
           page-instance-local proxy, if neither one is availble.

           Which exact storage implementation is uses is unspecified, and
           apps must not rely on it.
        */
        NS.storage = {
            storageKeyPrefix: storageKeyPrefix,
            /** Sets the storage key k to value v, implicitly converting
                it to a string. */
            set: (k,v)=>$storage.setItem(storageKeyPrefix+k,v),
            /** Sets storage key k to JSON.stringify(v). */
            setJSON: (k,v)=>$storage.setItem(storageKeyPrefix+k,JSON.stringify(v)),
            /** Returns the value for the given storage key, or
                dflt if the key is not found in the storage. */
            get: (k,dflt)=>$storageHolder.hasOwnProperty(
                storageKeyPrefix+k
            ) ? $storage.getItem(storageKeyPrefix+k) : dflt,
            /** Returns true if the given key has a value of "true".  If the
                key is not found, it returns true if the boolean value of dflt
                is "true". (Remember that JS persistent storage values are all
                strings.) */
            getBool: function(k,dflt){
                return 'true'===this.get(k,''+(!!dflt));
            },
            /** Returns the JSON.parse()'d value of the given
                storage key's value, or dflt is the key is not
                found or JSON.parse() fails. */
            getJSON: function f(k,dflt){
                try {
                    const x = this.get(k,f);
                    return x===f ? dflt : JSON.parse(x);
                }
                catch(e){return dflt}
            },
            /** Returns true if the storage contains the given key,
                else false. */
            contains: (k)=>$storageHolder.hasOwnProperty(storageKeyPrefix+k),
            /** Removes the given key from the storage. Returns this. */
            remove: function(k){
                $storage.removeItem(storageKeyPrefix+k);
                return this;
            },
            /** Clears ALL keys from the storage. Returns this. */
            clear: function(){
                this.keys().forEach((k)=>$storage.removeItem(/*w/o prefix*/k));
                return this;
            },
            /** Returns an array of all keys currently in the storage. */
            keys: ()=>Object.keys($storageHolder).filter((v)=>(v||'').startsWith(storageKeyPrefix)),
            /** Returns true if this storage is transient (only available
                until the page is reloaded), indicating that fileStorage
                and sessionStorage are unavailable. */
            isTransient: ()=>$storageHolder!==$storage,
            /** Returns a symbolic name for the current storage mechanism. */
            storageImplName: function(){
                if($storage===window.localStorage) return 'localStorage';
                else if($storage===window.sessionStorage) return 'sessionStorage';
                else return 'transient';
            },

            /**
               Returns a brief help text string for the currently-selected
               storage type.
            */
            storageHelpDescription: function(){
                return {
                    localStorage: "Browser-local persistent storage with an "+
                        "unspecified long-term lifetime (survives closing the browser, "+
                        "but maybe not a browser upgrade).",
                    sessionStorage: "Storage local to this browser tab, "+
                        "lost if this tab is closed.",
                    "transient": "Transient storage local to this invocation of this page."
                }[this.storageImplName()];
            }
        };
        return NS.storage;
    })({})/*storage API setup*/;


    /** Name of the stored copy of SqliteFiddle.config. */
    const configStorageKey = 'sqlite3-fiddle-config';

    /**
       The SqliteFiddle object is intended to be the primary
       app-level object for the main-thread side of the sqlite
       fiddle application. It uses a worker thread to load the
       sqlite WASM module and communicate with it.
    */
    const SF/*local convenience alias*/
    = window.SqliteFiddle/*canonical name*/ = {
        /* Config options. */
        config: {
            /* If true, SqliteFiddle.echo() will auto-scroll the
               output widget to the bottom when it receives output,
               else it won't. */
            autoScrollOutput: true,
            /* If true, the output area will be cleared before each
               command is run, else it will not. */
            autoClearOutput: false,
            /* If true, SqliteFiddle.echo() will echo its output to
               the console, in addition to its normal output widget.
               That slows it down but is useful for testing. */
            echoToConsole: false,
            /* If true, display input/output areas side-by-side. */
            sideBySide: false,
            /* If true, swap positions of the input/output areas. */
            swapInOut: false
        },
        /**
           Emits the given text, followed by a line break, to the
           output widget.  If given more than one argument, they are
           join()'d together with a space between each. As a special
           case, if passed a single array, that array is used in place
           of the arguments array (this is to facilitate receiving
           lists of arguments via worker events).
        */
        echo: function f(text) {
            /* Maintenance reminder: we currently require/expect a textarea
               output element. It might be nice to extend this to behave
               differently if the output element is a non-textarea element,
               in which case it would need to append the given text as a TEXT
               node and add a line break. */
            if(!f._){
                f._ = document.getElementById('output');
                f._.value = ''; // clear browser cache
            }
            if(arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
            else if(1===arguments.length && Array.isArray(text)) text = text.join(' ');
            // These replacements are necessary if you render to raw HTML
            //text = text.replace(/&/g, "&amp;");
            //text = text.replace(/</g, "&lt;");
            //text = text.replace(/>/g, "&gt;");
            //text = text.replace('\n', '<br>', 'g');
            if(null===text){/*special case: clear output*/
                f._.value = '';
                return;
            }else if(this.echo._clearPending){
                delete this.echo._clearPending;
                f._.value = '';
            }
            if(this.config.echoToConsole) console.log(text);
            if(this.jqTerm) this.jqTerm.echo(text);
            f._.value += text + "\n";
            if(this.config.autoScrollOutput){
                f._.scrollTop = f._.scrollHeight;
            }
        },
        _msgMap: {},
        /** Adds a worker message handler for messages of the given
            type. */
        addMsgHandler: function f(type,callback){
            if(Array.isArray(type)){
                type.forEach((t)=>this.addMsgHandler(t, callback));
                return this;
            }
            (this._msgMap.hasOwnProperty(type)
             ? this._msgMap[type]
             : (this._msgMap[type] = [])).push(callback);
            return this;
        },
        /** Given a worker message, runs all handlers for msg.type. */
        runMsgHandlers: function(msg){
            const list = (this._msgMap.hasOwnProperty(msg.type)
                          ? this._msgMap[msg.type] : false);
            if(!list){
                console.warn("No handlers found for message type:",msg);
                return false;
            }
            //console.debug("runMsgHandlers",msg);
            list.forEach((f)=>f(msg));
            return true;
        },
        /** Removes all message handlers for the given message type. */
        clearMsgHandlers: function(type){
            delete this._msgMap[type];
            return this;
        },
        /* Posts a message in the form {type, data} to the db worker. Returns this. */
        wMsg: function(type,data){
            this.worker.postMessage({type, data});
            return this;
        },
        /**
           Prompts for confirmation and, if accepted, deletes
           all content and tables in the (transient) database.
        */
        resetDb: function(){
            if(window.confirm("Really destroy all content and tables "
                              +"in the (transient) db?")){
                this.wMsg('db-reset');
            }
            return this;
        },
        /** Stores this object's config in the browser's storage. */
        storeConfig: function(){
            storage.setJSON(configStorageKey,this.config);
        }
    };

    if(1){ /* Restore SF.config */
        const storedConfig = storage.getJSON(configStorageKey);
        if(storedConfig){
            /* Copy all properties to SF.config which are currently in
               storedConfig. We don't bother copying any other
               properties: those have been removed from the app in the
               meantime. */
            Object.keys(SF.config).forEach(function(k){
                if(storedConfig.hasOwnProperty(k)){
                    SF.config[k] = storedConfig[k];
                }
            });
        }
    }

    SF.worker = new Worker('fiddle-worker.js');
    SF.worker.onmessage = (ev)=>SF.runMsgHandlers(ev.data);
    SF.addMsgHandler(['stdout', 'stderr'], (ev)=>SF.echo(ev.data));

    /* querySelectorAll() proxy */
    const EAll = function(/*[element=document,] cssSelector*/){
        return (arguments.length>1 ? arguments[0] : document)
            .querySelectorAll(arguments[arguments.length-1]);
    };
    /* querySelector() proxy */
    const E = function(/*[element=document,] cssSelector*/){
        return (arguments.length>1 ? arguments[0] : document)
            .querySelector(arguments[arguments.length-1]);
    };

    /** Handles status updates from the Module object. */
    SF.addMsgHandler('module', function f(ev){
        ev = ev.data;
        if('status'!==ev.type){
            console.warn("Unexpected module-type message:",ev);
            return;
        }
        if(!f.ui){
            f.ui = {
                status: E('#module-status'),
                progress: E('#module-progress'),
                spinner: E('#module-spinner')
            };
        }
        const msg = ev.data;
        if(f.ui.progres){
            progress.value = msg.step;
            progress.max = msg.step + 1/*we don't know how many steps to expect*/;
        }
        if(1==msg.step){
            f.ui.progress.classList.remove('hidden');
            f.ui.spinner.classList.remove('hidden');
        }
        if(msg.text){
            f.ui.status.classList.remove('hidden');
            f.ui.status.innerText = msg.text;
        }else{
            if(f.ui.progress){
                f.ui.progress.remove();
                f.ui.spinner.remove();
                delete f.ui.progress;
                delete f.ui.spinner;
            }
            f.ui.status.classList.add('hidden');
            /* The module can post messages about fatal problems,
               e.g. an exit() being triggered or assertion failure,
               after the last "load" message has arrived, so
               leave f.ui.status and message listener intact. */
        }
    });

    /**
       The 'fiddle-ready' event is fired (with no payload) when the
       wasm module has finished loading. Interestingly, that happens
       _before_ the final module:status event */
    SF.addMsgHandler('fiddle-ready', function(){
        SF.clearMsgHandlers('fiddle-ready');
        self.onSFLoaded();
    });

    /**
       Performs all app initialization which must wait until after the
       worker module is loaded. This function removes itself when it's
       called.
    */
    self.onSFLoaded = function(){
        delete this.onSFLoaded;
        // Unhide all elements which start out hidden
        EAll('.initially-hidden').forEach((e)=>e.classList.remove('initially-hidden'));
        E('#btn-reset').addEventListener('click',()=>SF.resetDb());
        const taInput = E('#input');
        const btnClearIn = E('#btn-clear');
        btnClearIn.addEventListener('click',function(){
            taInput.value = '';
        },false);
        // Ctrl-enter and shift-enter both run the current SQL.
        taInput.addEventListener('keydown',function(ev){
            if((ev.ctrlKey || ev.shiftKey) && 13 === ev.keyCode){
                ev.preventDefault();
                ev.stopPropagation();
                btnShellExec.click();
            }
        }, false);
        const taOutput = E('#output');
        const btnClearOut = E('#btn-clear-output');
        btnClearOut.addEventListener('click',function(){
            taOutput.value = '';
            if(SF.jqTerm) SF.jqTerm.clear();
        },false);
        const btnShellExec = E('#btn-shell-exec');
        btnShellExec.addEventListener('click',function(ev){
            let sql;
            ev.preventDefault();
            if(taInput.selectionStart<taInput.selectionEnd){
                sql = taInput.value.substring(taInput.selectionStart,taInput.selectionEnd).trim();
            }else{
                sql = taInput.value.trim();
            }
            if(sql) SF.dbExec(sql);
        },false);

        const btnInterrupt = E("#btn-interrupt");
        //btnInterrupt.classList.add('hidden');
        /** To be called immediately before work is sent to the
            worker. Updates some UI elements. The 'working'/'end'
            event will apply the inverse, undoing the bits this
            function does. This impl is not in the 'working'/'start'
            event handler because that event is given to us
            asynchronously _after_ we need to have performed this
            work.
        */
        const preStartWork = function f(){
            if(!f._){
                const title = E('title');
                f._ = {
                    btnLabel: btnShellExec.innerText,
                    pageTitle: title,
                    pageTitleOrig: title.innerText
                };
            }
            f._.pageTitle.innerText = "[working...] "+f._.pageTitleOrig;
            btnShellExec.setAttribute('disabled','disabled');
            btnInterrupt.removeAttribute('disabled','disabled');
        };

        /* Sends the given text to the db module to evaluate as if it
           had been entered in the sqlite3 CLI shell. If it's null or
           empty, this is a no-op except that the very first call will
           initialize the db and output an informational header. */
        SF.dbExec = function f(sql){
            if(this.config.autoClearOutput){
                this.echo._clearPending = true;
            }
            preStartWork();
            this.wMsg('shellExec',sql);
        };

        SF.addMsgHandler('working',function f(ev){
            switch(ev.data){
                case 'start': /* See notes in preStartWork(). */; return;
                case 'end':
                    preStartWork._.pageTitle.innerText = preStartWork._.pageTitleOrig;
                    btnShellExec.innerText = preStartWork._.btnLabel;
                    btnShellExec.removeAttribute('disabled');
                    btnInterrupt.setAttribute('disabled','disabled');
                    return;
            }
            console.warn("Unhandled 'working' event:",ev.data);
        });

        /* For each checkbox with data-csstgt, set up a handler which
           toggles the given CSS class on the element matching
           E(data-csstgt). */
        EAll('input[type=checkbox][data-csstgt]')
            .forEach(function(e){
                const tgt = E(e.dataset.csstgt);
                const cssClass = e.dataset.cssclass || 'error';
                e.checked = tgt.classList.contains(cssClass);
                e.addEventListener('change', function(){
                    tgt.classList[
                        this.checked ? 'add' : 'remove'
                    ](cssClass)
                }, false);
            });
        /* For each checkbox with data-config=X, set up a binding to
           SF.config[X]. These must be set up AFTER data-csstgt
           checkboxes so that those two states can be synced properly. */
        EAll('input[type=checkbox][data-config]')
            .forEach(function(e){
                const confVal = !!SF.config[e.dataset.config];
                if(e.checked !== confVal){
                    /* Ensure that data-csstgt mappings (if any) get
                       synced properly. */
                    e.checked = confVal;
                    e.dispatchEvent(new Event('change'));
                }
                e.addEventListener('change', function(){
                    SF.config[this.dataset.config] = this.checked;
                    SF.storeConfig();
                }, false);
            });
        /* For each button with data-cmd=X, map a click handler which
           calls SF.dbExec(X). */
        const cmdClick = function(){SF.dbExec(this.dataset.cmd);};
        EAll('button[data-cmd]').forEach(
            e => e.addEventListener('click', cmdClick, false)
        );

        btnInterrupt.addEventListener('click',function(){
            SF.wMsg('interrupt');
        });

        /** Initiate a download of the db. */
        const btnExport = E('#btn-export');
        const eDisableDuringExport = [
            /* UI elements to disable while export is running. Normally
               the export is fast enough that this won't matter, but we
               really don't want to be reading (from outside of sqlite)
               the db when the user taps btnShellExec. */
            btnShellExec, btnExport
        ];
        btnExport.addEventListener('click',function(){
            eDisableDuringExport.forEach(e=>e.setAttribute('disabled','disabled'));
            SF.wMsg('db-export');
        });
        SF.addMsgHandler('db-export', function(ev){
            eDisableDuringExport.forEach(e=>e.removeAttribute('disabled'));
            ev = ev.data;
            if(ev.error){
                SF.echo("Export failed:",ev.error);
                return;
            }
            const blob = new Blob([ev.buffer], {type:"application/x-sqlite3"});
            const a = document.createElement('a');
            document.body.appendChild(a);
            a.href = window.URL.createObjectURL(blob);
            a.download = ev.filename;
            a.addEventListener('click',function(){
                setTimeout(function(){
                    SF.echo("Exported (possibly auto-downloaded):",ev.filename);
                    window.URL.revokeObjectURL(a.href);
                    a.remove();
                },500);
            });
            a.click();
        });
        /**
           Handle load/import of an external db file.
        */
        E('#load-db').addEventListener('change',function(){
            const f = this.files[0];
            const r = new FileReader();
            const status = {loaded: 0, total: 0};
            this.setAttribute('disabled','disabled');
            r.addEventListener('loadstart', function(){
                SF.echo("Loading",f.name,"...");
            });
            r.addEventListener('progress', function(ev){
                SF.echo("Loading progress:",ev.loaded,"of",ev.total,"bytes.");
            });
            const that = this;
            r.addEventListener('load', function(){
                that.removeAttribute('disabled');
                SF.echo("Loaded",f.name+". Opening db...");
                SF.wMsg('open',{
                    filename: f.name,
                    buffer: this.result
                });
            });
            r.addEventListener('error',function(){
                that.removeAttribute('disabled');
                SF.echo("Loading",f.name,"failed for unknown reasons.");
            });
            r.addEventListener('abort',function(){
                that.removeAttribute('disabled');
                SF.echo("Cancelled loading of",f.name+".");
            });
            r.readAsArrayBuffer(f);
        });

        EAll('.fieldset.collapsible').forEach(function(fs){
            const legend = E(fs,'span.legend'),
                  content = EAll(fs,':scope > div');
            legend.addEventListener('click', function(){
                fs.classList.toggle('collapsed');
                content.forEach((d)=>d.classList.toggle('hidden'));
            }, false);
        });
        
        /**
           Given a DOM element, this routine measures its "effective
           height", which is the bounding top/bottom range of this element
           and all of its children, recursively. For some DOM structure
           cases, a parent may have a reported height of 0 even though
           children have non-0 sizes.

           Returns 0 if !e or if the element really has no height.
        */
        const effectiveHeight = function f(e){
            if(!e) return 0;
            if(!f.measure){
                f.measure = function callee(e, depth){
                    if(!e) return;
                    const m = e.getBoundingClientRect();
                    if(0===depth){
                        callee.top = m.top;
                        callee.bottom = m.bottom;
                    }else{
                        callee.top = m.top ? Math.min(callee.top, m.top) : callee.top;
                        callee.bottom = Math.max(callee.bottom, m.bottom);
                    }
                    Array.prototype.forEach.call(e.children,(e)=>callee(e,depth+1));
                    if(0===depth){
                        //console.debug("measure() height:",e.className, callee.top, callee.bottom, (callee.bottom - callee.top));
                        f.extra += callee.bottom - callee.top;
                    }
                    return f.extra;
                };
            }
            f.extra = 0;
            f.measure(e,0);
            return f.extra;
        };

        /**
           Returns a function, that, as long as it continues to be invoked,
           will not be triggered. The function will be called after it stops
           being called for N milliseconds. If `immediate` is passed, call
           the callback immediately and hinder future invocations until at
           least the given time has passed.

           If passed only 1 argument, or passed a falsy 2nd argument,
           the default wait time set in this function's $defaultDelay
           property is used.

           Source: underscore.js, by way of https://davidwalsh.name/javascript-debounce-function
        */
        const debounce = function f(func, wait, immediate) {
            var timeout;
            if(!wait) wait = f.$defaultDelay;
            return function() {
                const context = this, args = Array.prototype.slice.call(arguments);
                const later = function() {
                    timeout = undefined;
                    if(!immediate) func.apply(context, args);
                };
                const callNow = immediate && !timeout;
                clearTimeout(timeout);
                timeout = setTimeout(later, wait);
                if(callNow) func.apply(context, args);
            };
        };
        debounce.$defaultDelay = 500 /*arbitrary*/;

        const ForceResizeKludge = (function(){
            /* Workaround for Safari mayhem regarding use of vh CSS
               units....  We cannot use vh units to set the main view
               size because Safari chokes on that, so we calculate
               that height here. Larger than ~95% is too big for
               Firefox on Android, causing the input area to move
               off-screen. */
            const appViews = EAll('.app-view');
            const elemsToCount = [
                /* Elements which we need to always count in the
                   visible body size. */
                E('body > header'),
                E('body > footer')
            ];
            const resized = function f(){
                if(f.$disabled) return;
                const wh = window.innerHeight;
                var ht;
                var extra = 0;
                elemsToCount.forEach((e)=>e ? extra += effectiveHeight(e) : false);
                ht = wh - extra;
                appViews.forEach(function(e){
                    e.style.height =
                        e.style.maxHeight = [
                            "calc(", (ht>=100 ? ht : 100), "px",
                            " - 2em"/*fudge value*/,")"
                            /* ^^^^ hypothetically not needed, but both
                               Chrome/FF on Linux will force scrollbars on the
                               body if this value is too small. */
                        ].join('');
                });
            };
            resized.$disabled = true/*gets deleted when setup is finished*/;
            window.addEventListener('resize', debounce(resized, 250), false);
            return resized;
        })();

        /** Set up a selection list of examples */
        (function(){
            const xElem = E('#select-examples');
            const examples = [
                {name: "Timer on", sql: ".timer on"},
                {name: "Setup table T", sql:`.nullvalue NULL
CREATE TABLE t(a,b);
INSERT INTO t(a,b) VALUES('abc',123),('def',456),(NULL,789),('ghi',012);
SELECT * FROM t;`},
                {name: "Table list", sql: ".tables"},
                {name: "Box Mode", sql: ".mode box"},
                {name: "JSON Mode", sql: ".mode json"},
                {name: "Mandlebrot", sql: `WITH RECURSIVE
  xaxis(x) AS (VALUES(-2.0) UNION ALL SELECT x+0.05 FROM xaxis WHERE x<1.2),
  yaxis(y) AS (VALUES(-1.0) UNION ALL SELECT y+0.1 FROM yaxis WHERE y<1.0),
  m(iter, cx, cy, x, y) AS (
    SELECT 0, x, y, 0.0, 0.0 FROM xaxis, yaxis
    UNION ALL
    SELECT iter+1, cx, cy, x*x-y*y + cx, 2.0*x*y + cy FROM m 
     WHERE (x*x + y*y) < 4.0 AND iter<28
  ),
  m2(iter, cx, cy) AS (
    SELECT max(iter), cx, cy FROM m GROUP BY cx, cy
  ),
  a(t) AS (
    SELECT group_concat( substr(' .+*#', 1+min(iter/7,4), 1), '') 
    FROM m2 GROUP BY cy
  )
SELECT group_concat(rtrim(t),x'0a') as Mandelbrot FROM a;`}
            ];
            const newOpt = function(lbl,val){
                const o = document.createElement('option');
                o.value = val;
                if(!val) o.setAttribute('disabled',true);
                o.appendChild(document.createTextNode(lbl));
                xElem.appendChild(o);
            };
            newOpt("Examples (replaces input!)");
            examples.forEach((o)=>newOpt(o.name, o.sql));
            //xElem.setAttribute('disabled',true);
            xElem.selectedIndex = 0;
            xElem.addEventListener('change', function(){
                taInput.value = '-- ' +
                    this.selectedOptions[0].innerText +
                    '\n' + this.value;
                SF.dbExec(this.value);
            });
        })()/* example queries */;

        SF.echo(null/*clear any output generated by the init process*/);
        if(window.jQuery && window.jQuery.terminal){
            /* Set up the terminal-style view... */
            const eTerm = window.jQuery('#view-terminal').empty();
            SF.jqTerm = eTerm.terminal(SF.dbExec.bind(SF),{
                prompt: 'sqlite> ',
                greetings: false /* note that the docs incorrectly call this 'greeting' */
            });
            /* Set up a button to toggle the views... */
            const head = E('header#titlebar');
            const btnToggleView = document.createElement('button');
            btnToggleView.appendChild(document.createTextNode("Toggle View"));
            head.appendChild(btnToggleView);
            btnToggleView.addEventListener('click',function f(){
                EAll('.app-view').forEach(e=>e.classList.toggle('hidden'));
                if(document.body.classList.toggle('terminal-mode')){
                    ForceResizeKludge();
                }
            }, false);
            btnToggleView.click()/*default to terminal view*/;
        }
        SF.dbExec(null/*init the db and output the header*/);
        SF.echo('This experimental app is provided in the hope that it',
                'may prove interesting or useful but is not an officially',
                'supported deliverable of the sqlite project. It is subject to',
                'any number of changes or outright removal at any time.\n');
        delete ForceResizeKludge.$disabled;
        ForceResizeKludge();
    }/*onSFLoaded()*/;
})();
Added ext/fiddle/index.md.




























































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
This directory houses a "fiddle"-style application which embeds a
[Web Assembly (WASM)](https://en.wikipedia.org/wiki/WebAssembly)
build of the sqlite3 shell app into an HTML page, effectively running
the shell in a client-side browser.

It requires [emscripten][] and that the build environment be set up for
emscripten. A mini-HOWTO for setting that up follows...

First, install the Emscripten SDK, as documented
[here](https://emscripten.org/docs/getting_started/downloads.html) and summarized
below for Linux environments:

```
# Clone the emscripten repository:
$ git clone https://github.com/emscripten-core/emsdk.git
$ cd emsdk

# Download and install the latest SDK tools:
$ ./emsdk install latest

# Make the "latest" SDK "active" for the current user:
$ ./emsdk activate latest
```

Those parts only need to be run once. The following needs to be run for each
shell instance which needs the `emcc` compiler:

```
# Activate PATH and other environment variables in the current terminal:
$ source ./emsdk_env.sh

$ which emcc
/path/to/emsdk/upstream/emscripten/emcc
```

That `env` script needs to be sourced for building this application from the
top of the sqlite3 build tree:

```
$ make fiddle
```

Or:

```
$ cd ext/fiddle
$ make
```

That will generate the fiddle application under
[ext/fiddle](/dir/ext/fiddle), as `fiddle.html`. That application
cannot, due to XMLHttpRequest security limitations, run if the HTML
file is opened directly in the browser (i.e. if it is opened using a
`file://` URL), so it needs to be served via an HTTP server.  For
example, using [althttpd][]:

```
$ cd ext/fiddle
$ althttpd -debug 1 -jail 0 -port 9090 -root .
```

Then browse to `http://localhost:9090/fiddle.html`.

Note that when serving this app via [althttpd][], it must be a version
from 2022-05-17 or newer so that it recognizes the `.wasm` file
extension and responds with the mimetype `application/wasm`, as the
WASM loader is pedantic about that detail.

# Known Quirks and Limitations

Some "impedence mismatch" between C and WASM/JavaScript is to be
expected.

## No I/O

sqlite3 shell commands which require file I/O or pipes are disabled in
the WASM build.

## `exit()` Triggered from C

When C code calls `exit()`, as happens (for example) when running an
"unsafe" command when safe mode is active, WASM's connection to the
sqlite3 shell environment has no sensible choice but to shut down
because `exit()` leaves it in a state we can no longer recover
from. The JavaScript-side application attempts to recognize this and
warn the user that restarting the application is necessary. Currently
the only way to restart it is to reload the page. Restructuring the
shell code such that it could be "rebooted" without restarting the
JS app would require some invasive changes which are not currently
on any TODO list but have not been entirely ruled out long-term.


[emscripten]: https://emscripten.org
[althttpd]: https://sqlite.org/althttpd
Added ext/fiddle/sqlite3-api.js.








































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
/*
  2022-05-22

  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.

  ***********************************************************************

  This file is intended to be appended to the emcc-generated
  sqlite3.js via emcc:

  emcc ... -sMODULARIZE -sEXPORT_NAME=initSqlite3Module --post-js=THIS_FILE

  It is loaded by importing the emcc-generated sqlite3.js, then:

  initSqlite3Module({module object}).then(
    function(theModule){
      theModule.sqlite3 == an object containing this file's
      deliverables:
      {
        api: bindings for much of the core sqlite3 APIs,
        SQLite3: high-level OO API wrapper
      }
   });

  It is up to the caller to provide a module object compatible with
  emcc, but it can be a plain empty object. The object passed to
  initSqlite3Module() will get populated by the emscripten-generated
  bits and, in part, by the code from this file. Specifically, this file
  installs the `theModule.sqlite3` part shown above.

  The resulting sqlite3.api object wraps the standard sqlite3 C API in
  a way as close to its native form as JS allows for. The
  sqlite3.SQLite3 object provides a higher-level wrapper more
  appropriate for general client-side use in JS.

  Because using certain parts of the low-level API properly requires
  some degree of WASM-related magic, it is not recommended that that
  API be used as-is in client-level code. Rather, client code should
  use the higher-level OO API or write a custom wrapper on top of the
  lower-level API. In short, most of the C-style API is used in an
  intuitive manner from JS but any C-style APIs which take
  pointers-to-pointer arguments require WASM-specific interfaces
  installed by emcscripten-generated code. Those which take or return
  only integers, doubles, strings, or "plain" pointers to db or
  statement objects can be used in "as normal," noting that "pointers"
  in wasm are simply 32-bit integers.

  # Goals and Non-goals of this API

  Goals:

  - Except where noted in the non-goals, provide a more-or-less
    complete wrapper to the sqlite3 C API, insofar as WASM feature
    parity with C allows for. In fact, provide at least 3...

  - (1) The aforementioned C-style API. (2) An OO-style API on
    top of that, designed to run in the same thread (main window or
    Web Worker) as the C API. (3) A less-capable wrapper which can
    work across the main window/worker boundary, where the sqlite3 API
    is one of those and this wrapper is in the other. That
    constellation places some considerable limitations on how the API
    can be interacted with, but keeping the DB operations out of the
    UI thread is generally desirable.

  - Insofar as possible, support client-side storage using JS
    filesystem APIs. As of this writing, such things are still very
    much TODO.

  Non-goals:

  - As WASM is a web-centric technology and UTF-8 is the King of
    Encodings in that realm, there are no current plans to support the
    UTF16-related APIs. They would add a complication to the bindings
    for no appreciable benefit.

  - Supporting old or niche-market platforms. WASM is built for a
    modern web and requires modern platforms.

*/
if(!Module.postRun) Module.postRun = [];
/* ^^^^ the name Module is, in this setup, scope-local in the generated
   file sqlite3.js, with which this file gets combined at build-time. */
Module.postRun.push(function(namespace){
    'use strict';
    /* For reference: sql.js does essentially everything we want and
       it solves much of the wasm-related voodoo, but we'll need a
       different structure because we want the db connection to run in
       a worker thread and feed data back into the main
       thread. Regardless of those differences, it makes a great point
       of reference:

       https://github.com/sql-js/sql.js

       Some of the specific design goals here:

       - Bind a low-level sqlite3 API which is close to the native one
         in terms of usage.

       - Create a higher-level one, more akin to sql.js and
         node.js-style implementations. This one would speak directly
         to the low-level API. This API could be used by clients who
         import the low-level API directly into their main thread
         (which we don't want to recommend but also don't want to
         outright forbid).

       - Create a second higher-level one which speaks to the
         low-level API via worker messages. This one would be intended
         for use in the main thread, talking to the low-level UI via
         worker messages. Because workers have only a single message
         channel, some acrobatics will be needed here to feed async
         work results back into client-side callbacks (as those
         callbacks cannot simply be passed to the worker). Exactly
         what those acrobatics should look like is not yet entirely
         clear and much experimentation is pending.
    */

    const SQM = namespace/*the sqlite module object */;

    /** 
      Set up the main sqlite3 binding API here, mimicking the C API as
      closely as we can.

      Attribution: though not a direct copy/paste, much of what
      follows is strongly influenced by the sql.js implementation.
    */
    const api = {
        /* It is important that the following integer values match
           those from the C code. Ideally we could fetch them from the
           C API, e.g., in the form of a JSON object, but getting that
           JSON string constructed within our current confines is
           currently not worth the effort.

           Reminder to self: we could probably do so by adding the
           proverbial level of indirection, calling in to C to get it,
           and having that C func call an
           emscripten-installed/JS-implemented library function which
           builds the result object:

           const obj = {};
           sqlite3__get_enum(function(key,val){
               obj[key] = val;
           });

           but whether or not we can pass a function that way, via a
           (void*) is as yet unknown.
        */
        /* Minimum subset of sqlite result codes we'll need. */
        SQLITE_OK: 0,
        SQLITE_ROW: 100,
        SQLITE_DONE: 101,
        /* sqlite data types */
        SQLITE_INTEGER: 1,
        SQLITE_FLOAT: 2,
        SQLITE_TEXT: 3,
        SQLITE_BLOB: 4,
        SQLITE_NULL: 5,
        /* create_function() flags */
        SQLITE_DETERMINISTIC: 0x000000800,
        SQLITE_DIRECTONLY: 0x000080000,
        SQLITE_INNOCUOUS: 0x000200000,
        /* sqlite encodings, used for creating UDFs, noting that we
           will only support UTF8. */
        SQLITE_UTF8: 1
    };
    const cwrap = SQM.cwrap;
    [/* C-side functions to bind. Each entry is an array with 3 or 4
        elements:
        
        ["c-side name",
         "result type" (cwrap() syntax),
         [arg types in cwrap() syntax]
        ]

        If it has 4 elements, the first one is an alternate name to
        use for the JS-side binding. That's required when overloading
        a binding for two different uses.
     */
        ["sqlite3_bind_blob","number",["number", "number", "number", "number", "number"]],
        ["sqlite3_bind_double","number",["number", "number", "number"]],
        ["sqlite3_bind_int","number",["number", "number", "number"]],
        /*Noting that JS/wasm combo does not currently support 64-bit integers:
          ["sqlite3_bind_int64","number",["number", "number", "number"]],*/
        ["sqlite3_bind_null","void",["number"]],
        ["sqlite3_bind_parameter_count", "number", ["number"]],
        ["sqlite3_bind_parameter_index","number",["number", "string"]],
        ["sqlite3_bind_text","number",["number", "number", "number", "number", "number"]],
        ["sqlite3_changes", "number", ["number"]],
        ["sqlite3_clear_bindings","number",["number"]],
        ["sqlite3_close_v2", "number", ["number"]],
        ["sqlite3_column_blob","number", ["number", "number"]],
        ["sqlite3_column_bytes","number",["number", "number"]],
        ["sqlite3_column_count", "number", ["number"]],
        ["sqlite3_column_count","number",["number"]],
        ["sqlite3_column_double","number",["number", "number"]],
        ["sqlite3_column_int","number",["number", "number"]],
        /*Noting that JS/wasm combo does not currently support 64-bit integers:
          ["sqlite3_column_int64","number",["number", "number"]],*/
        ["sqlite3_column_name","string",["number", "number"]],
        ["sqlite3_column_text","string",["number", "number"]],
        ["sqlite3_column_type","number",["number", "number"]],
        ["sqlite3_compileoption_get", "string", ["number"]],
        ["sqlite3_compileoption_used", "number", ["string"]],
        ["sqlite3_create_function_v2", "number",
         ["number", "string", "number", "number","number",
          "number", "number", "number", "number"]],
        ["sqlite3_data_count", "number", ["number"]],
        ["sqlite3_db_filename", "string", ["number", "string"]],
        ["sqlite3_errmsg", "string", ["number"]],
        ["sqlite3_exec", "number", ["number", "string", "number", "number", "number"]],
        ["sqlite3_finalize", "number", ["number"]],
        ["sqlite3_interrupt", "void", ["number"]],
        ["sqlite3_libversion", "string", []],
        ["sqlite3_open", "number", ["string", "number"]],
        //["sqlite3_open_v2", "number", ["string", "number", "number", "string"]],
        //^^^^ TODO: add the flags needed for the 3rd arg
        ["sqlite3_prepare_v2", "number", ["number", "string", "number", "number", "number"]],
        ["sqlite3_prepare_v2_sqlptr", "sqlite3_prepare_v2",
         /* Impl which requires that the 2nd argument be a pointer to
            the SQL, instead of a string. This is used for cases where
            we require a non-NULL value for the final argument. We may
            or may not need this, depending on how our higher-level
            API shapes up, but this code's spiritual guide (sql.js)
            uses it we we'll include it. */
         "number", ["number", "number", "number", "number", "number"]],
        ["sqlite3_reset", "number", ["number"]],
        ["sqlite3_result_blob",null,["number", "number", "number", "number"]],
        ["sqlite3_result_double",null,["number", "number"]],
        ["sqlite3_result_error",null,["number", "string", "number"]],
        ["sqlite3_result_int",null,["number", "number"]],
        ["sqlite3_result_null",null,["number"]],
        ["sqlite3_result_text",null,["number", "string", "number", "number"]],
        ["sqlite3_sourceid", "string", []],
        ["sqlite3_sql", "string", ["number"]],
        ["sqlite3_step", "number", ["number"]],
        ["sqlite3_value_blob", "number", ["number"]],
        ["sqlite3_value_bytes","number",["number"]],
        ["sqlite3_value_double","number",["number"]],
        ["sqlite3_value_text", "string", ["number"]],
        ["sqlite3_value_type", "number", ["number"]]
        //["sqlite3_normalized_sql", "string", ["number"]]
    ].forEach(function(a){
        const k = (4==a.length) ? a.shift() : a[0];
        api[k] = cwrap.apply(this, a);
    });

    /* What follows is colloquially known as "OO API #1". It is a
       binding of the sqlite3 API which is designed to be run within
       the same thread (main or worker) as the one in which the
       sqlite3 WASM binding was initialized. This wrapper cannot use
       the sqlite3 binding if, e.g., the wrapper is in the main thread
       and the sqlite3 API is in a worker. */

    /** Memory for use in some pointer-to-pointer-passing routines. */
    const pPtrArg = stackAlloc(4);
    /** Throws a new error, concatenating all args with a space between
        each. */
    const toss = function(){
        throw new Error(Array.prototype.join.call(arguments, ' '));
    };

    /**
       The DB class wraps a sqlite3 db handle.

       It accepts the following argument signatures:

       - ()
       - (undefined) (same effect as ())
       - (Uint8Array holding an sqlite3 db image)

       It always generates a random filename and sets is to
       the `filename` property of this object.

       Developer's note: the reason it does not (any longer) support
       ":memory:" as a name is because we can apparently only export
       images of DBs which are stored in the pseudo-filesystem
       provided by the JS APIs. Since exporting and importing images
       is an important usability feature for this class, ":memory:"
       DBs are not supported (until/unless we can find a way to export
       those as well). The naming semantics will certainly evolve as
       this API does.
    */
    const DB = function(arg){
        const fn = "db-"+((Math.random() * 10000000) | 0)+
              "-"+((Math.random() * 10000000) | 0)+".sqlite3";
        let buffer;
        if(name instanceof Uint8Array){
            buffer = arg;
            arg = undefined;
        }else if(arguments.length && undefined!==arg){
            toss("Invalid arguments to DB constructor.",
                 "Expecting no args, undefined, or a",
                 "sqlite3 file as a Uint8Array.");
        }
        if(buffer){
            FS.createDataFile("/", fn, buffer, true, true);
        }
        setValue(pPtrArg, 0, "i32");
        this.checkRc(api.sqlite3_open(fn, pPtrArg));
        this._pDb = getValue(pPtrArg, "i32");
        this.filename = fn;
        this._statements = {/*map of open Stmt _pointers_ to Stmt*/};
        this._udfs = {/*map of UDF names to wasm function _pointers_*/};
    };

    /**
       Internal-use enum for mapping JS types to DB-bindable types.
       These do not (and need not) line up with the SQLITE_type
       values. All values in this enum must be truthy and distinct
       but they need not be numbers.
    */
    const BindTypes = {
        null: 1,
        number: 2,
        string: 3,
        boolean: 4,
        blob: 5
    };
    BindTypes['undefined'] == BindTypes.null;

    /**
       This class wraps sqlite3_stmt. Calling this constructor
       directly will trigger an exception. Use DB.prepare() to create
       new instances.
    */
    const Stmt = function(){
        if(BindTypes!==arguments[2]){
            toss("Do not call the Stmt constructor directly. Use DB.prepare().");
        }
        this.db = arguments[0];
        this._pStmt = arguments[1];
        this.columnCount = api.sqlite3_column_count(this._pStmt);
        this.parameterCount = api.sqlite3_bind_parameter_count(this._pStmt);
        this._allocs = [/*list of alloc'd memory blocks for bind() values*/]
    };

    /** Throws if the given DB has been closed, else it is returned. */
    const affirmDbOpen = function(db){
        if(!db._pDb) toss("DB has been closed.");
        return db;
    };

    /** Returns true if n is a 32-bit (signed) integer,
        else false. */
    const isInt32 = function(n){
        return (n===n|0 && n<0xFFFFFFFF) ? true : undefined;
    };

    /**
       Expects to be passed (arguments) from DB.exec() and
       DB.execMulti(). Does the argument processing/validation, throws
       on error, and returns a new object on success:

       { sql: the SQL, obt: optionsObj, cbArg: function}

       cbArg is only set if the opt.callback is set, in which case
       it's a function which expects to be passed the current Stmt
       and returns the callback argument of the type indicated by
       the input arguments.
    */
    const parseExecArgs = function(args){
        const out = {};
        switch(args.length){
            case 1:
                if('string'===typeof args[0]){
                    out.sql = args[0];
                    out.opt = {};
                }else if(args[0] && 'object'===typeof args[0]){
                    out.opt = args[0];
                    out.sql = out.opt.sql;
                }
            break;
            case 2:
                out.sql = args[0];
                out.opt = args[1];
            break;
            default: toss("Invalid argument count for exec().");
        };
        if('string'!==typeof out.sql) toss("Missing SQL argument.");
        if(out.opt.callback){
            switch((undefined===out.opt.rowMode)
                    ? 'stmt' : out.opt.rowMode) {
                case 'object': out.cbArg = (stmt)=>stmt.get({}); break;
                case 'array': out.cbArg = (stmt)=>stmt.get([]); break;
                case 'stmt': out.cbArg = (stmt)=>stmt; break;
                default: toss("Invalid rowMode:",out.opt.rowMode);
            }
        }
        return out;
    };

    /** If object opts has _its own_ property named p then that
        property's value is returned, else dflt is returned. */
    const getOwnOption = (opts, p, dflt)=>
        opts.hasOwnProperty(p) ? opts[p] : dflt;

    DB.prototype = {
        /**
           Expects to be given an sqlite3 API result code. If it is
           falsy, this function returns this object, else it throws an
           exception with an error message from sqlite3_errmsg(),
           using this object's db handle. Note that if it's passed a
           non-error code like SQLITE_ROW or SQLITE_DONE, it will
           still throw but the error string might be "Not an error."
           The various non-0 non-error codes need to be checked for in
           client code where they are expected.
        */
        checkRc: function(sqliteResultCode){
            if(!sqliteResultCode) return this;
            toss("sqlite result code",sqliteResultCode+":",
                 api.sqlite3_errmsg(this._pDb) || "Unknown db error.");
        },
        /**
           Finalizes all open statements and closes this database
           connection. This is a no-op if the db has already been
           closed.
        */
        close: function(){
            if(this._pDb){
                let s;
                const that = this;
                Object.keys(this._statements).forEach(function(k,s){
                    delete that._statements[k];
                    if(s && s._pStmt) s.finalize();
                });
                Object.values(this._udfs).forEach(SQM.removeFunction);
                delete this._udfs;
                delete this._statements;
                delete this.filename;
                api.sqlite3_close_v2(this._pDb);
                delete this._pDb;
            }
        },
        /**
           Similar to this.filename but will return NULL for
           special names like ":memory:". Not of much use until
           we have filesystem support. Throws if the DB has
           been closed. If passed an argument it then it will return
           the filename of the ATTACHEd db with that name, else it assumes
           a name of `main`.
        */
        fileName: function(dbName){
            return api.sqlite3_db_filename(affirmDbOpen(this)._pDb, dbName||"main");
        },
        /**
           Compiles the given SQL and returns a prepared Stmt. This is
           the only way to create new Stmt objects. Throws on error.
        */
        prepare: function(sql){
            affirmDbOpen(this);
            setValue(pPtrArg,0,"i32");
            this.checkRc(api.sqlite3_prepare_v2(this._pDb, sql, -1, pPtrArg, null));
            const pStmt = getValue(pPtrArg, "i32");
            if(!pStmt) toss("Empty SQL is not permitted.");
            const stmt = new Stmt(this, pStmt, BindTypes);
            this._statements[pStmt] = stmt;
            return stmt;
        },
        /**
           This function works like execMulti(), and takes the same
           arguments, but is more efficient (performs much less work)
           when the input SQL is only a single statement. If passed a
           multi-statement SQL, it only processes the first one.

           This function supports one additional option not used by
           execMulti():

           - .multi: if true, this function acts as a proxy for
             execMulti().
        */
        exec: function(/*(sql [,optionsObj]) or (optionsObj)*/){
            affirmDbOpen(this);
            const arg = parseExecArgs(arguments);
            if(!arg.sql) return this;
            else if(arg.opt.multi){
                return this.execMulti(arg, undefined, BindTypes);
            }
            const opt = arg.opt;
            let stmt;
            try {
                stmt = this.prepare(arg.sql);
                if(opt.bind) stmt.bind(opt.bind);
                if(opt.callback){
                    while(stmt.step()){
                        stmt._isLocked = true;
                        opt.callback(arg.cbArg(stmt), stmt);
                        stmt._isLocked = false;
                    }
                }else{
                    stmt.step();
                }
            }finally{
                if(stmt){
                    delete stmt._isLocked;
                    stmt.finalize();
                }
            }
            return this;

        }/*exec()*/,
        /**
           Executes one or more SQL statements. Its arguments
           must be either (sql,optionsObject) or (optionsObject).
           In the latter case, optionsObject.sql must contain the
           SQL to execute. Returns this object. Throws on error.

           If no SQL is provided, or a non-string is provided, an
           exception is triggered. Empty SQL, on the other hand, is
           simply a no-op.

           The optional options object may contain any of the following
           properties:

           - .sql = the SQL to run (unless it's provided as the first
             argument).

           - .bind = a single value valid as an argument for
             Stmt.bind(). This is ONLY applied to the FIRST non-empty
             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 (if it 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 ...

           - .rowMode = a string describing what type of argument
             should be passed as the first argument to the callback. A
             value of 'object' causes the results of `stmt.get({})` to
             be passed to the object. A value of 'array' causes the
             results of `stmt.get([])` to be passed to the callback.
             A value of 'stmt' is equivalent to the default, passing
             the current Stmt to the callback (noting that it's always
             passed as the 2nd argument). Any other value triggers an
             exception.

           - saveSql = an optional array. If set, the SQL of each
             executed statement is appended to this array before the
             statement is executed (but after it is prepared - we
             don't have the string until after that). Empty SQL
             statements are elided.

           ACHTUNG #1: The callback MUST NOT modify the Stmt
           object. Calling any of the Stmt.get() variants,
           Stmt.getColumnName(), or simililar, is legal, but calling
           step() or finalize() is not. Routines which are illegal
           in this context will trigger an exception.

           ACHTUNG #2: The semantics of the `bind` and `callback`
           options may well change or those options may be removed
           altogether for this function (but retained for exec()).
        */
        execMulti: function(/*(sql [,obj]) || (obj)*/){
            affirmDbOpen(this);
            const arg = (BindTypes===arguments[2]
                         /* ^^^ Being passed on from exec() */
                         ? arguments[0] : parseExecArgs(arguments));
            if(!arg.sql) return this;
            const opt = arg.opt;
            const stack = stackSave();
            let stmt;
            let bind = opt.bind;
            let rowMode = (
                (opt.callback && opt.rowMode)
                    ? opt.rowMode : false);
            try{
                let pSql = SQM.allocateUTF8OnStack(arg.sql)
                const pzTail = stackAlloc(4);
                while(getValue(pSql, "i8")){
                    setValue(pPtrArg, 0, "i32");
                    setValue(pzTail, 0, "i32");
                    this.checkRc(api.sqlite3_prepare_v2_sqlptr(
                        this._pDb, pSql, -1, pPtrArg, pzTail
                    ));
                    const pStmt = getValue(pPtrArg, "i32");
                    pSql = getValue(pzTail, "i32");
                    if(!pStmt) continue;
                    if(opt.saveSql){
                        opt.saveSql.push(api.sqlite3_sql(pStmt).trim());
                    }
                    stmt = new Stmt(this, pStmt, BindTypes);
                    if(bind && stmt.parameterCount){
                        stmt.bind(bind);
                        bind = null;
                    }
                    if(opt.callback && null!==rowMode){
                        while(stmt.step()){
                            stmt._isLocked = true;
                            callback(arg.cbArg(stmt), stmt);
                            stmt._isLocked = false;
                        }
                        rowMode = null;
                    }else{
                        // Do we need to while(stmt.step()){} here?
                        stmt.step();
                    }
                    stmt.finalize();
                    stmt = null;
                }
            }finally{
                if(stmt){
                    delete stmt._isLocked;
                    stmt.finalize();
                }
                stackRestore(stack);
            }
            return this;
        }/*execMulti()*/,
        /**
           Creates a new scalar UDF (User-Defined Function) which is
           accessible via SQL code. This function may be called in any
           of the following forms:

           - (name, function)
           - (name, function, optionsObject)
           - (name, optionsObject)
           - (optionsObject)

           In the final two cases, the function must be defined as the
           'callback' property of the options object. In the final
           case, the function's name must be the 'name' property.

           This can only be used to create scalar functions, not
           aggregate or window functions. UDFs cannot be removed from
           a DB handle after they're added.

           On success, returns this object. Throws on error.

           When called from SQL, arguments to the UDF, and its result,
           will be converted between JS and SQL with as much fidelity
           as is feasible, triggering an exception if a type
           conversion cannot be determined. Some freedom is afforded
           to numeric conversions due to friction between the JS and C
           worlds: integers which are larger than 32 bits will be
           treated as doubles, as JS does not support 64-bit integers
           and it is (as of this writing) illegal to use WASM
           functions which take or return 64-bit integers from JS.

           The optional options object may contain flags to modify how
           the function is defined:

           - .arity: the number of arguments which SQL calls to this
             function expect or require. The default value is the
             callback's length property (i.e. the number of declared
             parameters it has). A value of -1 means that the function
             is variadic and may accept any number of arguments, up to
             sqlite3's compile-time limits. sqlite3 will enforce the
             argument count if is zero or greater.

           The following properties correspond to flags documented at:

           https://sqlite.org/c3ref/create_function.html

           - .deterministic = SQLITE_DETERMINISTIC
           - .directOnly = SQLITE_DIRECTONLY
           - .innocuous = SQLITE_INNOCUOUS


           Maintenance reminder: the ability to add new
           WASM-accessible functions to the runtime requires that the
           WASM build is compiled with emcc's `-sALLOW_TABLE_GROWTH`
           flag.
        */
        createFunction: function f(name, callback,opt){
            switch(arguments.length){
                case 1: /* (optionsObject) */
                    opt = name;
                    name = opt.name;
                    callback = opt.callback;
                    break;
                case 2: /* (name, callback|optionsObject) */
                    if(!(callback instanceof Function)){
                        opt = callback;
                        callback = opt.callback;
                    }
                    break;
                default: break;
            }
            if(!opt) opt = {};
            if(!(callback instanceof Function)){
                toss("Invalid arguments: expecting a callback function.");
            }else if('string' !== typeof name){
                toss("Invalid arguments: missing function name.");
            }
            if(!f._extractArgs){
                /* Static init */
                f._extractArgs = function(argc, pArgv){
                    let i, pVal, valType, arg;
                    const tgt = [];
                    for(i = 0; i < argc; ++i){
                        pVal = getValue(pArgv + (4 * i), "i32");
                        valType = api.sqlite3_value_type(pVal);
                        switch(valType){
                            case api.SQLITE_INTEGER:
                            case api.SQLITE_FLOAT:
                                arg = api.sqlite3_value_double(pVal);
                                break;
                            case SQLITE_TEXT:
                                arg = api.sqlite3_value_text(pVal);
                                break;
                            case SQLITE_BLOB:{
                                const n = api.sqlite3_value_bytes(ptr);
                                const pBlob = api.sqlite3_value_blob(ptr);
                                arg = new Uint8Array(n);
                                let i;
                                for(i = 0; i < n; ++i) arg[i] = HEAP8[pBlob+i];
                                break;
                            }
                            default:
                                arg = null; break;
                        }
                        tgt.push(arg);
                    }
                    return tgt;
                }/*_extractArgs()*/;
                f._setResult = function(pCx, val){
                    switch(typeof val) {
                        case 'boolean':
                            api.sqlite3_result_int(pCx, val ? 1 : 0);
                            break;
                        case 'number': {
                            (isInt32(val)
                             ? api.sqlite3_result_int
                             : api.sqlite3_result_double)(pCx, val);
                            break;
                        }
                        case 'string':
                            api.sqlite3_result_text(pCx, val, -1,
                                                  -1/*==SQLITE_TRANSIENT*/);
                            break;
                        case 'object':
                            if(null===val) {
                                api.sqlite3_result_null(pCx);
                                break;
                            }else if(undefined!==val.length){
                                const pBlob =
                                      SQM.allocate(val, SQM.ALLOC_NORMAL);
                                api.sqlite3_result_blob(pCx, pBlob, val.length, -1/*==SQLITE_TRANSIENT*/);
                                SQM._free(blobptr);
                                break;
                            }
                            // else fall through
                        default:
                            toss("Don't not how to handle this UDF result value:",val);
                    };
                }/*_setResult()*/;
            }/*static init*/
            const wrapper = function(pCx, argc, pArgv){
                try{
                    f._setResult(pCx, callback.apply(null, f._extractArgs(argc, pArgv)));
                }catch(e){
                    api.sqlite3_result_error(pCx, e.message, -1);
                }
            };
            const pUdf = SQM.addFunction(wrapper, "viii");
            let fFlags = 0;
            if(getOwnOption(opt, 'deterministic')) fFlags |= api.SQLITE_DETERMINISTIC;
            if(getOwnOption(opt, 'directOnly')) fFlags |= api.SQLITE_DIRECTONLY;
            if(getOwnOption(opt, 'innocuous')) fFlags |= api.SQLITE_INNOCUOUS;
            name = name.toLowerCase();
            try {
                this.checkRc(api.sqlite3_create_function_v2(
                    this._pDb, name,
                    (opt.hasOwnProperty('arity') ? +opt.arity : callback.length),
                    api.SQLITE_UTF8 | fFlags, null/*pApp*/, pUdf,
                    null/*xStep*/, null/*xFinal*/, null/*xDestroy*/));
            }catch(e){
                SQM.removeFunction(pUdf);
                throw e;
            }
            if(this._udfs.hasOwnProperty(name)){
                SQM.removeFunction(this._udfs[name]);
            }
            this._udfs[name] = pUdf;
            return this;
        }/*createFunction()*/,
        /**
           Prepares the given SQL, step()s it one time, and returns
           the value of the first result column. If it has no results,
           undefined is returned. If passed a second argument, it is
           treated like an argument to Stmt.bind(), so may be any type
           supported by that function. Throws on error (e.g. malformed
           SQL).
        */
        selectValue: function(sql,bind){
            let stmt, rc;
            try {
                stmt = this.prepare(sql).bind(bind);
                if(stmt.step()) rc = stmt.get(0);
            }finally{
                if(stmt) stmt.finalize();
            }
            return rc;
        },

        /**
           Exports a copy of this db's file as a Uint8Array and
           returns it. It is technically not legal to call this while
           any prepared statement are currently active. Throws if this
           db is not open.

           Maintenance reminder: the corresponding sql.js impl of this
           feature closes the current db, finalizing any active
           statements and (seemingly unnecessarily) destroys any UDFs,
           copies the file, and then re-opens it (without restoring
           the UDFs). Those gymnastics are not necessary on the tested
           platform but might be necessary on others. Because of that
           eventuality, this interface currently enforces that no
           statements are active when this is run. It will throw if
           any are.
        */
        exportBinaryImage: function(){
            affirmDbOpen(this);
            if(Object.keys(this._statements).length){
                toss("Cannot export with prepared statements active!",
                     "finalize() all statements and try again.");
            }
            const img = FS.readFile(this.filename, {encoding:"binary"});
            return img;
        }
    }/*DB.prototype*/;


    /** Throws if the given Stmt has been finalized, else stmt is
        returned. */
    const affirmStmtOpen = function(stmt){
        if(!stmt._pStmt) toss("Stmt has been closed.");
        return stmt;
    };

    /** Returns an opaque truthy value from the BindTypes
        enum if v's type is a valid bindable type, else
        returns a falsy value. As a special case, a value of
        undefined is treated as a bind type of null. */
    const isSupportedBindType = function(v){
        let t = BindTypes[(null===v||undefined===v) ? 'null' : typeof v];
        switch(t){
            case BindTypes.boolean:
            case BindTypes.null:
            case BindTypes.number:
            case BindTypes.string:
                return t;
            default:
                if(v instanceof Uint8Array) return BindTypes.blob;
                return undefined;
        }
    };

    /**
       If isSupportedBindType(v) returns a truthy value, this
       function returns that value, else it throws.
    */
    const affirmSupportedBindType = function(v){
        return isSupportedBindType(v) || toss("Unsupport bind() argument type.");
    };

    /**
       If key is a number and within range of stmt's bound parameter
       count, key is returned.

       If key is not a number then it is checked against named
       parameters. If a match is found, its index is returned.

       Else it throws.
    */
    const affirmParamIndex = function(stmt,key){
        const n = ('number'===typeof key)
              ? key : api.sqlite3_bind_parameter_index(stmt._pStmt, key);
        if(0===n || (n===key && (n!==(n|0)/*floating point*/))){
            toss("Invalid bind() parameter name: "+key);
        }
        else if(n<1 || n>stmt.parameterCount) toss("Bind index",key,"is out of range.");
        return n;
    };

    /** Throws if ndx is not an integer or if it is out of range
        for stmt.columnCount, else returns stmt.

        Reminder: this will also fail after the statement is finalized
        but the resulting error will be about an out-of-bounds column
        index.
    */
    const affirmColIndex = function(stmt,ndx){
        if((ndx !== (ndx|0)) || ndx<0 || ndx>=stmt.columnCount){
            toss("Column index",ndx,"is out of range.");
        }
        return stmt;
    };

    /**
       If stmt._isLocked is truthy, this throws an exception
       complaining that the 2nd argument (an operation name,
       e.g. "bind()") is not legal while the statement is "locked".
       Locking happens before an exec()-like callback is passed a
       statement, to ensure that the callback does not mutate or
       finalize the statement. If it does not throw, it returns stmt.
    */
    const affirmUnlocked = function(stmt,currentOpName){
        if(stmt._isLocked){
            toss("Operation is illegal when statement is locked:",currentOpName);
        }
        return stmt;
    };

    /**
       Binds a single bound parameter value on the given stmt at the
       given index (numeric or named) using the given bindType (see
       the BindTypes enum) and value. Throws on error. Returns stmt on
       success.
    */
    const bindOne = function f(stmt,ndx,bindType,val){
        affirmUnlocked(stmt, 'bind()');
        if(!f._){
            f._ = {
                string: function(stmt, ndx, val, asBlob){
                    const bytes = intArrayFromString(val,true);
                    const pStr = SQM.allocate(bytes, ALLOC_NORMAL);
                    stmt._allocs.push(pStr);
                    const func =  asBlob ? api.sqlite3_bind_blob : api.sqlite3_bind_text;
                    return func(stmt._pStmt, ndx, pStr, bytes.length, 0);
                }
            };
        }
        affirmSupportedBindType(val);
        ndx = affirmParamIndex(stmt,ndx);
        let rc = 0;
        switch((null===val || undefined===val) ? BindTypes.null : bindType){
            case BindTypes.null:
                rc = api.sqlite3_bind_null(stmt._pStmt, ndx);
                break;
            case BindTypes.string:{
                rc = f._.string(stmt, ndx, val, false);
                break;
            }
            case BindTypes.number: {
                const m = (isInt32(val)
                           ? api.sqlite3_bind_int
                           /*It's illegal to bind a 64-bit int
                             from here*/
                           : api.sqlite3_bind_double);
                rc = m(stmt._pStmt, ndx, val);
                break;
            }
            case BindTypes.boolean:
                rc = api.sqlite3_bind_int(stmt._pStmt, ndx, val ? 1 : 0);
                break;
            case BindTypes.blob: {
                if('string'===typeof val){
                    rc = f._.string(stmt, ndx, val, true);
                }else{
                    const len = val.length;
                    if(undefined===len){
                        toss("Binding a value as a blob requires",
                             "that it have a length member.");
                    }
                    const pBlob = SQM.allocate(val, ALLOC_NORMAL);
                    stmt._allocs.push(pBlob);
                    rc = api.sqlite3_bind_blob(stmt._pStmt, ndx, pBlob, len, 0);
                }
            }
            default: toss("Unsupported bind() argument type.");
        }
        if(rc) stmt.db.checkRc(rc);
        return stmt;
    };

    /** Frees any memory explicitly allocated for the given
        Stmt object. Returns stmt. */
    const freeBindMemory = function(stmt){
        let m;
        while(undefined !== (m = stmt._allocs.pop())){
            SQM._free(m);
        }
        return stmt;
    };
    
    Stmt.prototype = {
        /**
           "Finalizes" this statement. This is a no-op if the
           statement has already been finalizes. Returns
           undefined. Most methods in this class will throw if called
           after this is.
        */
        finalize: function(){
            if(this._pStmt){
                affirmUnlocked(this,'finalize()');
                freeBindMemory(this);
                delete this.db._statements[this._pStmt];
                api.sqlite3_finalize(this._pStmt);
                delete this.columnCount;
                delete this.parameterCount;
                delete this._pStmt;
                delete this.db;
                delete this._isLocked;
            }
        },
        /** Clears all bound values. Returns this object.
            Throws if this statement has been finalized. */
        clearBindings: function(){
            freeBindMemory(
                affirmUnlocked(affirmStmtOpen(this), 'clearBindings()')
            );
            api.sqlite3_clear_bindings(this._pStmt);
            this._mayGet = false;
            return this;
        },
        /**
           Resets this statement so that it may be step()ed again
           from the beginning. Returns this object. Throws if this
           statement has been finalized.

           If passed a truthy argument then this.clearBindings() is
           also called, otherwise any existing bindings, along with
           any memory allocated for them, are retained.
        */
        reset: function(alsoClearBinds){
            affirmUnlocked(this,'reset()');
            if(alsoClearBinds) this.clearBindings();
            api.sqlite3_reset(affirmStmtOpen(this)._pStmt);
            this._mayGet = false;
            return this;
        },
        /**
           Binds one or more values to its bindable parameters. It
           accepts 1 or 2 arguments:

           If passed a single argument, it must be either an array, an
           object, or a value of a bindable type (see below).

           If passed 2 arguments, the first one is the 1-based bind
           index or bindable parameter name and the second one must be
           a value of a bindable type.

           Bindable value types:

           - null is bound as NULL.

           - undefined as a standalone value is a no-op intended to
             simplify certain client-side use cases: passing undefined
             as a value to this function will not actually bind
             anything and this function will skip confirmation that
             binding is even legal. (Those semantics simplify certain
             client-side uses.) Conversely, a value of undefined as an
             array or object property when binding an array/object
             (see below) is treated the same as null.

           - Numbers are bound as either doubles or integers: doubles
             if they are larger than 32 bits, else double or int32,
             depending on whether they have a fractional part. (It is,
             as of this writing, illegal to call (from JS) a WASM
             function which either takes or returns an int64.)
             Booleans are bound as integer 0 or 1. It is not expected
             the distinction of binding doubles which have no
             fractional parts is integers is significant for the
             majority of clients due to sqlite3's data typing
             model. This API does not currently support the BigInt
             type.

           - Strings are bound as strings (use bindAsBlob() to force
             blob binding).

           - Uint8Array instances are bound as blobs.

           If passed an array, each element of the array is bound at
           the parameter index equal to the array index plus 1
           (because arrays are 0-based but binding is 1-based).

           If passed an object, each object key is treated as a
           bindable parameter name. The object keys _must_ match any
           bindable parameter names, including any `$`, `@`, or `:`
           prefix. Because `$` is a legal identifier chararacter in
           JavaScript, that is the suggested prefix for bindable
           parameters.

           It returns this object on success and throws on
           error. Errors include:

           - Any bind index is out of range, a named bind parameter
             does not match, or this statement has no bindable
             parameters.

           - Any value to bind is of an unsupported type.

           - Passed no arguments or more than two.

           - The statement has been finalized.
        */
        bind: function(/*[ndx,] arg*/){
            affirmStmtOpen(this);
            let ndx, arg;
            switch(arguments.length){
                case 1: ndx = 1; arg = arguments[0]; break;
                case 2: ndx = arguments[0]; arg = arguments[1]; break;
                default: toss("Invalid bind() arguments.");
            }
            if(undefined===arg){
                /* It might seem intuitive to bind undefined as NULL
                   but this approach simplifies certain client-side
                   uses when passing on arguments between 2+ levels of
                   functions. */
                return this;
            }else if(!this.parameterCount){
                toss("This statement has no bindable parameters.");
            }
            this._mayGet = false;
            if(null===arg){
                /* bind NULL */
                return bindOne(this, ndx, BindTypes.null, arg);
            }
            else if(Array.isArray(arg)){
                /* bind each entry by index */
                if(1!==arguments.length){
                    toss("When binding an array, an index argument is not permitted.");
                }
                arg.forEach((v,i)=>bindOne(this, i+1, affirmSupportedBindType(v), v));
                return this;
            }
            else if('object'===typeof arg/*null was checked above*/){
                /* bind by name */
                if(1!==arguments.length){
                    toss("When binding an object, an index argument is not permitted.");
                }
                Object.keys(arg)
                    .forEach(k=>bindOne(this, k,
                                        affirmSupportedBindType(arg[k]),
                                        arg[k]));
                return this;
            }else{
                return bindOne(this, ndx,
                               affirmSupportedBindType(arg), arg);
            }
            toss("Should not reach this point.");
        },
        /**
           Special case of bind() which binds the given value
           using the BLOB binding mechanism instead of the default
           selected one for the value. The ndx may be a numbered
           or named bind index. The value must be of type string,
           Uint8Array, or null/undefined (both treated as null).

           If passed a single argument, a bind index of 1 is assumed.
        */
        bindAsBlob: function(ndx,arg){
            affirmStmtOpen(this);
            if(1===arguments.length){
                ndx = 1;
                arg = arguments[0];
            }
            const t = affirmSupportedBindType(arg);
            if(BindTypes.string !== t && BindTypes.blob !== t
               && BindTypes.null !== t){
                toss("Invalid value type for bindAsBlob()");
            }
            this._mayGet = false;
            return bindOne(this, ndx, BindTypes.blob, arg);
        },
        /**
           Steps the statement one time. If the result indicates that
           a row of data is available, true is returned.  If no row of
           data is available, false is returned.  Throws on error.
        */
        step: function(){
            affirmUnlocked(this, 'step()');
            const rc = api.sqlite3_step(affirmStmtOpen(this)._pStmt);
            switch(rc){
                case api.SQLITE_DONE: return this._mayGet = false;
                case api.SQLITE_ROW: return this._mayGet = true;
                default:
                    this._mayGet = false;
                    console.warn("sqlite3_step() rc=",rc,"SQL =",
                                 api.sqlite3_sql(this._pStmt));
                    this.db.checkRc(rc);
            };
        },
        /**
           Fetches the value from the given 0-based column index of
           the current data row, throwing if index is out of range. 

           Requires that step() has just returned a truthy value, else
           an exception is thrown.

           By default it will determine the data type of the result
           automatically. If passed a second arugment, it must be one
           of the enumeration values for sqlite3 types, which are
           defined as members of the sqlite3 module: SQLITE_INTEGER,
           SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB. Any other value,
           except for undefined, will trigger an exception. Passing
           undefined is the same as not passing a value. It is legal
           to, e.g., fetch an integer value as a string, in which case
           sqlite3 will convert the value to a string.

           If ndx is an array, this function behaves a differently: it
           assigns the indexes of the array, from 0 to the number of
           result columns, to the values of the corresponding column,
           and returns that array.

           If ndx is a plain object, this function behaves even
           differentlier: it assigns the properties of the object to
           the values of their corresponding result columns.

           Blobs are returned as Uint8Array instances.

           Potential TODO: add type ID SQLITE_JSON, which fetches the
           result as a string and passes it (if it's not null) to
           JSON.parse(), returning the result of that. Until then,
           getJSON() can be used for that.
        */
        get: function(ndx,asType){
            if(!affirmStmtOpen(this)._mayGet){
                toss("Stmt.step() has not (recently) returned true.");
            }
            if(Array.isArray(ndx)){
                let i = 0;
                while(i<this.columnCount){
                    ndx[i] = this.get(i++);
                }
                return ndx;
            }else if(ndx && 'object'===typeof ndx){
                let i = 0;
                while(i<this.columnCount){
                    ndx[api.sqlite3_column_name(this._pStmt,i)] = this.get(i++);
                }
                return ndx;
            }
            affirmColIndex(this, ndx);
            switch(undefined===asType
                   ? api.sqlite3_column_type(this._pStmt, ndx)
                   : asType){
                case api.SQLITE_NULL: return null;
                case api.SQLITE_INTEGER:{
                    return 0 | api.sqlite3_column_double(this._pStmt, ndx);
                    /* ^^^^^^^^ strips any fractional part and handles
                       handles >32bits */
                }
                case api.SQLITE_FLOAT:
                    return api.sqlite3_column_double(this._pStmt, ndx);
                case api.SQLITE_TEXT:
                    return api.sqlite3_column_text(this._pStmt, ndx);
                case api.SQLITE_BLOB: {
                    const n = api.sqlite3_column_bytes(this._pStmt, ndx);
                    const ptr = api.sqlite3_column_blob(this._pStmt, ndx);
                    const rc = new Uint8Array(n);
                    for(let i = 0; i < n; ++i) rc[i] = HEAP8[ptr + i];
                    return rc;
                }
                default: toss("Don't know how to translate",
                              "type of result column #"+ndx+".");
            }
            abort("Not reached.");
        },
        /** Equivalent to get(ndx) but coerces the result to an
            integer. */
        getInt: function(ndx){return this.get(ndx,api.SQLITE_INTEGER)},
        /** Equivalent to get(ndx) but coerces the result to a
            float. */
        getFloat: function(ndx){return this.get(ndx,api.SQLITE_FLOAT)},
        /** Equivalent to get(ndx) but coerces the result to a
            string. */
        getString: function(ndx){return this.get(ndx,api.SQLITE_TEXT)},
        /** Equivalent to get(ndx) but coerces the result to a
            Uint8Array. */
        getBlob: function(ndx){return this.get(ndx,api.SQLITE_BLOB)},
        /**
           A convenience wrapper around get() which fetches the value
           as a string and then, if it is not null, passes it to
           JSON.parse(), returning that result. Throws if parsing
           fails. If the result is null, null is returned. An empty
           string, on the other hand, will trigger an exception.
        */
        getJSON: function(ndx){
            const s = this.get(ndx, api.SQLITE_STRING);
            return null===s ? s : JSON.parse(s);
        },
        /**
           Returns the result column name of the given index, or
           throws if index is out of bounds or this statement has been
           finalized. This can be used without having run step()
           first.
        */
        getColumnName: function(ndx){
            return api.sqlite3_column_name(
                affirmColIndex(affirmStmtOpen(this),ndx)._pStmt, ndx
            );
        },
        /**
           If this statement potentially has result columns, this
           function returns an array of all such names. If passed an
           array, it is used as the target and all names are appended
           to it. Returns the target array. Throws if this statement
           cannot have result columns. This object's columnCount member
           holds the number of columns.
        */
        getColumnNames: function(tgt){
            affirmColIndex(affirmStmtOpen(this),0);
            if(!tgt) tgt = [];
            for(let i = 0; i < this.columnCount; ++i){
                tgt.push(api.sqlite3_column_name(this._pStmt, i));
            }
            return tgt;
        },
        /**
           If this statement has named bindable parameters and the
           given name matches one, its 1-based bind index is
           returned. If no match is found, 0 is returned. If it has no
           bindable parameters, the undefined value is returned.
        */
        getParamIndex: function(name){
            return (affirmStmtOpen(this).parameterCount
                    ? api.sqlite3_bind_parameter_index(this._pStmt, name)
                    : undefined);
        }
    }/*Stmt.prototype*/;

    /** OO binding's namespace. */
    const SQLite3 = {
        version: {
            lib: api.sqlite3_libversion(),
            ooApi: "0.0.1"
        },
        DB,
        Stmt,
        /**
           Reports whether a given compile-time option, named by the
           given argument. It has several distinct uses:

           If optName is an array then it is expected to be a list of
           compilation options and this function returns an object
           which maps each such option to true or false, indicating
           whether or not the given option was included in this
           build. That object is returned.

           If optName is an object, its keys are expected to be
           compilation options and this function sets each entry to
           true or false. That object is returned.

           If passed no arguments then it returns an object mapping
           all known compilation options to their compile-time values,
           or boolean true if they are defined with no value.

           In all other cases it returns true if the given option was
           active when when compiling the sqlite3 module, else false.

           Compile-time option names may optionally include their
           "SQLITE_" prefix. When it returns an object of all options,
           the prefix is elided.
        */
        compileOptionUsed: function f(optName){
            if(!arguments.length){
                if(!f._opt){
                    f._rx = /^([^=]+)=(.+)/;
                    f._rxInt = /^-?\d+$/;
                    f._opt = function(opt, rv){
                        const m = f._rx.exec(opt);
                        rv[0] = (m ? m[1] : opt);
                        rv[1] = m ? (f._rxInt.test(m[2]) ? +m[2] : m[2]) : true;
                    };                    
                }
                const rc = {}, ov = [0,0];
                let i = 0, k;
                while((k = api.sqlite3_compileoption_get(i++))){
                    f._opt(k,ov);
                    rc[ov[0]] = ov[1];
                }
                return rc;
            }
            else if(Array.isArray(optName)){
                const rc = {};
                optName.forEach((v)=>{
                    rc[v] = api.sqlite3_compileoption_used(v);
                });
                return rc;
            }
            else if('object' === typeof optName){
                Object.keys(optName).forEach((k)=> {
                    optName[k] = api.sqlite3_compileoption_used(k);
                });
                return optName;
            }
            return (
                'string'===typeof optName
            ) ? !!api.sqlite3_compileoption_used(optName) : false;
        }
    };

    namespace.sqlite3 = {
        api: api,
        SQLite3
    };
});
Added ext/fiddle/testing.css.






























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
textarea {
    font-family: monospace;
}
header {
    font-size: 130%;
    font-weight: bold;
}
.hidden, .initially-hidden {
    position: absolute !important;
    opacity: 0 !important;
    pointer-events: none !important;
    display: none !important;
}
fieldset.options {
    font-size: 75%;
}
fieldset > legend {
    padding: 0 0.5em;
}
span.labeled-input {
    padding: 0.25em;
    margin: 0.25em 0.5em;
    border-radius: 0.25em;
    white-space: nowrap;
    background: #0002;
}
.center { text-align: center; }
.error {
    color: red;
    background-color: yellow;
}
Added ext/fiddle/testing1.html.


































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<!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="emscripten.css"/>
    <link rel="stylesheet" href="testing.css"/>
    <title>sqlite3-api.js tests</title>
    <style></style>
  </head>
  <body>
    <header id='titlebar'><span>sqlite3-api.js tests</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>Everything on this page happens in the dev console.</div>
    <script src="sqlite3.js"></script>
    <script src="SqliteTestUtil.js"></script>
    <script src="testing1.js"></script>
  </body>
</html>
Added ext/fiddle/testing1.js.






















































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*
  2022-05-22

  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 test script for sqlite3-api.js.
*/
(function(){
    const T = self.SqliteTestUtil;
    const log = console.log.bind(console);

    const assert = function(condition, text) {
        if (!condition) {
            throw new Error('Assertion failed' + (text ? ': ' + text : ''));
        }
    };

    const test1 = function(db,sqlite3){
        const api = sqlite3.api;
        log("Basic sanity tests...");
        T.assert(db._pDb);
        let st = db.prepare("select 3 as a");
        //log("statement =",st);
        T.assert(st._pStmt)
            .assert(!st._mayGet)
            .assert('a' === st.getColumnName(0))
            .assert(st === db._statements[st._pStmt])
            .assert(1===st.columnCount)
            .assert(0===st.parameterCount)
            .mustThrow(()=>st.bind(1,null))
            .assert(true===st.step())
            .assert(3 === st.get(0))
            .mustThrow(()=>st.get(1))
            .mustThrow(()=>st.get(0,~api.SQLITE_INTEGER))
            .assert(3 === st.get(0,api.SQLITE_INTEGER))
            .assert(3 === st.getInt(0))
            .assert('3' === st.get(0,api.SQLITE_TEXT))
            .assert('3' === st.getString(0))
            .assert(3.0 === st.get(0,api.SQLITE_FLOAT))
            .assert(3.0 === st.getFloat(0))
            .assert(st.get(0,api.SQLITE_BLOB) instanceof Uint8Array)
            .assert(st.getBlob(0) instanceof Uint8Array)
            .assert(3 === st.get([])[0])
            .assert(3 === st.get({}).a)
            .assert(3 === st.getJSON(0))
            .assert(st._mayGet)
            .assert(false===st.step())
            .assert(!st._mayGet)
        ;
        let pId = st._pStmt;
        st.finalize();
        T.assert(!st._pStmt)
            .assert(!db._statements[pId]);

        let list = [];
        db.exec({
            sql:`CREATE TABLE t(a,b);
INSERT INTO t(a,b) VALUES(1,2),(3,4),(?,?);`,
            multi: true,
            saveSql: list,
            bind: [5,6]
        });
        T.assert(2 === list.length);
        //log("Exec'd SQL:", list);
        let counter = 0, colNames = [];
        db.exec("SELECT a a, b b FROM t",{
            rowMode: 'object',
            callback: function(row,stmt){
                if(!counter) stmt.getColumnNames(colNames);
                ++counter;
                T.assert(row.a%2 && row.a<6);
            }
        });
        assert(2 === colNames.length);
        assert('a' === colNames[0]);
        T.assert(3 === counter);
        db.exec("SELECT a a, b b FROM t",{
            rowMode: 'array',
            callback: function(row,stmt){
                ++counter;
                assert(Array.isArray(row));
                T.assert(0===row[1]%2 && row[1]<7);
            }
        });
        T.assert(6 === counter);
    };

    const testUDF = function(db){
        log("Testing UDF...");
        db.createFunction("foo",function(a,b){return a+b});
        T.assert(7===db.selectValue("select foo(3,4)")).
            assert(5===db.selectValue("select foo(3,?)",2)).
            assert(5===db.selectValue("select foo(?,?)",[1,4])).
            assert(5===db.selectValue("select foo($a,$b)",{$a:0,$b:5}));
        db.createFunction("bar", {
            arity: -1,
            callback: function(){
                var rc = 0;
                for(let i = 0; i < arguments.length; ++i) rc += arguments[i];
                return rc;
            }
        });

        log("Testing DB::selectValue() w/ UDF...");
        T.assert(0===db.selectValue("select bar()")).
            assert(1===db.selectValue("select bar(1)")).
            assert(3===db.selectValue("select bar(1,2)")).
            assert(-1===db.selectValue("select bar(1,2,-4)"));

        T.assert('hi' === db.selectValue("select ?",'hi')).
            assert(null===db.selectValue("select null")).
            assert(null === db.selectValue("select ?",null)).
            assert(null === db.selectValue("select ?",[null])).
            assert(null === db.selectValue("select $a",{$a:null}));
    };

    const runTests = function(Module){
        T.assert(Module._free instanceof Function).
            assert(Module.allocate instanceof Function).
            assert(Module.addFunction instanceof Function).
            assert(Module.removeFunction instanceof Function);
        const sqlite3 = Module.sqlite3;
        const api = sqlite3.api;
        const oo = sqlite3.SQLite3;
        console.log("Loaded module:",api.sqlite3_libversion(),
                    api.sqlite3_sourceid());
        log("Build options:",oo.compileOptionUsed());
        const db = new oo.DB();
        try {
            log("DB:",db.filename);
            [
                test1, testUDF
            ].forEach((f)=>f(db, sqlite3));
        }finally{
            db.close();
        }
        log("Total Test count:",T.counter);
    };

    initSqlite3Module(self.sqlite3TestModule).then(function(theModule){
        /** Use a timeout so that we are (hopefully) out from
            under the module init stack when our setup gets
            run. Just on principle, not because we _need_ to
            be. */
        //console.debug("theModule =",theModule);
        setTimeout(()=>runTests(theModule), 0);
    });
})();
Changes to src/alter.c.
1313
1314
1315
1316
1317
1318
1319

















1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339

1340
1341
1342
1343
1344
1345
1346
1347
    if( pStep->pSelect ){
      sqlite3SelectPrep(pParse, pStep->pSelect, &sNC);
      if( pParse->nErr ) rc = pParse->rc;
    }
    if( rc==SQLITE_OK && pStep->zTarget ){
      SrcList *pSrc = sqlite3TriggerStepSrc(pParse, pStep);
      if( pSrc ){

















        int i;
        for(i=0; i<pSrc->nSrc && rc==SQLITE_OK; i++){
          SrcItem *p = &pSrc->a[i];
          p->iCursor = pParse->nTab++;
          if( p->pSelect ){
            sqlite3SelectPrep(pParse, p->pSelect, 0);
            sqlite3ExpandSubquery(pParse, p);
            assert( i>0 );
            assert( pStep->pFrom->a[i-1].pSelect );
            sqlite3SelectPrep(pParse, pStep->pFrom->a[i-1].pSelect, 0);
          }else{
            p->pTab = sqlite3LocateTableItem(pParse, 0, p);
            if( p->pTab==0 ){
              rc = SQLITE_ERROR;
            }else{
              p->pTab->nTabRef++;
              rc = sqlite3ViewGetColumnNames(pParse, p->pTab);
            }
          }
        }

        if( rc==SQLITE_OK && db->mallocFailed ){
          rc = SQLITE_NOMEM;
        }
        sNC.pSrcList = pSrc;
        if( rc==SQLITE_OK && pStep->pWhere ){
          rc = sqlite3ResolveExprNames(&sNC, pStep->pWhere);
        }
        if( rc==SQLITE_OK ){







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
<
|
|
<
<
<
<
<
<
<
<
<
<
<



>
|







1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339

1340
1341











1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
    if( pStep->pSelect ){
      sqlite3SelectPrep(pParse, pStep->pSelect, &sNC);
      if( pParse->nErr ) rc = pParse->rc;
    }
    if( rc==SQLITE_OK && pStep->zTarget ){
      SrcList *pSrc = sqlite3TriggerStepSrc(pParse, pStep);
      if( pSrc ){
        Select *pSel = sqlite3SelectNew(
            pParse, pStep->pExprList, pSrc, 0, 0, 0, 0, 0, 0
        );
        if( pSel==0 ){
          pStep->pExprList = 0;
          pSrc = 0;
          rc = SQLITE_NOMEM;
        }else{
          sqlite3SelectPrep(pParse, pSel, 0);
          rc = pParse->nErr ? SQLITE_ERROR : SQLITE_OK;
          assert( pStep->pExprList==0 || pStep->pExprList==pSel->pEList );
          assert( pSrc==pSel->pSrc );
          if( pStep->pExprList ) pSel->pEList = 0;
          pSel->pSrc = 0;
          sqlite3SelectDelete(db, pSel);
        }
        if( pStep->pFrom ){
          int i;
          for(i=0; i<pStep->pFrom->nSrc && rc==SQLITE_OK; i++){
            SrcItem *p = &pStep->pFrom->a[i];

            if( p->pSelect ){
              sqlite3SelectPrep(pParse, p->pSelect, 0);











            }
          }
        }

        if(  db->mallocFailed ){
          rc = SQLITE_NOMEM;
        }
        sNC.pSrcList = pSrc;
        if( rc==SQLITE_OK && pStep->pWhere ){
          rc = sqlite3ResolveExprNames(&sNC, pStep->pWhere);
        }
        if( rc==SQLITE_OK ){
1784
1785
1786
1787
1788
1789
1790









1791
1792
1793
1794
1795
1796
1797
        if( isLegacy==0 ){
          rc = renameResolveTrigger(&sParse);
          if( rc==SQLITE_OK ){
            renameWalkTrigger(&sWalker, pTrigger);
            for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){
              if( pStep->zTarget && 0==sqlite3_stricmp(pStep->zTarget, zOld) ){
                renameTokenFind(&sParse, &sCtx, pStep->zTarget);









              }
            }
          }
        }
      }
#endif
    }







>
>
>
>
>
>
>
>
>







1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
        if( isLegacy==0 ){
          rc = renameResolveTrigger(&sParse);
          if( rc==SQLITE_OK ){
            renameWalkTrigger(&sWalker, pTrigger);
            for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){
              if( pStep->zTarget && 0==sqlite3_stricmp(pStep->zTarget, zOld) ){
                renameTokenFind(&sParse, &sCtx, pStep->zTarget);
              }
              if( pStep->pFrom ){
                int i;
                for(i=0; i<pStep->pFrom->nSrc; i++){
                  SrcItem *pItem = &pStep->pFrom->a[i];
                  if( 0==sqlite3_stricmp(pItem->zName, zOld) ){
                    renameTokenFind(&sParse, &sCtx, pItem->zName);
                  }
                }
              }
            }
          }
        }
      }
#endif
    }
Changes to src/expr.c.
1065
1066
1067
1068
1069
1070
1071

1072
1073
1074
1075
1076
1077
1078
  sqlite3 *db = pParse->db;
  assert( pToken );
  pNew = sqlite3ExprAlloc(db, TK_FUNCTION, pToken, 1);
  if( pNew==0 ){
    sqlite3ExprListDelete(db, pList); /* Avoid memory leak when malloc fails */
    return 0;
  }

  pNew->w.iOfst = (int)(pToken->z - pParse->zTail);
  if( pList 
   && pList->nExpr > pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG]
   && !pParse->nested
  ){
    sqlite3ErrorMsg(pParse, "too many arguments on function %T", pToken);
  }







>







1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
  sqlite3 *db = pParse->db;
  assert( pToken );
  pNew = sqlite3ExprAlloc(db, TK_FUNCTION, pToken, 1);
  if( pNew==0 ){
    sqlite3ExprListDelete(db, pList); /* Avoid memory leak when malloc fails */
    return 0;
  }
  assert( !ExprHasProperty(pNew, EP_InnerON|EP_OuterON) );
  pNew->w.iOfst = (int)(pToken->z - pParse->zTail);
  if( pList 
   && pList->nExpr > pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG]
   && !pParse->nested
  ){
    sqlite3ErrorMsg(pParse, "too many arguments on function %T", pToken);
  }
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
#ifndef SQLITE_OMIT_WINDOWFUNC
   || ExprHasProperty(p, EP_WinFunc)
#endif
  ){
    nSize = EXPR_FULLSIZE;
  }else{
    assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
    assert( !ExprHasProperty(p, EP_FromJoin) ); 
    assert( !ExprHasProperty(p, EP_MemToken) );
    assert( !ExprHasVVAProperty(p, EP_NoReduce) );
    if( p->pLeft || p->x.pList ){
      nSize = EXPR_REDUCEDSIZE | EP_Reduced;
    }else{
      assert( p->pRight==0 );
      nSize = EXPR_TOKENONLYSIZE | EP_TokenOnly;







|







1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
#ifndef SQLITE_OMIT_WINDOWFUNC
   || ExprHasProperty(p, EP_WinFunc)
#endif
  ){
    nSize = EXPR_FULLSIZE;
  }else{
    assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
    assert( !ExprHasProperty(p, EP_OuterON) ); 
    assert( !ExprHasProperty(p, EP_MemToken) );
    assert( !ExprHasVVAProperty(p, EP_NoReduce) );
    if( p->pLeft || p->x.pList ){
      nSize = EXPR_REDUCEDSIZE | EP_Reduced;
    }else{
      assert( p->pRight==0 );
      nSize = EXPR_TOKENONLYSIZE | EP_TokenOnly;
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
** malformed schema error.
*/
static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){

  /* If pWalker->eCode is 2 then any term of the expression that comes from
  ** the ON or USING clauses of an outer join disqualifies the expression
  ** from being considered constant. */
  if( pWalker->eCode==2 && ExprHasProperty(pExpr, EP_FromJoin) ){
    pWalker->eCode = 0;
    return WRC_Abort;
  }

  switch( pExpr->op ){
    /* Consider functions to be constant if all their arguments are constant
    ** and either pWalker->eCode==4 or 5 or the function has the







|







2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
** malformed schema error.
*/
static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){

  /* If pWalker->eCode is 2 then any term of the expression that comes from
  ** the ON or USING clauses of an outer join disqualifies the expression
  ** from being considered constant. */
  if( pWalker->eCode==2 && ExprHasProperty(pExpr, EP_OuterON) ){
    pWalker->eCode = 0;
    return WRC_Abort;
  }

  switch( pExpr->op ){
    /* Consider functions to be constant if all their arguments are constant
    ** and either pWalker->eCode==4 or 5 or the function has the
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
**        clause, not an ON clause.
*/
int sqlite3ExprIsTableConstraint(Expr *pExpr, const SrcItem *pSrc){
  if( pSrc->fg.jointype & JT_LTORJ ){
    return 0;  /* rule (3) */
  }
  if( pSrc->fg.jointype & JT_LEFT ){
    if( !ExprHasProperty(pExpr, EP_FromJoin) ) return 0;  /* rule (4a) */
    if( pExpr->w.iJoin!=pSrc->iCursor ) return 0;         /* rule (4b) */
  }else{
    if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0;   /* rule (5) */
  }
  return sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor); /* rules (1), (2) */
}


/*
** sqlite3WalkExpr() callback used by sqlite3ExprIsConstantOrGroupBy().







|


|







2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
**        clause, not an ON clause.
*/
int sqlite3ExprIsTableConstraint(Expr *pExpr, const SrcItem *pSrc){
  if( pSrc->fg.jointype & JT_LTORJ ){
    return 0;  /* rule (3) */
  }
  if( pSrc->fg.jointype & JT_LEFT ){
    if( !ExprHasProperty(pExpr, EP_OuterON) ) return 0;   /* rule (4a) */
    if( pExpr->w.iJoin!=pSrc->iCursor ) return 0;         /* rule (4b) */
  }else{
    if( ExprHasProperty(pExpr, EP_OuterON) ) return 0;    /* rule (5) */
  }
  return sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor); /* rules (1), (2) */
}


/*
** sqlite3WalkExpr() callback used by sqlite3ExprIsConstantOrGroupBy().
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
  int eType = 0;                        /* Type of RHS table. IN_INDEX_* */
  int iTab;                             /* Cursor of the RHS table */
  int mustBeUnique;                     /* True if RHS must be unique */
  Vdbe *v = sqlite3GetVdbe(pParse);     /* Virtual machine being coded */

  assert( pX->op==TK_IN );
  mustBeUnique = (inFlags & IN_INDEX_LOOP)!=0;
  if( pX->iTable && (inFlags & IN_INDEX_REUSE_CUR)!=0 ){
    iTab = pX->iTable;
  }else{
    iTab = pParse->nTab++;
  }

  /* If the RHS of this IN(...) operator is a SELECT, and if it matters 
  ** whether or not the SELECT result contains NULL values, check whether
  ** or not NULL is actually possible (it may not be, for example, due 
  ** to NOT NULL constraints in the schema). If no NULL values are possible,
  ** set prRhsHasNull to 0 before continuing.  */
  if( prRhsHasNull && ExprUseXSelect(pX) ){







<
<
<
|
<







2742
2743
2744
2745
2746
2747
2748



2749

2750
2751
2752
2753
2754
2755
2756
  int eType = 0;                        /* Type of RHS table. IN_INDEX_* */
  int iTab;                             /* Cursor of the RHS table */
  int mustBeUnique;                     /* True if RHS must be unique */
  Vdbe *v = sqlite3GetVdbe(pParse);     /* Virtual machine being coded */

  assert( pX->op==TK_IN );
  mustBeUnique = (inFlags & IN_INDEX_LOOP)!=0;



  iTab = pParse->nTab++;


  /* If the RHS of this IN(...) operator is a SELECT, and if it matters 
  ** whether or not the SELECT result contains NULL values, check whether
  ** or not NULL is actually possible (it may not be, for example, due 
  ** to NOT NULL constraints in the schema). If no NULL values are possible,
  ** set prRhsHasNull to 0 before continuing.  */
  if( prRhsHasNull && ExprUseXSelect(pX) ){
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
      if( ExprUseXSelect(pExpr) ){
        ExplainQueryPlan((pParse, 0, "REUSE LIST SUBQUERY %d",
              pExpr->x.pSelect->selId));
      }
      assert( ExprUseYSub(pExpr) );
      sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn,
                        pExpr->y.sub.iAddr);
      if( iTab!=pExpr->iTable ){
        sqlite3VdbeAddOp2(v, OP_OpenDup, iTab, pExpr->iTable);
      }
      sqlite3VdbeJumpHere(v, addrOnce);
      return;
    }

    /* Begin coding the subroutine */
    assert( !ExprUseYWin(pExpr) );
    ExprSetProperty(pExpr, EP_Subrtn);







|
|
<







3076
3077
3078
3079
3080
3081
3082
3083
3084

3085
3086
3087
3088
3089
3090
3091
      if( ExprUseXSelect(pExpr) ){
        ExplainQueryPlan((pParse, 0, "REUSE LIST SUBQUERY %d",
              pExpr->x.pSelect->selId));
      }
      assert( ExprUseYSub(pExpr) );
      sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn,
                        pExpr->y.sub.iAddr);
      assert( iTab!=pExpr->iTable );
      sqlite3VdbeAddOp2(v, OP_OpenDup, iTab, pExpr->iTable);

      sqlite3VdbeJumpHere(v, addrOnce);
      return;
    }

    /* Begin coding the subroutine */
    assert( !ExprUseYWin(pExpr) );
    ExprSetProperty(pExpr, EP_Subrtn);
5074
5075
5076
5077
5078
5079
5080
5081
5082
5083
5084
5085
5086
5087
5088
5089
    if( xJump ){
      xJump(pParse, &exprAnd, dest, jumpIfNull);
    }else{
      /* Mark the expression is being from the ON or USING clause of a join
      ** so that the sqlite3ExprCodeTarget() routine will not attempt to move
      ** it into the Parse.pConstExpr list.  We should use a new bit for this,
      ** for clarity, but we are out of bits in the Expr.flags field so we
      ** have to reuse the EP_FromJoin bit.  Bummer. */
      pDel->flags |= EP_FromJoin;
      sqlite3ExprCodeTarget(pParse, &exprAnd, dest);
    }
    sqlite3ReleaseTempReg(pParse, regFree1);
  }
  sqlite3ExprDelete(db, pDel);

  /* Ensure adequate test coverage */







|
|







5070
5071
5072
5073
5074
5075
5076
5077
5078
5079
5080
5081
5082
5083
5084
5085
    if( xJump ){
      xJump(pParse, &exprAnd, dest, jumpIfNull);
    }else{
      /* Mark the expression is being from the ON or USING clause of a join
      ** so that the sqlite3ExprCodeTarget() routine will not attempt to move
      ** it into the Parse.pConstExpr list.  We should use a new bit for this,
      ** for clarity, but we are out of bits in the Expr.flags field so we
      ** have to reuse the EP_OuterON bit.  Bummer. */
      pDel->flags |= EP_OuterON;
      sqlite3ExprCodeTarget(pParse, &exprAnd, dest);
    }
    sqlite3ReleaseTempReg(pParse, regFree1);
  }
  sqlite3ExprDelete(db, pDel);

  /* Ensure adequate test coverage */
5760
5761
5762
5763
5764
5765
5766
5767
5768
5769
5770
5771
5772
5773
5774
** This routine controls an optimization.  False positives (setting
** pWalker->eCode to 1 when it should not be) are deadly, but false-negatives
** (never setting pWalker->eCode) is a harmless missed optimization.
*/
static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
  testcase( pExpr->op==TK_AGG_COLUMN );
  testcase( pExpr->op==TK_AGG_FUNCTION );
  if( ExprHasProperty(pExpr, EP_FromJoin) ) return WRC_Prune;
  switch( pExpr->op ){
    case TK_ISNOT:
    case TK_ISNULL:
    case TK_NOTNULL:
    case TK_IS:
    case TK_OR:
    case TK_VECTOR:







|







5756
5757
5758
5759
5760
5761
5762
5763
5764
5765
5766
5767
5768
5769
5770
** This routine controls an optimization.  False positives (setting
** pWalker->eCode to 1 when it should not be) are deadly, but false-negatives
** (never setting pWalker->eCode) is a harmless missed optimization.
*/
static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
  testcase( pExpr->op==TK_AGG_COLUMN );
  testcase( pExpr->op==TK_AGG_FUNCTION );
  if( ExprHasProperty(pExpr, EP_OuterON) ) return WRC_Prune;
  switch( pExpr->op ){
    case TK_ISNOT:
    case TK_ISNULL:
    case TK_NOTNULL:
    case TK_IS:
    case TK_OR:
    case TK_VECTOR:
5857
5858
5859
5860
5861
5862
5863
5864
5865
5866
5867
5868
5869
5870
5871
** False negatives are acceptable.  In other words, it is ok to return
** zero even if expression p will never be true of every column of iTab
** is NULL.  A false negative is merely a missed optimization opportunity.
**
** False positives are not allowed, however.  A false positive may result
** in an incorrect answer.
**
** Terms of p that are marked with EP_FromJoin (and hence that come from
** the ON or USING clauses of OUTER JOINS) are excluded from the analysis.
**
** This routine is used to check if a LEFT JOIN can be converted into
** an ordinary JOIN.  The p argument is the WHERE clause.  If the WHERE
** clause requires that some column of the right table of the LEFT JOIN
** be non-NULL, then the LEFT JOIN can be safely converted into an
** ordinary join.







|







5853
5854
5855
5856
5857
5858
5859
5860
5861
5862
5863
5864
5865
5866
5867
** False negatives are acceptable.  In other words, it is ok to return
** zero even if expression p will never be true of every column of iTab
** is NULL.  A false negative is merely a missed optimization opportunity.
**
** False positives are not allowed, however.  A false positive may result
** in an incorrect answer.
**
** Terms of p that are marked with EP_OuterON (and hence that come from
** the ON or USING clauses of OUTER JOINS) are excluded from the analysis.
**
** This routine is used to check if a LEFT JOIN can be converted into
** an ordinary JOIN.  The p argument is the WHERE clause.  If the WHERE
** clause requires that some column of the right table of the LEFT JOIN
** be non-NULL, then the LEFT JOIN can be safely converted into an
** ordinary join.
Changes to src/func.c.
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
    }
    ans = log(x)/b;
  }else{
    ans = log(x);
    switch( SQLITE_PTR_TO_INT(sqlite3_user_data(context)) ){
      case 1:
        /* Convert from natural logarithm to log base 10 */
        ans *= 1.0/M_LN10;
        break;
      case 2:
        /* Convert from natural logarithm to log base 2 */
        ans *= 1.0/M_LN2;
        break;
      default:
        break;
    }
  }
  sqlite3_result_double(context, ans);
}







|



|







2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
    }
    ans = log(x)/b;
  }else{
    ans = log(x);
    switch( SQLITE_PTR_TO_INT(sqlite3_user_data(context)) ){
      case 1:
        /* Convert from natural logarithm to log base 10 */
        ans /= M_LN10;
        break;
      case 2:
        /* Convert from natural logarithm to log base 2 */
        ans /= M_LN2;
        break;
      default:
        break;
    }
  }
  sqlite3_result_double(context, ans);
}
Changes to src/loadext.c.
499
500
501
502
503
504
505
506
507
508
509
510

511
512
513
514
515
516
517
  0,
  0,
  0,
#endif
  /* Version 3.39.0 and later */
#ifndef SQLITE_OMIT_DESERIALIZE
  sqlite3_deserialize,
  sqlite3_serialize
#else
  0,
  0
#endif

};

/* True if x is the directory separator character
*/
#if SQLITE_OS_WIN
# define DirSep(X)  ((X)=='/'||(X)=='\\')
#else







|


|

>







499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
  0,
  0,
  0,
#endif
  /* Version 3.39.0 and later */
#ifndef SQLITE_OMIT_DESERIALIZE
  sqlite3_deserialize,
  sqlite3_serialize,
#else
  0,
  0,
#endif
  sqlite3_db_name
};

/* True if x is the directory separator character
*/
#if SQLITE_OS_WIN
# define DirSep(X)  ((X)=='/'||(X)=='\\')
#else
Changes to src/main.c.
4621
4622
4623
4624
4625
4626
4627


















4628
4629
4630
4631
4632
4633
4634
/*
** Return the Btree pointer identified by zDbName.  Return NULL if not found.
*/
Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){
  int iDb = zDbName ? sqlite3FindDbName(db, zDbName) : 0;
  return iDb<0 ? 0 : db->aDb[iDb].pBt;
}



















/*
** Return the filename of the database associated with a database
** connection.
*/
const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){
  Btree *pBt;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
/*
** Return the Btree pointer identified by zDbName.  Return NULL if not found.
*/
Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){
  int iDb = zDbName ? sqlite3FindDbName(db, zDbName) : 0;
  return iDb<0 ? 0 : db->aDb[iDb].pBt;
}

/*
** Return the name of the N-th database schema.  Return NULL if N is out
** of range.
*/
const char *sqlite3_db_name(sqlite3 *db, int N){
#ifdef SQLITE_ENABLE_API_ARMOR
  if( !sqlite3SafetyCheckOk(db) ){
    (void)SQLITE_MISUSE_BKPT;
    return 0;
  }
#endif
  if( N<0 || N>=db->nDb ){
    return 0;
  }else{
    return db->aDb[N].zDbSName;
  }
}

/*
** Return the filename of the database associated with a database
** connection.
*/
const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){
  Btree *pBt;
Changes to src/os.h.
34
35
36
37
38
39
40







41
42
43
44
45
46
47
#endif

/* Maximum pathname length.  Note: FILENAME_MAX defined by stdio.h
*/
#ifndef SQLITE_MAX_PATHLEN
# define SQLITE_MAX_PATHLEN FILENAME_MAX
#endif








/*
** The default size of a disk sector
*/
#ifndef SQLITE_DEFAULT_SECTOR_SIZE
# define SQLITE_DEFAULT_SECTOR_SIZE 4096
#endif







>
>
>
>
>
>
>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#endif

/* Maximum pathname length.  Note: FILENAME_MAX defined by stdio.h
*/
#ifndef SQLITE_MAX_PATHLEN
# define SQLITE_MAX_PATHLEN FILENAME_MAX
#endif

/* Maximum number of symlinks that will be resolved while trying to
** expand a filename in xFullPathname() in the VFS.
*/
#ifndef SQLITE_MAX_SYMLINK
# define SQLITE_MAX_SYMLINK 200
#endif

/*
** The default size of a disk sector
*/
#ifndef SQLITE_DEFAULT_SECTOR_SIZE
# define SQLITE_DEFAULT_SECTOR_SIZE 4096
#endif
Changes to src/os_unix.c.
6469
6470
6471
6472
6473
6474
6475
6476
6477
6478
6479




6480
6481
6482

6483
6484
6485
6486
6487
6488
6489
















6490
6491
6492
6493
6494
6495
6496
6497
6498
6499
6500
6501
6502
6503
6504
6505
6506
6507
6508
6509
6510
6511
6512
6513
6514
6515
6516
6517
6518
6519











6520
6521
6522
6523




6524
6525

6526
6527



6528

6529
6530
6531
6532
6533
6534
6535
6536

6537





6538
6539


6540
6541
6542
6543
6544



6545
6546
6547
6548
6549


6550
6551

6552
6553
6554
6555

6556
6557
6558
6559
6560
6561
6562
6563
6564
6565
6566
6567
6568
6569
6570
6571
6572
6573
6574
6575
6576
6577
6578
6579
6580
6581
6582
6583
6584
6585
6586
6587
6588
6589
6590
6591
6592
6593
6594
6595
6596
6597
6598
6599
6600
6601
6602
6603
6604
6605
6606
6607
6608
6609
6610
6611
6612
6613
6614
6615
6616
6617
6618
6619
6620
6621
6622
6623
6624
6625
6626
6627
6628
6629
6630
6631
6632
6633
6634
6635
6636
6637
6638
6639
6640
6641
6642
6643
6644
6645
6646
6647
6648
6649
6650
6651
6652
6653
6654
6655
6656
6657
6658
  }else{
    *pResOut = osAccess(zPath, W_OK|R_OK)==0;
  }
  return SQLITE_OK;
}

/*
** If the last component of the pathname in z[0]..z[j-1] is something
** other than ".." then back it out and return true.  If the last
** component is empty or if it is ".." then return false.
*/




static int unixBackupDir(const char *z, int *pJ){
  int j = *pJ;
  int i;

  if( j<=0 ) return 0;
  for(i=j-1; i>0 && z[i-1]!='/'; i--){}
  if( i==0 ) return 0;
  if( z[i]=='.' && i==j-2 && z[i+1]=='.' ) return 0;
  *pJ = i-1;
  return 1;
}

















/*
** Convert a relative pathname into a full pathname.  Also
** simplify the pathname as follows:
**
**    Remove all instances of /./
**    Remove all isntances of /X/../ for any X
*/
static int mkFullPathname(
  const char *zPath,              /* Input path */
  char *zOut,                     /* Output buffer */
  int nOut                        /* Allocated size of buffer zOut */
){
  int nPath = sqlite3Strlen30(zPath);
  int iOff = 0;
  int i, j;
  if( zPath[0]!='/' ){
    if( osGetcwd(zOut, nOut-2)==0 ){
      return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
    }
    iOff = sqlite3Strlen30(zOut);
    zOut[iOff++] = '/';
  }
  if( (iOff+nPath+1)>nOut ){
    /* SQLite assumes that xFullPathname() nul-terminates the output buffer
    ** even if it returns an error.  */
    zOut[iOff] = '\0';
    return SQLITE_CANTOPEN_BKPT;
  }
  sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath);












  /* Remove duplicate '/' characters.  Except, two // at the beginning
  ** of a pathname is allowed since this is important on windows. */
  for(i=j=1; zOut[i]; i++){




    zOut[j++] = zOut[i];
    while( zOut[i]=='/' && zOut[i+1]=='/' ) i++;

  }
  zOut[j] = 0;





  assert( zOut[0]=='/' );
  for(i=j=0; zOut[i]; i++){
    if( zOut[i]=='/' ){
      /* Skip over internal "/." directory components */
      if( zOut[i+1]=='.' && zOut[i+2]=='/' ){
        i += 1;
        continue;
      }







      /* If this is a "/.." directory component then back out the
      ** previous term of the directory if it is something other than "..".


      */
      if( zOut[i+1]=='.'
       && zOut[i+2]=='.'
       && zOut[i+3]=='/'
       && unixBackupDir(zOut, &j)



      ){
        i += 2;
        continue;
      }
    }


    if( ALWAYS(j>=0) ) zOut[j] = zOut[i];
    j++;

  }
  if( NEVER(j==0) ) zOut[j++] = '/';
  zOut[j] = 0;
  return SQLITE_OK;

}

/*
** Turn a relative pathname into a full pathname. The relative path
** is stored as a nul-terminated string in the buffer pointed to by
** zPath. 
**
** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes 
** (in this case, MAX_PATHNAME bytes). The full-path is written to
** this buffer before returning.
*/
static int unixFullPathname(
  sqlite3_vfs *pVfs,            /* Pointer to vfs object */
  const char *zPath,            /* Possibly relative input path */
  int nOut,                     /* Size of output buffer in bytes */
  char *zOut                    /* Output buffer */
){
#if !defined(HAVE_READLINK) || !defined(HAVE_LSTAT)
  return mkFullPathname(zPath, zOut, nOut);
#else
  int rc = SQLITE_OK;
  int nByte;
  int nLink = 0;                /* Number of symbolic links followed so far */
  const char *zIn = zPath;      /* Input path for each iteration of loop */
  char *zDel = 0;

  assert( pVfs->mxPathname==MAX_PATHNAME );
  UNUSED_PARAMETER(pVfs);

  /* It's odd to simulate an io-error here, but really this is just
  ** using the io-error infrastructure to test that SQLite handles this
  ** function failing. This function could fail if, for example, the
  ** current working directory has been unlinked.
  */
  SimulateIOError( return SQLITE_ERROR );

  do {

    /* Call stat() on path zIn. Set bLink to true if the path is a symbolic
    ** link, or false otherwise.  */
    int bLink = 0;
    struct stat buf;
    if( osLstat(zIn, &buf)!=0 ){
      if( errno!=ENOENT ){
        rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn);
      }
    }else{
      bLink = S_ISLNK(buf.st_mode);
    }

    if( bLink ){
      nLink++;
      if( zDel==0 ){
        zDel = sqlite3_malloc(nOut);
        if( zDel==0 ) rc = SQLITE_NOMEM_BKPT;
      }else if( nLink>=SQLITE_MAX_SYMLINKS ){
        rc = SQLITE_CANTOPEN_BKPT;
      }

      if( rc==SQLITE_OK ){
        nByte = osReadlink(zIn, zDel, nOut-1);
        if( nByte<0 ){
          rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn);
        }else{
          if( zDel[0]!='/' ){
            int n;
            for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--);
            if( nByte+n+1>nOut ){
              rc = SQLITE_CANTOPEN_BKPT;
            }else{
              memmove(&zDel[n], zDel, nByte+1);
              memcpy(zDel, zIn, n);
              nByte += n;
            }
          }
          zDel[nByte] = '\0';
        }
      }

      zIn = zDel;
    }

    assert( rc!=SQLITE_OK || zIn!=zOut || zIn[0]=='/' );
    if( rc==SQLITE_OK && zIn!=zOut ){
      rc = mkFullPathname(zIn, zOut, nOut);
    }
    if( bLink==0 ) break;
    zIn = zOut;
  }while( rc==SQLITE_OK );

  sqlite3_free(zDel);
  if( rc==SQLITE_OK && nLink ) rc = SQLITE_OK_SYMLINK;
  return rc;
#endif   /* HAVE_READLINK && HAVE_LSTAT */
}


#ifndef SQLITE_OMIT_LOAD_EXTENSION
/*
** Interfaces for opening a shared library, finding entry points
** within the shared library, and closing the shared library.
*/
#include <dlfcn.h>







|
<
<

>
>
>
>
|
|
|
>
|
<
|
<
<
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
|
<
|

<
<

|
<
<
|
|

|
>
>
>
>
>
>
>
>
>
>
>
|
<
<
<
>
>
>
>
|
<
>
|
|
>
>
>
|
>
|
<
<
<
<
|
<
|
>
|
>
>
>
>
>
|
<
>
>
|
<
<
<
<
>
>
>
|
|
|
<
<
>
>
|
<
>
|
<
|
<
>

















<
<
<
<
<
<
<
<
|
<

|
<
<
<
<
<
<
|
<
<
<
<
|
<
<
<
<
<
<
|
<
|
<
<
|
<
<
|
<
<
|
<
<
<
|
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
|
<
|
|
<
<
<
<
<
|
<
|
<
|
|
<

<







6469
6470
6471
6472
6473
6474
6475
6476


6477
6478
6479
6480
6481
6482
6483
6484
6485
6486

6487


6488
6489
6490
6491
6492
6493
6494
6495
6496
6497
6498
6499
6500
6501
6502
6503
6504
6505
6506







6507







6508

6509
6510


6511
6512


6513
6514
6515
6516
6517
6518
6519
6520
6521
6522
6523
6524
6525
6526
6527
6528



6529
6530
6531
6532
6533

6534
6535
6536
6537
6538
6539
6540
6541
6542




6543

6544
6545
6546
6547
6548
6549
6550
6551
6552

6553
6554
6555




6556
6557
6558
6559
6560
6561


6562
6563
6564

6565
6566

6567

6568
6569
6570
6571
6572
6573
6574
6575
6576
6577
6578
6579
6580
6581
6582
6583
6584
6585








6586

6587
6588






6589




6590






6591

6592


6593


6594


6595



6596










6597




6598

6599
6600





6601

6602

6603
6604

6605

6606
6607
6608
6609
6610
6611
6612
  }else{
    *pResOut = osAccess(zPath, W_OK|R_OK)==0;
  }
  return SQLITE_OK;
}

/*
** A pathname under construction


*/
typedef struct DbPath DbPath;
struct DbPath {
  int rc;           /* Non-zero following any error */
  int nSymlink;     /* Number of symlinks resolved */
  char *zOut;       /* Write the pathname here */
  int nOut;         /* Bytes of space available to zOut[] */
  int nUsed;        /* Bytes of zOut[] currently being used */
};


/* Forward reference */


static void appendAllPathElements(DbPath*,const char*);

/*
** Append a single path element to the DbPath under construction
*/
static void appendOnePathElement(
  DbPath *pPath,       /* Path under construction, to which to append zName */
  const char *zName,   /* Name to append to pPath.  Not zero-terminated */
  int nName            /* Number of significant bytes in zName */
){
  assert( nName>0 );
  assert( zName!=0 );
  if( zName[0]=='.' ){
    if( nName==1 ) return;
    if( zName[1]=='.' && nName==2 ){
      if( pPath->nUsed<=1 ){
        pPath->rc = SQLITE_ERROR;
        return;
      }







      assert( pPath->zOut[0]=='/' );







      while( pPath->zOut[--pPath->nUsed]!='/' ){}

      return;
    }


  }
  if( pPath->nUsed + nName + 2 >= pPath->nOut ){


    pPath->rc = SQLITE_ERROR;
    return;
  }
  pPath->zOut[pPath->nUsed++] = '/';
  memcpy(&pPath->zOut[pPath->nUsed], zName, nName);
  pPath->nUsed += nName;
#if defined(HAVE_READLINK) && defined(HAVE_LSTAT)
  if( pPath->rc==SQLITE_OK ){
    const char *zIn;
    struct stat buf;
    pPath->zOut[pPath->nUsed] = 0;
    zIn = pPath->zOut;
    if( osLstat(zIn, &buf)!=0 ){
      if( errno!=ENOENT ){
        pPath->rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn);
      }



    }else if( S_ISLNK(buf.st_mode) ){
      ssize_t got;
      char zLnk[SQLITE_MAX_PATHLEN+2];
      if( pPath->nSymlink++ > SQLITE_MAX_SYMLINK ){
        pPath->rc = SQLITE_CANTOPEN_BKPT;

        return;
      }
      got = osReadlink(zIn, zLnk, sizeof(zLnk)-2);
      if( got<=0 || got>=(ssize_t)sizeof(zLnk)-2 ){
        pPath->rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn);
        return;
      }
      zLnk[got] = 0;
      if( zLnk[0]=='/' ){




        pPath->nUsed = 0;

      }else{
        pPath->nUsed -= nName + 1;
      }
      appendAllPathElements(pPath, zLnk);
    }
  }
#endif
}


/*
** Append all path elements in zPath to the DbPath under construction.
*/




static void appendAllPathElements(
  DbPath *pPath,       /* Path under construction, to which to append zName */
  const char *zPath    /* Path to append to pPath.  Is zero-terminated */
){
  int i = 0;
  int j = 0;


  do{
    while( zPath[i] && zPath[i]!='/' ){ i++; }
    if( i>j ){

      appendOnePathElement(pPath, &zPath[j], i-j);
    }

    j = i+1;

  }while( zPath[i++] );
}

/*
** Turn a relative pathname into a full pathname. The relative path
** is stored as a nul-terminated string in the buffer pointed to by
** zPath. 
**
** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes 
** (in this case, MAX_PATHNAME bytes). The full-path is written to
** this buffer before returning.
*/
static int unixFullPathname(
  sqlite3_vfs *pVfs,            /* Pointer to vfs object */
  const char *zPath,            /* Possibly relative input path */
  int nOut,                     /* Size of output buffer in bytes */
  char *zOut                    /* Output buffer */
){








  DbPath path;

  UNUSED_PARAMETER(pVfs);
  path.rc = 0;






  path.nUsed = 0;




  path.nSymlink = 0;






  path.nOut = nOut;

  path.zOut = zOut;


  if( zPath[0]!='/' ){


    char zPwd[SQLITE_MAX_PATHLEN+2];


    if( osGetcwd(zPwd, sizeof(zPwd)-2)==0 ){



      return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);










    }




    appendAllPathElements(&path, zPwd);

  }
  appendAllPathElements(&path, zPath);





  zOut[path.nUsed] = 0;

  if( path.rc || path.nUsed<2 ) return SQLITE_CANTOPEN_BKPT;

  if( path.nSymlink ) return SQLITE_OK_SYMLINK;
  return SQLITE_OK;

}


#ifndef SQLITE_OMIT_LOAD_EXTENSION
/*
** Interfaces for opening a shared library, finding entry points
** within the shared library, and closing the shared library.
*/
#include <dlfcn.h>
Changes to src/parse.y.
935
936
937
938
939
940
941










942

943
944
945
946
947
948
949
950
951
952
953
954
955
956
957










958

959
960
961
962
963
964
965

////////////////////////// The UPDATE command ////////////////////////////////
//
%if SQLITE_ENABLE_UPDATE_DELETE_LIMIT || SQLITE_UDL_CAPABLE_PARSER
cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F)
        where_opt_ret(W) orderby_opt(O) limit_opt(L).  {
  sqlite3SrcListIndexedBy(pParse, X, &I);










  X = sqlite3SrcListAppendList(pParse, X, F);

  sqlite3ExprListCheckLength(pParse,Y,"set list"); 
#ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
  if( O || L ){
    updateDeleteLimitError(pParse,O,L);
    O = 0;
    L = 0;
  }
#endif
  sqlite3Update(pParse,X,Y,W,R,O,L,0);
}
%else
cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F)
        where_opt_ret(W). {
  sqlite3SrcListIndexedBy(pParse, X, &I);
  sqlite3ExprListCheckLength(pParse,Y,"set list"); 










  X = sqlite3SrcListAppendList(pParse, X, F);

  sqlite3Update(pParse,X,Y,W,R,0,0,0);
}
%endif



%type setlist {ExprList*}







>
>
>
>
>
>
>
>
>
>
|
>















>
>
>
>
>
>
>
>
>
>
|
>







935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987

////////////////////////// The UPDATE command ////////////////////////////////
//
%if SQLITE_ENABLE_UPDATE_DELETE_LIMIT || SQLITE_UDL_CAPABLE_PARSER
cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F)
        where_opt_ret(W) orderby_opt(O) limit_opt(L).  {
  sqlite3SrcListIndexedBy(pParse, X, &I);
  if( F ){
    SrcList *pFromClause = F;
    if( pFromClause->nSrc>1 ){
      Select *pSubquery;
      Token as;
      pSubquery = sqlite3SelectNew(pParse,0,pFromClause,0,0,0,0,SF_NestedFrom,0);
      as.n = 0;
      as.z = 0;
      pFromClause = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&as,pSubquery,0);
    }
    X = sqlite3SrcListAppendList(pParse, X, pFromClause);
  }
  sqlite3ExprListCheckLength(pParse,Y,"set list"); 
#ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
  if( O || L ){
    updateDeleteLimitError(pParse,O,L);
    O = 0;
    L = 0;
  }
#endif
  sqlite3Update(pParse,X,Y,W,R,O,L,0);
}
%else
cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F)
        where_opt_ret(W). {
  sqlite3SrcListIndexedBy(pParse, X, &I);
  sqlite3ExprListCheckLength(pParse,Y,"set list"); 
  if( F ){
    SrcList *pFromClause = F;
    if( pFromClause->nSrc>1 ){
      Select *pSubquery;
      Token as;
      pSubquery = sqlite3SelectNew(pParse,0,pFromClause,0,0,0,0,SF_NestedFrom,0);
      as.n = 0;
      as.z = 0;
      pFromClause = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&as,pSubquery,0);
    }
    X = sqlite3SrcListAppendList(pParse, X, pFromClause);
  }
  sqlite3Update(pParse,X,Y,W,R,0,0,0);
}
%endif



%type setlist {ExprList*}
1229
1230
1231
1232
1233
1234
1235








1236
1237
1238
1239
1240
1241
1242
  A = sqlite3PExpr(pParse,TK_IS,A,Y);
  binaryToUnaryIfNull(pParse, Y, A, TK_ISNULL);
}
expr(A) ::= expr(A) IS NOT expr(Y). {
  A = sqlite3PExpr(pParse,TK_ISNOT,A,Y);
  binaryToUnaryIfNull(pParse, Y, A, TK_NOTNULL);
}









expr(A) ::= NOT(B) expr(X).  
              {A = sqlite3PExpr(pParse, @B, X, 0);/*A-overwrites-B*/}
expr(A) ::= BITNOT(B) expr(X).
              {A = sqlite3PExpr(pParse, @B, X, 0);/*A-overwrites-B*/}
expr(A) ::= PLUS|MINUS(B) expr(X). [BITNOT] {
  A = sqlite3PExpr(pParse, @B==TK_PLUS ? TK_UPLUS : TK_UMINUS, X, 0);







>
>
>
>
>
>
>
>







1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
  A = sqlite3PExpr(pParse,TK_IS,A,Y);
  binaryToUnaryIfNull(pParse, Y, A, TK_ISNULL);
}
expr(A) ::= expr(A) IS NOT expr(Y). {
  A = sqlite3PExpr(pParse,TK_ISNOT,A,Y);
  binaryToUnaryIfNull(pParse, Y, A, TK_NOTNULL);
}
expr(A) ::= expr(A) IS NOT DISTINCT FROM expr(Y).     {
  A = sqlite3PExpr(pParse,TK_IS,A,Y);
  binaryToUnaryIfNull(pParse, Y, A, TK_ISNULL);
}
expr(A) ::= expr(A) IS DISTINCT FROM expr(Y). {
  A = sqlite3PExpr(pParse,TK_ISNOT,A,Y);
  binaryToUnaryIfNull(pParse, Y, A, TK_NOTNULL);
}

expr(A) ::= NOT(B) expr(X).  
              {A = sqlite3PExpr(pParse, @B, X, 0);/*A-overwrites-B*/}
expr(A) ::= BITNOT(B) expr(X).
              {A = sqlite3PExpr(pParse, @B, X, 0);/*A-overwrites-B*/}
expr(A) ::= PLUS|MINUS(B) expr(X). [BITNOT] {
  A = sqlite3PExpr(pParse, @B==TK_PLUS ? TK_UPLUS : TK_UMINUS, X, 0);
1274
1275
1276
1277
1278
1279
1280
1281

1282
1283
1284
1285
1286
1287
1288
      **      expr1 IN ()
      **      expr1 NOT IN ()
      **
      ** simplify to constants 0 (false) and 1 (true), respectively,
      ** regardless of the value of expr1.
      */
      sqlite3ExprUnmapAndDelete(pParse, A);
      A = sqlite3Expr(pParse->db, TK_INTEGER, N ? "1" : "0");

    }else{
      Expr *pRHS = Y->a[0].pExpr;
      if( Y->nExpr==1 && sqlite3ExprIsConstant(pRHS) && A->op!=TK_VECTOR ){
        Y->a[0].pExpr = 0;
        sqlite3ExprListDelete(pParse->db, Y);
        pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0);
        A = sqlite3PExpr(pParse, TK_EQ, A, pRHS);







|
>







1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
      **      expr1 IN ()
      **      expr1 NOT IN ()
      **
      ** simplify to constants 0 (false) and 1 (true), respectively,
      ** regardless of the value of expr1.
      */
      sqlite3ExprUnmapAndDelete(pParse, A);
      A = sqlite3Expr(pParse->db, TK_STRING, N ? "true" : "false");
      if( A ) sqlite3ExprIdToTrueFalse(A);
    }else{
      Expr *pRHS = Y->a[0].pExpr;
      if( Y->nExpr==1 && sqlite3ExprIsConstant(pRHS) && A->op!=TK_VECTOR ){
        Y->a[0].pExpr = 0;
        sqlite3ExprListDelete(pParse->db, Y);
        pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0);
        A = sqlite3PExpr(pParse, TK_EQ, A, pRHS);
Changes to src/printf.c.
950
951
952
953
954
955
956
957


958
959
960
961
962
963
964
}

/*
** If pExpr has a byte offset for the start of a token, record that as
** as the error offset.
*/
void sqlite3RecordErrorOffsetOfExpr(sqlite3 *db, const Expr *pExpr){
  while( pExpr && (ExprHasProperty(pExpr,EP_FromJoin) || pExpr->w.iOfst<=0) ){


    pExpr = pExpr->pLeft;
  }
  if( pExpr==0 ) return;
  db->errByteOffset = pExpr->w.iOfst;
}

/*







|
>
>







950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
}

/*
** If pExpr has a byte offset for the start of a token, record that as
** as the error offset.
*/
void sqlite3RecordErrorOffsetOfExpr(sqlite3 *db, const Expr *pExpr){
  while( pExpr
     && (ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) || pExpr->w.iOfst<=0)
  ){
    pExpr = pExpr->pLeft;
  }
  if( pExpr==0 ) return;
  db->errByteOffset = pExpr->w.iOfst;
}

/*
Changes to src/resolve.c.
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
      NameContext *p;
      int i;
      for(i=0, p=pNC; p && i<ArraySize(anRef); p=p->pNext, i++){ 
        anRef[i] = p->nRef;
      }
      sqlite3WalkExpr(pWalker, pExpr->pLeft);
      if( 0==sqlite3ExprCanBeNull(pExpr->pLeft) && !IN_RENAME_OBJECT ){
        testcase( ExprHasProperty(pExpr, EP_FromJoin) );
        assert( !ExprHasProperty(pExpr, EP_IntValue) );
        if( pExpr->op==TK_NOTNULL ){
          pExpr->u.zToken = "true";
          ExprSetProperty(pExpr, EP_IsTrue);
        }else{
          pExpr->u.zToken = "false";
          ExprSetProperty(pExpr, EP_IsFalse);







|







924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
      NameContext *p;
      int i;
      for(i=0, p=pNC; p && i<ArraySize(anRef); p=p->pNext, i++){ 
        anRef[i] = p->nRef;
      }
      sqlite3WalkExpr(pWalker, pExpr->pLeft);
      if( 0==sqlite3ExprCanBeNull(pExpr->pLeft) && !IN_RENAME_OBJECT ){
        testcase( ExprHasProperty(pExpr, EP_OuterON) );
        assert( !ExprHasProperty(pExpr, EP_IntValue) );
        if( pExpr->op==TK_NOTNULL ){
          pExpr->u.zToken = "true";
          ExprSetProperty(pExpr, EP_IsTrue);
        }else{
          pExpr->u.zToken = "false";
          ExprSetProperty(pExpr, EP_IsFalse);
Changes to src/select.c.
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
      return 1;
    }
  }
  return 0;
}

/*
** Set the EP_FromJoin property on all terms of the given expression.
** And set the Expr.w.iJoin to iTable for every term in the
** expression.
**
** The EP_FromJoin property is used on terms of an expression to tell
** the OUTER JOIN processing logic that this term is part of the
** join restriction specified in the ON or USING clause and not a part
** of the more general WHERE clause.  These terms are moved over to the
** WHERE clause during join processing but we need to remember that they
** originated in the ON or USING clause.
**
** The Expr.w.iJoin tells the WHERE clause processing that the







|



|







374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
      return 1;
    }
  }
  return 0;
}

/*
** Set the EP_OuterON property on all terms of the given expression.
** And set the Expr.w.iJoin to iTable for every term in the
** expression.
**
** The EP_OuterON property is used on terms of an expression to tell
** the OUTER JOIN processing logic that this term is part of the
** join restriction specified in the ON or USING clause and not a part
** of the more general WHERE clause.  These terms are moved over to the
** WHERE clause during join processing but we need to remember that they
** originated in the ON or USING clause.
**
** The Expr.w.iJoin tells the WHERE clause processing that the
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
** term until after the t2 loop of the join.  In that way, a
** NULL t2 row will be inserted whenever t1.x!=5.  If we do not
** defer the handling of t1.x=5, it will be processed immediately
** after the t1 loop and rows with t1.x!=5 will never appear in
** the output, which is incorrect.
*/
void sqlite3SetJoinExpr(Expr *p, int iTable, u32 joinFlag){
  assert( joinFlag==EP_FromJoin || joinFlag==EP_InnerJoin );
  while( p ){
    ExprSetProperty(p, joinFlag);
    assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
    ExprSetVVAProperty(p, EP_NoReduce);
    p->w.iJoin = iTable;
    if( p->op==TK_FUNCTION ){
      assert( ExprUseXList(p) );
      if( p->x.pList ){
        int i;
        for(i=0; i<p->x.pList->nExpr; i++){
          sqlite3SetJoinExpr(p->x.pList->a[i].pExpr, iTable, joinFlag);
        }
      }
    }
    sqlite3SetJoinExpr(p->pLeft, iTable, joinFlag);
    p = p->pRight;
  } 
}

/* Undo the work of sqlite3SetJoinExpr(). In the expression p, convert every
** term that is marked with EP_FromJoin and w.iJoin==iTable into
** an ordinary term that omits the EP_FromJoin mark.
**
** This happens when a LEFT JOIN is simplified into an ordinary JOIN.
*/
static void unsetJoinExpr(Expr *p, int iTable){
  while( p ){
    if( ExprHasProperty(p, EP_FromJoin)
     && (iTable<0 || p->w.iJoin==iTable) ){
      ExprClearProperty(p, EP_FromJoin);
      ExprSetProperty(p, EP_InnerJoin);
    }
    if( p->op==TK_COLUMN && p->iTable==iTable ){
      ExprClearProperty(p, EP_CanBeNull);
    }
    if( p->op==TK_FUNCTION ){
      assert( ExprUseXList(p) );
      if( p->x.pList ){







|




















|
|





|

|
|







400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
** term until after the t2 loop of the join.  In that way, a
** NULL t2 row will be inserted whenever t1.x!=5.  If we do not
** defer the handling of t1.x=5, it will be processed immediately
** after the t1 loop and rows with t1.x!=5 will never appear in
** the output, which is incorrect.
*/
void sqlite3SetJoinExpr(Expr *p, int iTable, u32 joinFlag){
  assert( joinFlag==EP_OuterON || joinFlag==EP_InnerON );
  while( p ){
    ExprSetProperty(p, joinFlag);
    assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
    ExprSetVVAProperty(p, EP_NoReduce);
    p->w.iJoin = iTable;
    if( p->op==TK_FUNCTION ){
      assert( ExprUseXList(p) );
      if( p->x.pList ){
        int i;
        for(i=0; i<p->x.pList->nExpr; i++){
          sqlite3SetJoinExpr(p->x.pList->a[i].pExpr, iTable, joinFlag);
        }
      }
    }
    sqlite3SetJoinExpr(p->pLeft, iTable, joinFlag);
    p = p->pRight;
  } 
}

/* Undo the work of sqlite3SetJoinExpr(). In the expression p, convert every
** term that is marked with EP_OuterON and w.iJoin==iTable into
** an ordinary term that omits the EP_OuterON mark.
**
** This happens when a LEFT JOIN is simplified into an ordinary JOIN.
*/
static void unsetJoinExpr(Expr *p, int iTable){
  while( p ){
    if( ExprHasProperty(p, EP_OuterON)
     && (iTable<0 || p->w.iJoin==iTable) ){
      ExprClearProperty(p, EP_OuterON);
      ExprSetProperty(p, EP_InnerON);
    }
    if( p->op==TK_COLUMN && p->iTable==iTable ){
      ExprClearProperty(p, EP_CanBeNull);
    }
    if( p->op==TK_FUNCTION ){
      assert( ExprUseXList(p) );
      if( p->x.pList ){
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
**
**   *  A NATURAL join is converted into a USING join.  After that, we
**      do not need to be concerned with NATURAL joins and we only have
**      think about USING joins.
**
**   *  ON and USING clauses result in extra terms being added to the
**      WHERE clause to enforce the specified constraints.  The extra
**      WHERE clause terms will be tagged with EP_FromJoin or
**      EP_InnerJoin so that we know that they originated in ON/USING.
**
** The terms of a FROM clause are contained in the Select.pSrc structure.
** The left most table is the first entry in Select.pSrc.  The right-most
** table is the last entry.  The join operator is held in the entry to
** the right.  Thus entry 1 contains the join operator for the join between
** entries 0 and 1.  Any ON or USING clauses associated with the join are
** also attached to the right entry.







|
|







459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
**
**   *  A NATURAL join is converted into a USING join.  After that, we
**      do not need to be concerned with NATURAL joins and we only have
**      think about USING joins.
**
**   *  ON and USING clauses result in extra terms being added to the
**      WHERE clause to enforce the specified constraints.  The extra
**      WHERE clause terms will be tagged with EP_OuterON or
**      EP_InnerON so that we know that they originated in ON/USING.
**
** The terms of a FROM clause are contained in the Select.pSrc structure.
** The left most table is the first entry in Select.pSrc.  The right-most
** table is the last entry.  The join operator is held in the entry to
** the right.  Thus entry 1 contains the join operator for the join between
** entries 0 and 1.  Any ON or USING clauses associated with the join are
** also attached to the right entry.
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
  pLeft = &pSrc->a[0];
  pRight = &pLeft[1];
  for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){
    Table *pRightTab = pRight->pTab;
    u32 joinType;

    if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue;
    joinType = (pRight->fg.jointype & JT_OUTER)!=0 ? EP_FromJoin : EP_InnerJoin;

    /* If this is a NATURAL join, synthesize an approprate USING clause
    ** to specify which columns should be joined.
    */
    if( pRight->fg.jointype & JT_NATURAL ){
      IdList *pUsing = 0;
      if( pRight->fg.isUsing || pRight->u3.pOn ){







|







485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
  pLeft = &pSrc->a[0];
  pRight = &pLeft[1];
  for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){
    Table *pRightTab = pRight->pTab;
    u32 joinType;

    if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue;
    joinType = (pRight->fg.jointype & JT_OUTER)!=0 ? EP_OuterON : EP_InnerON;

    /* If this is a NATURAL join, synthesize an approprate USING clause
    ** to specify which columns should be joined.
    */
    if( pRight->fg.jointype & JT_NATURAL ){
      IdList *pUsing = 0;
      if( pRight->fg.isUsing || pRight->u3.pOn ){
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199

2200
2201
2202
2203
2204
2205
2206
      Expr *pColExpr = sqlite3ExprSkipCollateAndLikely(pX->pExpr);
      while( ALWAYS(pColExpr!=0) && pColExpr->op==TK_DOT ){
        pColExpr = pColExpr->pRight;
        assert( pColExpr!=0 );
      }
      if( pColExpr->op==TK_COLUMN
       && ALWAYS( ExprUseYTab(pColExpr) )
       && (pTab = pColExpr->y.pTab)!=0
      ){
        /* For columns use the column name name */
        int iCol = pColExpr->iColumn;

        if( iCol<0 ) iCol = pTab->iPKey;
        zName = iCol>=0 ? pTab->aCol[iCol].zCnName : "rowid";
      }else if( pColExpr->op==TK_ID ){
        assert( !ExprHasProperty(pColExpr, EP_IntValue) );
        zName = pColExpr->u.zToken;
      }else{
        /* Use the original text of the column expression as its name */







|



>







2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
      Expr *pColExpr = sqlite3ExprSkipCollateAndLikely(pX->pExpr);
      while( ALWAYS(pColExpr!=0) && pColExpr->op==TK_DOT ){
        pColExpr = pColExpr->pRight;
        assert( pColExpr!=0 );
      }
      if( pColExpr->op==TK_COLUMN
       && ALWAYS( ExprUseYTab(pColExpr) )
       && ALWAYS( pColExpr->y.pTab!=0 )
      ){
        /* For columns use the column name name */
        int iCol = pColExpr->iColumn;
        pTab = pColExpr->y.pTab;
        if( iCol<0 ) iCol = pTab->iPKey;
        zName = iCol>=0 ? pTab->aCol[iCol].zCnName : "rowid";
      }else if( pColExpr->op==TK_ID ){
        assert( !ExprHasProperty(pColExpr, EP_IntValue) );
        zName = pColExpr->u.zToken;
      }else{
        /* Use the original text of the column expression as its name */
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
** of the subquery rather the result set of the subquery.
*/
static Expr *substExpr(
  SubstContext *pSubst,  /* Description of the substitution */
  Expr *pExpr            /* Expr in which substitution occurs */
){
  if( pExpr==0 ) return 0;
  if( ExprHasProperty(pExpr, EP_FromJoin)
   && pExpr->w.iJoin==pSubst->iTable
  ){
    pExpr->w.iJoin = pSubst->iNewTable;
  }
  if( pExpr->op==TK_COLUMN
   && pExpr->iTable==pSubst->iTable
   && !ExprHasProperty(pExpr, EP_FixedCol)







|







3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
** of the subquery rather the result set of the subquery.
*/
static Expr *substExpr(
  SubstContext *pSubst,  /* Description of the substitution */
  Expr *pExpr            /* Expr in which substitution occurs */
){
  if( pExpr==0 ) return 0;
  if( ExprHasProperty(pExpr, EP_OuterON)
   && pExpr->w.iJoin==pSubst->iTable
  ){
    pExpr->w.iJoin = pSubst->iNewTable;
  }
  if( pExpr->op==TK_COLUMN
   && pExpr->iTable==pSubst->iTable
   && !ExprHasProperty(pExpr, EP_FixedCol)
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
        if( db->mallocFailed ){
          sqlite3ExprDelete(db, pNew);
          return pExpr;
        }
        if( pSubst->isOuterJoin ){
          ExprSetProperty(pNew, EP_CanBeNull);
        }
        if( ExprHasProperty(pExpr,EP_FromJoin|EP_InnerJoin) ){
          sqlite3SetJoinExpr(pNew, pExpr->w.iJoin,
                             pExpr->flags & (EP_FromJoin|EP_InnerJoin));
        }
        sqlite3ExprDelete(db, pExpr);
        pExpr = pNew;

        /* Ensure that the expression now has an implicit collation sequence,
        ** just as it did when it was a column of a view or sub-query. */
        if( pExpr->op!=TK_COLUMN && pExpr->op!=TK_COLLATE ){







|

|







3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
        if( db->mallocFailed ){
          sqlite3ExprDelete(db, pNew);
          return pExpr;
        }
        if( pSubst->isOuterJoin ){
          ExprSetProperty(pNew, EP_CanBeNull);
        }
        if( ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) ){
          sqlite3SetJoinExpr(pNew, pExpr->w.iJoin,
                             pExpr->flags & (EP_OuterON|EP_InnerON));
        }
        sqlite3ExprDelete(db, pExpr);
        pExpr = pNew;

        /* Ensure that the expression now has an implicit collation sequence,
        ** just as it did when it was a column of a view or sub-query. */
        if( pExpr->op!=TK_COLUMN && pExpr->op!=TK_COLLATE ){
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
** Expr objects to match newly assigned cursor numbers.
*/
static int renumberCursorsCb(Walker *pWalker, Expr *pExpr){
  int op = pExpr->op;
  if( op==TK_COLUMN || op==TK_IF_NULL_ROW ){
    renumberCursorDoMapping(pWalker, &pExpr->iTable);
  }
  if( ExprHasProperty(pExpr, EP_FromJoin) ){
    renumberCursorDoMapping(pWalker, &pExpr->w.iJoin);
  }
  return WRC_Continue;
}

/*
** Assign a new cursor number to each cursor in the FROM clause (Select.pSrc)







|







3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
** Expr objects to match newly assigned cursor numbers.
*/
static int renumberCursorsCb(Walker *pWalker, Expr *pExpr){
  int op = pExpr->op;
  if( op==TK_COLUMN || op==TK_IF_NULL_ROW ){
    renumberCursorDoMapping(pWalker, &pExpr->iTable);
  }
  if( ExprHasProperty(pExpr, EP_OuterON) ){
    renumberCursorDoMapping(pWalker, &pExpr->w.iJoin);
  }
  return WRC_Continue;
}

/*
** Assign a new cursor number to each cursor in the FROM clause (Select.pSrc)
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
      assert( pParent->pOrderBy==0 );
      pParent->pOrderBy = pOrderBy;
      pSub->pOrderBy = 0;
    }
    pWhere = pSub->pWhere;
    pSub->pWhere = 0;
    if( isOuterJoin>0 ){
      sqlite3SetJoinExpr(pWhere, iNewParent, EP_FromJoin);
    }
    if( pWhere ){
      if( pParent->pWhere ){
        pParent->pWhere = sqlite3PExpr(pParse, TK_AND, pWhere, pParent->pWhere);
      }else{
        pParent->pWhere = pWhere;
      }







|







4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
      assert( pParent->pOrderBy==0 );
      pParent->pOrderBy = pOrderBy;
      pSub->pOrderBy = 0;
    }
    pWhere = pSub->pWhere;
    pSub->pWhere = 0;
    if( isOuterJoin>0 ){
      sqlite3SetJoinExpr(pWhere, iNewParent, EP_OuterON);
    }
    if( pWhere ){
      if( pParent->pWhere ){
        pParent->pWhere = sqlite3PExpr(pParse, TK_AND, pWhere, pParent->pWhere);
      }else{
        pParent->pWhere = pWhere;
      }
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
** is a constant expression and where the term must be true because it
** is part of the AND-connected terms of the expression.  For each term
** found, add it to the pConst structure.
*/
static void findConstInWhere(WhereConst *pConst, Expr *pExpr){
  Expr *pRight, *pLeft;
  if( NEVER(pExpr==0) ) return;
  if( ExprHasProperty(pExpr, EP_FromJoin) ) return;
  if( pExpr->op==TK_AND ){
    findConstInWhere(pConst, pExpr->pRight);
    findConstInWhere(pConst, pExpr->pLeft);
    return;
  }
  if( pExpr->op!=TK_EQ ) return;
  pRight = pExpr->pRight;







|







4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
** is a constant expression and where the term must be true because it
** is part of the AND-connected terms of the expression.  For each term
** found, add it to the pConst structure.
*/
static void findConstInWhere(WhereConst *pConst, Expr *pExpr){
  Expr *pRight, *pLeft;
  if( NEVER(pExpr==0) ) return;
  if( ExprHasProperty(pExpr, EP_OuterON) ) return;
  if( pExpr->op==TK_AND ){
    findConstInWhere(pConst, pExpr->pRight);
    findConstInWhere(pConst, pExpr->pLeft);
    return;
  }
  if( pExpr->op!=TK_EQ ) return;
  pRight = pExpr->pRight;
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
  WhereConst *pConst,
  Expr *pExpr, 
  int bIgnoreAffBlob
){
  int i;
  if( pConst->pOomFault[0] ) return WRC_Prune;
  if( pExpr->op!=TK_COLUMN ) return WRC_Continue;
  if( ExprHasProperty(pExpr, EP_FixedCol|EP_FromJoin) ){
    testcase( ExprHasProperty(pExpr, EP_FixedCol) );
    testcase( ExprHasProperty(pExpr, EP_FromJoin) );
    return WRC_Continue;
  }
  for(i=0; i<pConst->nConst; i++){
    Expr *pColumn = pConst->apExpr[i*2];
    if( pColumn==pExpr ) continue;
    if( pColumn->iTable!=pExpr->iTable ) continue;
    if( pColumn->iColumn!=pExpr->iColumn ) continue;







|

|







4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
  WhereConst *pConst,
  Expr *pExpr, 
  int bIgnoreAffBlob
){
  int i;
  if( pConst->pOomFault[0] ) return WRC_Prune;
  if( pExpr->op!=TK_COLUMN ) return WRC_Continue;
  if( ExprHasProperty(pExpr, EP_FixedCol|EP_OuterON) ){
    testcase( ExprHasProperty(pExpr, EP_FixedCol) );
    testcase( ExprHasProperty(pExpr, EP_OuterON) );
    return WRC_Continue;
  }
  for(i=0; i<pConst->nConst; i++){
    Expr *pColumn = pConst->apExpr[i*2];
    if( pColumn==pExpr ) continue;
    if( pColumn->iTable!=pExpr->iTable ) continue;
    if( pColumn->iColumn!=pExpr->iColumn ) continue;
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018
  while( pWhere->op==TK_AND ){
    nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, pSrc);
    pWhere = pWhere->pLeft;
  }

#if 0  /* Legacy code. Checks now done by sqlite3ExprIsTableConstraint() */
  if( isLeftJoin
   && (ExprHasProperty(pWhere,EP_FromJoin)==0
         || pWhere->w.iJoin!=iCursor)
  ){
    return 0; /* restriction (4) */
  }
  if( ExprHasProperty(pWhere,EP_FromJoin)
   && pWhere->w.iJoin!=iCursor 
  ){
    return 0; /* restriction (5) */
  }
#endif

  if( sqlite3ExprIsTableConstraint(pWhere, pSrc) ){







|




|







5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018
5019
  while( pWhere->op==TK_AND ){
    nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, pSrc);
    pWhere = pWhere->pLeft;
  }

#if 0  /* Legacy code. Checks now done by sqlite3ExprIsTableConstraint() */
  if( isLeftJoin
   && (ExprHasProperty(pWhere,EP_OuterON)==0
         || pWhere->w.iJoin!=iCursor)
  ){
    return 0; /* restriction (4) */
  }
  if( ExprHasProperty(pWhere,EP_OuterON)
   && pWhere->w.iJoin!=iCursor 
  ){
    return 0; /* restriction (5) */
  }
#endif

  if( sqlite3ExprIsTableConstraint(pWhere, pSrc) ){
6513
6514
6515
6516
6517
6518
6519























6520
6521
6522
6523
6524
6525
6526
    SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n"));
    sqlite3TreeViewSelect(0, p, 0);
  }
#endif
  return 1;
}
#endif /* SQLITE_COUNTOFVIEW_OPTIMIZATION */
























/*
** Generate code for the SELECT statement given in the p argument.  
**
** The results are returned according to the SelectDest structure.
** See comments in sqliteInt.h for further information.
**







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







6514
6515
6516
6517
6518
6519
6520
6521
6522
6523
6524
6525
6526
6527
6528
6529
6530
6531
6532
6533
6534
6535
6536
6537
6538
6539
6540
6541
6542
6543
6544
6545
6546
6547
6548
6549
6550
    SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n"));
    sqlite3TreeViewSelect(0, p, 0);
  }
#endif
  return 1;
}
#endif /* SQLITE_COUNTOFVIEW_OPTIMIZATION */

/*
** If any term of pSrc, or any SF_NestedFrom sub-query, is not the same
** as pSrcItem but has the same alias as p0, then return true.
** Otherwise return false.
*/
static int sameSrcAlias(SrcItem *p0, SrcList *pSrc){
  int i;
  for(i=0; i<pSrc->nSrc; i++){
    SrcItem *p1 = &pSrc->a[i];
    if( p1==p0 ) continue;
    if( p0->pTab==p1->pTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){
      return 1;
    }
    if( p1->pSelect
     && (p1->pSelect->selFlags & SF_NestedFrom)!=0
     && sameSrcAlias(p0, p1->pSelect->pSrc)
    ){
      return 1;
    }
  }
  return 0;
}

/*
** Generate code for the SELECT statement given in the p argument.  
**
** The results are returned according to the SelectDest structure.
** See comments in sqliteInt.h for further information.
**
6618
6619
6620
6621
6622
6623
6624
6625
6626
6627
6628
6629
6630
6631
6632
6633
6634
6635
6636
6637
6638
6639
6640
  **
  ** Postgres disallows this case too. The reason is that some other 
  ** systems handle this case differently, and not all the same way, 
  ** which is just confusing. To avoid this, we follow PG's lead and
  ** disallow it altogether.  */
  if( p->selFlags & SF_UFSrcCheck ){
    SrcItem *p0 = &p->pSrc->a[0];
    for(i=1; i<p->pSrc->nSrc; i++){
      SrcItem *p1 = &p->pSrc->a[i];
      if( p0->pTab==p1->pTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){
        sqlite3ErrorMsg(pParse, 
            "target object/alias may not appear in FROM clause: %s", 
            p0->zAlias ? p0->zAlias : p0->pTab->zName
        );
        goto select_end;
      }
    }

    /* Clear the SF_UFSrcCheck flag. The check has already been performed,
    ** and leaving this flag set can cause errors if a compound sub-query
    ** in p->pSrc is flattened into this query and this function called
    ** again as part of compound SELECT processing.  */
    p->selFlags &= ~SF_UFSrcCheck;







|
<
<
|
|
|
|
|
<







6642
6643
6644
6645
6646
6647
6648
6649


6650
6651
6652
6653
6654

6655
6656
6657
6658
6659
6660
6661
  **
  ** Postgres disallows this case too. The reason is that some other 
  ** systems handle this case differently, and not all the same way, 
  ** which is just confusing. To avoid this, we follow PG's lead and
  ** disallow it altogether.  */
  if( p->selFlags & SF_UFSrcCheck ){
    SrcItem *p0 = &p->pSrc->a[0];
    if( sameSrcAlias(p0, p->pSrc) ){


      sqlite3ErrorMsg(pParse, 
          "target object/alias may not appear in FROM clause: %s", 
          p0->zAlias ? p0->zAlias : p0->pTab->zName
      );
      goto select_end;

    }

    /* Clear the SF_UFSrcCheck flag. The check has already been performed,
    ** and leaving this flag set can cause errors if a compound sub-query
    ** in p->pSrc is flattened into this query and this function called
    ** again as part of compound SELECT processing.  */
    p->selFlags &= ~SF_UFSrcCheck;
6901
6902
6903
6904
6905
6906
6907
6908
6909
6910
6911
6912
6913
6914
6915
    }

    zSavedAuthContext = pParse->zAuthContext;
    pParse->zAuthContext = pItem->zName;

    /* Generate code to implement the subquery
    **
    ** The subquery is implemented as a co-routine all of the following are
    ** true:
    **
    **    (1)  the subquery is guaranteed to be the outer loop (so that
    **         it does not need to be computed more than once), and
    **    (2)  the subquery is not a CTE that should be materialized
    **    (3)  the subquery is not part of a left operand for a RIGHT JOIN
    */







|







6922
6923
6924
6925
6926
6927
6928
6929
6930
6931
6932
6933
6934
6935
6936
    }

    zSavedAuthContext = pParse->zAuthContext;
    pParse->zAuthContext = pItem->zName;

    /* Generate code to implement the subquery
    **
    ** The subquery is implemented as a co-routine all if the following are
    ** true:
    **
    **    (1)  the subquery is guaranteed to be the outer loop (so that
    **         it does not need to be computed more than once), and
    **    (2)  the subquery is not a CTE that should be materialized
    **    (3)  the subquery is not part of a left operand for a RIGHT JOIN
    */
6959
6960
6961
6962
6963
6964
6965
6966
6967
6968
6969
6970

6971
6972
6973
6974
6975
6976
6977
6978
6979
6980
6981
6982
6983
6984
6985
6986
6987
6988
6989
6990
6991
6992
6993
6994
      pSub->nSelectRow = pPrior->pSelect->nSelectRow;
    }else{
      /* Materialize the view.  If the view is not correlated, generate a
      ** subroutine to do the materialization so that subsequent uses of
      ** the same view can reuse the materialization. */
      int topAddr;
      int onceAddr = 0;
      int retAddr;

      pItem->regReturn = ++pParse->nMem;
      topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
      pItem->addrFillSub = topAddr+1;

      if( pItem->fg.isCorrelated==0 ){
        /* If the subquery is not correlated and if we are not inside of
        ** a trigger, then we only need to compute the value of the subquery
        ** once. */
        onceAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
        VdbeComment((v, "materialize %!S", pItem));
      }else{
        VdbeNoopComment((v, "materialize %!S", pItem));
      }
      sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
      ExplainQueryPlan((pParse, 1, "MATERIALIZE %!S", pItem));
      sqlite3Select(pParse, pSub, &dest);
      pItem->pTab->nRowLogEst = pSub->nSelectRow;
      if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
      retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
      VdbeComment((v, "end %!S", pItem));
      sqlite3VdbeChangeP1(v, topAddr, retAddr);
      sqlite3ClearTempRegCache(pParse);
      if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){
        CteUse *pCteUse = pItem->u2.pCteUse;
        pCteUse->addrM9e = pItem->addrFillSub;
        pCteUse->regRtn = pItem->regReturn;
        pCteUse->iCur = pItem->iCursor;
        pCteUse->nRowEst = pSub->nSelectRow;







<


|

>














|

|







6980
6981
6982
6983
6984
6985
6986

6987
6988
6989
6990
6991
6992
6993
6994
6995
6996
6997
6998
6999
7000
7001
7002
7003
7004
7005
7006
7007
7008
7009
7010
7011
7012
7013
7014
7015
      pSub->nSelectRow = pPrior->pSelect->nSelectRow;
    }else{
      /* Materialize the view.  If the view is not correlated, generate a
      ** subroutine to do the materialization so that subsequent uses of
      ** the same view can reuse the materialization. */
      int topAddr;
      int onceAddr = 0;


      pItem->regReturn = ++pParse->nMem;
      topAddr = sqlite3VdbeAddOp0(v, OP_Goto);
      pItem->addrFillSub = topAddr+1;
      pItem->fg.isMaterialized = 1;
      if( pItem->fg.isCorrelated==0 ){
        /* If the subquery is not correlated and if we are not inside of
        ** a trigger, then we only need to compute the value of the subquery
        ** once. */
        onceAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
        VdbeComment((v, "materialize %!S", pItem));
      }else{
        VdbeNoopComment((v, "materialize %!S", pItem));
      }
      sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
      ExplainQueryPlan((pParse, 1, "MATERIALIZE %!S", pItem));
      sqlite3Select(pParse, pSub, &dest);
      pItem->pTab->nRowLogEst = pSub->nSelectRow;
      if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
      sqlite3VdbeAddOp2(v, OP_Return, pItem->regReturn, topAddr+1);
      VdbeComment((v, "end %!S", pItem));
      sqlite3VdbeJumpHere(v, topAddr);
      sqlite3ClearTempRegCache(pParse);
      if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){
        CteUse *pCteUse = pItem->u2.pCteUse;
        pCteUse->addrM9e = pItem->addrFillSub;
        pCteUse->regRtn = pItem->regReturn;
        pCteUse->iCur = pItem->iCursor;
        pCteUse->nRowEst = pSub->nSelectRow;
7703
7704
7705
7706
7707
7708
7709
7710
7711
7712
7713
7714
7715
7716
7717
        if( pWInfo==0 ){
          goto select_end;
        }
        SELECTTRACE(1,pParse,p,("WhereBegin returns\n"));
        eDist = sqlite3WhereIsDistinct(pWInfo);
        updateAccumulator(pParse, regAcc, pAggInfo, eDist);
        if( eDist!=WHERE_DISTINCT_NOOP ){
          struct AggInfo_func *pF = &pAggInfo->aFunc[0];
          if( pF ){
            fixDistinctOpenEph(pParse, eDist, pF->iDistinct, pF->iDistAddr);
          }
        }

        if( regAcc ) sqlite3VdbeAddOp2(v, OP_Integer, 1, regAcc);
        if( minMaxFlag ){







|







7724
7725
7726
7727
7728
7729
7730
7731
7732
7733
7734
7735
7736
7737
7738
        if( pWInfo==0 ){
          goto select_end;
        }
        SELECTTRACE(1,pParse,p,("WhereBegin returns\n"));
        eDist = sqlite3WhereIsDistinct(pWInfo);
        updateAccumulator(pParse, regAcc, pAggInfo, eDist);
        if( eDist!=WHERE_DISTINCT_NOOP ){
          struct AggInfo_func *pF = pAggInfo->aFunc;
          if( pF ){
            fixDistinctOpenEph(pParse, eDist, pF->iDistinct, pF->iDistAddr);
          }
        }

        if( regAcc ) sqlite3VdbeAddOp2(v, OP_Integer, 1, regAcc);
        if( minMaxFlag ){
Changes to src/shell.c.in.
225
226
227
228
229
230
231










232
233
234
235
236
237
238
  _setmode(_fileno(file), _O_TEXT);
}
#else
# define setBinaryMode(X,Y)
# define setTextMode(X,Y)
#endif












/* True if the timer is enabled */
static int enableTimer = 0;

/* Return the current wall-clock time */
static sqlite3_int64 timeOfDay(void){
  static sqlite3_vfs *clockVfs = 0;







>
>
>
>
>
>
>
>
>
>







225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
  _setmode(_fileno(file), _O_TEXT);
}
#else
# define setBinaryMode(X,Y)
# define setTextMode(X,Y)
#endif

/*
** When compiling with emcc (a.k.a. emscripten), we're building a
** WebAssembly (WASM) bundle and need to disable and rewire a few
** things.
*/
#ifdef __EMSCRIPTEN__
#define SQLITE_SHELL_WASM_MODE
#else
#undef SQLITE_SHELL_WASM_MODE
#endif

/* True if the timer is enabled */
static int enableTimer = 0;

/* Return the current wall-clock time */
static sqlite3_int64 timeOfDay(void){
  static sqlite3_vfs *clockVfs = 0;
687
688
689
690
691
692
693

694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
** If zPrior is not NULL then it is a buffer from a prior call to this
** routine that can be reused.
**
** The result is stored in space obtained from malloc() and must either
** be freed by the caller or else passed back into this routine via the
** zPrior argument for reuse.
*/

static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
  char *zPrompt;
  char *zResult;
  if( in!=0 ){
    zResult = local_getline(zPrior, in);
  }else{
    zPrompt = isContinuation ? continuePrompt : mainPrompt;
#if SHELL_USE_LOCAL_GETLINE
    printf("%s", zPrompt);
    fflush(stdout);
    zResult = local_getline(zPrior, stdin);
#else
    free(zPrior);
    zResult = shell_readline(zPrompt);
    if( zResult && *zResult ) shell_add_history(zResult);
#endif
  }
  return zResult;
}


/*
** Return the value of a hexadecimal digit.  Return -1 if the input
** is not a hex digit.
*/
static int hexDigitValue(char c){
  if( c>='0' && c<='9' ) return c - '0';







>



















|







697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
** If zPrior is not NULL then it is a buffer from a prior call to this
** routine that can be reused.
**
** The result is stored in space obtained from malloc() and must either
** be freed by the caller or else passed back into this routine via the
** zPrior argument for reuse.
*/
#ifndef SQLITE_SHELL_WASM_MODE
static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
  char *zPrompt;
  char *zResult;
  if( in!=0 ){
    zResult = local_getline(zPrior, in);
  }else{
    zPrompt = isContinuation ? continuePrompt : mainPrompt;
#if SHELL_USE_LOCAL_GETLINE
    printf("%s", zPrompt);
    fflush(stdout);
    zResult = local_getline(zPrior, stdin);
#else
    free(zPrior);
    zResult = shell_readline(zPrompt);
    if( zResult && *zResult ) shell_add_history(zResult);
#endif
  }
  return zResult;
}
#endif /* !SQLITE_SHELL_WASM_MODE */

/*
** Return the value of a hexadecimal digit.  Return -1 if the input
** is not a hex digit.
*/
static int hexDigitValue(char c){
  if( c>='0' && c<='9' ) return c - '0';
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
** from malloc(), or a NULL pointer. The string pointed to by zAppend is
** added to zIn, and the result returned in memory obtained from malloc().
** zIn, if it was not NULL, is freed.
**
** If the third argument, quote, is not '\0', then it is used as a
** quote character for zAppend.
*/
static void appendText(ShellText *p, char const *zAppend, char quote){
  int len;
  int i;
  int nAppend = strlen30(zAppend);

  len = nAppend+p->n+1;
  if( quote ){
    len += 2;







|







805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
** from malloc(), or a NULL pointer. The string pointed to by zAppend is
** added to zIn, and the result returned in memory obtained from malloc().
** zIn, if it was not NULL, is freed.
**
** If the third argument, quote, is not '\0', then it is used as a
** quote character for zAppend.
*/
static void appendText(ShellText *p, const char *zAppend, char quote){
  int len;
  int i;
  int nAppend = strlen30(zAppend);

  len = nAppend+p->n+1;
  if( quote ){
    len += 2;
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021





1022
1023
1024
1025
1026
1027
1028
#define SQLITE_EXTENSION_INIT2(X) (void)(X)

#if defined(_WIN32) && defined(_MSC_VER)
INCLUDE test_windirent.h
INCLUDE test_windirent.c
#define dirent DIRENT
#endif
INCLUDE ../ext/misc/shathree.c
INCLUDE ../ext/misc/fileio.c
INCLUDE ../ext/misc/completion.c
INCLUDE ../ext/misc/appendvfs.c
INCLUDE ../ext/misc/memtrace.c
INCLUDE ../ext/misc/uint.c
INCLUDE ../ext/misc/decimal.c
INCLUDE ../ext/misc/ieee754.c
INCLUDE ../ext/misc/series.c
INCLUDE ../ext/misc/regexp.c





#ifdef SQLITE_HAVE_ZLIB
INCLUDE ../ext/misc/zipfile.c
INCLUDE ../ext/misc/sqlar.c
#endif
INCLUDE ../ext/expert/sqlite3expert.h
INCLUDE ../ext/expert/sqlite3expert.c








|
|
<
<
<





>
>
>
>
>







1016
1017
1018
1019
1020
1021
1022
1023
1024



1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
#define SQLITE_EXTENSION_INIT2(X) (void)(X)

#if defined(_WIN32) && defined(_MSC_VER)
INCLUDE test_windirent.h
INCLUDE test_windirent.c
#define dirent DIRENT
#endif
INCLUDE ../ext/misc/memtrace.c
INCLUDE ../ext/misc/shathree.c



INCLUDE ../ext/misc/uint.c
INCLUDE ../ext/misc/decimal.c
INCLUDE ../ext/misc/ieee754.c
INCLUDE ../ext/misc/series.c
INCLUDE ../ext/misc/regexp.c
#ifndef SQLITE_SHELL_WASM_MODE
INCLUDE ../ext/misc/fileio.c
INCLUDE ../ext/misc/completion.c
INCLUDE ../ext/misc/appendvfs.c
#endif
#ifdef SQLITE_HAVE_ZLIB
INCLUDE ../ext/misc/zipfile.c
INCLUDE ../ext/misc/sqlar.c
#endif
INCLUDE ../ext/expert/sqlite3expert.h
INCLUDE ../ext/expert/sqlite3expert.c

1145
1146
1147
1148
1149
1150
1151






1152




1153
1154
1155
1156
1157
1158
1159
    *pAuxDb;             /* Currently active database connection */
  int *aiIndent;         /* Array of indents used in MODE_Explain */
  int nIndent;           /* Size of array aiIndent[] */
  int iIndent;           /* Index of current op in aiIndent[] */
  char *zNonce;          /* Nonce for temporary safe-mode excapes */
  EQPGraph sGraph;       /* Information for the graphical EXPLAIN QUERY PLAN */
  ExpertInfo expert;     /* Valid if previous command was ".expert OPT..." */






};






/* Allowed values for ShellState.autoEQP
*/
#define AUTOEQP_off      0           /* Automatic EXPLAIN QUERY PLAN is off */
#define AUTOEQP_on       1           /* Automatic EQP is on */
#define AUTOEQP_trigger  2           /* On and also show plans for triggers */







>
>
>
>
>
>

>
>
>
>







1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
    *pAuxDb;             /* Currently active database connection */
  int *aiIndent;         /* Array of indents used in MODE_Explain */
  int nIndent;           /* Size of array aiIndent[] */
  int iIndent;           /* Index of current op in aiIndent[] */
  char *zNonce;          /* Nonce for temporary safe-mode excapes */
  EQPGraph sGraph;       /* Information for the graphical EXPLAIN QUERY PLAN */
  ExpertInfo expert;     /* Valid if previous command was ".expert OPT..." */
#ifdef SQLITE_SHELL_WASM_MODE
  struct {
    const char * zInput; /* Input string from wasm/JS proxy */
    const char * zPos;   /* Cursor pos into zInput */
  } wasm;
#endif
};

#ifdef SQLITE_SHELL_WASM_MODE
static ShellState shellState;
#endif


/* Allowed values for ShellState.autoEQP
*/
#define AUTOEQP_off      0           /* Automatic EXPLAIN QUERY PLAN is off */
#define AUTOEQP_on       1           /* Automatic EQP is on */
#define AUTOEQP_trigger  2           /* On and also show plans for triggers */
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
*/
#define SHFLG_Pagecache      0x00000001 /* The --pagecache option is used */
#define SHFLG_Lookaside      0x00000002 /* Lookaside memory is used */
#define SHFLG_Backslash      0x00000004 /* The --backslash option is used */
#define SHFLG_PreserveRowid  0x00000008 /* .dump preserves rowid values */
#define SHFLG_Newlines       0x00000010 /* .dump --newline flag */
#define SHFLG_CountChanges   0x00000020 /* .changes setting */
#define SHFLG_Echo           0x00000040 /* .echo or --echo setting */
#define SHFLG_HeaderSet      0x00000080 /* showHeader has been specified */
#define SHFLG_DumpDataOnly   0x00000100 /* .dump show data only */
#define SHFLG_DumpNoSys      0x00000200 /* .dump omits system tables */

/*
** Macros for testing and setting shellFlgs
*/







|







1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
*/
#define SHFLG_Pagecache      0x00000001 /* The --pagecache option is used */
#define SHFLG_Lookaside      0x00000002 /* Lookaside memory is used */
#define SHFLG_Backslash      0x00000004 /* The --backslash option is used */
#define SHFLG_PreserveRowid  0x00000008 /* .dump preserves rowid values */
#define SHFLG_Newlines       0x00000010 /* .dump --newline flag */
#define SHFLG_CountChanges   0x00000020 /* .changes setting */
#define SHFLG_Echo           0x00000040 /* .echo on/off, or --echo setting */
#define SHFLG_HeaderSet      0x00000080 /* showHeader has been specified */
#define SHFLG_DumpDataOnly   0x00000100 /* .dump show data only */
#define SHFLG_DumpNoSys      0x00000200 /* .dump omits system tables */

/*
** Macros for testing and setting shellFlgs
*/
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834

      /* save off the prepared statment handle and reset row count */
      if( pArg ){
        pArg->pStmt = pStmt;
        pArg->cnt = 0;
      }

      /* echo the sql statement if echo on */
      if( pArg && ShellHasFlag(pArg, SHFLG_Echo) ){
        utf8_printf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql);
      }

      /* Show the EXPLAIN QUERY PLAN if .eqp is on */
      if( pArg && pArg->autoEQP && sqlite3_stmt_isexplain(pStmt)==0 ){
        sqlite3_stmt *pExplain;
        char *zEQP;
        int triggerEQP = 0;
        disable_debug_trace_modes();
        sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, -1, &triggerEQP);







<
<
<
<
<







3839
3840
3841
3842
3843
3844
3845





3846
3847
3848
3849
3850
3851
3852

      /* save off the prepared statment handle and reset row count */
      if( pArg ){
        pArg->pStmt = pStmt;
        pArg->cnt = 0;
      }






      /* Show the EXPLAIN QUERY PLAN if .eqp is on */
      if( pArg && pArg->autoEQP && sqlite3_stmt_isexplain(pStmt)==0 ){
        sqlite3_stmt *pExplain;
        char *zEQP;
        int triggerEQP = 0;
        disable_debug_trace_modes();
        sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, -1, &triggerEQP);
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232

4233
4234
4235
4236
4237
4238
4239
  return rc;
}

/*
** Text of help messages.
**
** The help text for each individual command begins with a line that starts
** with ".".  Subsequent lines are supplimental information.
**
** There must be two or more spaces between the end of the command and the
** start of the description of what that command does.
*/
static const char *(azHelp[]) = {
#if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE)

  ".archive ...             Manage SQL archives",
  "   Each command must have exactly one of the following options:",
  "     -c, --create               Create a new archive",
  "     -u, --update               Add or update files with changed mtime",
  "     -i, --insert               Like -u but always add even if unchanged",
  "     -r, --remove               Remove files from archive",
  "     -t, --list                 List contents of archive",







|





|
>







4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
  return rc;
}

/*
** Text of help messages.
**
** The help text for each individual command begins with a line that starts
** with ".".  Subsequent lines are supplemental information.
**
** There must be two or more spaces between the end of the command and the
** start of the description of what that command does.
*/
static const char *(azHelp[]) = {
#if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE) \
  && !defined(SQLITE_SHELL_WASM_MODE)
  ".archive ...             Manage SQL archives",
  "   Each command must have exactly one of the following options:",
  "     -c, --create               Create a new archive",
  "     -u, --update               Add or update files with changed mtime",
  "     -i, --insert               Like -u but always add even if unchanged",
  "     -r, --remove               Remove files from archive",
  "     -t, --list                 List contents of archive",
4251
4252
4253
4254
4255
4256
4257

4258
4259
4260
4261

4262
4263

4264

4265

4266
4267

4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287

4288
4289


4290

4291
4292
4293
4294
4295
4296
4297
4298

4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312

4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328

4329

4330
4331
4332
4333
4334
4335
4336
  "     .ar -xvf ARCHIVE         # Verbosely extract files from ARCHIVE",
  "   See also:",
  "      http://sqlite.org/cli.html#sqlite_archive_support",
#endif
#ifndef SQLITE_OMIT_AUTHORIZATION
  ".auth ON|OFF             Show authorizer callbacks",
#endif

  ".backup ?DB? FILE        Backup DB (default \"main\") to FILE",
  "   Options:",
  "       --append            Use the appendvfs",
  "       --async             Write to FILE without journal and fsync()",

  ".bail on|off             Stop after hitting an error.  Default OFF",
  ".binary on|off           Turn binary output on or off.  Default OFF",

  ".cd DIRECTORY            Change the working directory to DIRECTORY",

  ".changes on|off          Show number of rows changed by SQL",

  ".check GLOB              Fail if output since .testcase does not match",
  ".clone NEWDB             Clone data into NEWDB from the existing database",

  ".connection [close] [#]  Open or close an auxiliary database connection",
  ".databases               List names and files of attached databases",
  ".dbconfig ?op? ?val?     List or change sqlite3_db_config() options",
  ".dbinfo ?DB?             Show status information about the database",
  ".dump ?OBJECTS?          Render database content as SQL",
  "   Options:",
  "     --data-only            Output only INSERT statements",
  "     --newlines             Allow unescaped newline characters in output",
  "     --nosys                Omit system tables (ex: \"sqlite_stat1\")",
  "     --preserve-rowids      Include ROWID values in the output",
  "   OBJECTS is a LIKE pattern for tables, indexes, triggers or views to dump",
  "   Additional LIKE patterns can be given in subsequent arguments",
  ".echo on|off             Turn command echo on or off",
  ".eqp on|off|full|...     Enable or disable automatic EXPLAIN QUERY PLAN",
  "   Other Modes:",
#ifdef SQLITE_DEBUG
  "      test                  Show raw EXPLAIN QUERY PLAN output",
  "      trace                 Like \"full\" but enable \"PRAGMA vdbe_trace\"",
#endif
  "      trigger               Like \"full\" but also show trigger bytecode",

  ".excel                   Display the output of next command in spreadsheet",
  "   --bom                   Put a UTF8 byte-order mark on intermediate file",


  ".exit ?CODE?             Exit this program with return-code CODE",

  ".expert                  EXPERIMENTAL. Suggest indexes for queries",
  ".explain ?on|off|auto?   Change the EXPLAIN formatting mode.  Default: auto",
  ".filectrl CMD ...        Run various sqlite3_file_control() operations",
  "   --schema SCHEMA         Use SCHEMA instead of \"main\"",
  "   --help                  Show CMD details",
  ".fullschema ?--indent?   Show schema and the content of sqlite_stat tables",
  ".headers on|off          Turn display of headers on or off",
  ".help ?-all? ?PATTERN?   Show help text for PATTERN",

  ".import FILE TABLE       Import data from FILE into TABLE",
  "   Options:",
  "     --ascii               Use \\037 and \\036 as column and row separators",
  "     --csv                 Use , and \\n as column and row separators",
  "     --skip N              Skip the first N rows of input",
  "     --schema S            Target table to be S.TABLE",
  "     -v                    \"Verbose\" - increase auxiliary output",
  "   Notes:",
  "     *  If TABLE does not exist, it is created.  The first row of input",
  "        determines the column names.",
  "     *  If neither --csv or --ascii are used, the input mode is derived",
  "        from the \".mode\" output mode",
  "     *  If FILE begins with \"|\" then it is a command that generates the",
  "        input text.",

#ifndef SQLITE_OMIT_TEST_CONTROL
  ".imposter INDEX TABLE    Create imposter table TABLE on index INDEX",
#endif
  ".indexes ?TABLE?         Show names of indexes",
  "                           If TABLE is specified, only show indexes for",
  "                           tables matching TABLE using the LIKE operator.",
#ifdef SQLITE_ENABLE_IOTRACE
  ".iotrace FILE            Enable I/O diagnostic logging to FILE",
#endif
  ".limit ?LIMIT? ?VAL?     Display or change the value of an SQLITE_LIMIT",
  ".lint OPTIONS            Report potential schema issues.",
  "     Options:",
  "        fkey-indexes     Find missing foreign key indexes",
#ifndef SQLITE_OMIT_LOAD_EXTENSION
  ".load FILE ?ENTRY?       Load an extension library",
#endif

  ".log FILE|off            Turn logging on or off.  FILE can be stderr/stdout",

  ".mode MODE ?OPTIONS?     Set output mode",
  "   MODE is one of:",
  "     ascii       Columns/rows delimited by 0x1F and 0x1E",
  "     box         Tables using unicode box-drawing characters",
  "     csv         Comma-separated values",
  "     column      Output in columns.  (See .width)",
  "     html        HTML <table> code",







>




>


>

>

>


>




















>


>
>

>








>














>













|


>

>







4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
  "     .ar -xvf ARCHIVE         # Verbosely extract files from ARCHIVE",
  "   See also:",
  "      http://sqlite.org/cli.html#sqlite_archive_support",
#endif
#ifndef SQLITE_OMIT_AUTHORIZATION
  ".auth ON|OFF             Show authorizer callbacks",
#endif
#ifndef SQLITE_SHELL_WASM_MODE
  ".backup ?DB? FILE        Backup DB (default \"main\") to FILE",
  "   Options:",
  "       --append            Use the appendvfs",
  "       --async             Write to FILE without journal and fsync()",
#endif
  ".bail on|off             Stop after hitting an error.  Default OFF",
  ".binary on|off           Turn binary output on or off.  Default OFF",
#ifndef SQLITE_SHELL_WASM_MODE
  ".cd DIRECTORY            Change the working directory to DIRECTORY",
#endif
  ".changes on|off          Show number of rows changed by SQL",
#ifndef SQLITE_SHELL_WASM_MODE
  ".check GLOB              Fail if output since .testcase does not match",
  ".clone NEWDB             Clone data into NEWDB from the existing database",
#endif
  ".connection [close] [#]  Open or close an auxiliary database connection",
  ".databases               List names and files of attached databases",
  ".dbconfig ?op? ?val?     List or change sqlite3_db_config() options",
  ".dbinfo ?DB?             Show status information about the database",
  ".dump ?OBJECTS?          Render database content as SQL",
  "   Options:",
  "     --data-only            Output only INSERT statements",
  "     --newlines             Allow unescaped newline characters in output",
  "     --nosys                Omit system tables (ex: \"sqlite_stat1\")",
  "     --preserve-rowids      Include ROWID values in the output",
  "   OBJECTS is a LIKE pattern for tables, indexes, triggers or views to dump",
  "   Additional LIKE patterns can be given in subsequent arguments",
  ".echo on|off             Turn command echo on or off",
  ".eqp on|off|full|...     Enable or disable automatic EXPLAIN QUERY PLAN",
  "   Other Modes:",
#ifdef SQLITE_DEBUG
  "      test                  Show raw EXPLAIN QUERY PLAN output",
  "      trace                 Like \"full\" but enable \"PRAGMA vdbe_trace\"",
#endif
  "      trigger               Like \"full\" but also show trigger bytecode",
#ifndef SQLITE_SHELL_WASM_MODE
  ".excel                   Display the output of next command in spreadsheet",
  "   --bom                   Put a UTF8 byte-order mark on intermediate file",
#endif
#ifndef SQLITE_SHELL_WASM_MODE
  ".exit ?CODE?             Exit this program with return-code CODE",
#endif
  ".expert                  EXPERIMENTAL. Suggest indexes for queries",
  ".explain ?on|off|auto?   Change the EXPLAIN formatting mode.  Default: auto",
  ".filectrl CMD ...        Run various sqlite3_file_control() operations",
  "   --schema SCHEMA         Use SCHEMA instead of \"main\"",
  "   --help                  Show CMD details",
  ".fullschema ?--indent?   Show schema and the content of sqlite_stat tables",
  ".headers on|off          Turn display of headers on or off",
  ".help ?-all? ?PATTERN?   Show help text for PATTERN",
#ifndef SQLITE_SHELL_WASM_MODE
  ".import FILE TABLE       Import data from FILE into TABLE",
  "   Options:",
  "     --ascii               Use \\037 and \\036 as column and row separators",
  "     --csv                 Use , and \\n as column and row separators",
  "     --skip N              Skip the first N rows of input",
  "     --schema S            Target table to be S.TABLE",
  "     -v                    \"Verbose\" - increase auxiliary output",
  "   Notes:",
  "     *  If TABLE does not exist, it is created.  The first row of input",
  "        determines the column names.",
  "     *  If neither --csv or --ascii are used, the input mode is derived",
  "        from the \".mode\" output mode",
  "     *  If FILE begins with \"|\" then it is a command that generates the",
  "        input text.",
#endif
#ifndef SQLITE_OMIT_TEST_CONTROL
  ".imposter INDEX TABLE    Create imposter table TABLE on index INDEX",
#endif
  ".indexes ?TABLE?         Show names of indexes",
  "                           If TABLE is specified, only show indexes for",
  "                           tables matching TABLE using the LIKE operator.",
#ifdef SQLITE_ENABLE_IOTRACE
  ".iotrace FILE            Enable I/O diagnostic logging to FILE",
#endif
  ".limit ?LIMIT? ?VAL?     Display or change the value of an SQLITE_LIMIT",
  ".lint OPTIONS            Report potential schema issues.",
  "     Options:",
  "        fkey-indexes     Find missing foreign key indexes",
#if !defined(SQLITE_OMIT_LOAD_EXTENSION) && !defined(SQLITE_SHELL_WASM_MODE)
  ".load FILE ?ENTRY?       Load an extension library",
#endif
#ifndef SQLITE_SHELL_WASM_MODE
  ".log FILE|off            Turn logging on or off.  FILE can be stderr/stdout",
#endif
  ".mode MODE ?OPTIONS?     Set output mode",
  "   MODE is one of:",
  "     ascii       Columns/rows delimited by 0x1F and 0x1E",
  "     box         Tables using unicode box-drawing characters",
  "     csv         Comma-separated values",
  "     column      Output in columns.  (See .width)",
  "     html        HTML <table> code",
4347
4348
4349
4350
4351
4352
4353

4354

4355

4356
4357
4358
4359
4360



4361
4362
4363

4364
4365
4366
4367
4368
4369
4370
4371
4372

4373
4374
4375
4376
4377
4378

4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394

4395
4396
4397

4398
4399
4400
4401
4402
4403
4404
4405

4406
4407

4408
4409
4410
4411
4412
4413
4414
  "   OPTIONS: (for columnar modes or insert mode):",
  "     --wrap N       Wrap output lines to no longer than N characters",
  "     --wordwrap B   Wrap or not at word boundaries per B (on/off)",
  "     --ww           Shorthand for \"--wordwrap 1\"",
  "     --quote        Quote output text as SQL literals",
  "     --noquote      Do not quote output text",
  "     TABLE          The name of SQL table used for \"insert\" mode",

  ".nonce STRING            Suspend safe mode for one command if nonce matches",

  ".nullvalue STRING        Use STRING in place of NULL values",

  ".once ?OPTIONS? ?FILE?   Output for the next SQL command only to FILE",
  "     If FILE begins with '|' then open as a pipe",
  "       --bom  Put a UTF8 byte-order mark at the beginning",
  "       -e     Send output to the system text editor",
  "       -x     Send output as CSV to a spreadsheet (same as \".excel\")",



  ".open ?OPTIONS? ?FILE?   Close existing database and reopen FILE",
  "     Options:",
  "        --append        Use appendvfs to append database to the end of FILE",

#ifndef SQLITE_OMIT_DESERIALIZE
  "        --deserialize   Load into memory using sqlite3_deserialize()",
  "        --hexdb         Load the output of \"dbtotxt\" as an in-memory db",
  "        --maxsize N     Maximum size for --hexdb or --deserialized database",
#endif
  "        --new           Initialize FILE to an empty database",
  "        --nofollow      Do not follow symbolic links",
  "        --readonly      Open FILE readonly",
  "        --zip           FILE is a ZIP archive",

  ".output ?FILE?           Send output to FILE or stdout if FILE is omitted",
  "   If FILE begins with '|' then open it as a pipe.",
  "   Options:",
  "     --bom                 Prefix output with a UTF8 byte-order mark",
  "     -e                    Send output to the system text editor",
  "     -x                    Send output as CSV to a spreadsheet",

  ".parameter CMD ...       Manage SQL parameter bindings",
  "   clear                   Erase all bindings",
  "   init                    Initialize the TEMP table that holds bindings",
  "   list                    List the current parameter bindings",
  "   set PARAMETER VALUE     Given SQL parameter PARAMETER a value of VALUE",
  "                           PARAMETER should start with one of: $ : @ ?",
  "   unset PARAMETER         Remove PARAMETER from the binding table",
  ".print STRING...         Print literal STRING",
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
  ".progress N              Invoke progress handler after every N opcodes",
  "   --limit N                 Interrupt after N progress callbacks",
  "   --once                    Do no more than one progress interrupt",
  "   --quiet|-q                No output except at interrupts",
  "   --reset                   Reset the count for each input and interrupt",
#endif
  ".prompt MAIN CONTINUE    Replace the standard prompts",

  ".quit                    Exit this program",
  ".read FILE               Read input from FILE or command output",
  "    If FILE begins with \"|\", it is a command that generates the input.",

#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
  ".recover                 Recover as much data as possible from corrupt db.",
  "   --freelist-corrupt       Assume the freelist is corrupt",
  "   --recovery-db NAME       Store recovery metadata in database file NAME",
  "   --lost-and-found TABLE   Alternative name for the lost-and-found table",
  "   --no-rowids              Do not attempt to recover rowid values",
  "                            that are not also INTEGER PRIMARY KEYs",
#endif

  ".restore ?DB? FILE       Restore content of DB (default \"main\") from FILE",
  ".save ?OPTIONS? FILE     Write database to FILE (an alias for .backup ...)",

  ".scanstats on|off        Turn sqlite3_stmt_scanstatus() metrics on or off",
  ".schema ?PATTERN?        Show the CREATE statements matching PATTERN",
  "   Options:",
  "      --indent             Try to pretty-print the schema",
  "      --nosys              Omit objects whose names start with \"sqlite_\"",
  ".selftest ?OPTIONS?      Run tests defined in the SELFTEST table",
  "    Options:",







>

>

>





>
>
>



>









>






>
















>



>








>


>







4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
  "   OPTIONS: (for columnar modes or insert mode):",
  "     --wrap N       Wrap output lines to no longer than N characters",
  "     --wordwrap B   Wrap or not at word boundaries per B (on/off)",
  "     --ww           Shorthand for \"--wordwrap 1\"",
  "     --quote        Quote output text as SQL literals",
  "     --noquote      Do not quote output text",
  "     TABLE          The name of SQL table used for \"insert\" mode",
#ifndef SQLITE_SHELL_WASM_MODE
  ".nonce STRING            Suspend safe mode for one command if nonce matches",
#endif
  ".nullvalue STRING        Use STRING in place of NULL values",
#ifndef SQLITE_SHELL_WASM_MODE
  ".once ?OPTIONS? ?FILE?   Output for the next SQL command only to FILE",
  "     If FILE begins with '|' then open as a pipe",
  "       --bom  Put a UTF8 byte-order mark at the beginning",
  "       -e     Send output to the system text editor",
  "       -x     Send output as CSV to a spreadsheet (same as \".excel\")",
  /* Note that .open is (partially) available in WASM builds but is
  ** currently only intended to be used by the fiddle tool, not
  ** end users, so is "undocumented." */
  ".open ?OPTIONS? ?FILE?   Close existing database and reopen FILE",
  "     Options:",
  "        --append        Use appendvfs to append database to the end of FILE",
#endif
#ifndef SQLITE_OMIT_DESERIALIZE
  "        --deserialize   Load into memory using sqlite3_deserialize()",
  "        --hexdb         Load the output of \"dbtotxt\" as an in-memory db",
  "        --maxsize N     Maximum size for --hexdb or --deserialized database",
#endif
  "        --new           Initialize FILE to an empty database",
  "        --nofollow      Do not follow symbolic links",
  "        --readonly      Open FILE readonly",
  "        --zip           FILE is a ZIP archive",
#ifndef SQLITE_SHELL_WASM_MODE
  ".output ?FILE?           Send output to FILE or stdout if FILE is omitted",
  "   If FILE begins with '|' then open it as a pipe.",
  "   Options:",
  "     --bom                 Prefix output with a UTF8 byte-order mark",
  "     -e                    Send output to the system text editor",
  "     -x                    Send output as CSV to a spreadsheet",
#endif
  ".parameter CMD ...       Manage SQL parameter bindings",
  "   clear                   Erase all bindings",
  "   init                    Initialize the TEMP table that holds bindings",
  "   list                    List the current parameter bindings",
  "   set PARAMETER VALUE     Given SQL parameter PARAMETER a value of VALUE",
  "                           PARAMETER should start with one of: $ : @ ?",
  "   unset PARAMETER         Remove PARAMETER from the binding table",
  ".print STRING...         Print literal STRING",
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
  ".progress N              Invoke progress handler after every N opcodes",
  "   --limit N                 Interrupt after N progress callbacks",
  "   --once                    Do no more than one progress interrupt",
  "   --quiet|-q                No output except at interrupts",
  "   --reset                   Reset the count for each input and interrupt",
#endif
  ".prompt MAIN CONTINUE    Replace the standard prompts",
#ifndef SQLITE_SHELL_WASM_MODE
  ".quit                    Exit this program",
  ".read FILE               Read input from FILE or command output",
  "    If FILE begins with \"|\", it is a command that generates the input.",
#endif
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
  ".recover                 Recover as much data as possible from corrupt db.",
  "   --freelist-corrupt       Assume the freelist is corrupt",
  "   --recovery-db NAME       Store recovery metadata in database file NAME",
  "   --lost-and-found TABLE   Alternative name for the lost-and-found table",
  "   --no-rowids              Do not attempt to recover rowid values",
  "                            that are not also INTEGER PRIMARY KEYs",
#endif
#ifndef SQLITE_SHELL_WASM_MODE
  ".restore ?DB? FILE       Restore content of DB (default \"main\") from FILE",
  ".save ?OPTIONS? FILE     Write database to FILE (an alias for .backup ...)",
#endif
  ".scanstats on|off        Turn sqlite3_stmt_scanstatus() metrics on or off",
  ".schema ?PATTERN?        Show the CREATE statements matching PATTERN",
  "   Options:",
  "      --indent             Try to pretty-print the schema",
  "      --nosys              Omit objects whose names start with \"sqlite_\"",
  ".selftest ?OPTIONS?      Run tests defined in the SELFTEST table",
  "    Options:",
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453

4454

4455
4456
4457
4458
4459
4460
4461
  "    Options:",
  "      --schema              Also hash the sqlite_schema table",
  "      --sha3-224            Use the sha3-224 algorithm",
  "      --sha3-256            Use the sha3-256 algorithm (default)",
  "      --sha3-384            Use the sha3-384 algorithm",
  "      --sha3-512            Use the sha3-512 algorithm",
  "    Any other argument is a LIKE pattern for tables to hash",
#ifndef SQLITE_NOHAVE_SYSTEM
  ".shell CMD ARGS...       Run CMD ARGS... in a system shell",
#endif
  ".show                    Show the current values for various settings",
  ".stats ?ARG?             Show stats or turn stats on or off",
  "   off                      Turn off automatic stat display",
  "   on                       Turn on automatic stat display",
  "   stmt                     Show statement stats",
  "   vmstep                   Show the virtual machine step count only",
#ifndef SQLITE_NOHAVE_SYSTEM
  ".system CMD ARGS...      Run CMD ARGS... in a system shell",
#endif
  ".tables ?TABLE?          List names of tables matching LIKE pattern TABLE",

  ".testcase NAME           Begin redirecting output to 'testcase-out.txt'",

  ".testctrl CMD ...        Run various sqlite3_test_control() operations",
  "                           Run \".testctrl\" with no arguments for details",
  ".timeout MS              Try opening locked tables for MS milliseconds",
  ".timer on|off            Turn SQL timer on or off",
#ifndef SQLITE_OMIT_TRACE
  ".trace ?OPTIONS?         Output each SQL statement as it is run",
  "    FILE                    Send output to FILE",







|








|



>

>







4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
  "    Options:",
  "      --schema              Also hash the sqlite_schema table",
  "      --sha3-224            Use the sha3-224 algorithm",
  "      --sha3-256            Use the sha3-256 algorithm (default)",
  "      --sha3-384            Use the sha3-384 algorithm",
  "      --sha3-512            Use the sha3-512 algorithm",
  "    Any other argument is a LIKE pattern for tables to hash",
#if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_WASM_MODE)
  ".shell CMD ARGS...       Run CMD ARGS... in a system shell",
#endif
  ".show                    Show the current values for various settings",
  ".stats ?ARG?             Show stats or turn stats on or off",
  "   off                      Turn off automatic stat display",
  "   on                       Turn on automatic stat display",
  "   stmt                     Show statement stats",
  "   vmstep                   Show the virtual machine step count only",
#if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_WASM_MODE)
  ".system CMD ARGS...      Run CMD ARGS... in a system shell",
#endif
  ".tables ?TABLE?          List names of tables matching LIKE pattern TABLE",
#ifndef SQLITE_SHELL_WASM_MODE
  ".testcase NAME           Begin redirecting output to 'testcase-out.txt'",
#endif
  ".testctrl CMD ...        Run various sqlite3_test_control() operations",
  "                           Run \".testctrl\" with no arguments for details",
  ".timeout MS              Try opening locked tables for MS milliseconds",
  ".timer on|off            Turn SQL timer on or off",
#ifndef SQLITE_OMIT_TRACE
  ".trace ?OPTIONS?         Output each SQL statement as it is run",
  "    FILE                    Send output to FILE",
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006




5007
5008
5009
5010
5011
5012
5013
        return;
      }
      exit(1);
    }
#ifndef SQLITE_OMIT_LOAD_EXTENSION
    sqlite3_enable_load_extension(p->db, 1);
#endif
    sqlite3_fileio_init(p->db, 0, 0);
    sqlite3_shathree_init(p->db, 0, 0);
    sqlite3_completion_init(p->db, 0, 0);
    sqlite3_uint_init(p->db, 0, 0);
    sqlite3_decimal_init(p->db, 0, 0);
    sqlite3_regexp_init(p->db, 0, 0);
    sqlite3_ieee_init(p->db, 0, 0);
    sqlite3_series_init(p->db, 0, 0);




#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
    sqlite3_dbdata_init(p->db, 0, 0);
#endif
#ifdef SQLITE_HAVE_ZLIB
    if( !p->bSafeModePersist ){
      sqlite3_zipfile_init(p->db, 0, 0);
      sqlite3_sqlar_init(p->db, 0, 0);







<

<





>
>
>
>







5040
5041
5042
5043
5044
5045
5046

5047

5048
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
        return;
      }
      exit(1);
    }
#ifndef SQLITE_OMIT_LOAD_EXTENSION
    sqlite3_enable_load_extension(p->db, 1);
#endif

    sqlite3_shathree_init(p->db, 0, 0);

    sqlite3_uint_init(p->db, 0, 0);
    sqlite3_decimal_init(p->db, 0, 0);
    sqlite3_regexp_init(p->db, 0, 0);
    sqlite3_ieee_init(p->db, 0, 0);
    sqlite3_series_init(p->db, 0, 0);
#ifndef SQLITE_SHELL_WASM_MODE
    sqlite3_fileio_init(p->db, 0, 0);
    sqlite3_completion_init(p->db, 0, 0);
#endif
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
    sqlite3_dbdata_init(p->db, 0, 0);
#endif
#ifdef SQLITE_HAVE_ZLIB
    if( !p->bSafeModePersist ){
      sqlite3_zipfile_init(p->db, 0, 0);
      sqlite3_sqlar_init(p->db, 0, 0);
8122
8123
8124
8125
8126
8127
8128
8129

8130
8131
8132
8133
8134
8135
8136

8137
8138
8139
8140
8141
8142
8143
      sqlite3_set_authorizer(p->db, safeModeAuth, p);
    }else{
      sqlite3_set_authorizer(p->db, 0, 0);
    }
  }else
#endif

#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)

  if( c=='a' && strncmp(azArg[0], "archive", n)==0 ){
    open_db(p, 0);
    failIfSafeMode(p, "cannot run .archive in safe mode");
    rc = arDotCommand(p, 0, azArg, nArg);
  }else
#endif


  if( (c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0)
   || (c=='s' && n>=3 && strncmp(azArg[0], "save", n)==0)
  ){
    const char *zDestFile = 0;
    const char *zDb = 0;
    sqlite3 *pDest;
    sqlite3_backup *pBackup;







|
>







>







8172
8173
8174
8175
8176
8177
8178
8179
8180
8181
8182
8183
8184
8185
8186
8187
8188
8189
8190
8191
8192
8193
8194
8195
      sqlite3_set_authorizer(p->db, safeModeAuth, p);
    }else{
      sqlite3_set_authorizer(p->db, 0, 0);
    }
  }else
#endif

#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) \
  && !defined(SQLITE_SHELL_WASM_MODE)
  if( c=='a' && strncmp(azArg[0], "archive", n)==0 ){
    open_db(p, 0);
    failIfSafeMode(p, "cannot run .archive in safe mode");
    rc = arDotCommand(p, 0, azArg, nArg);
  }else
#endif

#ifndef SQLITE_SHELL_WASM_MODE
  if( (c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0)
   || (c=='s' && n>=3 && strncmp(azArg[0], "save", n)==0)
  ){
    const char *zDestFile = 0;
    const char *zDb = 0;
    sqlite3 *pDest;
    sqlite3_backup *pBackup;
8198
8199
8200
8201
8202
8203
8204

8205
8206
8207
8208
8209
8210
8211
      rc = 0;
    }else{
      utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
      rc = 1;
    }
    close_db(pDest);
  }else


  if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 ){
    if( nArg==2 ){
      bail_on_error = booleanValue(azArg[1]);
    }else{
      raw_printf(stderr, "Usage: .bail on|off\n");
      rc = 1;







>







8250
8251
8252
8253
8254
8255
8256
8257
8258
8259
8260
8261
8262
8263
8264
      rc = 0;
    }else{
      utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
      rc = 1;
    }
    close_db(pDest);
  }else
#endif /* !defined(SQLITE_SHELL_WASM_MODE) */

  if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 ){
    if( nArg==2 ){
      bail_on_error = booleanValue(azArg[1]);
    }else{
      raw_printf(stderr, "Usage: .bail on|off\n");
      rc = 1;
8228
8229
8230
8231
8232
8233
8234

8235
8236
8237
8238
8239
8240
8241
8242
8243
8244
8245
8246
8247
8248
8249
8250
8251
8252
8253

8254
8255
8256
8257
8258
8259
8260
8261
8262
8263

8264
8265
8266
8267
8268
8269
8270
  /* The undocumented ".breakpoint" command causes a call to the no-op
  ** routine named test_breakpoint().
  */
  if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){
    test_breakpoint();
  }else


  if( c=='c' && strcmp(azArg[0],"cd")==0 ){
    failIfSafeMode(p, "cannot run .cd in safe mode");
    if( nArg==2 ){
#if defined(_WIN32) || defined(WIN32)
      wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]);
      rc = !SetCurrentDirectoryW(z);
      sqlite3_free(z);
#else
      rc = chdir(azArg[1]);
#endif
      if( rc ){
        utf8_printf(stderr, "Cannot change to directory \"%s\"\n", azArg[1]);
        rc = 1;
      }
    }else{
      raw_printf(stderr, "Usage: .cd DIRECTORY\n");
      rc = 1;
    }
  }else


  if( c=='c' && n>=3 && strncmp(azArg[0], "changes", n)==0 ){
    if( nArg==2 ){
      setOrClearFlag(p, SHFLG_CountChanges, azArg[1]);
    }else{
      raw_printf(stderr, "Usage: .changes on|off\n");
      rc = 1;
    }
  }else


  /* Cancel output redirection, if it is currently set (by .testcase)
  ** Then read the content of the testcase-out.txt file and compare against
  ** azArg[1].  If there are differences, report an error and exit.
  */
  if( c=='c' && n>=3 && strncmp(azArg[0], "check", n)==0 ){
    char *zRes = 0;
    output_reset(p);







>



















>










>







8281
8282
8283
8284
8285
8286
8287
8288
8289
8290
8291
8292
8293
8294
8295
8296
8297
8298
8299
8300
8301
8302
8303
8304
8305
8306
8307
8308
8309
8310
8311
8312
8313
8314
8315
8316
8317
8318
8319
8320
8321
8322
8323
8324
8325
8326
  /* The undocumented ".breakpoint" command causes a call to the no-op
  ** routine named test_breakpoint().
  */
  if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){
    test_breakpoint();
  }else

#ifndef SQLITE_SHELL_WASM_MODE
  if( c=='c' && strcmp(azArg[0],"cd")==0 ){
    failIfSafeMode(p, "cannot run .cd in safe mode");
    if( nArg==2 ){
#if defined(_WIN32) || defined(WIN32)
      wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]);
      rc = !SetCurrentDirectoryW(z);
      sqlite3_free(z);
#else
      rc = chdir(azArg[1]);
#endif
      if( rc ){
        utf8_printf(stderr, "Cannot change to directory \"%s\"\n", azArg[1]);
        rc = 1;
      }
    }else{
      raw_printf(stderr, "Usage: .cd DIRECTORY\n");
      rc = 1;
    }
  }else
#endif /* !defined(SQLITE_SHELL_WASM_MODE) */

  if( c=='c' && n>=3 && strncmp(azArg[0], "changes", n)==0 ){
    if( nArg==2 ){
      setOrClearFlag(p, SHFLG_CountChanges, azArg[1]);
    }else{
      raw_printf(stderr, "Usage: .changes on|off\n");
      rc = 1;
    }
  }else

#ifndef SQLITE_SHELL_WASM_MODE
  /* Cancel output redirection, if it is currently set (by .testcase)
  ** Then read the content of the testcase-out.txt file and compare against
  ** azArg[1].  If there are differences, report an error and exit.
  */
  if( c=='c' && n>=3 && strncmp(azArg[0], "check", n)==0 ){
    char *zRes = 0;
    output_reset(p);
8281
8282
8283
8284
8285
8286
8287

8288

8289
8290
8291
8292
8293
8294
8295
8296
8297

8298
8299
8300
8301
8302
8303
8304
      rc = 1;
    }else{
      utf8_printf(stdout, "testcase-%s ok\n", p->zTestcase);
      p->nCheck++;
    }
    sqlite3_free(zRes);
  }else



  if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){
    failIfSafeMode(p, "cannot run .clone in safe mode");
    if( nArg==2 ){
      tryToClone(p, azArg[1]);
    }else{
      raw_printf(stderr, "Usage: .clone FILENAME\n");
      rc = 1;
    }
  }else


  if( c=='c' && strncmp(azArg[0], "connection", n)==0 ){
    if( nArg==1 ){
      /* List available connections */
      int i;
      for(i=0; i<ArraySize(p->aAuxDb); i++){
        const char *zFile = p->aAuxDb[i].zDbFilename;







>

>









>







8337
8338
8339
8340
8341
8342
8343
8344
8345
8346
8347
8348
8349
8350
8351
8352
8353
8354
8355
8356
8357
8358
8359
8360
8361
8362
8363
      rc = 1;
    }else{
      utf8_printf(stdout, "testcase-%s ok\n", p->zTestcase);
      p->nCheck++;
    }
    sqlite3_free(zRes);
  }else
#endif /* !defined(SQLITE_SHELL_WASM_MODE) */

#ifndef SQLITE_SHELL_WASM_MODE
  if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){
    failIfSafeMode(p, "cannot run .clone in safe mode");
    if( nArg==2 ){
      tryToClone(p, azArg[1]);
    }else{
      raw_printf(stderr, "Usage: .clone FILENAME\n");
      rc = 1;
    }
  }else
#endif /* !defined(SQLITE_SHELL_WASM_MODE) */

  if( c=='c' && strncmp(azArg[0], "connection", n)==0 ){
    if( nArg==1 ){
      /* List available connections */
      int i;
      for(i=0; i<ArraySize(p->aAuxDb); i++){
        const char *zFile = p->aAuxDb[i].zDbFilename;
8433
8434
8435
8436
8437
8438
8439
8440
8441
8442
8443
8444
8445
8446
8447

  if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
    char *zLike = 0;
    char *zSql;
    int i;
    int savedShowHeader = p->showHeader;
    int savedShellFlags = p->shellFlgs;
    ShellClearFlag(p, 
       SHFLG_PreserveRowid|SHFLG_Newlines|SHFLG_Echo
       |SHFLG_DumpDataOnly|SHFLG_DumpNoSys);
    for(i=1; i<nArg; i++){
      if( azArg[i][0]=='-' ){
        const char *z = azArg[i]+1;
        if( z[0]=='-' ) z++;
        if( strcmp(z,"preserve-rowids")==0 ){







|







8492
8493
8494
8495
8496
8497
8498
8499
8500
8501
8502
8503
8504
8505
8506

  if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
    char *zLike = 0;
    char *zSql;
    int i;
    int savedShowHeader = p->showHeader;
    int savedShellFlags = p->shellFlgs;
    ShellClearFlag(p,
       SHFLG_PreserveRowid|SHFLG_Newlines|SHFLG_Echo
       |SHFLG_DumpDataOnly|SHFLG_DumpNoSys);
    for(i=1; i<nArg; i++){
      if( azArg[i][0]=='-' ){
        const char *z = azArg[i]+1;
        if( z[0]=='-' ) z++;
        if( strcmp(z,"preserve-rowids")==0 ){
8579
8580
8581
8582
8583
8584
8585

8586
8587
8588
8589

8590
8591
8592
8593
8594
8595
8596
      }
    }else{
      raw_printf(stderr, "Usage: .eqp off|on|trace|trigger|full\n");
      rc = 1;
    }
  }else


  if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
    if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) exit(rc);
    rc = 2;
  }else


  /* The ".explain" command is automatic now.  It is largely pointless.  It
  ** retained purely for backwards compatibility */
  if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
    int val = 1;
    if( nArg>=2 ){
      if( strcmp(azArg[1],"auto")==0 ){







>




>







8638
8639
8640
8641
8642
8643
8644
8645
8646
8647
8648
8649
8650
8651
8652
8653
8654
8655
8656
8657
      }
    }else{
      raw_printf(stderr, "Usage: .eqp off|on|trace|trigger|full\n");
      rc = 1;
    }
  }else

#ifndef SQLITE_SHELL_WASM_MODE
  if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
    if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) exit(rc);
    rc = 2;
  }else
#endif

  /* The ".explain" command is automatic now.  It is largely pointless.  It
  ** retained purely for backwards compatibility */
  if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
    int val = 1;
    if( nArg>=2 ){
      if( strcmp(azArg[1],"auto")==0 ){
8837
8838
8839
8840
8841
8842
8843

8844
8845
8846
8847
8848
8849
8850
        utf8_printf(p->out, "Nothing matches '%s'\n", azArg[1]);
      }
    }else{
      showHelp(p->out, 0);
    }
  }else


  if( c=='i' && strncmp(azArg[0], "import", n)==0 ){
    char *zTable = 0;           /* Insert data into this table */
    char *zSchema = 0;          /* within this schema (may default to "main") */
    char *zFile = 0;            /* Name of file to extra content from */
    sqlite3_stmt *pStmt = NULL; /* A statement */
    int nCol;                   /* Number of columns in the table */
    int nByte;                  /* Number of bytes in an SQL string */







>







8898
8899
8900
8901
8902
8903
8904
8905
8906
8907
8908
8909
8910
8911
8912
        utf8_printf(p->out, "Nothing matches '%s'\n", azArg[1]);
      }
    }else{
      showHelp(p->out, 0);
    }
  }else

#ifndef SQLITE_SHELL_WASM_MODE
  if( c=='i' && strncmp(azArg[0], "import", n)==0 ){
    char *zTable = 0;           /* Insert data into this table */
    char *zSchema = 0;          /* within this schema (may default to "main") */
    char *zFile = 0;            /* Name of file to extra content from */
    sqlite3_stmt *pStmt = NULL; /* A statement */
    int nCol;                   /* Number of columns in the table */
    int nByte;                  /* Number of bytes in an SQL string */
8858
8859
8860
8861
8862
8863
8864
8865
8866
8867
8868
8869
8870
8871
8872
8873
8874

8875
8876
8877
8878
8879
8880
8881
8882
8883
8884
8885
8886
8887
8888
8889
8890
8891
8892
8893
    int eVerbose = 0;           /* Larger for more console output */
    int nSkip = 0;              /* Initial lines to skip */
    int useOutputMode = 1;      /* Use output mode to determine separators */
    char *zCreate = 0;          /* CREATE TABLE statement text */

    failIfSafeMode(p, "cannot run .import in safe mode");
    memset(&sCtx, 0, sizeof(sCtx));
    sCtx.z = sqlite3_malloc64(120);
    if( sCtx.z==0 ){
      import_cleanup(&sCtx);
      shell_out_of_memory();
    }
    if( p->mode==MODE_Ascii ){
      xRead = ascii_read_one_field;
    }else{
      xRead = csv_read_one_field;
    }

    for(i=1; i<nArg; i++){
      char *z = azArg[i];
      if( z[0]=='-' && z[1]=='-' ) z++;
      if( z[0]!='-' ){
        if( zFile==0 ){
          zFile = z;
        }else if( zTable==0 ){
          zTable = z;
        }else{
          utf8_printf(p->out, "ERROR: extra argument: \"%s\".  Usage:\n", z);
          showHelp(p->out, "import");
          rc = 1;
          goto meta_command_exit;
        }
      }else if( strcmp(z,"-v")==0 ){
        eVerbose++;
      }else if( strcmp(z,"-schema")==0 && i<nArg-1 ){
        zSchema = azArg[++i];
      }else if( strcmp(z,"-skip")==0 && i<nArg-1 ){







<
<
<
<
<





>











<







8920
8921
8922
8923
8924
8925
8926





8927
8928
8929
8930
8931
8932
8933
8934
8935
8936
8937
8938
8939
8940
8941
8942
8943

8944
8945
8946
8947
8948
8949
8950
    int eVerbose = 0;           /* Larger for more console output */
    int nSkip = 0;              /* Initial lines to skip */
    int useOutputMode = 1;      /* Use output mode to determine separators */
    char *zCreate = 0;          /* CREATE TABLE statement text */

    failIfSafeMode(p, "cannot run .import in safe mode");
    memset(&sCtx, 0, sizeof(sCtx));





    if( p->mode==MODE_Ascii ){
      xRead = ascii_read_one_field;
    }else{
      xRead = csv_read_one_field;
    }
    rc = 1;
    for(i=1; i<nArg; i++){
      char *z = azArg[i];
      if( z[0]=='-' && z[1]=='-' ) z++;
      if( z[0]!='-' ){
        if( zFile==0 ){
          zFile = z;
        }else if( zTable==0 ){
          zTable = z;
        }else{
          utf8_printf(p->out, "ERROR: extra argument: \"%s\".  Usage:\n", z);
          showHelp(p->out, "import");

          goto meta_command_exit;
        }
      }else if( strcmp(z,"-v")==0 ){
        eVerbose++;
      }else if( strcmp(z,"-schema")==0 && i<nArg-1 ){
        zSchema = azArg[++i];
      }else if( strcmp(z,"-skip")==0 && i<nArg-1 ){
8901
8902
8903
8904
8905
8906
8907
8908
8909
8910
8911
8912
8913
8914
8915
8916
8917
8918
8919
8920
8921
8922
8923
8924
8925
8926
8927
8928
8929
8930
8931
8932
8933
8934
8935
8936
8937
8938
8939
8940
8941
8942
8943
8944
8945
8946
8947
8948
8949
8950
8951
8952
8953
8954
8955
8956
8957
8958
8959
8960
8961
8962
8963
8964
8965
8966
8967
8968
8969
8970
8971
8972
8973
8974
8975
8976
8977
8978
8979
8980
8981
8982
8983
8984
8985
8986
8987
8988
8989
8990
8991
8992
8993





8994
8995
8996
8997
8998
8999
9000
        sCtx.cColSep = ',';
        sCtx.cRowSep = '\n';
        xRead = csv_read_one_field;
        useOutputMode = 0;
      }else{
        utf8_printf(p->out, "ERROR: unknown option: \"%s\".  Usage:\n", z);
        showHelp(p->out, "import");
        rc = 1;
        goto meta_command_exit;
      }
    }
    if( zTable==0 ){
      utf8_printf(p->out, "ERROR: missing %s argument. Usage:\n",
                  zFile==0 ? "FILE" : "TABLE");
      showHelp(p->out, "import");
      rc = 1;
      goto meta_command_exit;
    }
    seenInterrupt = 0;
    open_db(p, 0);
    if( useOutputMode ){
      /* If neither the --csv or --ascii options are specified, then set
      ** the column and row separator characters from the output mode. */
      nSep = strlen30(p->colSeparator);
      if( nSep==0 ){
        raw_printf(stderr,
                   "Error: non-null column separator required for import\n");
        rc = 1;
        goto meta_command_exit;
      }
      if( nSep>1 ){
        raw_printf(stderr, 
              "Error: multi-character column separators not allowed"
              " for import\n");
        rc = 1;
        goto meta_command_exit;
      }
      nSep = strlen30(p->rowSeparator);
      if( nSep==0 ){
        raw_printf(stderr,
            "Error: non-null row separator required for import\n");
        rc = 1;
        goto meta_command_exit;
      }
      if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator,SEP_CrLf)==0 ){
        /* When importing CSV (only), if the row separator is set to the
        ** default output row separator, change it to the default input
        ** row separator.  This avoids having to maintain different input
        ** and output row separators. */
        sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
        nSep = strlen30(p->rowSeparator);
      }
      if( nSep>1 ){
        raw_printf(stderr, "Error: multi-character row separators not allowed"
                           " for import\n");
        rc = 1;
        goto meta_command_exit;
      }
      sCtx.cColSep = p->colSeparator[0];
      sCtx.cRowSep = p->rowSeparator[0];
    }
    sCtx.zFile = zFile;
    sCtx.nLine = 1;
    if( sCtx.zFile[0]=='|' ){
#ifdef SQLITE_OMIT_POPEN
      raw_printf(stderr, "Error: pipes are not supported in this OS\n");
      rc = 1;
      goto meta_command_exit;
#else
      sCtx.in = popen(sCtx.zFile+1, "r");
      sCtx.zFile = "<pipe>";
      sCtx.xCloser = pclose;
#endif
    }else{
      sCtx.in = fopen(sCtx.zFile, "rb");
      sCtx.xCloser = fclose;
    }
    if( sCtx.in==0 ){
      utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
      rc = 1;
      import_cleanup(&sCtx);
      goto meta_command_exit;
    }
    if( eVerbose>=2 || (eVerbose>=1 && useOutputMode) ){
      char zSep[2];
      zSep[1] = 0;
      zSep[0] = sCtx.cColSep;
      utf8_printf(p->out, "Column separator ");
      output_c_string(p->out, zSep);
      utf8_printf(p->out, ", row separator ");
      zSep[0] = sCtx.cRowSep;
      output_c_string(p->out, zSep);
      utf8_printf(p->out, "\n");





    }
    /* Below, resources must be freed before exit. */
    while( (nSkip--)>0 ){
      while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
    }
    if( zSchema!=0 ){
      zFullTabName = sqlite3_mprintf("\"%w\".\"%w\"", zSchema, zTable);







<







<











<



|


<






<













<










<












<
<












>
>
>
>
>







8958
8959
8960
8961
8962
8963
8964

8965
8966
8967
8968
8969
8970
8971

8972
8973
8974
8975
8976
8977
8978
8979
8980
8981
8982

8983
8984
8985
8986
8987
8988

8989
8990
8991
8992
8993
8994

8995
8996
8997
8998
8999
9000
9001
9002
9003
9004
9005
9006
9007

9008
9009
9010
9011
9012
9013
9014
9015
9016
9017

9018
9019
9020
9021
9022
9023
9024
9025
9026
9027
9028
9029


9030
9031
9032
9033
9034
9035
9036
9037
9038
9039
9040
9041
9042
9043
9044
9045
9046
9047
9048
9049
9050
9051
9052
9053
        sCtx.cColSep = ',';
        sCtx.cRowSep = '\n';
        xRead = csv_read_one_field;
        useOutputMode = 0;
      }else{
        utf8_printf(p->out, "ERROR: unknown option: \"%s\".  Usage:\n", z);
        showHelp(p->out, "import");

        goto meta_command_exit;
      }
    }
    if( zTable==0 ){
      utf8_printf(p->out, "ERROR: missing %s argument. Usage:\n",
                  zFile==0 ? "FILE" : "TABLE");
      showHelp(p->out, "import");

      goto meta_command_exit;
    }
    seenInterrupt = 0;
    open_db(p, 0);
    if( useOutputMode ){
      /* If neither the --csv or --ascii options are specified, then set
      ** the column and row separator characters from the output mode. */
      nSep = strlen30(p->colSeparator);
      if( nSep==0 ){
        raw_printf(stderr,
                   "Error: non-null column separator required for import\n");

        goto meta_command_exit;
      }
      if( nSep>1 ){
        raw_printf(stderr,
              "Error: multi-character column separators not allowed"
              " for import\n");

        goto meta_command_exit;
      }
      nSep = strlen30(p->rowSeparator);
      if( nSep==0 ){
        raw_printf(stderr,
            "Error: non-null row separator required for import\n");

        goto meta_command_exit;
      }
      if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator,SEP_CrLf)==0 ){
        /* When importing CSV (only), if the row separator is set to the
        ** default output row separator, change it to the default input
        ** row separator.  This avoids having to maintain different input
        ** and output row separators. */
        sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
        nSep = strlen30(p->rowSeparator);
      }
      if( nSep>1 ){
        raw_printf(stderr, "Error: multi-character row separators not allowed"
                           " for import\n");

        goto meta_command_exit;
      }
      sCtx.cColSep = p->colSeparator[0];
      sCtx.cRowSep = p->rowSeparator[0];
    }
    sCtx.zFile = zFile;
    sCtx.nLine = 1;
    if( sCtx.zFile[0]=='|' ){
#ifdef SQLITE_OMIT_POPEN
      raw_printf(stderr, "Error: pipes are not supported in this OS\n");

      goto meta_command_exit;
#else
      sCtx.in = popen(sCtx.zFile+1, "r");
      sCtx.zFile = "<pipe>";
      sCtx.xCloser = pclose;
#endif
    }else{
      sCtx.in = fopen(sCtx.zFile, "rb");
      sCtx.xCloser = fclose;
    }
    if( sCtx.in==0 ){
      utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);


      goto meta_command_exit;
    }
    if( eVerbose>=2 || (eVerbose>=1 && useOutputMode) ){
      char zSep[2];
      zSep[1] = 0;
      zSep[0] = sCtx.cColSep;
      utf8_printf(p->out, "Column separator ");
      output_c_string(p->out, zSep);
      utf8_printf(p->out, ", row separator ");
      zSep[0] = sCtx.cRowSep;
      output_c_string(p->out, zSep);
      utf8_printf(p->out, "\n");
    }
    sCtx.z = sqlite3_malloc64(120);
    if( sCtx.z==0 ){
      import_cleanup(&sCtx);
      shell_out_of_memory();
    }
    /* Below, resources must be freed before exit. */
    while( (nSkip--)>0 ){
      while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
    }
    if( zSchema!=0 ){
      zFullTabName = sqlite3_mprintf("\"%w\".\"%w\"", zSchema, zTable);
9136
9137
9138
9139
9140
9141
9142

9143
9144
9145
9146
9147
9148
9149
    if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
    if( eVerbose>0 ){
      utf8_printf(p->out,
          "Added %d rows with %d errors using %d lines of input\n",
          sCtx.nRow, sCtx.nErr, sCtx.nLine-1);
    }
  }else


#ifndef SQLITE_UNTESTABLE
  if( c=='i' && strncmp(azArg[0], "imposter", n)==0 ){
    char *zSql;
    char *zCollist = 0;
    sqlite3_stmt *pStmt;
    int tnum = 0;







>







9189
9190
9191
9192
9193
9194
9195
9196
9197
9198
9199
9200
9201
9202
9203
    if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
    if( eVerbose>0 ){
      utf8_printf(p->out,
          "Added %d rows with %d errors using %d lines of input\n",
          sCtx.nRow, sCtx.nErr, sCtx.nLine-1);
    }
  }else
#endif /* !defined(SQLITE_SHELL_WASM_MODE) */

#ifndef SQLITE_UNTESTABLE
  if( c=='i' && strncmp(azArg[0], "imposter", n)==0 ){
    char *zSql;
    char *zCollist = 0;
    sqlite3_stmt *pStmt;
    int tnum = 0;
9325
9326
9327
9328
9329
9330
9331
9332
9333
9334
9335
9336
9337
9338
9339
  }else

  if( c=='l' && n>2 && strncmp(azArg[0], "lint", n)==0 ){
    open_db(p, 0);
    lintDotCommand(p, azArg, nArg);
  }else

#ifndef SQLITE_OMIT_LOAD_EXTENSION
  if( c=='l' && strncmp(azArg[0], "load", n)==0 ){
    const char *zFile, *zProc;
    char *zErrMsg = 0;
    failIfSafeMode(p, "cannot run .load in safe mode");
    if( nArg<2 ){
      raw_printf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n");
      rc = 1;







|







9379
9380
9381
9382
9383
9384
9385
9386
9387
9388
9389
9390
9391
9392
9393
  }else

  if( c=='l' && n>2 && strncmp(azArg[0], "lint", n)==0 ){
    open_db(p, 0);
    lintDotCommand(p, azArg, nArg);
  }else

#if !defined(SQLITE_OMIT_LOAD_EXTENSION) && !defined(SQLITE_SHELL_WASM_MODE)
  if( c=='l' && strncmp(azArg[0], "load", n)==0 ){
    const char *zFile, *zProc;
    char *zErrMsg = 0;
    failIfSafeMode(p, "cannot run .load in safe mode");
    if( nArg<2 ){
      raw_printf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n");
      rc = 1;
9347
9348
9349
9350
9351
9352
9353

9354
9355
9356
9357
9358
9359
9360
9361
9362
9363
9364

9365
9366
9367
9368
9369
9370
9371
      utf8_printf(stderr, "Error: %s\n", zErrMsg);
      sqlite3_free(zErrMsg);
      rc = 1;
    }
  }else
#endif


  if( c=='l' && strncmp(azArg[0], "log", n)==0 ){
    failIfSafeMode(p, "cannot run .log in safe mode");
    if( nArg!=2 ){
      raw_printf(stderr, "Usage: .log FILENAME\n");
      rc = 1;
    }else{
      const char *zFile = azArg[1];
      output_file_close(p->pLog);
      p->pLog = output_file_open(zFile, 0);
    }
  }else


  if( c=='m' && strncmp(azArg[0], "mode", n)==0 ){
    const char *zMode = 0;
    const char *zTabname = 0;
    int i, n2;
    ColModeOpts cmOpts = ColModeOpts_default;
    for(i=1; i<nArg; i++){







>











>







9401
9402
9403
9404
9405
9406
9407
9408
9409
9410
9411
9412
9413
9414
9415
9416
9417
9418
9419
9420
9421
9422
9423
9424
9425
9426
9427
      utf8_printf(stderr, "Error: %s\n", zErrMsg);
      sqlite3_free(zErrMsg);
      rc = 1;
    }
  }else
#endif

#ifndef SQLITE_SHELL_WASM_MODE
  if( c=='l' && strncmp(azArg[0], "log", n)==0 ){
    failIfSafeMode(p, "cannot run .log in safe mode");
    if( nArg!=2 ){
      raw_printf(stderr, "Usage: .log FILENAME\n");
      rc = 1;
    }else{
      const char *zFile = azArg[1];
      output_file_close(p->pLog);
      p->pLog = output_file_open(zFile, 0);
    }
  }else
#endif

  if( c=='m' && strncmp(azArg[0], "mode", n)==0 ){
    const char *zMode = 0;
    const char *zTabname = 0;
    int i, n2;
    ColModeOpts cmOpts = ColModeOpts_default;
    for(i=1; i<nArg; i++){
9482
9483
9484
9485
9486
9487
9488

9489
9490
9491
9492
9493
9494
9495
9496
9497
9498
9499
9500
9501
9502

9503
9504
9505
9506
9507
9508
9509
         "ascii box column csv html insert json line list markdown "
         "qbox quote table tabs tcl\n");
      rc = 1;
    }
    p->cMode = p->mode;
  }else


  if( c=='n' && strcmp(azArg[0], "nonce")==0 ){
    if( nArg!=2 ){
      raw_printf(stderr, "Usage: .nonce NONCE\n");
      rc = 1;
    }else if( p->zNonce==0 || strcmp(azArg[1],p->zNonce)!=0 ){
      raw_printf(stderr, "line %d: incorrect nonce: \"%s\"\n",
                 p->lineno, azArg[1]);
      exit(1);
    }else{
      p->bSafeMode = 0;
      return 0;  /* Return immediately to bypass the safe mode reset
                 ** at the end of this procedure */
    }
  }else


  if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){
    if( nArg==2 ){
      sqlite3_snprintf(sizeof(p->nullValue), p->nullValue,
                       "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]);
    }else{
      raw_printf(stderr, "Usage: .nullvalue STRING\n");







>














>







9538
9539
9540
9541
9542
9543
9544
9545
9546
9547
9548
9549
9550
9551
9552
9553
9554
9555
9556
9557
9558
9559
9560
9561
9562
9563
9564
9565
9566
9567
         "ascii box column csv html insert json line list markdown "
         "qbox quote table tabs tcl\n");
      rc = 1;
    }
    p->cMode = p->mode;
  }else

#ifndef SQLITE_SHELL_WASM_MODE
  if( c=='n' && strcmp(azArg[0], "nonce")==0 ){
    if( nArg!=2 ){
      raw_printf(stderr, "Usage: .nonce NONCE\n");
      rc = 1;
    }else if( p->zNonce==0 || strcmp(azArg[1],p->zNonce)!=0 ){
      raw_printf(stderr, "line %d: incorrect nonce: \"%s\"\n",
                 p->lineno, azArg[1]);
      exit(1);
    }else{
      p->bSafeMode = 0;
      return 0;  /* Return immediately to bypass the safe mode reset
                 ** at the end of this procedure */
    }
  }else
#endif /* !defined(SQLITE_SHELL_WASM_MODE) */

  if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){
    if( nArg==2 ){
      sqlite3_snprintf(sizeof(p->nullValue), p->nullValue,
                       "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]);
    }else{
      raw_printf(stderr, "Usage: .nullvalue STRING\n");
9517
9518
9519
9520
9521
9522
9523

9524
9525
9526
9527
9528
9529
9530
9531
9532
9533
9534
9535
9536
9537
9538
9539
9540
9541
9542
9543


9544
9545
9546
9547
9548
9549
9550
9551
    int iName = 1;           /* Index in azArg[] of the filename */
    int newFlag = 0;         /* True to delete file before opening */
    int openMode = SHELL_OPEN_UNSPEC;

    /* Check for command-line arguments */
    for(iName=1; iName<nArg; iName++){
      const char *z = azArg[iName];

      if( optionMatch(z,"new") ){
        newFlag = 1;
#ifdef SQLITE_HAVE_ZLIB
      }else if( optionMatch(z, "zip") ){
        openMode = SHELL_OPEN_ZIPFILE;
#endif
      }else if( optionMatch(z, "append") ){
        openMode = SHELL_OPEN_APPENDVFS;
      }else if( optionMatch(z, "readonly") ){
        openMode = SHELL_OPEN_READONLY;
      }else if( optionMatch(z, "nofollow") ){
        p->openFlags |= SQLITE_OPEN_NOFOLLOW;
#ifndef SQLITE_OMIT_DESERIALIZE
      }else if( optionMatch(z, "deserialize") ){
        openMode = SHELL_OPEN_DESERIALIZE;
      }else if( optionMatch(z, "hexdb") ){
        openMode = SHELL_OPEN_HEXDB;
      }else if( optionMatch(z, "maxsize") && iName+1<nArg ){
        p->szMax = integerValue(azArg[++iName]);
#endif /* SQLITE_OMIT_DESERIALIZE */


      }else if( z[0]=='-' ){
        utf8_printf(stderr, "unknown option: %s\n", z);
        rc = 1;
        goto meta_command_exit;
      }else if( zFN ){
        utf8_printf(stderr, "extra argument: \"%s\"\n", z);
        rc = 1;
        goto meta_command_exit;







>




















>
>
|







9575
9576
9577
9578
9579
9580
9581
9582
9583
9584
9585
9586
9587
9588
9589
9590
9591
9592
9593
9594
9595
9596
9597
9598
9599
9600
9601
9602
9603
9604
9605
9606
9607
9608
9609
9610
9611
9612
    int iName = 1;           /* Index in azArg[] of the filename */
    int newFlag = 0;         /* True to delete file before opening */
    int openMode = SHELL_OPEN_UNSPEC;

    /* Check for command-line arguments */
    for(iName=1; iName<nArg; iName++){
      const char *z = azArg[iName];
#ifndef SQLITE_SHELL_WASM_MODE
      if( optionMatch(z,"new") ){
        newFlag = 1;
#ifdef SQLITE_HAVE_ZLIB
      }else if( optionMatch(z, "zip") ){
        openMode = SHELL_OPEN_ZIPFILE;
#endif
      }else if( optionMatch(z, "append") ){
        openMode = SHELL_OPEN_APPENDVFS;
      }else if( optionMatch(z, "readonly") ){
        openMode = SHELL_OPEN_READONLY;
      }else if( optionMatch(z, "nofollow") ){
        p->openFlags |= SQLITE_OPEN_NOFOLLOW;
#ifndef SQLITE_OMIT_DESERIALIZE
      }else if( optionMatch(z, "deserialize") ){
        openMode = SHELL_OPEN_DESERIALIZE;
      }else if( optionMatch(z, "hexdb") ){
        openMode = SHELL_OPEN_HEXDB;
      }else if( optionMatch(z, "maxsize") && iName+1<nArg ){
        p->szMax = integerValue(azArg[++iName]);
#endif /* SQLITE_OMIT_DESERIALIZE */
      }else
#endif /* !SQLITE_SHELL_WASM_MODE */
      if( z[0]=='-' ){
        utf8_printf(stderr, "unknown option: %s\n", z);
        rc = 1;
        goto meta_command_exit;
      }else if( zFN ){
        utf8_printf(stderr, "extra argument: \"%s\"\n", z);
        rc = 1;
        goto meta_command_exit;
9564
9565
9566
9567
9568
9569
9570

9571
9572
9573
9574
9575
9576
9577



9578
9579
9580
9581
9582
9583
9584
    p->openMode = openMode;
    p->openFlags = 0;
    p->szMax = 0;

    /* If a filename is specified, try to open it first */
    if( zFN || p->openMode==SHELL_OPEN_HEXDB ){
      if( newFlag && zFN && !p->bSafeMode ) shellDeleteFile(zFN);

      if( p->bSafeMode
       && p->openMode!=SHELL_OPEN_HEXDB
       && zFN
       && strcmp(zFN,":memory:")!=0
      ){
        failIfSafeMode(p, "cannot open disk-based database files in safe mode");
      }



      if( zFN ){
        zNewFilename = sqlite3_mprintf("%s", zFN);
        shell_check_oom(zNewFilename);
      }else{
        zNewFilename = 0;
      }
      p->pAuxDb->zDbFilename = zNewFilename;







>







>
>
>







9625
9626
9627
9628
9629
9630
9631
9632
9633
9634
9635
9636
9637
9638
9639
9640
9641
9642
9643
9644
9645
9646
9647
9648
9649
    p->openMode = openMode;
    p->openFlags = 0;
    p->szMax = 0;

    /* If a filename is specified, try to open it first */
    if( zFN || p->openMode==SHELL_OPEN_HEXDB ){
      if( newFlag && zFN && !p->bSafeMode ) shellDeleteFile(zFN);
#ifndef SQLITE_SHELL_WASM_MODE
      if( p->bSafeMode
       && p->openMode!=SHELL_OPEN_HEXDB
       && zFN
       && strcmp(zFN,":memory:")!=0
      ){
        failIfSafeMode(p, "cannot open disk-based database files in safe mode");
      }
#else
      /* WASM mode has its own sandboxed pseudo-filesystem. */
#endif
      if( zFN ){
        zNewFilename = sqlite3_mprintf("%s", zFN);
        shell_check_oom(zNewFilename);
      }else{
        zNewFilename = 0;
      }
      p->pAuxDb->zDbFilename = zNewFilename;
9593
9594
9595
9596
9597
9598
9599

9600
9601
9602
9603
9604
9605
9606
    if( p->db==0 ){
      /* As a fall-back open a TEMP database */
      p->pAuxDb->zDbFilename = 0;
      open_db(p, 0);
    }
  }else


  if( (c=='o'
        && (strncmp(azArg[0], "output", n)==0||strncmp(azArg[0], "once", n)==0))
   || (c=='e' && n==5 && strcmp(azArg[0],"excel")==0)
  ){
    char *zFile = 0;
    int bTxtMode = 0;
    int i;







>







9658
9659
9660
9661
9662
9663
9664
9665
9666
9667
9668
9669
9670
9671
9672
    if( p->db==0 ){
      /* As a fall-back open a TEMP database */
      p->pAuxDb->zDbFilename = 0;
      open_db(p, 0);
    }
  }else

#ifndef SQLITE_SHELL_WASM_MODE
  if( (c=='o'
        && (strncmp(azArg[0], "output", n)==0||strncmp(azArg[0], "once", n)==0))
   || (c=='e' && n==5 && strcmp(azArg[0],"excel")==0)
  ){
    char *zFile = 0;
    int bTxtMode = 0;
    int i;
9708
9709
9710
9711
9712
9713
9714

9715
9716
9717
9718
9719
9720
9721
      } else {
        if( zBOM[0] ) fwrite(zBOM, 1, 3, p->out);
        sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
      }
    }
    sqlite3_free(zFile);
  }else


  if( c=='p' && n>=3 && strncmp(azArg[0], "parameter", n)==0 ){
    open_db(p,0);
    if( nArg<=1 ) goto parameter_syntax_error;

    /* .parameter clear
    ** Clear all bind parameters by dropping the TEMP table that holds them.







>







9774
9775
9776
9777
9778
9779
9780
9781
9782
9783
9784
9785
9786
9787
9788
      } else {
        if( zBOM[0] ) fwrite(zBOM, 1, 3, p->out);
        sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
      }
    }
    sqlite3_free(zFile);
  }else
#endif /* !defined(SQLITE_SHELL_WASM_MODE) */

  if( c=='p' && n>=3 && strncmp(azArg[0], "parameter", n)==0 ){
    open_db(p,0);
    if( nArg<=1 ) goto parameter_syntax_error;

    /* .parameter clear
    ** Clear all bind parameters by dropping the TEMP table that holds them.
9877
9878
9879
9880
9881
9882
9883

9884
9885
9886

9887

9888
9889
9890
9891
9892
9893
9894
      strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1);
    }
    if( nArg >= 3) {
      strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1);
    }
  }else


  if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){
    rc = 2;
  }else



  if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 ){
    FILE *inSaved = p->in;
    int savedLineno = p->lineno;
    failIfSafeMode(p, "cannot run .read in safe mode");
    if( nArg!=2 ){
      raw_printf(stderr, "Usage: .read FILE\n");
      rc = 1;







>



>

>







9944
9945
9946
9947
9948
9949
9950
9951
9952
9953
9954
9955
9956
9957
9958
9959
9960
9961
9962
9963
9964
      strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1);
    }
    if( nArg >= 3) {
      strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1);
    }
  }else

#ifndef SQLITE_SHELL_WASM_MODE
  if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){
    rc = 2;
  }else
#endif

#ifndef SQLITE_SHELL_WASM_MODE
  if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 ){
    FILE *inSaved = p->in;
    int savedLineno = p->lineno;
    failIfSafeMode(p, "cannot run .read in safe mode");
    if( nArg!=2 ){
      raw_printf(stderr, "Usage: .read FILE\n");
      rc = 1;
9915
9916
9917
9918
9919
9920
9921

9922

9923
9924
9925
9926
9927
9928
9929
    }else{
      rc = process_input(p);
      fclose(p->in);
    }
    p->in = inSaved;
    p->lineno = savedLineno;
  }else



  if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 ){
    const char *zSrcFile;
    const char *zDb;
    sqlite3 *pSrc;
    sqlite3_backup *pBackup;
    int nTimeout = 0;








>

>







9985
9986
9987
9988
9989
9990
9991
9992
9993
9994
9995
9996
9997
9998
9999
10000
10001
    }else{
      rc = process_input(p);
      fclose(p->in);
    }
    p->in = inSaved;
    p->lineno = savedLineno;
  }else
#endif /* !defined(SQLITE_SHELL_WASM_MODE) */

#ifndef SQLITE_SHELL_WASM_MODE
  if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 ){
    const char *zSrcFile;
    const char *zDb;
    sqlite3 *pSrc;
    sqlite3_backup *pBackup;
    int nTimeout = 0;

9967
9968
9969
9970
9971
9972
9973

9974
9975
9976
9977
9978
9979
9980
      rc = 1;
    }else{
      utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
      rc = 1;
    }
    close_db(pSrc);
  }else


  if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){
    if( nArg==2 ){
      p->scanstatsOn = (u8)booleanValue(azArg[1]);
#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
      raw_printf(stderr, "Warning: .scanstats not available in this build.\n");
#endif







>







10039
10040
10041
10042
10043
10044
10045
10046
10047
10048
10049
10050
10051
10052
10053
      rc = 1;
    }else{
      utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
      rc = 1;
    }
    close_db(pSrc);
  }else
#endif /* !defined(SQLITE_SHELL_WASM_MODE) */

  if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){
    if( nArg==2 ){
      p->scanstatsOn = (u8)booleanValue(azArg[1]);
#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
      raw_printf(stderr, "Warning: .scanstats not available in this build.\n");
#endif
10592
10593
10594
10595
10596
10597
10598
10599
10600
10601
10602
10603
10604
10605
10606
10607
10608
10609
10610
10611
10612
10613
10614
10615
10616
10617
10618
10619
10620
10621
10622
10623
10624
10625
10626
10627
10628
10629
10630
10631
10632
10633
10634
10635
10636
10637
10638
10639
      utf8_printf(p->out, "%s\n", zSql);
    }else{
      shell_exec(p, zSql, 0);
    }
    sqlite3_free(zSql);
  }else

#ifndef SQLITE_NOHAVE_SYSTEM
  if( c=='s'
   && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0)
  ){
    char *zCmd;
    int i, x;
    failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
    if( nArg<2 ){
      raw_printf(stderr, "Usage: .system COMMAND\n");
      rc = 1;
      goto meta_command_exit;
    }
    zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]);
    for(i=2; i<nArg && zCmd!=0; i++){
      zCmd = sqlite3_mprintf(strchr(azArg[i],' ')==0?"%z %s":"%z \"%s\"",
                             zCmd, azArg[i]);
    }
    x = zCmd!=0 ? system(zCmd) : 1;
    sqlite3_free(zCmd);
    if( x ) raw_printf(stderr, "System command returns %d\n", x);
  }else
#endif /* !defined(SQLITE_NOHAVE_SYSTEM) */

  if( c=='s' && strncmp(azArg[0], "show", n)==0 ){
    static const char *azBool[] = { "off", "on", "trigger", "full"};
    const char *zOut;
    int i;
    if( nArg!=1 ){
      raw_printf(stderr, "Usage: .show\n");
      rc = 1;
      goto meta_command_exit;
    }
    utf8_printf(p->out, "%12.12s: %s\n","echo",
                                  azBool[ShellHasFlag(p, SHFLG_Echo)]);
    utf8_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]);
    utf8_printf(p->out, "%12.12s: %s\n","explain",
         p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off");
    utf8_printf(p->out,"%12.12s: %s\n","headers", azBool[p->showHeader!=0]);
    if( p->mode==MODE_Column
     || (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
    ){







|




















|











|







10665
10666
10667
10668
10669
10670
10671
10672
10673
10674
10675
10676
10677
10678
10679
10680
10681
10682
10683
10684
10685
10686
10687
10688
10689
10690
10691
10692
10693
10694
10695
10696
10697
10698
10699
10700
10701
10702
10703
10704
10705
10706
10707
10708
10709
10710
10711
10712
      utf8_printf(p->out, "%s\n", zSql);
    }else{
      shell_exec(p, zSql, 0);
    }
    sqlite3_free(zSql);
  }else

#if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_WASM_MODE)
  if( c=='s'
   && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0)
  ){
    char *zCmd;
    int i, x;
    failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
    if( nArg<2 ){
      raw_printf(stderr, "Usage: .system COMMAND\n");
      rc = 1;
      goto meta_command_exit;
    }
    zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]);
    for(i=2; i<nArg && zCmd!=0; i++){
      zCmd = sqlite3_mprintf(strchr(azArg[i],' ')==0?"%z %s":"%z \"%s\"",
                             zCmd, azArg[i]);
    }
    x = zCmd!=0 ? system(zCmd) : 1;
    sqlite3_free(zCmd);
    if( x ) raw_printf(stderr, "System command returns %d\n", x);
  }else
#endif /* !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_WASM_MODE) */

  if( c=='s' && strncmp(azArg[0], "show", n)==0 ){
    static const char *azBool[] = { "off", "on", "trigger", "full"};
    const char *zOut;
    int i;
    if( nArg!=1 ){
      raw_printf(stderr, "Usage: .show\n");
      rc = 1;
      goto meta_command_exit;
    }
    utf8_printf(p->out, "%12.12s: %s\n","echo",
                azBool[ShellHasFlag(p, SHFLG_Echo)]);
    utf8_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]);
    utf8_printf(p->out, "%12.12s: %s\n","explain",
         p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off");
    utf8_printf(p->out,"%12.12s: %s\n","headers", azBool[p->showHeader!=0]);
    if( p->mode==MODE_Column
     || (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
    ){
10793
10794
10795
10796
10797
10798
10799

10800
10801
10802
10803
10804
10805
10806
10807
10808
10809
10810
10811
10812

10813
10814
10815
10816
10817
10818
10819
      }
    }

    for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]);
    sqlite3_free(azResult);
  }else


  /* Begin redirecting output to the file "testcase-out.txt" */
  if( c=='t' && strcmp(azArg[0],"testcase")==0 ){
    output_reset(p);
    p->out = output_file_open("testcase-out.txt", 0);
    if( p->out==0 ){
      raw_printf(stderr, "Error: cannot open 'testcase-out.txt'\n");
    }
    if( nArg>=2 ){
      sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s", azArg[1]);
    }else{
      sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "?");
    }
  }else


#ifndef SQLITE_UNTESTABLE
  if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 ){
    static const struct {
       const char *zCtrlName;   /* Name of a test-control option */
       int ctrlCode;            /* Integer code for that option */
       int unSafe;              /* Not valid for --safe mode */







>













>







10866
10867
10868
10869
10870
10871
10872
10873
10874
10875
10876
10877
10878
10879
10880
10881
10882
10883
10884
10885
10886
10887
10888
10889
10890
10891
10892
10893
10894
      }
    }

    for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]);
    sqlite3_free(azResult);
  }else

#ifndef SQLITE_SHELL_WASM_MODE
  /* Begin redirecting output to the file "testcase-out.txt" */
  if( c=='t' && strcmp(azArg[0],"testcase")==0 ){
    output_reset(p);
    p->out = output_file_open("testcase-out.txt", 0);
    if( p->out==0 ){
      raw_printf(stderr, "Error: cannot open 'testcase-out.txt'\n");
    }
    if( nArg>=2 ){
      sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s", azArg[1]);
    }else{
      sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "?");
    }
  }else
#endif /* !defined(SQLITE_SHELL_WASM_MODE) */

#ifndef SQLITE_UNTESTABLE
  if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 ){
    static const struct {
       const char *zCtrlName;   /* Name of a test-control option */
       int ctrlCode;            /* Integer code for that option */
       int unSafe;              /* Not valid for --safe mode */
11375
11376
11377
11378
11379
11380
11381
11382
11383
11384
11385
11386
11387
11388
11389
11390
11391
11392
11393
11394
11395
11396
11397
11398
11399
11400
11401
11402
11403
11404
11405
11406
11407
11408
11409
11410
            continue;
          }
          /* fall thru */
        case ']':
          cWait = 0;
          qss = QSS_SETV(qss, 0);
          goto PlainScan;
        default: assert(0); 
        }
      }
    }
  }
  return qss;
}

/*
** Return TRUE if the line typed in is an SQL command terminator other
** than a semi-colon.  The SQL Server style "go" command is understood
** as is the Oracle "/".
*/
static int line_is_command_terminator(char *zLine){
  while( IsSpace(zLine[0]) ){ zLine++; };
  if( zLine[0]=='/' )
    zLine += 1; /* Oracle */
  else if ( ToLower(zLine[0])=='g' && ToLower(zLine[1])=='o' )
    zLine += 2; /* SQL Server */
  else
    return 0;
  return quickscan(zLine,QSS_Start)==QSS_Start;
}

/*
** We need a default sqlite3_complete() implementation to use in case
** the shell is compiled with SQLITE_OMIT_COMPLETE.  The default assumes
** any arbitrary text is a complete SQL statement.  This is not very
** user-friendly, but it does seem to work.







|




















|







11450
11451
11452
11453
11454
11455
11456
11457
11458
11459
11460
11461
11462
11463
11464
11465
11466
11467
11468
11469
11470
11471
11472
11473
11474
11475
11476
11477
11478
11479
11480
11481
11482
11483
11484
11485
            continue;
          }
          /* fall thru */
        case ']':
          cWait = 0;
          qss = QSS_SETV(qss, 0);
          goto PlainScan;
        default: assert(0);
        }
      }
    }
  }
  return qss;
}

/*
** Return TRUE if the line typed in is an SQL command terminator other
** than a semi-colon.  The SQL Server style "go" command is understood
** as is the Oracle "/".
*/
static int line_is_command_terminator(char *zLine){
  while( IsSpace(zLine[0]) ){ zLine++; };
  if( zLine[0]=='/' )
    zLine += 1; /* Oracle */
  else if ( ToLower(zLine[0])=='g' && ToLower(zLine[1])=='o' )
    zLine += 2; /* SQL Server */
  else
    return 0;
  return quickscan(zLine, QSS_Start)==QSS_Start;
}

/*
** We need a default sqlite3_complete() implementation to use in case
** the shell is compiled with SQLITE_OMIT_COMPLETE.  The default assumes
** any arbitrary text is a complete SQL statement.  This is not very
** user-friendly, but it does seem to work.
11473
11474
11475
11476
11477
11478
11479




































11480
11481
11482
11483
11484
11485
11486
            "changes: %lld   total_changes: %lld",
            sqlite3_changes64(p->db), sqlite3_total_changes64(p->db));
    raw_printf(p->out, "%s\n", zLineBuf);
  }
  return 0;
}






































/*
** Read input from *in and process it.  If *in==0 then input
** is interactive - the user is typing it it.  Otherwise, input
** is coming from a file or device.  A prompt is issued and history
** is saved only if input is interactive.  An interrupt signal will
** cause this routine to exit immediately, unless input is interactive.







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







11548
11549
11550
11551
11552
11553
11554
11555
11556
11557
11558
11559
11560
11561
11562
11563
11564
11565
11566
11567
11568
11569
11570
11571
11572
11573
11574
11575
11576
11577
11578
11579
11580
11581
11582
11583
11584
11585
11586
11587
11588
11589
11590
11591
11592
11593
11594
11595
11596
11597
            "changes: %lld   total_changes: %lld",
            sqlite3_changes64(p->db), sqlite3_total_changes64(p->db));
    raw_printf(p->out, "%s\n", zLineBuf);
  }
  return 0;
}

static void echo_group_input(ShellState *p, const char *zDo){
  if( ShellHasFlag(p, SHFLG_Echo) ) utf8_printf(p->out, "%s\n", zDo);
}

#ifdef SQLITE_SHELL_WASM_MODE
/*
** Alternate one_input_line() impl for wasm mode. This is not in the primary impl
** because we need the global shellState and cannot access it from that function
** without moving lots of code around (creating a larger/messier diff).
*/
static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
  /* Parse the next line from shellState.wasm.zInput. */
  const char *zBegin = shellState.wasm.zPos;
  const char *z = zBegin;
  char *zLine = 0;
  int nZ = 0;

  UNUSED_PARAMETER(in);
  UNUSED_PARAMETER(isContinuation);
  if(!z || !*z){
    return 0;
  }
  while(*z && isspace(*z)) ++z;
  zBegin = z;
  for(; *z && '\n'!=*z; ++nZ, ++z){}
  if(nZ>0 && '\r'==zBegin[nZ-1]){
    --nZ;
  }
  shellState.wasm.zPos = z;
  zLine = realloc(zPrior, nZ+1);
  shell_check_oom(zLine);
  memcpy(zLine, zBegin, (size_t)nZ);
  zLine[nZ] = 0;
  return zLine;
}
#endif /* SQLITE_SHELL_WASM_MODE */

/*
** Read input from *in and process it.  If *in==0 then input
** is interactive - the user is typing it it.  Otherwise, input
** is coming from a file or device.  A prompt is issued and history
** is saved only if input is interactive.  An interrupt signal will
** cause this routine to exit immediately, unless input is interactive.
11522
11523
11524
11525
11526
11527
11528
11529
11530
11531

11532
11533
11534
11535
11536
11537
11538
11539
11540
11541
11542
11543
    if( QSS_INPLAIN(qss)
        && line_is_command_terminator(zLine)
        && line_is_complete(zSql, nSql) ){
      memcpy(zLine,";",2);
    }
    qss = quickscan(zLine, qss);
    if( QSS_PLAINWHITE(qss) && nSql==0 ){
      if( ShellHasFlag(p, SHFLG_Echo) )
        printf("%s\n", zLine);
      /* Just swallow single-line whitespace */

      qss = QSS_Start;
      continue;
    }
    if( zLine && (zLine[0]=='.' || zLine[0]=='#') && nSql==0 ){
      if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zLine);
      if( zLine[0]=='.' ){
        rc = do_meta_command(zLine, p);
        if( rc==2 ){ /* exit requested */
          break;
        }else if( rc ){
          errCnt++;
        }







<
<

>




|







11633
11634
11635
11636
11637
11638
11639


11640
11641
11642
11643
11644
11645
11646
11647
11648
11649
11650
11651
11652
11653
    if( QSS_INPLAIN(qss)
        && line_is_command_terminator(zLine)
        && line_is_complete(zSql, nSql) ){
      memcpy(zLine,";",2);
    }
    qss = quickscan(zLine, qss);
    if( QSS_PLAINWHITE(qss) && nSql==0 ){


      /* Just swallow single-line whitespace */
      echo_group_input(p, zLine);
      qss = QSS_Start;
      continue;
    }
    if( zLine && (zLine[0]=='.' || zLine[0]=='#') && nSql==0 ){
      echo_group_input(p, zLine);
      if( zLine[0]=='.' ){
        rc = do_meta_command(zLine, p);
        if( rc==2 ){ /* exit requested */
          break;
        }else if( rc ){
          errCnt++;
        }
11562
11563
11564
11565
11566
11567
11568

11569
11570
11571
11572
11573
11574
11575
11576
11577
11578
11579
11580
11581
11582
11583
11584
11585
11586

11587
11588
11589
11590
11591
11592
11593
      nSql = nLine-i;
    }else{
      zSql[nSql++] = '\n';
      memcpy(zSql+nSql, zLine, nLine+1);
      nSql += nLine;
    }
    if( nSql && QSS_SEMITERM(qss) && sqlite3_complete(zSql) ){

      errCnt += runOneSqlLine(p, zSql, p->in, startline);
      nSql = 0;
      if( p->outCount ){
        output_reset(p);
        p->outCount = 0;
      }else{
        clearTempFile(p);
      }
      p->bSafeMode = p->bSafeModePersist;
      qss = QSS_Start;
    }else if( nSql && QSS_PLAINWHITE(qss) ){
      if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zSql);
      nSql = 0;
      qss = QSS_Start;
    }
  }
  if( nSql ){
    /* This may be incomplete. Let the SQL parser deal with that. */

    errCnt += runOneSqlLine(p, zSql, p->in, startline);
  }
  free(zSql);
  free(zLine);
  --p->inputNesting;
  return errCnt>0;
}







>











|






>







11672
11673
11674
11675
11676
11677
11678
11679
11680
11681
11682
11683
11684
11685
11686
11687
11688
11689
11690
11691
11692
11693
11694
11695
11696
11697
11698
11699
11700
11701
11702
11703
11704
11705
      nSql = nLine-i;
    }else{
      zSql[nSql++] = '\n';
      memcpy(zSql+nSql, zLine, nLine+1);
      nSql += nLine;
    }
    if( nSql && QSS_SEMITERM(qss) && sqlite3_complete(zSql) ){
      echo_group_input(p, zSql);
      errCnt += runOneSqlLine(p, zSql, p->in, startline);
      nSql = 0;
      if( p->outCount ){
        output_reset(p);
        p->outCount = 0;
      }else{
        clearTempFile(p);
      }
      p->bSafeMode = p->bSafeModePersist;
      qss = QSS_Start;
    }else if( nSql && QSS_PLAINWHITE(qss) ){
      echo_group_input(p, zSql);
      nSql = 0;
      qss = QSS_Start;
    }
  }
  if( nSql ){
    /* This may be incomplete. Let the SQL parser deal with that. */
    echo_group_input(p, zSql);
    errCnt += runOneSqlLine(p, zSql, p->in, startline);
  }
  free(zSql);
  free(zLine);
  --p->inputNesting;
  return errCnt>0;
}
11718
11719
11720
11721
11722
11723
11724
11725
11726
11727
11728
11729
11730
11731
11732
  "   -box                 set output mode to 'box'\n"
  "   -column              set output mode to 'column'\n"
  "   -cmd COMMAND         run \"COMMAND\" before reading stdin\n"
  "   -csv                 set output mode to 'csv'\n"
#if !defined(SQLITE_OMIT_DESERIALIZE)
  "   -deserialize         open the database using sqlite3_deserialize()\n"
#endif
  "   -echo                print commands before execution\n"
  "   -init FILENAME       read/process named file\n"
  "   -[no]header          turn headers on or off\n"
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
  "   -heap SIZE           Size of heap for memsys3 or memsys5\n"
#endif
  "   -help                show this message\n"
  "   -html                set output mode to HTML\n"







|







11830
11831
11832
11833
11834
11835
11836
11837
11838
11839
11840
11841
11842
11843
11844
  "   -box                 set output mode to 'box'\n"
  "   -column              set output mode to 'column'\n"
  "   -cmd COMMAND         run \"COMMAND\" before reading stdin\n"
  "   -csv                 set output mode to 'csv'\n"
#if !defined(SQLITE_OMIT_DESERIALIZE)
  "   -deserialize         open the database using sqlite3_deserialize()\n"
#endif
  "   -echo                print inputs before execution\n"
  "   -init FILENAME       read/process named file\n"
  "   -[no]header          turn headers on or off\n"
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
  "   -heap SIZE           Size of heap for memsys3 or memsys5\n"
#endif
  "   -help                show this message\n"
  "   -html                set output mode to HTML\n"
11853
11854
11855
11856
11857
11858
11859




11860
11861
11862
11863
11864
11865
11866



11867



11868

11869
11870
11871
11872
11873
11874
11875
11876
11877
11878
11879
11880
11881
11882
11883




11884
11885

11886
11887
11888
11889
11890
11891
11892
#  if (defined(_WIN32) || defined(WIN32)) \
   && (defined(_MSC_VER) || (defined(UNICODE) && defined(__GNUC__)))
#    define SQLITE_SHELL_IS_UTF8          (0)
#  else
#    define SQLITE_SHELL_IS_UTF8          (1)
#  endif
#endif





#if SQLITE_SHELL_IS_UTF8
int SQLITE_CDECL main(int argc, char **argv){
#else
int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
  char **argv;
#endif



  char *zErrMsg = 0;



  ShellState data;

  const char *zInitFile = 0;
  int i;
  int rc = 0;
  int warnInmemoryDb = 0;
  int readStdin = 1;
  int nCmd = 0;
  char **azCmd = 0;
  const char *zVfs = 0;           /* Value of -vfs command-line option */
#if !SQLITE_SHELL_IS_UTF8
  char **argvToFree = 0;
  int argcToFree = 0;
#endif

  setBinaryMode(stdin, 0);
  setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */




  stdin_is_interactive = isatty(0);
  stdout_is_console = isatty(1);


#if !defined(_WIN32_WCE)
  if( getenv("SQLITE_DEBUG_BREAK") ){
    if( isatty(0) && isatty(2) ){
      fprintf(stderr,
          "attach debugger to process %d and press any key to continue.\n",
          GETPID());







>
>
>
>







>
>
>

>
>
>

>















>
>
>
>


>







11965
11966
11967
11968
11969
11970
11971
11972
11973
11974
11975
11976
11977
11978
11979
11980
11981
11982
11983
11984
11985
11986
11987
11988
11989
11990
11991
11992
11993
11994
11995
11996
11997
11998
11999
12000
12001
12002
12003
12004
12005
12006
12007
12008
12009
12010
12011
12012
12013
12014
12015
12016
12017
12018
12019
12020
#  if (defined(_WIN32) || defined(WIN32)) \
   && (defined(_MSC_VER) || (defined(UNICODE) && defined(__GNUC__)))
#    define SQLITE_SHELL_IS_UTF8          (0)
#  else
#    define SQLITE_SHELL_IS_UTF8          (1)
#  endif
#endif

#ifdef SQLITE_SHELL_WASM_MODE
#  define main fiddle_main
#endif

#if SQLITE_SHELL_IS_UTF8
int SQLITE_CDECL main(int argc, char **argv){
#else
int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
  char **argv;
#endif
#ifdef SQLITE_DEBUG
  sqlite3_uint64 mem_main_enter = sqlite3_memory_used();
#endif
  char *zErrMsg = 0;
#ifdef SQLITE_SHELL_WASM_MODE
#  define data shellState
#else
  ShellState data;
#endif
  const char *zInitFile = 0;
  int i;
  int rc = 0;
  int warnInmemoryDb = 0;
  int readStdin = 1;
  int nCmd = 0;
  char **azCmd = 0;
  const char *zVfs = 0;           /* Value of -vfs command-line option */
#if !SQLITE_SHELL_IS_UTF8
  char **argvToFree = 0;
  int argcToFree = 0;
#endif

  setBinaryMode(stdin, 0);
  setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
#ifdef SQLITE_SHELL_WASM_MODE
  stdin_is_interactive = 0;
  stdout_is_console = 1;
#else
  stdin_is_interactive = isatty(0);
  stdout_is_console = isatty(1);
#endif

#if !defined(_WIN32_WCE)
  if( getenv("SQLITE_DEBUG_BREAK") ){
    if( isatty(0) && isatty(2) ){
      fprintf(stderr,
          "attach debugger to process %d and press any key to continue.\n",
          GETPID());
12125
12126
12127
12128
12129
12130
12131

12132

12133
12134
12135
12136
12137
12138
12139
    warnInmemoryDb = argc==1;
#else
    utf8_printf(stderr,"%s: Error: no database filename specified\n", Argv0);
    return 1;
#endif
  }
  data.out = stdout;

  sqlite3_appendvfs_init(0,0,0);


  /* Go ahead and open the database file if it already exists.  If the
  ** file does not exist, delay opening it.  This prevents empty database
  ** files from being created if a user mistypes the database name argument
  ** to the sqlite command-line tool.
  */
  if( access(data.pAuxDb->zDbFilename, 0)==0 ){







>

>







12253
12254
12255
12256
12257
12258
12259
12260
12261
12262
12263
12264
12265
12266
12267
12268
12269
    warnInmemoryDb = argc==1;
#else
    utf8_printf(stderr,"%s: Error: no database filename specified\n", Argv0);
    return 1;
#endif
  }
  data.out = stdout;
#ifndef SQLITE_SHELL_WASM_MODE
  sqlite3_appendvfs_init(0,0,0);
#endif

  /* Go ahead and open the database file if it already exists.  If the
  ** file does not exist, delay opening it.  This prevents empty database
  ** files from being created if a user mistypes the database name argument
  ** to the sqlite command-line tool.
  */
  if( access(data.pAuxDb->zDbFilename, 0)==0 ){
12391
12392
12393
12394
12395
12396
12397



12398
12399
12400
12401
12402
12403
12404
        free(zHistory);
      }
    }else{
      data.in = stdin;
      rc = process_input(&data);
    }
  }



  free(azCmd);
  set_table_name(&data, 0);
  if( data.db ){
    session_close_all(&data, -1);
    close_db(data.db);
  }
  for(i=0; i<ArraySize(data.aAuxDb); i++){







>
>
>







12521
12522
12523
12524
12525
12526
12527
12528
12529
12530
12531
12532
12533
12534
12535
12536
12537
        free(zHistory);
      }
    }else{
      data.in = stdin;
      rc = process_input(&data);
    }
  }
#ifndef SQLITE_SHELL_WASM_MODE
  /* In WASM mode we have to leave the db state in place so that
  ** client code can "push" SQL into it after this call returns. */
  free(azCmd);
  set_table_name(&data, 0);
  if( data.db ){
    session_close_all(&data, -1);
    close_db(data.db);
  }
  for(i=0; i<ArraySize(data.aAuxDb); i++){
12417
12418
12419
12420
12421
12422
12423







12424
12425




























































































































  free(argvToFree);
#endif
  free(data.colWidth);
  free(data.zNonce);
  /* Clear the global data structure so that valgrind will detect memory
  ** leaks */
  memset(&data, 0, sizeof(data));







  return rc;
}



































































































































>
>
>
>
>
>
>


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
12550
12551
12552
12553
12554
12555
12556
12557
12558
12559
12560
12561
12562
12563
12564
12565
12566
12567
12568
12569
12570
12571
12572
12573
12574
12575
12576
12577
12578
12579
12580
12581
12582
12583
12584
12585
12586
12587
12588
12589
12590
12591
12592
12593
12594
12595
12596
12597
12598
12599
12600
12601
12602
12603
12604
12605
12606
12607
12608
12609
12610
12611
12612
12613
12614
12615
12616
12617
12618
12619
12620
12621
12622
12623
12624
12625
12626
12627
12628
12629
12630
12631
12632
12633
12634
12635
12636
12637
12638
12639
12640
12641
12642
12643
12644
12645
12646
12647
12648
12649
12650
12651
12652
12653
12654
12655
12656
12657
12658
12659
12660
12661
12662
12663
12664
12665
12666
12667
12668
12669
12670
12671
12672
12673
12674
12675
12676
12677
12678
12679
12680
12681
12682
12683
12684
12685
12686
12687
12688
12689
  free(argvToFree);
#endif
  free(data.colWidth);
  free(data.zNonce);
  /* Clear the global data structure so that valgrind will detect memory
  ** leaks */
  memset(&data, 0, sizeof(data));
#ifdef SQLITE_DEBUG
  if( sqlite3_memory_used()>mem_main_enter ){
    utf8_printf(stderr, "Memory leaked: %u bytes\n",
                (unsigned int)(sqlite3_memory_used()-mem_main_enter));
  }
#endif
#endif /* !SQLITE_SHELL_WASM_MODE */
  return rc;
}


#ifdef SQLITE_SHELL_WASM_MODE
/* Only for emcc experimentation purposes. */
int fiddle_experiment(int a,int b){
   return a + b;
}

/* Only for emcc experimentation purposes.

  Define this function in JS using:

  emcc ... --js-library somefile.js

  containing:

mergeInto(LibraryManager.library, {
    my_foo: function(){
        console.debug("my_foo()",arguments);
    }
});
*/
/*extern void my_foo(sqlite3 *);*/
/* Only for emcc experimentation purposes. */
sqlite3 * fiddle_the_db(){
    printf("fiddle_the_db(%p)\n", (const void*)globalDb);
    /*my_foo(globalDb);*/
    return globalDb;
}
/* Only for emcc experimentation purposes. */
sqlite3 * fiddle_db_arg(sqlite3 *arg){
    printf("fiddle_db_arg(%p)\n", (const void*)arg);
    return arg;
}

/*
** Intended to be called via a SharedWorker() while a separate
** SharedWorker() (which manages the wasm module) is performing work
** which should be interrupted. Unfortunately, SharedWorker is not
** portable enough to make real use of.
*/
void fiddle_interrupt(void){
  if(globalDb) sqlite3_interrupt(globalDb);
}

/*
** Returns the filename of the given db name, assuming "main" if
** zDbName is NULL. Returns NULL if globalDb is not opened.
*/
const char * fiddle_db_filename(const char * zDbName){
    return globalDb
      ? sqlite3_db_filename(globalDb, zDbName ? zDbName : "main")
      : NULL;
}

/*
** Closes, unlinks, and reopens the db using its current filename (or
** the default if the db is currently closed). It is assumed, for
** purposes of the fiddle build, that the file is in a transient
** virtual filesystem within the browser.
*/
void fiddle_reset_db(void){
  char *zFilename = 0;
  if(0==globalDb){
    shellState.pAuxDb->zDbFilename = "/fiddle.sqlite3";
  }else{
    zFilename =
      sqlite3_mprintf("%s", sqlite3_db_filename(globalDb, "main"));
    shell_check_oom(zFilename);
    close_db(globalDb);
    shellDeleteFile(zFilename);
    shellState.db = 0;
    shellState.pAuxDb->zDbFilename = zFilename;
  }
  open_db(&shellState, 0);
  sqlite3_free(zFilename);
}

/*
** Trivial exportable function for emscripten. Needs to be exported using:
**
** emcc ..flags... -sEXPORTED_FUNCTIONS=_fiddle_exec -sEXPORTED_RUNTIME_METHODS=ccall,cwrap
**
** (Note the underscore before the function name.) It processes zSql
** as if it were input to the sqlite3 shell and redirects all output
** to the wasm binding.
*/
void fiddle_exec(const char * zSql){
  static int once = 0;
  int rc = 0;
  if(!once){
    /* Simulate an argv array for main() */
    static char * argv[] = {"fiddle",
                            "-bail",
                            "-safe"};
    rc = fiddle_main((int)(sizeof(argv)/sizeof(argv[0])), argv);
    once = rc ? -1 : 1;
    memset(&shellState.wasm, 0, sizeof(shellState.wasm));
    printf(
        "SQLite version %s %.19s\n" /*extra-version-info*/,
        sqlite3_libversion(), sqlite3_sourceid()
    );
    puts("WASM shell");
    puts("Enter \".help\" for usage hints.");
    if(once>0){
      fiddle_reset_db();
    }
    if(shellState.db){
      printf("Connected to %s.\n", fiddle_db_filename(NULL));
    }else{
      fprintf(stderr,"ERROR initializing db!\n");
      return;
    }
  }
  if(once<0){
    puts("DB init failed. Not executing SQL.");
  }else if(zSql && *zSql){
    shellState.wasm.zInput = zSql;
    shellState.wasm.zPos = zSql;
    process_input(&shellState);
    memset(&shellState.wasm, 0, sizeof(shellState.wasm));
  }
}
#endif /* SQLITE_SHELL_WASM_MODE */
Changes to src/sqlite.h.in.
6272
6273
6274
6275
6276
6277
6278






















6279
6280
6281
6282
6283
6284
6285
** returned by sqlite3_db_handle is the same [database connection]
** that was the first argument
** to the [sqlite3_prepare_v2()] call (or its variants) that was used to
** create the statement in the first place.
*/
sqlite3 *sqlite3_db_handle(sqlite3_stmt*);























/*
** CAPI3REF: Return The Filename For A Database Connection
** METHOD: sqlite3
**
** ^The sqlite3_db_filename(D,N) interface returns a pointer to the filename
** associated with database N of connection D.
** ^If there is no attached database N on the database







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







6272
6273
6274
6275
6276
6277
6278
6279
6280
6281
6282
6283
6284
6285
6286
6287
6288
6289
6290
6291
6292
6293
6294
6295
6296
6297
6298
6299
6300
6301
6302
6303
6304
6305
6306
6307
** returned by sqlite3_db_handle is the same [database connection]
** that was the first argument
** to the [sqlite3_prepare_v2()] call (or its variants) that was used to
** create the statement in the first place.
*/
sqlite3 *sqlite3_db_handle(sqlite3_stmt*);

/*
** CAPI3REF: Return The Schema Name For A Database Connection
** METHOD: sqlite3
**
** ^The sqlite3_db_name(D,N) interface returns a pointer to the schema name
** for the N-th database on database connection D, or a NULL pointer of N is
** out of range.  An N alue of 0 means the main database file.  An N of 1 is
** the "temp" schema.  Larger values of N correspond to various ATTACH-ed
** databases.
**
** Space to hold the string that is returned by sqlite3_db_name() is managed
** by SQLite itself.  The string might be deallocated by any operation that
** changes the schema, including [ATTACH] or [DETACH] or calls to
** [sqlite3_serialize()] or [sqlite3_deserialize()], even operations that
** occur on a different thread.  Applications that need to
** remember the string long-term should make their own copy.  Applications that
** are accessing the same database connection simultaneously on multiple
** threads should mutex-protect calls to this API and should make their own
** private copy of the result prior to releasing the mutex.
*/
const char *sqlite3_db_name(sqlite3 *db, int N);

/*
** CAPI3REF: Return The Filename For A Database Connection
** METHOD: sqlite3
**
** ^The sqlite3_db_filename(D,N) interface returns a pointer to the filename
** associated with database N of connection D.
** ^If there is no attached database N on the database
Changes to src/sqlite3ext.h.
352
353
354
355
356
357
358

359
360
361
362
363
364
365
  int (*vtab_in_first)(sqlite3_value*,sqlite3_value**);
  int (*vtab_in_next)(sqlite3_value*,sqlite3_value**);
  /* Version 3.39.0 and later */
  int (*deserialize)(sqlite3*,const char*,unsigned char*,
                     sqlite3_int64,sqlite3_int64,unsigned);
  unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*,
                              unsigned int);

};

/*
** This is the function signature used for all extension entry points.  It
** is also defined in the file "loadext.c".
*/
typedef int (*sqlite3_loadext_entry)(







>







352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
  int (*vtab_in_first)(sqlite3_value*,sqlite3_value**);
  int (*vtab_in_next)(sqlite3_value*,sqlite3_value**);
  /* Version 3.39.0 and later */
  int (*deserialize)(sqlite3*,const char*,unsigned char*,
                     sqlite3_int64,sqlite3_int64,unsigned);
  unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*,
                              unsigned int);
  const char *(*db_name)(sqlite3*,int);
};

/*
** This is the function signature used for all extension entry points.  It
** is also defined in the file "loadext.c".
*/
typedef int (*sqlite3_loadext_entry)(
670
671
672
673
674
675
676

677
678
679
680

681
682
683
684
685
686
687
/* Version 3.38.0 and later */
#define sqlite3_error_offset           sqlite3_api->error_offset
#define sqlite3_vtab_rhs_value         sqlite3_api->vtab_rhs_value
#define sqlite3_vtab_distinct          sqlite3_api->vtab_distinct
#define sqlite3_vtab_in                sqlite3_api->vtab_in
#define sqlite3_vtab_in_first          sqlite3_api->vtab_in_first
#define sqlite3_vtab_in_next           sqlite3_api->vtab_in_next

#ifndef SQLITE_OMIT_DESERIALIZE
#define sqlite3_deserialize            sqlite3_api->deserialize
#define sqlite3_serialize              sqlite3_api->serialize
#endif

#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */

#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
  /* This case when the file really is being compiled as a loadable 
  ** extension */
# define SQLITE_EXTENSION_INIT1     const sqlite3_api_routines *sqlite3_api=0;
# define SQLITE_EXTENSION_INIT2(v)  sqlite3_api=v;







>




>







671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
/* Version 3.38.0 and later */
#define sqlite3_error_offset           sqlite3_api->error_offset
#define sqlite3_vtab_rhs_value         sqlite3_api->vtab_rhs_value
#define sqlite3_vtab_distinct          sqlite3_api->vtab_distinct
#define sqlite3_vtab_in                sqlite3_api->vtab_in
#define sqlite3_vtab_in_first          sqlite3_api->vtab_in_first
#define sqlite3_vtab_in_next           sqlite3_api->vtab_in_next
/* Version 3.39.0 and later */
#ifndef SQLITE_OMIT_DESERIALIZE
#define sqlite3_deserialize            sqlite3_api->deserialize
#define sqlite3_serialize              sqlite3_api->serialize
#endif
#define sqlite3_db_name                sqlite3_api->db_name
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */

#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
  /* This case when the file really is being compiled as a loadable 
  ** extension */
# define SQLITE_EXTENSION_INIT1     const sqlite3_api_routines *sqlite3_api=0;
# define SQLITE_EXTENSION_INIT2(v)  sqlite3_api=v;
Changes to src/sqliteInt.h.
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892

2893
2894
2895
2896

2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907

2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
                         ** TK_SELECT_COLUMN: Number of columns on the LHS
                         ** TK_SELECT: 1st register of result vector */
  ynVar iColumn;         /* TK_COLUMN: column index.  -1 for rowid.
                         ** TK_VARIABLE: variable number (always >= 1).
                         ** TK_SELECT_COLUMN: column of the result vector */
  i16 iAgg;              /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
  union {
    int iJoin;             /* If EP_FromJoin, the right table of the join */
    int iOfst;             /* else: start of token from start of statement */
  } w;
  AggInfo *pAggInfo;     /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
  union {
    Table *pTab;           /* TK_COLUMN: Table containing column. Can be NULL
                           ** for a column of an index on an expression */
    Window *pWin;          /* EP_WinFunc: Window/Filter defn for a function */
    struct {               /* TK_IN, TK_SELECT, and TK_EXISTS */
      int iAddr;             /* Subroutine entry address */
      int regReturn;         /* Register used to hold return address */
    } sub;
  } y;
};

/* The following are the meanings of bits in the Expr.flags field.
** Value restrictions:
**
**          EP_Agg == NC_HasAgg == SF_HasAgg
**          EP_Win == NC_HasWin
*/
#define EP_FromJoin   0x000001 /* Originates in ON/USING clause of outer join */

#define EP_Distinct   0x000002 /* Aggregate function with DISTINCT keyword */
#define EP_HasFunc    0x000004 /* Contains one or more functions of any kind */
#define EP_FixedCol   0x000008 /* TK_Column with a known fixed value */
#define EP_Agg        0x000010 /* Contains one or more aggregate functions */

#define EP_VarSelect  0x000020 /* pSelect is correlated, not constant */
#define EP_DblQuoted  0x000040 /* token.z was originally in "..." */
#define EP_InfixFunc  0x000080 /* True for an infix function: LIKE, GLOB, etc */
#define EP_Collate    0x000100 /* Tree contains a TK_COLLATE operator */
#define EP_Commuted   0x000200 /* Comparison operator has been commuted */
#define EP_IntValue   0x000400 /* Integer value contained in u.iValue */
#define EP_xIsSelect  0x000800 /* x.pSelect is valid (otherwise x.pList is) */
#define EP_Skip       0x001000 /* Operator does not contribute to affinity */
#define EP_Reduced    0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
#define EP_TokenOnly  0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
#define EP_Win        0x008000 /* Contains window functions */

#define EP_MemToken   0x010000 /* Need to sqlite3DbFree() Expr.zToken */
#define EP_IfNullRow  0x020000 /* The TK_IF_NULL_ROW opcode */
#define EP_Unlikely   0x040000 /* unlikely() or likelihood() function */
#define EP_ConstFunc  0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
#define EP_CanBeNull  0x100000 /* Can be null despite NOT NULL constraint */
#define EP_Subquery   0x200000 /* Tree contains a TK_SELECT operator */
#define EP_InnerJoin  0x400000 /* Originates in ON/USING of an inner join */
#define EP_Leaf       0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
#define EP_WinFunc   0x1000000 /* TK_FUNCTION with Expr.y.pWin set */
#define EP_Subrtn    0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */
#define EP_Quoted    0x4000000 /* TK_ID was originally quoted */
#define EP_Static    0x8000000 /* Held in memory not obtained from malloc() */
#define EP_IsTrue   0x10000000 /* Always has boolean value of TRUE */
#define EP_IsFalse  0x20000000 /* Always has boolean value of FALSE */







|




















|
>
|
|
<

>
|
|
|
|
|
|
|
|
|
<

>
|
|
|
|
|
|
<







2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895

2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906

2907
2908
2909
2910
2911
2912
2913
2914

2915
2916
2917
2918
2919
2920
2921
                         ** TK_SELECT_COLUMN: Number of columns on the LHS
                         ** TK_SELECT: 1st register of result vector */
  ynVar iColumn;         /* TK_COLUMN: column index.  -1 for rowid.
                         ** TK_VARIABLE: variable number (always >= 1).
                         ** TK_SELECT_COLUMN: column of the result vector */
  i16 iAgg;              /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
  union {
    int iJoin;             /* If EP_OuterON or EP_InnerON, the right table */
    int iOfst;             /* else: start of token from start of statement */
  } w;
  AggInfo *pAggInfo;     /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
  union {
    Table *pTab;           /* TK_COLUMN: Table containing column. Can be NULL
                           ** for a column of an index on an expression */
    Window *pWin;          /* EP_WinFunc: Window/Filter defn for a function */
    struct {               /* TK_IN, TK_SELECT, and TK_EXISTS */
      int iAddr;             /* Subroutine entry address */
      int regReturn;         /* Register used to hold return address */
    } sub;
  } y;
};

/* The following are the meanings of bits in the Expr.flags field.
** Value restrictions:
**
**          EP_Agg == NC_HasAgg == SF_HasAgg
**          EP_Win == NC_HasWin
*/
#define EP_OuterON    0x000001 /* Originates in ON/USING clause of outer join */
#define EP_InnerON    0x000002 /* Originates in ON/USING of an inner join */
#define EP_Distinct   0x000004 /* Aggregate function with DISTINCT keyword */
#define EP_HasFunc    0x000008 /* Contains one or more functions of any kind */

#define EP_Agg        0x000010 /* Contains one or more aggregate functions */
#define EP_FixedCol   0x000020 /* TK_Column with a known fixed value */
#define EP_VarSelect  0x000040 /* pSelect is correlated, not constant */
#define EP_DblQuoted  0x000080 /* token.z was originally in "..." */
#define EP_InfixFunc  0x000100 /* True for an infix function: LIKE, GLOB, etc */
#define EP_Collate    0x000200 /* Tree contains a TK_COLLATE operator */
#define EP_Commuted   0x000400 /* Comparison operator has been commuted */
#define EP_IntValue   0x000800 /* Integer value contained in u.iValue */
#define EP_xIsSelect  0x001000 /* x.pSelect is valid (otherwise x.pList is) */
#define EP_Skip       0x002000 /* Operator does not contribute to affinity */
#define EP_Reduced    0x004000 /* Expr struct EXPR_REDUCEDSIZE bytes only */

#define EP_Win        0x008000 /* Contains window functions */
#define EP_TokenOnly  0x010000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
#define EP_MemToken   0x020000 /* Need to sqlite3DbFree() Expr.zToken */
#define EP_IfNullRow  0x040000 /* The TK_IF_NULL_ROW opcode */
#define EP_Unlikely   0x080000 /* unlikely() or likelihood() function */
#define EP_ConstFunc  0x100000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
#define EP_CanBeNull  0x200000 /* Can be null despite NOT NULL constraint */
#define EP_Subquery   0x400000 /* Tree contains a TK_SELECT operator */

#define EP_Leaf       0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
#define EP_WinFunc   0x1000000 /* TK_FUNCTION with Expr.y.pWin set */
#define EP_Subrtn    0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */
#define EP_Quoted    0x4000000 /* TK_ID was originally quoted */
#define EP_Static    0x8000000 /* Held in memory not obtained from malloc() */
#define EP_IsTrue   0x10000000 /* Always has boolean value of TRUE */
#define EP_IsFalse  0x20000000 /* Always has boolean value of FALSE */
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
/* Macros can be used to test, set, or clear bits in the
** Expr.flags field.
*/
#define ExprHasProperty(E,P)     (((E)->flags&(P))!=0)
#define ExprHasAllProperty(E,P)  (((E)->flags&(P))==(P))
#define ExprSetProperty(E,P)     (E)->flags|=(P)
#define ExprClearProperty(E,P)   (E)->flags&=~(P)
#define ExprAlwaysTrue(E)   (((E)->flags&(EP_FromJoin|EP_IsTrue))==EP_IsTrue)
#define ExprAlwaysFalse(E)  (((E)->flags&(EP_FromJoin|EP_IsFalse))==EP_IsFalse)

/* Macros used to ensure that the correct members of unions are accessed
** in Expr.
*/
#define ExprUseUToken(E)    (((E)->flags&EP_IntValue)==0)
#define ExprUseUValue(E)    (((E)->flags&EP_IntValue)!=0)
#define ExprUseXList(E)     (((E)->flags&EP_xIsSelect)==0)







|
|







2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
/* Macros can be used to test, set, or clear bits in the
** Expr.flags field.
*/
#define ExprHasProperty(E,P)     (((E)->flags&(P))!=0)
#define ExprHasAllProperty(E,P)  (((E)->flags&(P))==(P))
#define ExprSetProperty(E,P)     (E)->flags|=(P)
#define ExprClearProperty(E,P)   (E)->flags&=~(P)
#define ExprAlwaysTrue(E)   (((E)->flags&(EP_OuterON|EP_IsTrue))==EP_IsTrue)
#define ExprAlwaysFalse(E)  (((E)->flags&(EP_OuterON|EP_IsFalse))==EP_IsFalse)

/* Macros used to ensure that the correct members of unions are accessed
** in Expr.
*/
#define ExprUseUToken(E)    (((E)->flags&EP_IntValue)==0)
#define ExprUseUValue(E)    (((E)->flags&EP_IntValue)!=0)
#define ExprUseXList(E)     (((E)->flags&EP_xIsSelect)==0)
3110
3111
3112
3113
3114
3115
3116

3117
3118
3119
3120
3121
3122
3123
  int regResult;    /* Registers holding results of a co-routine */
  struct {
    u8 jointype;      /* Type of join between this table and the previous */
    unsigned notIndexed :1;    /* True if there is a NOT INDEXED clause */
    unsigned isIndexedBy :1;   /* True if there is an INDEXED BY clause */
    unsigned isTabFunc :1;     /* True if table-valued-function syntax */
    unsigned isCorrelated :1;  /* True if sub-query is correlated */

    unsigned viaCoroutine :1;  /* Implemented as a co-routine */
    unsigned isRecursive :1;   /* True for recursive reference in WITH */
    unsigned fromDDL :1;       /* Comes from sqlite_schema */
    unsigned isCte :1;         /* This is a CTE */
    unsigned notCte :1;        /* This item may not match a CTE */
    unsigned isUsing :1;       /* u3.pUsing is valid */
    unsigned isSynthUsing :1;  /* u3.pUsing is synthensized from NATURAL */







>







3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
  int regResult;    /* Registers holding results of a co-routine */
  struct {
    u8 jointype;      /* Type of join between this table and the previous */
    unsigned notIndexed :1;    /* True if there is a NOT INDEXED clause */
    unsigned isIndexedBy :1;   /* True if there is an INDEXED BY clause */
    unsigned isTabFunc :1;     /* True if table-valued-function syntax */
    unsigned isCorrelated :1;  /* True if sub-query is correlated */
    unsigned isMaterialized:1; /* This is a materialized view */
    unsigned viaCoroutine :1;  /* Implemented as a co-routine */
    unsigned isRecursive :1;   /* True for recursive reference in WITH */
    unsigned fromDDL :1;       /* Comes from sqlite_schema */
    unsigned isCte :1;         /* This is a CTE */
    unsigned notCte :1;        /* This item may not match a CTE */
    unsigned isUsing :1;       /* u3.pUsing is valid */
    unsigned isSynthUsing :1;  /* u3.pUsing is synthensized from NATURAL */
5341
5342
5343
5344
5345
5346
5347
5348
5349
5350
5351
5352
5353
5354
5355
#define IN_INDEX_NOOP         5   /* No table available. Use comparisons */
/*
** Allowed flags for the 3rd parameter to sqlite3FindInIndex().
*/
#define IN_INDEX_NOOP_OK     0x0001  /* OK to return IN_INDEX_NOOP */
#define IN_INDEX_MEMBERSHIP  0x0002  /* IN operator used for membership test */
#define IN_INDEX_LOOP        0x0004  /* IN operator used as a loop */
#define IN_INDEX_REUSE_CUR   0x0008  /* Reuse prior table cursor */
int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*, int*);

int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
int sqlite3JournalSize(sqlite3_vfs *);
#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
 || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
  int sqlite3JournalCreate(sqlite3_file *);







<







5342
5343
5344
5345
5346
5347
5348

5349
5350
5351
5352
5353
5354
5355
#define IN_INDEX_NOOP         5   /* No table available. Use comparisons */
/*
** Allowed flags for the 3rd parameter to sqlite3FindInIndex().
*/
#define IN_INDEX_NOOP_OK     0x0001  /* OK to return IN_INDEX_NOOP */
#define IN_INDEX_MEMBERSHIP  0x0002  /* IN operator used for membership test */
#define IN_INDEX_LOOP        0x0004  /* IN operator used as a loop */

int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*, int*);

int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
int sqlite3JournalSize(sqlite3_vfs *);
#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
 || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
  int sqlite3JournalCreate(sqlite3_file *);
Changes to src/test4.c.
56
57
58
59
60
61
62





63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

79
80

81
82
83
84
85
86

87
88

89
90
91
92
93
94
95
96
97
98
99
100
101

102
103
104
105
106
107
108
/*
** There can be as many as 26 threads running at once.  Each is named
** by a capital letter: A, B, C, ..., Y, Z.
*/
#define N_THREAD 26
static Thread threadset[N_THREAD];







/*
** The main loop for a thread.  Threads use busy waiting. 
*/
static void *test_thread_main(void *pArg){
  Thread *p = (Thread*)pArg;
  if( p->db ){
    sqlite3_close(p->db);
  }
  sqlite3_open(p->zFilename, &p->db);
  if( SQLITE_OK!=sqlite3_errcode(p->db) ){
    p->zErr = strdup(sqlite3_errmsg(p->db));
    sqlite3_close(p->db);
    p->db = 0;
  }
  p->pStmt = 0;

  p->completed = 1;
  while( p->opnum<=p->completed ) sched_yield();

  while( p->xOp ){
    if( p->zErr && p->zErr!=p->zStaticErr ){
      sqlite3_free(p->zErr);
      p->zErr = 0;
    }
    (*p->xOp)(p);

    p->completed++;
    while( p->opnum<=p->completed ) sched_yield();

  }
  if( p->pStmt ){
    sqlite3_finalize(p->pStmt);
    p->pStmt = 0;
  }
  if( p->db ){
    sqlite3_close(p->db);
    p->db = 0;
  }
  if( p->zErr && p->zErr!=p->zStaticErr ){
    sqlite3_free(p->zErr);
    p->zErr = 0;
  }

  p->completed++;
#ifndef SQLITE_OMIT_DEPRECATED
  sqlite3_thread_cleanup();
#endif
  return 0;
}








>
>
>
>
>
















>


>






>


>













>







56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/*
** There can be as many as 26 threads running at once.  Each is named
** by a capital letter: A, B, C, ..., Y, Z.
*/
#define N_THREAD 26
static Thread threadset[N_THREAD];

static void test_barrier(){
  sqlite3_mutex *pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_APP1);
  sqlite3_mutex_enter(pMutex);
  sqlite3_mutex_leave(pMutex);
}

/*
** The main loop for a thread.  Threads use busy waiting. 
*/
static void *test_thread_main(void *pArg){
  Thread *p = (Thread*)pArg;
  if( p->db ){
    sqlite3_close(p->db);
  }
  sqlite3_open(p->zFilename, &p->db);
  if( SQLITE_OK!=sqlite3_errcode(p->db) ){
    p->zErr = strdup(sqlite3_errmsg(p->db));
    sqlite3_close(p->db);
    p->db = 0;
  }
  p->pStmt = 0;
  test_barrier();
  p->completed = 1;
  while( p->opnum<=p->completed ) sched_yield();
  test_barrier();
  while( p->xOp ){
    if( p->zErr && p->zErr!=p->zStaticErr ){
      sqlite3_free(p->zErr);
      p->zErr = 0;
    }
    (*p->xOp)(p);
    test_barrier();
    p->completed++;
    while( p->opnum<=p->completed ) sched_yield();
    test_barrier();
  }
  if( p->pStmt ){
    sqlite3_finalize(p->pStmt);
    p->pStmt = 0;
  }
  if( p->db ){
    sqlite3_close(p->db);
    p->db = 0;
  }
  if( p->zErr && p->zErr!=p->zStaticErr ){
    sqlite3_free(p->zErr);
    p->zErr = 0;
  }
  test_barrier();
  p->completed++;
#ifndef SQLITE_OMIT_DEPRECATED
  sqlite3_thread_cleanup();
#endif
  return 0;
}

162
163
164
165
166
167
168

169

170
171
172
173
174
175
176
  return TCL_OK;
}

/*
** Wait for a thread to reach its idle state.
*/
static void test_thread_wait(Thread *p){

  while( p->opnum>p->completed ) sched_yield();

}

/*
** Usage:  thread_wait ID
**
** Wait on thread ID to reach its idle state.
*/







>

>







172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
  return TCL_OK;
}

/*
** Wait for a thread to reach its idle state.
*/
static void test_thread_wait(Thread *p){
  test_barrier();
  while( p->opnum>p->completed ) sched_yield();
  test_barrier();
}

/*
** Usage:  thread_wait ID
**
** Wait on thread ID to reach its idle state.
*/
452
453
454
455
456
457
458

459
460
461
462
463
464
465
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  test_thread_wait(&threadset[i]);
  threadset[i].xOp = do_compile;
  sqlite3_free(threadset[i].zArg);
  threadset[i].zArg = sqlite3_mprintf("%s", argv[2]);

  threadset[i].opnum++;
  return TCL_OK;
}

/*
** This procedure runs in the thread to step the virtual machine.
*/







>







464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  test_thread_wait(&threadset[i]);
  threadset[i].xOp = do_compile;
  sqlite3_free(threadset[i].zArg);
  threadset[i].zArg = sqlite3_mprintf("%s", argv[2]);
  test_barrier();
  threadset[i].opnum++;
  return TCL_OK;
}

/*
** This procedure runs in the thread to step the virtual machine.
*/
503
504
505
506
507
508
509

510
511
512
513
514
515
516
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  test_thread_wait(&threadset[i]);
  threadset[i].xOp = do_step;

  threadset[i].opnum++;
  return TCL_OK;
}

/*
** This procedure runs in the thread to finalize a virtual machine.
*/







>







516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  test_thread_wait(&threadset[i]);
  threadset[i].xOp = do_step;
  test_barrier();
  threadset[i].opnum++;
  return TCL_OK;
}

/*
** This procedure runs in the thread to finalize a virtual machine.
*/
547
548
549
550
551
552
553

554
555
556
557
558
559
560
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  test_thread_wait(&threadset[i]);
  threadset[i].xOp = do_finalize;
  sqlite3_free(threadset[i].zArg);
  threadset[i].zArg = 0;

  threadset[i].opnum++;
  return TCL_OK;
}

/*
** Usage: thread_swap ID ID
**







>







561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  test_thread_wait(&threadset[i]);
  threadset[i].xOp = do_finalize;
  sqlite3_free(threadset[i].zArg);
  threadset[i].zArg = 0;
  test_barrier();
  threadset[i].opnum++;
  return TCL_OK;
}

/*
** Usage: thread_swap ID ID
**
Changes to src/treeview.c.
485
486
487
488
489
490
491
492



493
494
495
496
497
498
499
500
    return;
  }
  if( pExpr->flags || pExpr->affExpr || pExpr->vvaFlags ){
    StrAccum x;
    sqlite3StrAccumInit(&x, 0, zFlgs, sizeof(zFlgs), 0);
    sqlite3_str_appendf(&x, " fg.af=%x.%c",
      pExpr->flags, pExpr->affExpr ? pExpr->affExpr : 'n');
    if( ExprHasProperty(pExpr, EP_FromJoin) ){



      sqlite3_str_appendf(&x, " iJoin=%d", pExpr->w.iJoin);
    }
    if( ExprHasProperty(pExpr, EP_FromDDL) ){
      sqlite3_str_appendf(&x, " DDL");
    }
    if( ExprHasVVAProperty(pExpr, EP_Immutable) ){
      sqlite3_str_appendf(&x, " IMMUTABLE");
    }







|
>
>
>
|







485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
    return;
  }
  if( pExpr->flags || pExpr->affExpr || pExpr->vvaFlags ){
    StrAccum x;
    sqlite3StrAccumInit(&x, 0, zFlgs, sizeof(zFlgs), 0);
    sqlite3_str_appendf(&x, " fg.af=%x.%c",
      pExpr->flags, pExpr->affExpr ? pExpr->affExpr : 'n');
    if( ExprHasProperty(pExpr, EP_OuterON) ){
      sqlite3_str_appendf(&x, " outer.iJoin=%d", pExpr->w.iJoin);
    }
    if( ExprHasProperty(pExpr, EP_InnerON) ){
      sqlite3_str_appendf(&x, " inner.iJoin=%d", pExpr->w.iJoin);
    }
    if( ExprHasProperty(pExpr, EP_FromDDL) ){
      sqlite3_str_appendf(&x, " DDL");
    }
    if( ExprHasVVAProperty(pExpr, EP_Immutable) ){
      sqlite3_str_appendf(&x, " IMMUTABLE");
    }
Changes to src/trigger.c.
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
** Construct a trigger step that implements an UPDATE statement and return
** a pointer to that trigger step.  The parser calls this routine when it
** sees an UPDATE statement inside the body of a CREATE TRIGGER.
*/
TriggerStep *sqlite3TriggerUpdateStep(
  Parse *pParse,          /* Parser */
  Token *pTableName,   /* Name of the table to be updated */
  SrcList *pFrom,
  ExprList *pEList,    /* The SET clause: list of column and new values */
  Expr *pWhere,        /* The WHERE clause */
  u8 orconf,           /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
  const char *zStart,  /* Start of SQL text */
  const char *zEnd     /* End of SQL text */
){
  sqlite3 *db = pParse->db;







|







510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
** Construct a trigger step that implements an UPDATE statement and return
** a pointer to that trigger step.  The parser calls this routine when it
** sees an UPDATE statement inside the body of a CREATE TRIGGER.
*/
TriggerStep *sqlite3TriggerUpdateStep(
  Parse *pParse,          /* Parser */
  Token *pTableName,   /* Name of the table to be updated */
  SrcList *pFrom,      /* FROM clause for an UPDATE-FROM, or NULL */
  ExprList *pEList,    /* The SET clause: list of column and new values */
  Expr *pWhere,        /* The WHERE clause */
  u8 orconf,           /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
  const char *zStart,  /* Start of SQL text */
  const char *zEnd     /* End of SQL text */
){
  sqlite3 *db = pParse->db;
846
847
848
849
850
851
852








853
854
855
856
857
858
859
    Schema *pSchema = pStep->pTrig->pSchema;
    pSrc->a[0].zName = zName;
    if( pSchema!=db->aDb[1].pSchema ){
      pSrc->a[0].pSchema = pSchema;
    }
    if( pStep->pFrom ){
      SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0);








      pSrc = sqlite3SrcListAppendList(pParse, pSrc, pDup);
    }
  }else{
    sqlite3DbFree(db, zName);
  }
  return pSrc;
}







>
>
>
>
>
>
>
>







846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
    Schema *pSchema = pStep->pTrig->pSchema;
    pSrc->a[0].zName = zName;
    if( pSchema!=db->aDb[1].pSchema ){
      pSrc->a[0].pSchema = pSchema;
    }
    if( pStep->pFrom ){
      SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0);
      if( pDup && pDup->nSrc>1 && !IN_RENAME_OBJECT ){
        Select *pSubquery;
        Token as;
        pSubquery = sqlite3SelectNew(pParse,0,pDup,0,0,0,0,SF_NestedFrom,0);
        as.n = 0;
        as.z = 0;
        pDup = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&as,pSubquery,0);
      }
      pSrc = sqlite3SrcListAppendList(pParse, pSrc, pDup);
    }
  }else{
    sqlite3DbFree(db, zName);
  }
  return pSrc;
}
Changes to src/vdbeaux.c.
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583

1584
1585
1586
1587
1588
1589
1590
      if( c=='P' ){
        c = zSynopsis[++ii];
        if( c=='4' ){
          sqlite3_str_appendall(&x, zP4);
        }else if( c=='X' ){
          if( pOp->zComment && pOp->zComment[0] ){
            sqlite3_str_appendall(&x, pOp->zComment);
          }else{
            sqlite3_str_appendall(&x, zSynopsis+1);
          }
          seenCom = 1;
          break;

        }else{
          int v1 = translateP(c, pOp);
          int v2;
          if( strncmp(zSynopsis+ii+1, "@P", 2)==0 ){
            ii += 3;
            v2 = translateP(zSynopsis[ii], pOp);
            if( strncmp(zSynopsis+ii+1,"+1",2)==0 ){







<
<
<
|
|
>







1572
1573
1574
1575
1576
1577
1578



1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
      if( c=='P' ){
        c = zSynopsis[++ii];
        if( c=='4' ){
          sqlite3_str_appendall(&x, zP4);
        }else if( c=='X' ){
          if( pOp->zComment && pOp->zComment[0] ){
            sqlite3_str_appendall(&x, pOp->zComment);



            seenCom = 1;
            break;
          }
        }else{
          int v1 = translateP(c, pOp);
          int v2;
          if( strncmp(zSynopsis+ii+1, "@P", 2)==0 ){
            ii += 3;
            v2 = translateP(zSynopsis[ii], pOp);
            if( strncmp(zSynopsis+ii+1,"+1",2)==0 ){
Changes to src/where.c.
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
      for(pTerm=pWC->a+k; k<pWC->nTerm; k++, pTerm++){
        assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 || pTerm->leftCursor<0 );
        if( pTerm->leftCursor==iCur
         && pTerm->u.x.leftColumn==iColumn
         && (iColumn!=XN_EXPR
             || sqlite3ExprCompareSkip(pTerm->pExpr->pLeft,
                                       pScan->pIdxExpr,iCur)==0)
         && (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin))
        ){
          if( (pTerm->eOperator & WO_EQUIV)!=0
           && pScan->nEquiv<ArraySize(pScan->aiCur)
           && (pX = whereRightSubexprIsColumn(pTerm->pExpr))!=0
          ){
            int j;
            for(j=0; j<pScan->nEquiv; j++){







|







326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
      for(pTerm=pWC->a+k; k<pWC->nTerm; k++, pTerm++){
        assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 || pTerm->leftCursor<0 );
        if( pTerm->leftCursor==iCur
         && pTerm->u.x.leftColumn==iColumn
         && (iColumn!=XN_EXPR
             || sqlite3ExprCompareSkip(pTerm->pExpr->pLeft,
                                       pScan->pIdxExpr,iCur)==0)
         && (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_OuterON))
        ){
          if( (pTerm->eOperator & WO_EQUIV)!=0
           && pScan->nEquiv<ArraySize(pScan->aiCur)
           && (pX = whereRightSubexprIsColumn(pTerm->pExpr))!=0
          ){
            int j;
            for(j=0; j<pScan->nEquiv; j++){
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
  const SrcItem *pSrc,           /* Table we are trying to access */
  const Bitmask notReady         /* Tables in outer loops of the join */
){
  char aff;
  if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
  if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0;
  if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ))!=0
   && !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
   && (pTerm->eOperator & WO_IS)
  ){
    /* Cannot use an IS term from the WHERE clause as an index driver for
    ** the RHS of a LEFT JOIN or for the LHS of a RIGHT JOIN. Such a term
    ** can only be used if it is from the ON clause.  */
    return 0;
  }







|







753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
  const SrcItem *pSrc,           /* Table we are trying to access */
  const Bitmask notReady         /* Tables in outer loops of the join */
){
  char aff;
  if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
  if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0;
  if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ))!=0
   && !ExprHasProperty(pTerm->pExpr, EP_OuterON)
   && (pTerm->eOperator & WO_IS)
  ){
    /* Cannot use an IS term from the WHERE clause as an index driver for
    ** the RHS of a LEFT JOIN or for the LHS of a RIGHT JOIN. Such a term
    ** can only be used if it is from the ON clause.  */
    return 0;
  }
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
    assert( pTerm->u.x.leftColumn<pTab->nCol );

    /* tag-20191211-002: WHERE-clause constraints are not useful to the
    ** right-hand table of a LEFT JOIN nor to the left-hand table of a
    ** RIGHT JOIN.  See tag-20191211-001 for the
    ** equivalent restriction for ordinary tables. */
    if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ))!=0
     && !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
    ){
      continue;
    }
    nTerm++;
    pTerm->wtFlags |= TERM_OK;
  }








|







1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
    assert( pTerm->u.x.leftColumn<pTab->nCol );

    /* tag-20191211-002: WHERE-clause constraints are not useful to the
    ** right-hand table of a LEFT JOIN nor to the left-hand table of a
    ** RIGHT JOIN.  See tag-20191211-001 for the
    ** equivalent restriction for ordinary tables. */
    if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ))!=0
     && !ExprHasProperty(pTerm->pExpr, EP_OuterON)
    ){
      continue;
    }
    nTerm++;
    pTerm->wtFlags |= TERM_OK;
  }

2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
    sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm);
  }else{
    char zType[8];
    char zLeft[50];
    memcpy(zType, "....", 5);
    if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V';
    if( pTerm->eOperator & WO_EQUIV  ) zType[1] = 'E';
    if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L';
    if( pTerm->wtFlags & TERM_CODED  ) zType[3] = 'C';
    if( pTerm->eOperator & WO_SINGLE ){
      assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
      sqlite3_snprintf(sizeof(zLeft),zLeft,"left={%d:%d}",
                       pTerm->leftCursor, pTerm->u.x.leftColumn);
    }else if( (pTerm->eOperator & WO_OR)!=0 && pTerm->u.pOrInfo!=0 ){
      sqlite3_snprintf(sizeof(zLeft),zLeft,"indexable=0x%llx", 







|







2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
    sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm);
  }else{
    char zType[8];
    char zLeft[50];
    memcpy(zType, "....", 5);
    if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V';
    if( pTerm->eOperator & WO_EQUIV  ) zType[1] = 'E';
    if( ExprHasProperty(pTerm->pExpr, EP_OuterON) ) zType[2] = 'L';
    if( pTerm->wtFlags & TERM_CODED  ) zType[3] = 'C';
    if( pTerm->eOperator & WO_SINGLE ){
      assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
      sqlite3_snprintf(sizeof(zLeft),zLeft,"left={%d:%d}",
                       pTerm->leftCursor, pTerm->u.x.leftColumn);
    }else if( (pTerm->eOperator & WO_OR)!=0 && pTerm->u.pOrInfo!=0 ){
      sqlite3_snprintf(sizeof(zLeft),zLeft,"indexable=0x%llx", 
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
    if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue;

    /* tag-20191211-001:  Do not allow constraints from the WHERE clause to
    ** be used by the right table of a LEFT JOIN nor by the left table of a
    ** RIGHT JOIN.  Only constraints in the
    ** ON clause are allowed.  See tag-20191211-002 for the vtab equivalent. */
    if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ))!=0
     && !ExprHasProperty(pTerm->pExpr, EP_FromJoin|EP_InnerJoin)
    ){
      continue;
    }

    if( IsUniqueIndex(pProbe) && saved_nEq==pProbe->nKeyCol-1 ){
      pBuilder->bldFlags1 |= SQLITE_BLDF1_UNIQUE;
    }else{







|







2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
    if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue;

    /* tag-20191211-001:  Do not allow constraints from the WHERE clause to
    ** be used by the right table of a LEFT JOIN nor by the left table of a
    ** RIGHT JOIN.  Only constraints in the
    ** ON clause are allowed.  See tag-20191211-002 for the vtab equivalent. */
    if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ))!=0
     && !ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON)
    ){
      continue;
    }

    if( IsUniqueIndex(pProbe) && saved_nEq==pProbe->nKeyCol-1 ){
      pBuilder->bldFlags1 |= SQLITE_BLDF1_UNIQUE;
    }else{
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
    if( !whereUsablePartialIndex(iTab,isLeft,pWC,pWhere->pLeft) ) return 0;
    pWhere = pWhere->pRight;
  }
  if( pParse->db->flags & SQLITE_EnableQPSG ) pParse = 0;
  for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
    Expr *pExpr;
    pExpr = pTerm->pExpr;
    if( (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->w.iJoin==iTab)
     && (isLeft==0 || ExprHasProperty(pExpr, EP_FromJoin))
     && sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab)
     && (pTerm->wtFlags & TERM_VNULL)==0
    ){
      return 1;
    }
  }
  return 0;







|
|







3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
    if( !whereUsablePartialIndex(iTab,isLeft,pWC,pWhere->pLeft) ) return 0;
    pWhere = pWhere->pRight;
  }
  if( pParse->db->flags & SQLITE_EnableQPSG ) pParse = 0;
  for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
    Expr *pExpr;
    pExpr = pTerm->pExpr;
    if( (!ExprHasProperty(pExpr, EP_OuterON) || pExpr->w.iJoin==iTab)
     && (isLeft==0 || ExprHasProperty(pExpr, EP_OuterON))
     && sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab)
     && (pTerm->wtFlags & TERM_VNULL)==0
    ){
      return 1;
    }
  }
  return 0;
3478
3479
3480
3481
3482
3483
3484






3485

3486
3487
3488
3489
3490
3491
3492
            }
          }
          
          pNew->rRun = sqlite3LogEstAdd(pNew->rRun, nLookup);
        }
        ApplyCostMultiplier(pNew->rRun, pTab->costMult);
        whereLoopOutputAdjust(pWC, pNew, rSize);






        rc = whereLoopInsert(pBuilder, pNew);

        pNew->nOut = rSize;
        if( rc ) break;
      }
    }

    pBuilder->bldFlags1 = 0;
    rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 0);







>
>
>
>
>
>
|
>







3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
            }
          }
          
          pNew->rRun = sqlite3LogEstAdd(pNew->rRun, nLookup);
        }
        ApplyCostMultiplier(pNew->rRun, pTab->costMult);
        whereLoopOutputAdjust(pWC, pNew, rSize);
        if( (pSrc->fg.jointype & JT_RIGHT)!=0 && pProbe->aColExpr ){
          /* Do not do an SCAN of a index-on-expression in a RIGHT JOIN
          ** because the cursor used to access the index might not be
          ** positioned to the correct row during the right-join no-match
          ** loop. */
        }else{
          rc = whereLoopInsert(pBuilder, pNew);
        }
        pNew->nOut = rSize;
        if( rc ) break;
      }
    }

    pBuilder->bldFlags1 = 0;
    rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 0);
3653
3654
3655
3656
3657
3658
3659

3660
3661
3662
3663
3664
3665
3666
        ** (2) Multiple outputs from a single IN value will not merge
        ** together.  */
        pIdxInfo->orderByConsumed = 0;
        pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE;
        *pbIn = 1; assert( (mExclude & WO_IN)==0 );
      }


      if( isLimitTerm(pTerm) && *pbIn ){
        /* If there is an IN(...) term handled as an == (separate call to
        ** xFilter for each value on the RHS of the IN) and a LIMIT or
        ** OFFSET term handled as well, the plan is unusable. Set output
        ** variable *pbRetryLimit to true to tell the caller to retry with
        ** LIMIT and OFFSET disabled. */
        if( pIdxInfo->needToFreeIdxStr ){







>







3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
        ** (2) Multiple outputs from a single IN value will not merge
        ** together.  */
        pIdxInfo->orderByConsumed = 0;
        pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE;
        *pbIn = 1; assert( (mExclude & WO_IN)==0 );
      }

      assert( pbRetryLimit || !isLimitTerm(pTerm) );
      if( isLimitTerm(pTerm) && *pbIn ){
        /* If there is an IN(...) term handled as an == (separate call to
        ** xFilter for each value on the RHS of the IN) and a LIMIT or
        ** OFFSET term handled as well, the plan is unusable. Set output
        ** variable *pbRetryLimit to true to tell the caller to retry with
        ** LIMIT and OFFSET disabled. */
        if( pIdxInfo->needToFreeIdxStr ){
4126
4127
4128
4129
4130
4131
4132

4133

4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146


4147

4148
4149
4150
4151
4152
4153
4154
  Bitmask mPrior = 0;
  int iTab;
  SrcList *pTabList = pWInfo->pTabList;
  SrcItem *pItem;
  SrcItem *pEnd = &pTabList->a[pWInfo->nLevel];
  sqlite3 *db = pWInfo->pParse->db;
  int rc = SQLITE_OK;

  WhereLoop *pNew;


  /* Loop over the tables in the join, from left to right */
  pNew = pBuilder->pNew;
  whereLoopInit(pNew);
  pBuilder->iPlanLimit = SQLITE_QUERY_PLANNER_LIMIT;
  for(iTab=0, pItem=pTabList->a; pItem<pEnd; iTab++, pItem++){
    Bitmask mUnusable = 0;
    pNew->iTab = iTab;
    pBuilder->iPlanLimit += SQLITE_QUERY_PLANNER_LIMIT_INCR;
    pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor);
    if( (pItem->fg.jointype & (JT_OUTER|JT_CROSS))!=0 ){
      /* This condition is true when pItem is the FROM clause term on the
      ** right-hand-side of a OUTER or CROSS JOIN.  */


      mPrereq |= mPrior;

    }
#ifndef SQLITE_OMIT_VIRTUALTABLE
    if( IsVirtual(pItem->pTab) ){
      SrcItem *p;
      for(p=&pItem[1]; p<pEnd; p++){
        if( mUnusable || (p->fg.jointype & (JT_OUTER|JT_CROSS)) ){
          mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor);







>

>










|
|
|
>
>

>







4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
  Bitmask mPrior = 0;
  int iTab;
  SrcList *pTabList = pWInfo->pTabList;
  SrcItem *pItem;
  SrcItem *pEnd = &pTabList->a[pWInfo->nLevel];
  sqlite3 *db = pWInfo->pParse->db;
  int rc = SQLITE_OK;
  int bFirstPastRJ = 0;
  WhereLoop *pNew;


  /* Loop over the tables in the join, from left to right */
  pNew = pBuilder->pNew;
  whereLoopInit(pNew);
  pBuilder->iPlanLimit = SQLITE_QUERY_PLANNER_LIMIT;
  for(iTab=0, pItem=pTabList->a; pItem<pEnd; iTab++, pItem++){
    Bitmask mUnusable = 0;
    pNew->iTab = iTab;
    pBuilder->iPlanLimit += SQLITE_QUERY_PLANNER_LIMIT_INCR;
    pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor);
    if( bFirstPastRJ || (pItem->fg.jointype & (JT_OUTER|JT_CROSS))!=0 ){
      /* Add prerequisites to prevent reordering of FROM clause terms
      ** across CROSS joins and outer joins.  The bFirstPastRJ boolean
      ** prevents the right operand of a RIGHT JOIN from being swapped with
      ** other elements even further to the right. */
      mPrereq |= mPrior;
      bFirstPastRJ = (pItem->fg.jointype & JT_RIGHT)!=0;
    }
#ifndef SQLITE_OMIT_VIRTUALTABLE
    if( IsVirtual(pItem->pTab) ){
      SrcItem *p;
      for(p=&pItem[1]; p<pEnd; p++){
        if( mUnusable || (p->fg.jointype & (JT_OUTER|JT_CROSS)) ){
          mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor);
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
    ){
      continue;
    }
    if( (tabUsed & pLoop->maskSelf)!=0 ) continue;
    pEnd = pWInfo->sWC.a + pWInfo->sWC.nTerm;
    for(pTerm=pWInfo->sWC.a; pTerm<pEnd; pTerm++){
      if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
        if( !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
         || pTerm->pExpr->w.iJoin!=pItem->iCursor
        ){
          break;
        }
      }
    }
    if( pTerm<pEnd ) continue;







|







5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
    ){
      continue;
    }
    if( (tabUsed & pLoop->maskSelf)!=0 ) continue;
    pEnd = pWInfo->sWC.a + pWInfo->sWC.nTerm;
    for(pTerm=pWInfo->sWC.a; pTerm<pEnd; pTerm++){
      if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
        if( !ExprHasProperty(pTerm->pExpr, EP_OuterON)
         || pTerm->pExpr->w.iJoin!=pItem->iCursor
        ){
          break;
        }
      }
    }
    if( pTerm<pEnd ) continue;
5836
5837
5838
5839
5840
5841
5842

5843
5844
5845
5846
5847
5848
5849
      }else if( iAuxArg && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ){
        iIndexCur = iAuxArg;
        op = OP_ReopenIdx;
      }else{
        iIndexCur = pParse->nTab++;
      }
      pLevel->iIdxCur = iIndexCur;

      assert( pIx->pSchema==pTab->pSchema );
      assert( iIndexCur>=0 );
      if( op ){
        sqlite3VdbeAddOp3(v, op, iIndexCur, pIx->tnum, iDb);
        sqlite3VdbeSetP4KeyInfo(pParse, pIx);
        if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0
         && (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0







>







5849
5850
5851
5852
5853
5854
5855
5856
5857
5858
5859
5860
5861
5862
5863
      }else if( iAuxArg && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ){
        iIndexCur = iAuxArg;
        op = OP_ReopenIdx;
      }else{
        iIndexCur = pParse->nTab++;
      }
      pLevel->iIdxCur = iIndexCur;
      assert( pIx!=0 );
      assert( pIx->pSchema==pTab->pSchema );
      assert( iIndexCur>=0 );
      if( op ){
        sqlite3VdbeAddOp3(v, op, iIndexCur, pIx->tnum, iDb);
        sqlite3VdbeSetP4KeyInfo(pParse, pIx);
        if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0
         && (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0
5911
5912
5913
5914
5915
5916
5917

5918
5919
5920










5921
5922
5923
5924
5925
5926
5927
  /* Generate the code to do the search.  Each iteration of the for
  ** loop below generates code for a single nested loop of the VM
  ** program.
  */
  for(ii=0; ii<nTabList; ii++){
    int addrExplain;
    int wsFlags;

    if( pParse->nErr ) goto whereBeginError;
    pLevel = &pWInfo->a[ii];
    wsFlags = pLevel->pWLoop->wsFlags;










    if( (wsFlags & (WHERE_AUTO_INDEX|WHERE_BLOOMFILTER))!=0 ){
      if( (wsFlags & WHERE_AUTO_INDEX)!=0 ){
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
        constructAutomaticIndex(pParse, &pWInfo->sWC,
                  &pTabList->a[pLevel->iFrom], notReady, pLevel);
#endif
      }else{







>



>
>
>
>
>
>
>
>
>
>







5925
5926
5927
5928
5929
5930
5931
5932
5933
5934
5935
5936
5937
5938
5939
5940
5941
5942
5943
5944
5945
5946
5947
5948
5949
5950
5951
5952
  /* Generate the code to do the search.  Each iteration of the for
  ** loop below generates code for a single nested loop of the VM
  ** program.
  */
  for(ii=0; ii<nTabList; ii++){
    int addrExplain;
    int wsFlags;
    SrcItem *pSrc;
    if( pParse->nErr ) goto whereBeginError;
    pLevel = &pWInfo->a[ii];
    wsFlags = pLevel->pWLoop->wsFlags;
    pSrc = &pTabList->a[pLevel->iFrom];
    if( pSrc->fg.isMaterialized ){
      if( pSrc->fg.isCorrelated ){
        sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub);
      }else{
        int iOnce = sqlite3VdbeAddOp0(v, OP_Once);  VdbeCoverage(v);
        sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub);
        sqlite3VdbeJumpHere(v, iOnce);
      }
    }
    if( (wsFlags & (WHERE_AUTO_INDEX|WHERE_BLOOMFILTER))!=0 ){
      if( (wsFlags & WHERE_AUTO_INDEX)!=0 ){
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
        constructAutomaticIndex(pParse, &pWInfo->sWC,
                  &pTabList->a[pLevel->iFrom], notReady, pLevel);
#endif
      }else{
6164
6165
6166
6167
6168
6169
6170

6171
6172
6173
6174
6175
6176
6177
      sqlite3VdbeJumpHere(v, addr);
    }
    VdbeModuleComment((v, "End WHERE-loop%d: %s", i,
                     pWInfo->pTabList->a[pLevel->iFrom].pTab->zName));
  }

  assert( pWInfo->nLevel<=pTabList->nSrc );

  for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){
    int k, last;
    VdbeOp *pOp, *pLastOp;
    Index *pIdx = 0;
    SrcItem *pTabItem = &pTabList->a[pLevel->iFrom];
    Table *pTab = pTabItem->pTab;
    assert( pTab!=0 );







>







6189
6190
6191
6192
6193
6194
6195
6196
6197
6198
6199
6200
6201
6202
6203
      sqlite3VdbeJumpHere(v, addr);
    }
    VdbeModuleComment((v, "End WHERE-loop%d: %s", i,
                     pWInfo->pTabList->a[pLevel->iFrom].pTab->zName));
  }

  assert( pWInfo->nLevel<=pTabList->nSrc );
  if( pWInfo->pExprMods ) whereUndoExprMods(pWInfo);
  for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){
    int k, last;
    VdbeOp *pOp, *pLastOp;
    Index *pIdx = 0;
    SrcItem *pTabItem = &pTabList->a[pLevel->iFrom];
    Table *pTab = pTabItem->pTab;
    assert( pTab!=0 );
6300
6301
6302
6303
6304
6305
6306
6307
6308
6309
6310
6311
  /* The "break" point is here, just past the end of the outer loop.
  ** Set it.
  */
  sqlite3VdbeResolveLabel(v, pWInfo->iBreak);

  /* Final cleanup
  */
  if( pWInfo->pExprMods ) whereUndoExprMods(pWInfo);
  pParse->nQueryLoop = pWInfo->savedNQueryLoop;
  whereInfoFree(db, pWInfo);
  return;
}







<




6326
6327
6328
6329
6330
6331
6332

6333
6334
6335
6336
  /* The "break" point is here, just past the end of the outer loop.
  ** Set it.
  */
  sqlite3VdbeResolveLabel(v, pWInfo->iBreak);

  /* Final cleanup
  */

  pParse->nQueryLoop = pWInfo->savedNQueryLoop;
  whereInfoFree(db, pWInfo);
  return;
}
Changes to src/whereInt.h.
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

/*
** This object is a header on a block of allocated memory that will be
** automatically freed when its WInfo oject is destructed.
*/
struct WhereMemBlock {
  WhereMemBlock *pNext;      /* Next block in the chain */
  u8 sz;                     /* Bytes of space */
};

/*
** Extra information attached to a WhereLevel that is a RIGHT JOIN.
*/
struct WhereRightJoin {
  int iMatch;          /* Cursor used to determine prior matched rows */







|







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

/*
** This object is a header on a block of allocated memory that will be
** automatically freed when its WInfo oject is destructed.
*/
struct WhereMemBlock {
  WhereMemBlock *pNext;      /* Next block in the chain */
  u64 sz;                    /* Bytes of space */
};

/*
** Extra information attached to a WhereLevel that is a RIGHT JOIN.
*/
struct WhereRightJoin {
  int iMatch;          /* Cursor used to determine prior matched rows */
Changes to src/wherecode.c.
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
** a conditional such that is only evaluated on the second pass of a
** LIKE-optimization loop, when scanning BLOBs instead of strings.
*/
static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
  int nLoop = 0;
  assert( pTerm!=0 );
  while( (pTerm->wtFlags & TERM_CODED)==0
      && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
      && (pLevel->notReady & pTerm->prereqAll)==0
  ){
    if( nLoop && (pTerm->wtFlags & TERM_LIKE)!=0 ){
      pTerm->wtFlags |= TERM_LIKECOND;
    }else{
      pTerm->wtFlags |= TERM_CODED;
    }







|







346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
** a conditional such that is only evaluated on the second pass of a
** LIKE-optimization loop, when scanning BLOBs instead of strings.
*/
static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
  int nLoop = 0;
  assert( pTerm!=0 );
  while( (pTerm->wtFlags & TERM_CODED)==0
      && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_OuterON))
      && (pLevel->notReady & pTerm->prereqAll)==0
  ){
    if( nLoop && (pTerm->wtFlags & TERM_LIKE)!=0 ){
      pTerm->wtFlags |= TERM_LIKECOND;
    }else{
      pTerm->wtFlags |= TERM_CODED;
    }
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
          aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
          eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap,&iTab);
          pExpr->iTable = iTab;
        }
        sqlite3ExprDelete(db, pX);
      }else{
        aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
        eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP|IN_INDEX_REUSE_CUR,                                   0, aiMap,&iTab);
        iTab = pExpr->iTable;
      }
      pX = pExpr;
    }

    if( eType==IN_INDEX_INDEX_DESC ){
      testcase( bRev );
      bRev = !bRev;







|
<







619
620
621
622
623
624
625
626

627
628
629
630
631
632
633
          aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
          eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap,&iTab);
          pExpr->iTable = iTab;
        }
        sqlite3ExprDelete(db, pX);
      }else{
        aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
        eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab);

      }
      pX = pExpr;
    }

    if( eType==IN_INDEX_INDEX_DESC ){
      testcase( bRev );
      bRev = !bRev;
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
    **
    **   WHERE 1 = (t2.c IS NULL)
    **
    ** are also excluded. See codeCursorHintIsOrFunction() for details.
    */
    if( pTabItem->fg.jointype & JT_LEFT ){
      Expr *pExpr = pTerm->pExpr;
      if( !ExprHasProperty(pExpr, EP_FromJoin) 
       || pExpr->w.iJoin!=pTabItem->iCursor
      ){
        sWalker.eCode = 0;
        sWalker.xExprCallback = codeCursorHintIsOrFunction;
        sqlite3WalkExpr(&sWalker, pTerm->pExpr);
        if( sWalker.eCode ) continue;
      }
    }else{
      if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue;
    }

    /* All terms in pWLoop->aLTerm[] except pEndRange are used to initialize
    ** the cursor.  These terms are not needed as hints for a pure range
    ** scan (that has no == terms) so omit them. */
    if( pLoop->u.btree.nEq==0 && pTerm!=pEndRange ){
      for(j=0; j<pLoop->nLTerm && pLoop->aLTerm[j]!=pTerm; j++){}







|








|







1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
    **
    **   WHERE 1 = (t2.c IS NULL)
    **
    ** are also excluded. See codeCursorHintIsOrFunction() for details.
    */
    if( pTabItem->fg.jointype & JT_LEFT ){
      Expr *pExpr = pTerm->pExpr;
      if( !ExprHasProperty(pExpr, EP_OuterON) 
       || pExpr->w.iJoin!=pTabItem->iCursor
      ){
        sWalker.eCode = 0;
        sWalker.xExprCallback = codeCursorHintIsOrFunction;
        sqlite3WalkExpr(&sWalker, pTerm->pExpr);
        if( sWalker.eCode ) continue;
      }
    }else{
      if( ExprHasProperty(pTerm->pExpr, EP_OuterON) ) continue;
    }

    /* All terms in pWLoop->aLTerm[] except pEndRange are used to initialize
    ** the cursor.  These terms are not needed as hints for a pure range
    ** scan (that has no == terms) so omit them. */
    if( pLoop->u.btree.nEq==0 && pTerm!=pEndRange ){
      for(j=0; j<pLoop->nLTerm && pLoop->aLTerm[j]!=pTerm; j++){}
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
      WhereTerm *pOrTerm = &pOrWc->a[ii];
      if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
        WhereInfo *pSubWInfo;           /* Info for single OR-term scan */
        Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */
        Expr *pDelete;                  /* Local copy of OR clause term */
        int jmp1 = 0;                   /* Address of jump operation */
        testcase( (pTabItem[0].fg.jointype & JT_LEFT)!=0
               && !ExprHasProperty(pOrExpr, EP_FromJoin)
        ); /* See TH3 vtab25.400 and ticket 614b25314c766238 */
        pDelete = pOrExpr = sqlite3ExprDup(db, pOrExpr, 0);
        if( db->mallocFailed ){
          sqlite3ExprDelete(db, pDelete);
          continue;
        }
        if( pAndExpr ){







|







2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
      WhereTerm *pOrTerm = &pOrWc->a[ii];
      if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
        WhereInfo *pSubWInfo;           /* Info for single OR-term scan */
        Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */
        Expr *pDelete;                  /* Local copy of OR clause term */
        int jmp1 = 0;                   /* Address of jump operation */
        testcase( (pTabItem[0].fg.jointype & JT_LEFT)!=0
               && !ExprHasProperty(pOrExpr, EP_OuterON)
        ); /* See TH3 vtab25.400 and ticket 614b25314c766238 */
        pDelete = pOrExpr = sqlite3ExprDup(db, pOrExpr, 0);
        if( db->mallocFailed ){
          sqlite3ExprDelete(db, pDelete);
          continue;
        }
        if( pAndExpr ){
2616
2617
2618
2619
2620
2621
2622
2623
2624





2625

2626
2627
2628

2629
2630
2631
2632
2633
2634
2635
        testcase( pWInfo->untestedTerms==0
            && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 );
        pWInfo->untestedTerms = 1;
        continue;
      }
      pE = pTerm->pExpr;
      assert( pE!=0 );
      if( (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ))
       && !ExprHasProperty(pE,EP_FromJoin|EP_InnerJoin)





      ){

        continue;
      }
      

      if( iLoop==1 && !sqlite3ExprCoveredByIndex(pE, pLevel->iTabCur, pIdx) ){
        iNext = 2;
        continue;
      }
      if( iLoop<3 && (pTerm->wtFlags & TERM_VARSELECT) ){
        if( iNext==0 ) iNext = 3;
        continue;







|
|
>
>
>
>
>
|
>
|
|
|
>







2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
        testcase( pWInfo->untestedTerms==0
            && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 );
        pWInfo->untestedTerms = 1;
        continue;
      }
      pE = pTerm->pExpr;
      assert( pE!=0 );
      if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT) ){
        if( !ExprHasProperty(pE,EP_OuterON|EP_InnerON) ){
          /* Defer processing WHERE clause constraints until after outer
          ** join processing.  tag-20220513a */
          continue;
        }else{
          Bitmask m = sqlite3WhereGetMask(&pWInfo->sMaskSet, pE->w.iJoin);
          if( m & pLevel->notReady ){
            /* An ON clause that is not ripe */
            continue;
          }
        }
      }
      if( iLoop==1 && !sqlite3ExprCoveredByIndex(pE, pLevel->iTabCur, pIdx) ){
        iNext = 2;
        continue;
      }
      if( iLoop<3 && (pTerm->wtFlags & TERM_VARSELECT) ){
        if( iNext==0 ) iNext = 3;
        continue;
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
  for(pTerm=pWC->a, j=pWC->nBase; j>0; j--, pTerm++){
    Expr *pE, sEAlt;
    WhereTerm *pAlt;
    if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
    if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue;
    if( (pTerm->eOperator & WO_EQUIV)==0 ) continue;
    if( pTerm->leftCursor!=iCur ) continue;
    if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ) ) continue;
    pE = pTerm->pExpr;
#ifdef WHERETRACE_ENABLED /* 0x800 */
    if( sqlite3WhereTrace & 0x800 ){
      sqlite3DebugPrintf("Coding transitive constraint:\n");
      sqlite3WhereTermPrint(pTerm, pWC->nTerm-j);
    }
#endif
    assert( !ExprHasProperty(pE, EP_FromJoin) );
    assert( (pTerm->prereqRight & pLevel->notReady)!=0 );
    assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
    pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.x.leftColumn, notReady,
                    WO_EQ|WO_IN|WO_IS, 0);
    if( pAlt==0 ) continue;
    if( pAlt->wtFlags & (TERM_CODED) ) continue;
    if( (pAlt->eOperator & WO_IN) 







|







|







2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
  for(pTerm=pWC->a, j=pWC->nBase; j>0; j--, pTerm++){
    Expr *pE, sEAlt;
    WhereTerm *pAlt;
    if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
    if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue;
    if( (pTerm->eOperator & WO_EQUIV)==0 ) continue;
    if( pTerm->leftCursor!=iCur ) continue;
    if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT) ) continue;
    pE = pTerm->pExpr;
#ifdef WHERETRACE_ENABLED /* 0x800 */
    if( sqlite3WhereTrace & 0x800 ){
      sqlite3DebugPrintf("Coding transitive constraint:\n");
      sqlite3WhereTermPrint(pTerm, pWC->nTerm-j);
    }
#endif
    assert( !ExprHasProperty(pE, EP_OuterON) );
    assert( (pTerm->prereqRight & pLevel->notReady)!=0 );
    assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
    pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.x.leftColumn, notReady,
                    WO_EQ|WO_IN|WO_IS, 0);
    if( pAlt==0 ) continue;
    if( pAlt->wtFlags & (TERM_CODED) ) continue;
    if( (pAlt->eOperator & WO_IN) 
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777

2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792




















2793
2794
2795
2796
2797
2798
2799
  /* For a LEFT OUTER JOIN, generate code that will record the fact that
  ** at least one row of the right table has matched the left table.  
  */
  if( pLevel->iLeftJoin ){
    pLevel->addrFirst = sqlite3VdbeCurrentAddr(v);
    sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin);
    VdbeComment((v, "record LEFT JOIN hit"));
    for(pTerm=pWC->a, j=0; j<pWC->nBase; j++, pTerm++){
      testcase( pTerm->wtFlags & TERM_VIRTUAL );
      testcase( pTerm->wtFlags & TERM_CODED );
      if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
      if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
        assert( pWInfo->untestedTerms );
        continue;
      }
      if( pTabItem->fg.jointype & JT_LTORJ ) continue;
      assert( pTerm->pExpr );
      sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
      pTerm->wtFlags |= TERM_CODED;

    }
  }

  if( pLevel->pRJ ){
    /* Create a subroutine used to process all interior loops and code
    ** of the RIGHT JOIN.  During normal operation, the subroutine will
    ** be in-line with the rest of the code.  But at the end, a separate
    ** loop will run that invokes this subroutine for unmatched rows
    ** of pTab, with all tables to left begin set to NULL.
    */
    WhereRightJoin *pRJ = pLevel->pRJ;
    sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pRJ->regReturn);
    pRJ->addrSubrtn = sqlite3VdbeCurrentAddr(v);
    assert( pParse->withinRJSubrtn < 255 );
    pParse->withinRJSubrtn++;




















  }

#if WHERETRACE_ENABLED /* 0x20800 */
  if( sqlite3WhereTrace & 0x20000 ){
    sqlite3DebugPrintf("All WHERE-clause terms after coding level %d:\n",
                       iLevel);
    sqlite3WhereClausePrint(pWC);







<
<
<
<
|
<
<
<
<
<
<
<
>















>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







2765
2766
2767
2768
2769
2770
2771




2772







2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
  /* For a LEFT OUTER JOIN, generate code that will record the fact that
  ** at least one row of the right table has matched the left table.  
  */
  if( pLevel->iLeftJoin ){
    pLevel->addrFirst = sqlite3VdbeCurrentAddr(v);
    sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin);
    VdbeComment((v, "record LEFT JOIN hit"));




    if( pLevel->pRJ==0 ){







      goto code_outer_join_constraints; /* WHERE clause constraints */
    }
  }

  if( pLevel->pRJ ){
    /* Create a subroutine used to process all interior loops and code
    ** of the RIGHT JOIN.  During normal operation, the subroutine will
    ** be in-line with the rest of the code.  But at the end, a separate
    ** loop will run that invokes this subroutine for unmatched rows
    ** of pTab, with all tables to left begin set to NULL.
    */
    WhereRightJoin *pRJ = pLevel->pRJ;
    sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pRJ->regReturn);
    pRJ->addrSubrtn = sqlite3VdbeCurrentAddr(v);
    assert( pParse->withinRJSubrtn < 255 );
    pParse->withinRJSubrtn++;

    /* WHERE clause constraints must be deferred until after outer join
    ** row elimination has completed, since WHERE clause constraints apply
    ** to the results of the OUTER JOIN.  The following loop generates the
    ** appropriate WHERE clause constraint checks.  tag-20220513a.
    */
  code_outer_join_constraints:
    for(pTerm=pWC->a, j=0; j<pWC->nBase; j++, pTerm++){
      testcase( pTerm->wtFlags & TERM_VIRTUAL );
      testcase( pTerm->wtFlags & TERM_CODED );
      if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
      if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
        assert( pWInfo->untestedTerms );
        continue;
      }
      if( pTabItem->fg.jointype & JT_LTORJ ) continue;
      assert( pTerm->pExpr );
      sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
      pTerm->wtFlags |= TERM_CODED;
    }
  }

#if WHERETRACE_ENABLED /* 0x20800 */
  if( sqlite3WhereTrace & 0x20000 ){
    sqlite3DebugPrintf("All WHERE-clause terms after coding level %d:\n",
                       iLevel);
    sqlite3WhereClausePrint(pWC);
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
  }
  if( (pTabItem->fg.jointype & JT_LTORJ)==0 ){
    mAll |= pLoop->maskSelf;
    for(k=0; k<pWC->nTerm; k++){
      WhereTerm *pTerm = &pWC->a[k];
      if( pTerm->wtFlags & TERM_VIRTUAL ) break;
      if( pTerm->prereqAll & ~mAll ) continue;
      if( ExprHasProperty(pTerm->pExpr, EP_FromJoin|EP_InnerJoin) ) continue;
      pSubWhere = sqlite3ExprAnd(pParse, pSubWhere,
                                 sqlite3ExprDup(pParse->db, pTerm->pExpr, 0));
    }
  }
  sFrom.nSrc = 1;
  sFrom.nAlloc = 1;
  memcpy(&sFrom.a[0], pTabItem, sizeof(SrcItem));







|







2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
  }
  if( (pTabItem->fg.jointype & JT_LTORJ)==0 ){
    mAll |= pLoop->maskSelf;
    for(k=0; k<pWC->nTerm; k++){
      WhereTerm *pTerm = &pWC->a[k];
      if( pTerm->wtFlags & TERM_VIRTUAL ) break;
      if( pTerm->prereqAll & ~mAll ) continue;
      if( ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON) ) continue;
      pSubWhere = sqlite3ExprAnd(pParse, pSubWhere,
                                 sqlite3ExprDup(pParse->db, pTerm->pExpr, 0));
    }
  }
  sFrom.nSrc = 1;
  sFrom.nAlloc = 1;
  memcpy(&sFrom.a[0], pTabItem, sizeof(SrcItem));
Changes to src/whereexpr.c.
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
#endif /* SQLITE_OMIT_VIRTUALTABLE */

/*
** If the pBase expression originated in the ON or USING clause of
** a join, then transfer the appropriate markings over to derived.
*/
static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
  if( pDerived ){
    pDerived->flags |= pBase->flags & EP_FromJoin;
    pDerived->w.iJoin = pBase->w.iJoin;
  }
}

/*
** Mark term iChild as being a child of term iParent
*/







|
|







457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
#endif /* SQLITE_OMIT_VIRTUALTABLE */

/*
** If the pBase expression originated in the ON or USING clause of
** a join, then transfer the appropriate markings over to derived.
*/
static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
  if( pDerived && ExprHasProperty(pBase, EP_OuterON|EP_InnerON) ){
    pDerived->flags |= pBase->flags & (EP_OuterON|EP_InnerON);
    pDerived->w.iJoin = pBase->w.iJoin;
  }
}

/*
** Mark term iChild as being a child of term iParent
*/
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
** returned when it should not be, then incorrect answers might result.
*/
static int termIsEquivalence(Parse *pParse, Expr *pExpr){
  char aff1, aff2;
  CollSeq *pColl;
  if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0;
  if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0;
  if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0;
  aff1 = sqlite3ExprAffinity(pExpr->pLeft);
  aff2 = sqlite3ExprAffinity(pExpr->pRight);
  if( aff1!=aff2
   && (!sqlite3IsNumericAffinity(aff1) || !sqlite3IsNumericAffinity(aff2))
  ){
    return 0;
  }







|







913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
** returned when it should not be, then incorrect answers might result.
*/
static int termIsEquivalence(Parse *pParse, Expr *pExpr){
  char aff1, aff2;
  CollSeq *pColl;
  if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0;
  if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0;
  if( ExprHasProperty(pExpr, EP_OuterON) ) return 0;
  aff1 = sqlite3ExprAffinity(pExpr->pLeft);
  aff2 = sqlite3ExprAffinity(pExpr->pRight);
  if( aff1!=aff2
   && (!sqlite3IsNumericAffinity(aff1) || !sqlite3IsNumericAffinity(aff2))
  ){
    return 0;
  }
1105
1106
1107
1108
1109
1110
1111
1112
1113

1114
1115
1116
1117
1118
1119







1120
1121
1122
1123
1124
1125
1126
  if( prereqAll!=sqlite3WhereExprUsageNN(pMaskSet, pExpr) ){
    printf("\n*** Incorrect prereqAll computed for:\n");
    sqlite3TreeViewExpr(0,pExpr,0);
    abort();
  }
#endif

  if( ExprHasProperty(pExpr, EP_FromJoin) ){
    Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->w.iJoin);

    prereqAll |= x;
    extraRight = x-1;  /* ON clause terms may not be used with an index
                       ** on left table of a LEFT JOIN.  Ticket #3015 */
    if( (prereqAll>>1)>=x ){
      sqlite3ErrorMsg(pParse, "ON clause references tables to its right");
      return;







    }
  }
  pTerm->prereqAll = prereqAll;
  pTerm->leftCursor = -1;
  pTerm->iParent = -1;
  pTerm->eOperator = 0;
  if( allowedOp(op) ){







|

>
|
|
|
|
|
|
>
>
>
>
>
>
>







1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
  if( prereqAll!=sqlite3WhereExprUsageNN(pMaskSet, pExpr) ){
    printf("\n*** Incorrect prereqAll computed for:\n");
    sqlite3TreeViewExpr(0,pExpr,0);
    abort();
  }
#endif

  if( ExprHasProperty(pExpr, EP_OuterON|EP_InnerON) ){
    Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->w.iJoin);
    if( ExprHasProperty(pExpr, EP_OuterON) ){
      prereqAll |= x;
      extraRight = x-1;  /* ON clause terms may not be used with an index
                         ** on left table of a LEFT JOIN.  Ticket #3015 */
      if( (prereqAll>>1)>=x ){
        sqlite3ErrorMsg(pParse, "ON clause references tables to its right");
        return;
      }
    }else if( (prereqAll>>1)>=x ){
      /* The ON clause of an INNER JOIN references a table to its right.
      ** Most other SQL database engines raise an error.  But all versions
      ** of SQLite going back to 3.0.0 have just put the ON clause constraint
      ** into the WHERE clause and carried on. */
      ExprClearProperty(pExpr, EP_InnerON);
    }
  }
  pTerm->prereqAll = prereqAll;
  pTerm->leftCursor = -1;
  pTerm->iParent = -1;
  pTerm->eOperator = 0;
  if( allowedOp(op) ){
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
      pNew->u.x.leftColumn = aiCurCol[1];
      testcase( (prereqLeft | extraRight) != prereqLeft );
      pNew->prereqRight = prereqLeft | extraRight;
      pNew->prereqAll = prereqAll;
      pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask;
    }else 
    if( op==TK_ISNULL
     && !ExprHasProperty(pExpr,EP_FromJoin)
     && 0==sqlite3ExprCanBeNull(pLeft)
    ){
      assert( !ExprHasProperty(pExpr, EP_IntValue) );
      pExpr->op = TK_TRUEFALSE;
      pExpr->u.zToken = "false";
      ExprSetProperty(pExpr, EP_IsFalse);
      pTerm->prereqAll = 0;







|







1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
      pNew->u.x.leftColumn = aiCurCol[1];
      testcase( (prereqLeft | extraRight) != prereqLeft );
      pNew->prereqRight = prereqLeft | extraRight;
      pNew->prereqAll = prereqAll;
      pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask;
    }else 
    if( op==TK_ISNULL
     && !ExprHasProperty(pExpr,EP_OuterON)
     && 0==sqlite3ExprCanBeNull(pLeft)
    ){
      assert( !ExprHasProperty(pExpr, EP_IntValue) );
      pExpr->op = TK_TRUEFALSE;
      pExpr->u.zToken = "false";
      ExprSetProperty(pExpr, EP_IsFalse);
      pTerm->prereqAll = 0;
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
  ** virtual term of that form.
  **
  ** The virtual term must be tagged with TERM_VNULL.
  */
  else if( pExpr->op==TK_NOTNULL ){
    if( pExpr->pLeft->op==TK_COLUMN
     && pExpr->pLeft->iColumn>=0
     && !ExprHasProperty(pExpr, EP_FromJoin)
    ){
      Expr *pNewExpr;
      Expr *pLeft = pExpr->pLeft;
      int idxNew;
      WhereTerm *pNewTerm;
  
      pNewExpr = sqlite3PExpr(pParse, TK_GT,







|







1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
  ** virtual term of that form.
  **
  ** The virtual term must be tagged with TERM_VNULL.
  */
  else if( pExpr->op==TK_NOTNULL ){
    if( pExpr->pLeft->op==TK_COLUMN
     && pExpr->pLeft->iColumn>=0
     && !ExprHasProperty(pExpr, EP_OuterON)
    ){
      Expr *pNewExpr;
      Expr *pLeft = pExpr->pLeft;
      int idxNew;
      WhereTerm *pNewTerm;
  
      pNewExpr = sqlite3PExpr(pParse, TK_GT,
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470

      prereqExpr = sqlite3WhereExprUsage(pMaskSet, pRight);
      prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft);
      if( (prereqExpr & prereqColumn)==0 ){
        Expr *pNewExpr;
        pNewExpr = sqlite3PExpr(pParse, TK_MATCH, 
            0, sqlite3ExprDup(db, pRight, 0));
        if( ExprHasProperty(pExpr, EP_FromJoin) && pNewExpr ){
          ExprSetProperty(pNewExpr, EP_FromJoin);
          pNewExpr->w.iJoin = pExpr->w.iJoin;
        }
        idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
        testcase( idxNew==0 );
        pNewTerm = &pWC->a[idxNew];
        pNewTerm->prereqRight = prereqExpr;
        pNewTerm->leftCursor = pLeft->iTable;







|
|







1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478

      prereqExpr = sqlite3WhereExprUsage(pMaskSet, pRight);
      prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft);
      if( (prereqExpr & prereqColumn)==0 ){
        Expr *pNewExpr;
        pNewExpr = sqlite3PExpr(pParse, TK_MATCH, 
            0, sqlite3ExprDup(db, pRight, 0));
        if( ExprHasProperty(pExpr, EP_OuterON) && pNewExpr ){
          ExprSetProperty(pNewExpr, EP_OuterON);
          pNewExpr->w.iJoin = pExpr->w.iJoin;
        }
        idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
        testcase( idxNew==0 );
        pNewTerm = &pWC->a[idxNew];
        pNewTerm->prereqRight = prereqExpr;
        pNewTerm->leftCursor = pLeft->iTable;
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
    assert( ExprUseYTab(pColRef) );
    pColRef->y.pTab = pTab;
    pItem->colUsed |= sqlite3ExprColUsed(pColRef);
    pRhs = sqlite3PExpr(pParse, TK_UPLUS, 
        sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0);
    pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs);
    if( pItem->fg.jointype & (JT_LEFT|JT_LTORJ) ){
      joinType = EP_FromJoin;
    }else{
      joinType = EP_InnerJoin;
    }
    sqlite3SetJoinExpr(pTerm, pItem->iCursor, joinType);
    whereClauseInsert(pWC, pTerm, TERM_DYNAMIC);
  }
}







|

|





1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
    assert( ExprUseYTab(pColRef) );
    pColRef->y.pTab = pTab;
    pItem->colUsed |= sqlite3ExprColUsed(pColRef);
    pRhs = sqlite3PExpr(pParse, TK_UPLUS, 
        sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0);
    pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs);
    if( pItem->fg.jointype & (JT_LEFT|JT_LTORJ) ){
      joinType = EP_OuterON;
    }else{
      joinType = EP_InnerON;
    }
    sqlite3SetJoinExpr(pTerm, pItem->iCursor, joinType);
    whereClauseInsert(pWC, pTerm, TERM_DYNAMIC);
  }
}
Changes to test/altermalloc3.test.
16
17
18
19
20
21
22

23
24
25
26
27
28
29
set testprefix altermalloc3

# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
ifcapable !altertable {
  finish_test
  return
}


set ::TMPDBERROR [list 1 \
  {unable to open a temporary database file for storing temporary tables}
]

do_execsql_test 1.0 {
  CREATE TABLE x1(







>







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
set testprefix altermalloc3

# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
ifcapable !altertable {
  finish_test
  return
}


set ::TMPDBERROR [list 1 \
  {unable to open a temporary database file for storing temporary tables}
]

do_execsql_test 1.0 {
  CREATE TABLE x1(
42
43
44
45
46
47
48

49
50
51
52
53
54
55
56
57
58
59
60
61





62
63
64
65
66
67
68
do_faultsim_test 1 -prep {
  faultsim_restore_and_reopen
} -body {
  execsql { ALTER TABLE t1 DROP COLUMN c }
} -test {
  faultsim_test_result {0 {}} $::TMPDBERROR
}


#-------------------------------------------------------------------------
# dbsqlfuzz e3dd84cda3848016a6a6024c7249d09bc2ef2615
#
reset_db
do_execsql_test 2.0 {
  CREATE TABLE t2(k,v);
  CREATE TRIGGER r2 AFTER INSERT ON t2 BEGIN
    UPDATE t2 SET (k,v)= (
       (WITH cte1(a) AS ( SELECT 1 FROM ( SELECT * FROM t2 ) )
       SELECT a FROM cte1
    ), 1);
  END;





}

faultsim_save_and_close
faultsim_restore_and_reopen

do_execsql_test 2.1 {
  ALTER TABLE t2 RENAME TO t2x;







>













>
>
>
>
>







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
do_faultsim_test 1 -prep {
  faultsim_restore_and_reopen
} -body {
  execsql { ALTER TABLE t1 DROP COLUMN c }
} -test {
  faultsim_test_result {0 {}} $::TMPDBERROR
}


#-------------------------------------------------------------------------
# dbsqlfuzz e3dd84cda3848016a6a6024c7249d09bc2ef2615
#
reset_db
do_execsql_test 2.0 {
  CREATE TABLE t2(k,v);
  CREATE TRIGGER r2 AFTER INSERT ON t2 BEGIN
    UPDATE t2 SET (k,v)= (
       (WITH cte1(a) AS ( SELECT 1 FROM ( SELECT * FROM t2 ) )
       SELECT a FROM cte1
    ), 1);
  END;

  CREATE TRIGGER r1 AFTER INSERT ON t2 BEGIN
    UPDATE t2 SET k=1 FROM t2 AS one, t2 AS two NATURAL JOIN t2 AS three 
    WHERE one.k=two.v;
  END;
}

faultsim_save_and_close
faultsim_restore_and_reopen

do_execsql_test 2.1 {
  ALTER TABLE t2 RENAME TO t2x;
Changes to test/altertab3.test.
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
  CREATE TABLE t1(xx);
  CREATE TRIGGER xx INSERT ON t1 BEGIN
     UPDATE t1 SET xx=xx FROM(SELECT xx);
  END;
} {}
do_catchsql_test 26.6 {
  ALTER TABLE t1 RENAME TO t2;
} {1 {error in trigger xx: ambiguous column name: xx}}


#-------------------------------------------------------------------------
reset_db

do_execsql_test 27.1 {
  CREATE TABLE t1(a, b AS ((WITH w1 (xyz) AS  ( SELECT t1.b FROM t1 )  SELECT 123) IN ()), c);







|







641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
  CREATE TABLE t1(xx);
  CREATE TRIGGER xx INSERT ON t1 BEGIN
     UPDATE t1 SET xx=xx FROM(SELECT xx);
  END;
} {}
do_catchsql_test 26.6 {
  ALTER TABLE t1 RENAME TO t2;
} {1 {error in trigger xx: no such column: xx}}


#-------------------------------------------------------------------------
reset_db

do_execsql_test 27.1 {
  CREATE TABLE t1(a, b AS ((WITH w1 (xyz) AS  ( SELECT t1.b FROM t1 )  SELECT 123) IN ()), c);
Added test/altertrig.test.






































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# 2022 May 27
#
# 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.
#
#*************************************************************************
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix altertrig

# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
ifcapable !altertable {
  finish_test
  return
}

proc collapse_whitespace {in} {
  regsub -all {[ \t\n]+} [string trim $in] { }
}

proc do_whitespace_sql_test {tn sql res} {
  set got [execsql $sql]
  set wgot [list]
  set wres [list]
  foreach g $got { lappend wgot [collapse_whitespace $g] }
  foreach r $res { lappend wres [collapse_whitespace $r] }

  uplevel [list do_test $tn [list set {} $wgot] $wres]
}

do_execsql_test 1.0 {
  CREATE TABLE t1(x);
  CREATE TABLE t2(y);
  CREATE TABLE t3(z);
  CREATE TABLE t4(a);

  CREATE TRIGGER r1 INSERT ON t1 BEGIN 
    UPDATE t1 SET d='xyz' FROM t2, t3; 
  END;
}

do_whitespace_sql_test 1.1 {
  ALTER TABLE t3 RENAME TO t5;
  SELECT sql FROM sqlite_schema WHERE type='trigger';
} {{
  CREATE TRIGGER r1 INSERT ON t1 BEGIN 
    UPDATE t1 SET d='xyz' FROM t2, "t5"; 
  END
}}

do_execsql_test 1.2 {
  DROP TRIGGER r1;
  CREATE TRIGGER r1 INSERT ON t1 BEGIN 
    UPDATE t1 SET d='xyz' FROM t2, (SELECT * FROM t5); 
  END;
}

do_whitespace_sql_test 1.3 {
  ALTER TABLE t5 RENAME TO t3;
  SELECT sql FROM sqlite_schema WHERE type='trigger';
} {{
  CREATE TRIGGER r1 INSERT ON t1 BEGIN 
    UPDATE t1 SET d='xyz' FROM t2, (SELECT * FROM "t3"); 
  END
}}

foreach {tn alter update final} {
  1 {
    ALTER TABLE t3 RENAME TO t10
  } {
    UPDATE t1 SET d='xyz' FROM t2, (SELECT * FROM t3)
  } {
    UPDATE t1 SET d='xyz' FROM t2, (SELECT * FROM "t10")
  }

  2 {
    ALTER TABLE t3 RENAME TO t10
  } {
    UPDATE t1 SET a='xyz' FROM t3, (SELECT * FROM (SELECT e FROM t3))
  } {
    UPDATE t1 SET a='xyz' FROM "t10", (SELECT * FROM (SELECT e FROM "t10"))
  }

  3 {
    ALTER TABLE t3 RENAME e TO abc
  } {
    UPDATE t1 SET a='xyz' FROM t3, (SELECT * FROM (SELECT e FROM t3))
  } {
    UPDATE t1 SET a='xyz' FROM t3, (SELECT * FROM (SELECT abc FROM t3))
  }

  4 {
    ALTER TABLE t2 RENAME c TO abc
  } {
    UPDATE t1 SET a='xyz' FROM t3, (SELECT 1 FROM t2 WHERE c)
  } {
    UPDATE t1 SET a='xyz' FROM t3, (SELECT 1 FROM t2 WHERE abc)
  }

  5 {
    ALTER TABLE t2 RENAME c TO abc
  } {
    UPDATE t1 SET a=t2.c FROM t2
  } {
    UPDATE t1 SET a=t2.abc FROM t2
  }

  6 {
    ALTER TABLE t2 RENAME c TO abc
  } {
    UPDATE t1 SET a=t2.c FROM t2, t3
  } {
    UPDATE t1 SET a=t2.abc FROM t2, t3
  }

  7 {
    ALTER TABLE t4 RENAME e TO abc
  } {
    UPDATE t1 SET a=1 FROM t3 NATURAL JOIN t4 WHERE t4.e=a
  } {
    UPDATE t1 SET a=1 FROM t3 NATURAL JOIN t4 WHERE t4.abc=a
  }

  8 {
    ALTER TABLE t4 RENAME TO abc
  } {
    UPDATE t1 SET a=1 FROM t3 NATURAL JOIN t4 WHERE t4.e=a
  } {
    UPDATE t1 SET a=1 FROM t3 NATURAL JOIN "abc" WHERE "abc".e=a
  }
 
} {
  reset_db
  do_execsql_test 2.$tn.1 {
    CREATE TABLE t1(a,b);
    CREATE TABLE t2(c,d);
    CREATE TABLE t3(e,f);
    CREATE TABLE t4(e,f);
  }
  do_execsql_test 2.$tn.2 "
    CREATE TRIGGER r1 INSERT ON t1 BEGIN 
      $update;
    END
  "
  do_execsql_test 2.$tn.3 $alter

  do_whitespace_sql_test 2.$tn.4 {
    SELECT sqL FROM sqlite_schema WHERE type='trigger'
  } "{
    CREATE TRIGGER r1 INSERT ON t1 BEGIN 
      $final;
    END
  }"
}

finish_test

Changes to test/e_select.test.
614
615
616
617
618
619
620

621
622
623
624
625
626
627
628
629
630
631
632
     {aa cc cc bb DD dd}
  4b { SELECT * FROM (SELECT a COLLATE nocase, b FROM t6) AS x
       %JOIN% t5 ON (x.a=t5.a) } 
     {aa cc AA cc bb DD BB dd}
} {
  do_join_test e_select-1.7.$tn $select $res
}

# EVIDENCE-OF: R-42531-52874 If the join-operator is a "LEFT JOIN" or
# "LEFT OUTER JOIN", then after the ON or USING filtering clauses have
# been applied, an extra row is added to the output for each row in the
# original left-hand input dataset that corresponds to no rows at all in
# the composite dataset (if any).
#
do_execsql_test e_select-1.8.0 {
  CREATE TABLE t7(a, b, c);
  CREATE TABLE t8(a, d, e);

  INSERT INTO t7 VALUES('x', 'ex',  24);
  INSERT INTO t7 VALUES('y', 'why', 25);







>
|


|
|







614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
     {aa cc cc bb DD dd}
  4b { SELECT * FROM (SELECT a COLLATE nocase, b FROM t6) AS x
       %JOIN% t5 ON (x.a=t5.a) } 
     {aa cc AA cc bb DD BB dd}
} {
  do_join_test e_select-1.7.$tn $select $res
}

# EVIDENCE-OF: R-24610-05866 If the join-operator is a "LEFT JOIN" or
# "LEFT OUTER JOIN", then after the ON or USING filtering clauses have
# been applied, an extra row is added to the output for each row in the
# original left-hand input dataset that does not match any row in the
# right-hand dataset.
#
do_execsql_test e_select-1.8.0 {
  CREATE TABLE t7(a, b, c);
  CREATE TABLE t8(a, d, e);

  INSERT INTO t7 VALUES('x', 'ex',  24);
  INSERT INTO t7 VALUES('y', 'why', 25);
Changes to test/expr.test.
177
178
179
180
181
182
183

184

185

186

187
188


189
190


191
192


193
194


195

196

197

198

199
200


201
202


203
204


205
206


207
208
209
210
211
212
213
test_expr expr-1.109 {i1=0} {1/0} {{}}

if {[working_64bit_int]} {
  test_expr expr-1.110 {i1=0} {-9223372036854775807/-1} 9223372036854775807
}

test_expr expr-1.111 {i1=NULL, i2=8} {i1 IS i2} 0

test_expr expr-1.112 {i1=NULL, i2=NULL} {i1 IS i2} 1

test_expr expr-1.113 {i1=6, i2=NULL} {i1 IS i2} 0

test_expr expr-1.114 {i1=6, i2=6} {i1 IS i2} 1

test_expr expr-1.115 {i1=NULL, i2=8} \
  {CASE WHEN i1 IS i2 THEN 'yes' ELSE 'no' END} no


test_expr expr-1.116 {i1=NULL, i2=NULL} \
  {CASE WHEN i1 IS i2 THEN 'yes' ELSE 'no' END} yes


test_expr expr-1.117 {i1=6, i2=NULL} \
  {CASE WHEN i1 IS i2 THEN 'yes' ELSE 'no' END} no


test_expr expr-1.118 {i1=8, i2=8} \
  {CASE WHEN i1 IS i2 THEN 'yes' ELSE 'no' END} yes


test_expr expr-1.119 {i1=NULL, i2=8} {i1 IS NOT i2} 1

test_expr expr-1.120 {i1=NULL, i2=NULL} {i1 IS NOT i2} 0

test_expr expr-1.121 {i1=6, i2=NULL} {i1 IS NOT i2} 1

test_expr expr-1.122 {i1=6, i2=6} {i1 IS NOT i2} 0

test_expr expr-1.123 {i1=NULL, i2=8} \
  {CASE WHEN i1 IS NOT i2 THEN 'yes' ELSE 'no' END} yes


test_expr expr-1.124 {i1=NULL, i2=NULL} \
  {CASE WHEN i1 IS NOT i2 THEN 'yes' ELSE 'no' END} no


test_expr expr-1.125 {i1=6, i2=NULL} \
  {CASE WHEN i1 IS NOT i2 THEN 'yes' ELSE 'no' END} yes


test_expr expr-1.126 {i1=8, i2=8} \
  {CASE WHEN i1 IS NOT i2 THEN 'yes' ELSE 'no' END} no



do_catchsql_test expr-1.127 {
  SELECT 1 IS #1;
} {1 {near "#1": syntax error}}

ifcapable floatingpoint {if {[working_64bit_int]} {
  test_expr expr-1.200\







>

>

>

>


>
>


>
>


>
>


>
>

>

>

>

>


>
>


>
>


>
>


>
>







177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
test_expr expr-1.109 {i1=0} {1/0} {{}}

if {[working_64bit_int]} {
  test_expr expr-1.110 {i1=0} {-9223372036854775807/-1} 9223372036854775807
}

test_expr expr-1.111 {i1=NULL, i2=8} {i1 IS i2} 0
test_expr expr-1.111b {i1=NULL, i2=8} {i1 IS NOT DISTINCT FROM i2} 0
test_expr expr-1.112 {i1=NULL, i2=NULL} {i1 IS i2} 1
test_expr expr-1.112b {i1=NULL, i2=NULL} {i1 IS NOT DISTINCT FROM i2} 1
test_expr expr-1.113 {i1=6, i2=NULL} {i1 IS i2} 0
test_expr expr-1.113b {i1=6, i2=NULL} {i1 IS NOT DISTINCT FROM i2} 0
test_expr expr-1.114 {i1=6, i2=6} {i1 IS i2} 1
test_expr expr-1.114b {i1=6, i2=6} {i1 IS NOT DISTINCT FROM i2} 1
test_expr expr-1.115 {i1=NULL, i2=8} \
  {CASE WHEN i1 IS i2 THEN 'yes' ELSE 'no' END} no
test_expr expr-1.115b {i1=NULL, i2=8} \
  {CASE WHEN i1 IS NOT DISTINCT FROM i2 THEN 'yes' ELSE 'no' END} no
test_expr expr-1.116 {i1=NULL, i2=NULL} \
  {CASE WHEN i1 IS i2 THEN 'yes' ELSE 'no' END} yes
test_expr expr-1.116b {i1=NULL, i2=NULL} \
  {CASE WHEN i1 IS NOT DISTINCT FROM i2 THEN 'yes' ELSE 'no' END} yes
test_expr expr-1.117 {i1=6, i2=NULL} \
  {CASE WHEN i1 IS i2 THEN 'yes' ELSE 'no' END} no
test_expr expr-1.117b {i1=6, i2=NULL} \
  {CASE WHEN i1 IS NOT DISTINCT FROM i2 THEN 'yes' ELSE 'no' END} no
test_expr expr-1.118 {i1=8, i2=8} \
  {CASE WHEN i1 IS i2 THEN 'yes' ELSE 'no' END} yes
test_expr expr-1.118b {i1=8, i2=8} \
  {CASE WHEN i1 IS NOT DISTINCT FROM i2 THEN 'yes' ELSE 'no' END} yes
test_expr expr-1.119 {i1=NULL, i2=8} {i1 IS NOT i2} 1
test_expr expr-1.119b {i1=NULL, i2=8} {i1 IS DISTINCT FROM i2} 1
test_expr expr-1.120 {i1=NULL, i2=NULL} {i1 IS NOT i2} 0
test_expr expr-1.120b {i1=NULL, i2=NULL} {i1 IS DISTINCT FROM i2} 0
test_expr expr-1.121 {i1=6, i2=NULL} {i1 IS NOT i2} 1
test_expr expr-1.121b {i1=6, i2=NULL} {i1 IS DISTINCT FROM i2} 1
test_expr expr-1.122 {i1=6, i2=6} {i1 IS NOT i2} 0
test_expr expr-1.122b {i1=6, i2=6} {i1 IS DISTINCT FROM i2} 0
test_expr expr-1.123 {i1=NULL, i2=8} \
  {CASE WHEN i1 IS NOT i2 THEN 'yes' ELSE 'no' END} yes
test_expr expr-1.123b {i1=NULL, i2=8} \
  {CASE WHEN i1 IS DISTINCT FROM i2 THEN 'yes' ELSE 'no' END} yes
test_expr expr-1.124 {i1=NULL, i2=NULL} \
  {CASE WHEN i1 IS NOT i2 THEN 'yes' ELSE 'no' END} no
test_expr expr-1.124b {i1=NULL, i2=NULL} \
  {CASE WHEN i1 IS DISTINCT FROM i2 THEN 'yes' ELSE 'no' END} no
test_expr expr-1.125 {i1=6, i2=NULL} \
  {CASE WHEN i1 IS NOT i2 THEN 'yes' ELSE 'no' END} yes
test_expr expr-1.125b {i1=6, i2=NULL} \
  {CASE WHEN i1 IS DISTINCT FROM i2 THEN 'yes' ELSE 'no' END} yes
test_expr expr-1.126 {i1=8, i2=8} \
  {CASE WHEN i1 IS NOT i2 THEN 'yes' ELSE 'no' END} no
test_expr expr-1.126b {i1=8, i2=8} \
  {CASE WHEN i1 IS DISTINCT FROM i2 THEN 'yes' ELSE 'no' END} no

do_catchsql_test expr-1.127 {
  SELECT 1 IS #1;
} {1 {near "#1": syntax error}}

ifcapable floatingpoint {if {[working_64bit_int]} {
  test_expr expr-1.200\
Changes to test/func7.test.
56
57
58
59
60
61
62






63
64
65
66
67
68
69
} {0.6931472}
do_execsql_test func7-pg-170 {
  SELECT log(100.0)
} {2.0}
do_execsql_test func7-pg-180 {
  SELECT log10(1000.0)
} {3.0}






do_execsql_test func7-pg-190 {
  SELECT log(2.0, 64.0)
} {6.0}
do_execsql_test func7-pg-200 {
   SELECT mod(9,4);
} {1.0}
do_execsql_test func7-pg-210 {







>
>
>
>
>
>







56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
} {0.6931472}
do_execsql_test func7-pg-170 {
  SELECT log(100.0)
} {2.0}
do_execsql_test func7-pg-180 {
  SELECT log10(1000.0)
} {3.0}
do_execsql_test func7-pg-181 {
  SELECT format('%.30f', log10(100.0) );
} {2.000000000000000000000000000000}
do_execsql_test func7-pg-182 {
  SELECT format('%.30f', ln(exp(2.0)) );
} {2.000000000000000000000000000000}
do_execsql_test func7-pg-190 {
  SELECT log(2.0, 64.0)
} {6.0}
do_execsql_test func7-pg-200 {
   SELECT mod(9,4);
} {1.0}
do_execsql_test func7-pg-210 {
Changes to test/in.test.
793
794
795
796
797
798
799









800
801
} {ok}

# Ticket f3ff1472887
#
do_execsql_test in-20.1 {
  SELECT (1 IN (2 IS TRUE));
} {1}










finish_test







>
>
>
>
>
>
>
>
>


793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
} {ok}

# Ticket f3ff1472887
#
do_execsql_test in-20.1 {
  SELECT (1 IN (2 IS TRUE));
} {1}

# Forum post: https://sqlite.org/forum/forumpost/5782619992.
#
reset_db
do_execsql_test in-21.1 {
  CREATE TABLE t0(c0);
  SELECT COUNT(*) FROM t0 ORDER BY (t0.c0 IN ());
} {0}


finish_test
Changes to test/join.test.
246
247
248
249
250
251
252













253
254
255
256
257
258
259

do_test join-2.1 {
  execsql {
    SELECT * FROM t1 NATURAL LEFT JOIN t2;
  }
} {1 2 3 4 2 3 4 5 3 4 5 {}}














# ticket #3522
do_test join-2.1.1 {
  execsql2 {
    SELECT * FROM t1 NATURAL LEFT JOIN t2;
  }
} {a 1 b 2 c 3 d 4 a 2 b 3 c 4 d 5 a 3 b 4 c 5 d {}}
do_test join-2.1.2 {







>
>
>
>
>
>
>
>
>
>
>
>
>







246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272

do_test join-2.1 {
  execsql {
    SELECT * FROM t1 NATURAL LEFT JOIN t2;
  }
} {1 2 3 4 2 3 4 5 3 4 5 {}}

# EVIDENCE-OF: R-52129-05406 you can say things like "OUTER LEFT NATURAL
# JOIN" which means the same as "NATURAL LEFT OUTER JOIN".
do_test join-2.1b {
  execsql {
    SELECT * FROM t1 OUTER LEFT NATURAL JOIN t2;
  }
} {1 2 3 4 2 3 4 5 3 4 5 {}}
do_test join-2.1c {
  execsql {
    SELECT * FROM t1 NATURAL LEFT OUTER JOIN t2;
  }
} {1 2 3 4 2 3 4 5 3 4 5 {}}

# ticket #3522
do_test join-2.1.1 {
  execsql2 {
    SELECT * FROM t1 NATURAL LEFT JOIN t2;
  }
} {a 1 b 2 c 3 d 4 a 2 b 3 c 4 d 5 a 3 b 4 c 5 d {}}
do_test join-2.1.2 {
324
325
326
327
328
329
330



331
332
333
334
335
336
337
  catchsql { SELECT * FROM t1 USING(a) }
} {1 {a JOIN clause is required before USING}}
do_test join-3.6 {
  catchsql {
    SELECT * FROM t1 JOIN t2 ON t3.a=t2.b;
  }
} {1 {no such column: t3.a}}



do_test join-3.7 {
  catchsql {
    SELECT * FROM t1 INNER OUTER JOIN t2;
  }
} {1 {unknown join type: INNER OUTER}}
do_test join-3.8 {
  catchsql {







>
>
>







337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
  catchsql { SELECT * FROM t1 USING(a) }
} {1 {a JOIN clause is required before USING}}
do_test join-3.6 {
  catchsql {
    SELECT * FROM t1 JOIN t2 ON t3.a=t2.b;
  }
} {1 {no such column: t3.a}}

# EVIDENCE-OF: R-47973-48020 you cannot say "INNER OUTER JOIN", because
# that would be contradictory.
do_test join-3.7 {
  catchsql {
    SELECT * FROM t1 INNER OUTER JOIN t2;
  }
} {1 {unknown join type: INNER OUTER}}
do_test join-3.8 {
  catchsql {
Changes to test/join8.test.
16
17
18
19
20
21
22


23
24
25
26
27
28
29

ifcapable !vtab {
  finish_test
  return
}

db null NULL


do_execsql_test join8-10 {
  CREATE TABLE t1(a,b,c);
  CREATE TABLE t2(x,y);
  CREATE INDEX t2x ON t2(x);
  SELECT avg(DISTINCT b) FROM (SELECT * FROM t2 LEFT RIGHT JOIN t1 ON c);
} {NULL}








>
>







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

ifcapable !vtab {
  finish_test
  return
}

db null NULL
# EVIDENCE-OF: R-33754-02880 you can say "LEFT RIGHT JOIN" which is the
# same as "FULL JOIN".
do_execsql_test join8-10 {
  CREATE TABLE t1(a,b,c);
  CREATE TABLE t2(x,y);
  CREATE INDEX t2x ON t2(x);
  SELECT avg(DISTINCT b) FROM (SELECT * FROM t2 LEFT RIGHT JOIN t1 ON c);
} {NULL}

222
223
224
225
226
227
228





















229
230
231
232
233
234
235
236
237
238
239

























































































































































































240
  -    -    -    -    -  -  200  0    -   -
  -    -    -    -    -  -  203  3    -   -
  -    -    -    -    -  -  209  9    -   -
  -    -    -    -    -  -    -  -  300   0
  -    -    -    -    -  -    -  -  305   5
  -    -    -    -    -  -    -  -  310  10
}





















do_execsql_test join8-7020 {
  EXPLAIN QUERY PLAN
  WITH t0 AS MATERIALIZED (
    SELECT t1.*, t2.*, t3.*
      FROM t1 INNER JOIN t2 ON t1.b=t2.b AND t2.x>0
        RIGHT JOIN t3 ON t1.c=t3.c AND t3.y>0
  )
  SELECT * FROM t0 FULL JOIN t4 ON t0.a=t4.d AND t4.z>0
   ORDER BY coalesce(t0.a, t0.y+200, t4.d);
} {/.*BLOOM FILTER ON t2.*BLOOM FILTER ON t3.*BLOOM FILTER ON t4.*/}


























































































































































































finish_test







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>











>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
  -    -    -    -    -  -  200  0    -   -
  -    -    -    -    -  -  203  3    -   -
  -    -    -    -    -  -  209  9    -   -
  -    -    -    -    -  -    -  -  300   0
  -    -    -    -    -  -    -  -  305   5
  -    -    -    -    -  -    -  -  310  10
}

# EVIDENCE-OF: R-33754-02880 you can say "LEFT RIGHT JOIN" which is the
# same as "FULL JOIN".
do_execsql_test join8-7011 {
  WITH t0 AS MATERIALIZED (
    SELECT t1.*, t2.*, t3.*
      FROM t1 INNER JOIN t2 ON t1.b=t2.b AND t2.x>0
        RIGHT JOIN t3 ON t1.c=t3.c AND t3.y>0
  )
  SELECT * FROM t0 LEFT RIGHT JOIN t4 ON t0.a=t4.d AND t4.z>0
   ORDER BY coalesce(t0.a, t0.y+200, t4.d);
} {
  6  106  206  306  106  6  206  6    -   -
  -    -    -    -    -  -  200  0    -   -
  -    -    -    -    -  -  203  3    -   -
  -    -    -    -    -  -  209  9    -   -
  -    -    -    -    -  -    -  -  300   0
  -    -    -    -    -  -    -  -  305   5
  -    -    -    -    -  -    -  -  310  10
}

do_execsql_test join8-7020 {
  EXPLAIN QUERY PLAN
  WITH t0 AS MATERIALIZED (
    SELECT t1.*, t2.*, t3.*
      FROM t1 INNER JOIN t2 ON t1.b=t2.b AND t2.x>0
        RIGHT JOIN t3 ON t1.c=t3.c AND t3.y>0
  )
  SELECT * FROM t0 FULL JOIN t4 ON t0.a=t4.d AND t4.z>0
   ORDER BY coalesce(t0.a, t0.y+200, t4.d);
} {/.*BLOOM FILTER ON t2.*BLOOM FILTER ON t3.*BLOOM FILTER ON t4.*/}

# 2022-05-12 Difference with PG found (by Dan) while exploring
# https://sqlite.org/forum/forumpost/677a0ab93fcd9ccd
#
reset_db
do_execsql_test join8-8000 {
  CREATE TABLE t1(a INT, b INT);
  CREATE TABLE t2(c INT, d INT);
  CREATE TABLE t3(e INT, f INT);
  INSERT INTO t1 VALUES(1, 2);
  INSERT INTO t2 VALUES(3, 4);
  INSERT INTO t3 VALUES(5, 6);
} {}
do_execsql_test join8-8010 {
  SELECT *
    FROM t3 LEFT JOIN t2 ON true
            JOIN t1 ON (t3.e IS t2.c);
} {}
do_execsql_test join8-8020 {
  SELECT *
    FROM t3 LEFT JOIN t2 ON true
            JOIN t1 ON (t3.e IS NOT DISTINCT FROM t2.c);
} {}

# 2022-05-13 The idea of reusing subquery cursors does not
# work, if the cursors are used both for scanning and lookups.
#
reset_db
db null -
do_execsql_test join8-9000 {
  CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT, c TEXT, d REAL);
  INSERT INTO t1 VALUES(1,'E','bb',NULL),(2,NULL,NULL,NULL);
  SELECT * FROM t1 NATURAL RIGHT JOIN t1 AS t2 WHERE (a,b) IN (SELECT a+0, b FROM t1);
} {1 E bb -}

# 2022-05-14 https://sqlite.org/forum/forumpost/c06b10ad7e
#
reset_db
db null -
do_execsql_test join8-10000 {
  CREATE TABLE t1(c0 INT UNIQUE);
  CREATE TABLE t2(c0);
  CREATE TABLE t2i(c0 INT);
  CREATE TABLE t3(c0 INT);
  INSERT INTO t1 VALUES(1);
  INSERT INTO t2 VALUES(2);
  INSERT INTO t2i VALUES(2);
  INSERT INTO t3 VALUES(3);
} {}
do_execsql_test join8-10010 {
  SELECT DISTINCT t1.c0, t3.c0
    FROM t2 NATURAL JOIN t1 RIGHT JOIN t3 ON t1.c0;
} {- 3}
do_execsql_test join8-10020 {
  SELECT t1.c0, t3.c0
    FROM t2 NATURAL JOIN t1 RIGHT JOIN t3 ON t1.c0;
} {- 3}
do_execsql_test join8-10030 {
  SELECT DISTINCT t1.c0, t3.c0
    FROM t2 NATURAL CROSS JOIN t1 RIGHT JOIN t3 ON t1.c0;
} {- 3}
do_execsql_test join8-10040 {
  SELECT t1.c0, t3.c0
    FROM t1 NATURAL CROSS JOIN t2 RIGHT JOIN t3 ON t1.c0;
} {- 3}
do_execsql_test join8-10050 {
  SELECT DISTINCT t1.c0, t3.c0
    FROM t2i NATURAL JOIN t1 RIGHT JOIN t3 ON t1.c0;
} {- 3}
do_execsql_test join8-10060 {
  SELECT DISTINCT +t1.c0, t3.c0
    FROM t2 NATURAL JOIN t1 RIGHT JOIN t3 ON t1.c0;
} {- 3}
do_execsql_test join8-10070 {
  SELECT DISTINCT +t1.c0, t3.c0
    FROM t1 NATURAL CROSS JOIN t2 RIGHT JOIN t3 ON t1.c0;
} {- 3}
do_execsql_test join8-10080 {
  SELECT DISTINCT t1.c0, t3.c0
    FROM t2 NATURAL JOIN t1 RIGHT JOIN t3 ON t1.c0<>0;
} {- 3}

# 2022-05-14
# index-on-expr scan on a RIGHT JOIN
# dbsqlfuzz 39ee60004ff027a9e2846cf76e02cd5ac0953739
#
reset_db
db null -
do_execsql_test join8-11000 {
  CREATE TABLE t1(a);
  CREATE TABLE t2(b);
  INSERT INTO t2 VALUES(0),(1),(2);
  SELECT * FROM t1 RIGHT JOIN t2 ON (a=b) WHERE 99+(b+1)!=99;
} {- 0 - 1 - 2}
do_execsql_test join8-11010 {
  CREATE INDEX t2b ON t2(b+1) WHERE b IS NOT NULL;
  SELECT * FROM t1 RIGHT JOIN t2 ON (a=b) WHERE 99+(b+1)!=99;
} {- 0 - 1 - 2}
do_execsql_test join8-11020 {
  DROP TABLE t1;
  DROP TABLE t2;
  CREATE TABLE t1(a);
  CREATE TABLE t2(b, c, d);
  INSERT INTO t2 VALUES(1, 3, 'not-4');
  SELECT b, d FROM t1 RIGHT JOIN t2 WHERE (b+0)=1 AND d!=4;
} {1 not-4}
do_execsql_test join8-11030 {
  CREATE INDEX i2 ON t2((b+0), d);
  SELECT b, d FROM t1 RIGHT JOIN t2 WHERE (b+0)=1 AND d!=4;
} {1 not-4}
do_execsql_test join8-11040 {
  DROP INDEX i2;
  CREATE INDEX i2 ON t2((b+0), d) WHERE d IS NOT NULL;
  SELECT b, d FROM t1 RIGHT JOIN t2 WHERE (b+0)=1 AND d!=4;
} {1 not-4}

# 2022-05-23
# NATURAL JOIN name resolution is more forgiving with LEFT JOIN
# https://sqlite.org/forum/forumpost/e90a8e6e6f
#
reset_db
db null -
do_execsql_test join8-12000 {
  CREATE TABLE t1(a INT);  INSERT INTO t1 VALUES(0),(1);
  CREATE TABLE t2(a INT);  INSERT INTO t2 VALUES(0),(2);
  CREATE TABLE t3(a INT);  INSERT INTO t3 VALUES(0),(3);
} {}
do_catchsql_test join8-12010 {
  SELECT * FROM t1 RIGHT JOIN t2 ON t2.a<>0 NATURAL RIGHT JOIN t3;
} {1 {ambiguous reference to a in USING()}}
do_catchsql_test join8-12020 {
  SELECT * FROM t1 RIGHT JOIN t2 ON t2.a<>0 NATURAL LEFT JOIN t3;
} {1 {ambiguous reference to a in USING()}}
do_catchsql_test join8-12030 {
  SELECT * FROM t1 LEFT JOIN t2 ON t2.a<>0 NATURAL RIGHT JOIN t3;
} {1 {ambiguous reference to a in USING()}}

# The following query should probably also return the same error as the
# previous three cases.  However, historical versions of SQLite have always
# let it pass.  We will not "fix" this, since to do so might break legacy
# applications.
#
do_catchsql_test join8-12040 {
  SELECT * FROM t1 LEFT JOIN t2 ON t2.a<>0 NATURAL LEFT JOIN t3;
} {0 {0 2 1 2}}

# 2022-05-24
# https://sqlite.org/forum/forumpost/687b0bf563a1d4f1
#
reset_db
do_execsql_test join8-13000 {
  CREATE TABLE t0(t TEXT, u TEXT);  INSERT INTO t0 VALUES('t', 'u');
  CREATE TABLE t1(v TEXT, w TEXT);  INSERT INTO t1 VALUES('v', 'w');
  CREATE TABLE t2(x TEXT, y TEXT);  INSERT INTO t2 VALUES('x', 'y');
  SELECT * FROM t0 JOIN t1 ON (t2.x NOTNULL) LEFT JOIN t2 ON false;
  SELECT * FROM t0 JOIN t1 ON (t2.x NOTNULL) LEFT JOIN t2 ON false
   WHERE t2.y ISNULL;
} {}

# 2022-05-25
# https://sqlite.org/forum/forumpost/5cfe08eed6
#
reset_db
do_execsql_test join8-14000 {
  CREATE TABLE t0(a TEXT, b TEXT, c TEXT);
  CREATE TABLE t1(a TEXT);
  INSERT INTO t1 VALUES('1');
  CREATE VIEW v0 AS SELECT 'xyz' AS d;
  SELECT * FROM v0 RIGHT JOIN t1 ON t1.a<>'' INNER JOIN t0 ON t0.c<>'';
  SELECT * FROM v0 RIGHT JOIN t1 ON t1.a<>'' INNER JOIN t0 ON t0.c<>'' WHERE b ISNULL;
} {}
do_execsql_test join8-14010 {
  CREATE TABLE y0(a INT);
  CREATE TABLE y1(b INT); INSERT INTO y1 VALUES(1), (2);
  CREATE TABLE y2(c INT); INSERT INTO y2 VALUES(3), (4);
} {}
db null -
do_execsql_test join8-14020 {
  SELECT * FROM y0 RIGHT JOIN y1 ON true INNER JOIN y2 ON true WHERE y2.c!=99 AND y2.c!=98;
} {
  - 1 3
  - 1 4
  - 2 3
  - 2 4
}

finish_test
Added test/joinE.test.






















































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
# 2022-05-13
#
# 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.
#
#***********************************************************************
#
# This file implements tests for JOINs that use Bloom filters.
#
# The test case output is (mostly) all generated by PostgreSQL 14.  This
# test module was created as follows:
#
#   1.   Run a TCL script (included at the bottom of this file) that
#        generates an input script for "psql" that will run man
#        diverse tests on joins.
#
#   2.   Run the script from step (1) through psql and collect the
#        output.
#
#   3.   Make a few minor global search-and-replace operations to convert
#        the psql output into a form suitable for this test module.
#
#   4.   Add this header, and the script content at the footer.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
db nullvalue -
db eval {
  CREATE TABLE t1(a INT);
  INSERT INTO t1 VALUES(1),(NULL);
  CREATE TABLE t2(b INT);
  INSERT INTO t2 VALUES(2),(NULL);
}
do_execsql_test joinE-1 {
  SELECT a, b
  FROM t1 INNER JOIN t2 ON true
  ORDER BY coalesce(a,b,3);
} {
  1 2
  1 -
  - 2
  - -
}
do_execsql_test joinE-2 {
  SELECT a, b
  FROM t1 INNER JOIN t2 ON true WHERE a IS NULL
  ORDER BY coalesce(a,b,3);
} {
  - 2
  - -
}
do_execsql_test joinE-3 {
  SELECT a, b
  FROM t1 INNER JOIN t2 ON a IS NULL
  ORDER BY coalesce(a,b,3);
} {
  - 2
  - -
}
do_execsql_test joinE-4 {
  SELECT a, b
  FROM t1 INNER JOIN t2 ON true WHERE b IS NULL
  ORDER BY coalesce(a,b,3);
} {
  1 -
  - -
}
do_execsql_test joinE-5 {
  SELECT a, b
  FROM t1 INNER JOIN t2 ON b IS NULL
  ORDER BY coalesce(a,b,3);
} {
  1 -
  - -
}
do_execsql_test joinE-6 {
  SELECT a, b
  FROM t1 LEFT JOIN t2 ON true
  ORDER BY coalesce(a,b,3);
} {
  1 2
  1 -
  - 2
  - -
}
do_execsql_test joinE-7 {
  SELECT a, b
  FROM t1 LEFT JOIN t2 ON true WHERE a IS NULL
  ORDER BY coalesce(a,b,3);
} {
  - 2
  - -
}
do_execsql_test joinE-8 {
  SELECT a, b
  FROM t1 LEFT JOIN t2 ON a IS NULL
  ORDER BY coalesce(a,b,3);
} {
  1 -
  - 2
  - -
}
do_execsql_test joinE-9 {
  SELECT a, b
  FROM t1 LEFT JOIN t2 ON true WHERE b IS NULL
  ORDER BY coalesce(a,b,3);
} {
  1 -
  - -
}
do_execsql_test joinE-10 {
  SELECT a, b
  FROM t1 LEFT JOIN t2 ON b IS NULL
  ORDER BY coalesce(a,b,3);
} {
  1 -
  - -
}
do_execsql_test joinE-11 {
  SELECT a, b
  FROM t1 RIGHT JOIN t2 ON true
  ORDER BY coalesce(a,b,3);
} {
  1 2
  1 -
  - 2
  - -
}
do_execsql_test joinE-12 {
  SELECT a, b
  FROM t1 RIGHT JOIN t2 ON true WHERE a IS NULL
  ORDER BY coalesce(a,b,3);
} {
  - 2
  - -
}
do_execsql_test joinE-13 {
  SELECT a, b
  FROM t1 RIGHT JOIN t2 ON a IS NULL
  ORDER BY coalesce(a,b,3);
} {
  - 2
  - -
}
do_execsql_test joinE-14 {
  SELECT a, b
  FROM t1 RIGHT JOIN t2 ON true WHERE b IS NULL
  ORDER BY coalesce(a,b,3);
} {
  1 -
  - -
}
do_execsql_test joinE-15 {
  SELECT a, b
  FROM t1 RIGHT JOIN t2 ON b IS NULL
  ORDER BY coalesce(a,b,3);
} {
  1 -
  - 2
  - -
}
do_execsql_test joinE-16 {
  SELECT a, b
  FROM t1 FULL JOIN t2 ON true
  ORDER BY coalesce(a,b,3);
} {
  1 2
  1 -
  - 2
  - -
}
do_execsql_test joinE-17 {
  SELECT a, b
  FROM t1 FULL JOIN t2 ON true WHERE a IS NULL
  ORDER BY coalesce(a,b,3);
} {
  - 2
  - -
}

# PG-14 is unable to perform this join.  It says:  FULL JOIN is only
# supported with merge-joinable or hash-joinable join conditions
#   
# do_execsql_test joinE-18 {
#  SELECT a, b
#  FROM t1 FULL JOIN t2 ON a IS NULL
#  ORDER BY coalesce(a,b,3);
# } {
# }

do_execsql_test joinE-19 {
  SELECT a, b
  FROM t1 FULL JOIN t2 ON true WHERE b IS NULL
  ORDER BY coalesce(a,b,3);
} {
  1 -
  - -
}

# PG-14 is unable to perform this join.  It says:  FULL JOIN is only
# supported with merge-joinable or hash-joinable join conditions
#   
# do_execsql_test joinE-20 {
#   SELECT a, b
#   FROM t1 FULL JOIN t2 ON b IS NULL
#   ORDER BY coalesce(a,b,3);
# } {
# }

db eval {
  DELETE FROM t1;
  INSERT INTO t1 VALUES(1);
  DELETE FROM t2;
  INSERT INTO t2 VALUES(NULL);
}

do_execsql_test joinE-21 {
  SELECT a, b
  FROM t1 INNER JOIN t2 ON true
  ORDER BY coalesce(a,b,3);
} {
  1 -
}
do_execsql_test joinE-22 {
  SELECT a, b
  FROM t1 INNER JOIN t2 ON true WHERE a IS NULL
  ORDER BY coalesce(a,b,3);
} {
}
do_execsql_test joinE-23 {
  SELECT a, b
  FROM t1 INNER JOIN t2 ON a IS NULL
  ORDER BY coalesce(a,b,3);
} {
}
do_execsql_test joinE-24 {
  SELECT a, b
  FROM t1 INNER JOIN t2 ON true WHERE b IS NULL
  ORDER BY coalesce(a,b,3);
} {
  1 -
}
do_execsql_test joinE-25 {
  SELECT a, b
  FROM t1 INNER JOIN t2 ON b IS NULL
  ORDER BY coalesce(a,b,3);
} {
  1 -
}
do_execsql_test joinE-26 {
  SELECT a, b
  FROM t1 LEFT JOIN t2 ON true
  ORDER BY coalesce(a,b,3);
} {
  1 -
}
do_execsql_test joinE-27 {
  SELECT a, b
  FROM t1 LEFT JOIN t2 ON true WHERE a IS NULL
  ORDER BY coalesce(a,b,3);
} {
}
do_execsql_test joinE-28 {
  SELECT a, b
  FROM t1 LEFT JOIN t2 ON a IS NULL
  ORDER BY coalesce(a,b,3);
} {
  1 -
}
do_execsql_test joinE-29 {
  SELECT a, b
  FROM t1 LEFT JOIN t2 ON true WHERE b IS NULL
  ORDER BY coalesce(a,b,3);
} {
  1 -
}
do_execsql_test joinE-30 {
  SELECT a, b
  FROM t1 LEFT JOIN t2 ON b IS NULL
  ORDER BY coalesce(a,b,3);
} {
  1 -
}
do_execsql_test joinE-31 {
  SELECT a, b
  FROM t1 RIGHT JOIN t2 ON true
  ORDER BY coalesce(a,b,3);
} {
  1 -
}

do_execsql_test joinE-32 {
  SELECT a, b
  FROM t1 RIGHT JOIN t2 ON true WHERE a IS NULL
  ORDER BY coalesce(a,b,3);
} {
}

do_execsql_test joinE-33 {
  SELECT a, b
  FROM t1 RIGHT JOIN t2 ON a IS NULL
  ORDER BY coalesce(a,b,3);
} {
  - -
}
do_execsql_test joinE-34 {
  SELECT a, b
  FROM t1 RIGHT JOIN t2 ON true WHERE b IS NULL
  ORDER BY coalesce(a,b,3);
} {
  1 -
}
do_execsql_test joinE-35 {
  SELECT a, b
  FROM t1 RIGHT JOIN t2 ON b IS NULL
  ORDER BY coalesce(a,b,3);
} {
  1 -
}
do_execsql_test joinE-36 {
  SELECT a, b
  FROM t1 FULL JOIN t2 ON true
  ORDER BY coalesce(a,b,3);
} {
  1 -
}
do_execsql_test joinE-37 {
  SELECT a, b
  FROM t1 FULL JOIN t2 ON true WHERE a IS NULL
  ORDER BY coalesce(a,b,3);
} {
}

# PG-14 is unable
#
# do_execsql_test joinE-38 {
#   SELECT a, b
#   FROM t1 FULL JOIN t2 ON a IS NULL
#   ORDER BY coalesce(a,b,3);
# } {
# }

do_execsql_test joinE-39 {
  SELECT a, b
  FROM t1 FULL JOIN t2 ON true WHERE b IS NULL
  ORDER BY coalesce(a,b,3);
} {
  1 -
}

# PG-14 is unable
# do_execsql_test joinE-40 {
#   SELECT a, b
#   FROM t1 FULL JOIN t2 ON b IS NULL
#   ORDER BY coalesce(a,b,3);
# } {
# }

finish_test

##############################################################################
# This is the PG-14 test script generator
#
# puts "
# \\pset border off
# \\pset tuples_only on
# \\pset null -
# 
# DROP TABLE IF EXISTS t1;
# DROP TABLE IF EXISTS t2;
# CREATE TABLE t1(a INT);
# INSERT INTO t1 VALUES(1),(NULL);
# CREATE TABLE t2(b INT);
# INSERT INTO t2 VALUES(2),(NULL);
# "
# 
# proc echo {prefix txt} {
#   regsub -all {\n} $txt \n$prefix txt
#   puts "$prefix$txt"
# }
# 
# set n 0
# set k 0
# foreach j1 {INNER LEFT RIGHT FULL} {
#   foreach on1 {
#      true
#      {true WHERE a IS NULL}
#      {a IS NULL}
#      {true WHERE b IS NULL}
#      {b IS NULL}
#   } {
# 
# incr n
# incr k
# set q1 ""
# append q1 "SELECT a, b\n"
# append q1 "  FROM t1 $j1 JOIN t2 ON $on1\n"
# append q1 " ORDER BY coalesce(a,b,3);"
# 
# echo "\\qecho " "do_execsql_test joinE-$n \{"
# echo "\\qecho X  " $q1
# echo "\\qecho " "\} \{"
# puts $q1
# echo "\\qecho " "\}"
# 
#   }
# }
# 
# puts "
# DELETE FROM t1;
# INSERT INTO t1 VALUES(1);
# DELETE FROM t2;
# INSERT INTO t2 VALUES(NULL);
# "
# 
# foreach j1 {INNER LEFT RIGHT FULL} {
#   foreach on1 {
#      true
#      {true WHERE a IS NULL}
#      {a IS NULL}
#      {true WHERE b IS NULL}
#      {b IS NULL}
#   } {
# 
# incr n
# incr k
# set q1 ""
# append q1 "SELECT a, b\n"
# append q1 "  FROM t1 $j1 JOIN t2 ON $on1\n"
# append q1 " ORDER BY coalesce(a,b,3);"
# 
# echo "\\qecho " "do_execsql_test joinE-$n \{"
# echo "\\qecho X  " $q1
# echo "\\qecho " "\} \{"
# puts $q1
# echo "\\qecho " "\}"
# 
#   }
# }
Changes to test/permutations.test.
213
214
215
216
217
218
219

220
221
222
223
224
225
226
227
]

test_suite "valgrind" -prefix "" -description {
  Run the "veryquick" test suite with a couple of multi-process tests (that
  fail under valgrind) omitted.
} -files [
  test_set $allquicktests -exclude *malloc* *ioerr* *fault* *_err* wal.test \

              shell*.test crash8.test atof1.test selectG.test \
              tkt-fc62af4523.test numindex1.test corruptK.test
] -initialize {
  set ::G(valgrind) 1
} -shutdown {
  unset -nocomplain ::G(valgrind)
}








>
|







213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
]

test_suite "valgrind" -prefix "" -description {
  Run the "veryquick" test suite with a couple of multi-process tests (that
  fail under valgrind) omitted.
} -files [
  test_set $allquicktests -exclude *malloc* *ioerr* *fault* *_err* wal.test \
              shell2.test shell6.test shell7.test \
              crash8.test atof1.test selectG.test \
              tkt-fc62af4523.test numindex1.test corruptK.test
] -initialize {
  set ::G(valgrind) 1
} -shutdown {
  unset -nocomplain ::G(valgrind)
}

Changes to test/shell1.test.
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#   shell1-2.*: Basic "dot" command token parsing.
#   shell1-3.*: Basic test that "dot" command can be called.
#   shell1-{4-8}.*: Test various "dot" commands's functionality.
#   shell1-9.*: Basic test that "dot" commands and SQL intermix ok.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set CLI [test_find_cli]
db close
forcedelete test.db test.db-journal test.db-wal
sqlite3 db test.db

#----------------------------------------------------------------------------
# Test cases shell1-1.*: Basic command line option handling.
#







|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#   shell1-2.*: Basic "dot" command token parsing.
#   shell1-3.*: Basic test that "dot" command can be called.
#   shell1-{4-8}.*: Test various "dot" commands's functionality.
#   shell1-9.*: Basic test that "dot" commands and SQL intermix ok.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set CLI [test_cli_invocation]
db close
forcedelete test.db test.db-journal test.db-wal
sqlite3 db test.db

#----------------------------------------------------------------------------
# Test cases shell1-1.*: Basic command line option handling.
#
Changes to test/shell2.test.
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
INSERT INTO foo1(a) VALUES(2); INSERT INTO foo2(b) VALUES(2);
SELECT * FROM foo1; SELECT * FROM foo2;
}
} {0 {CREATE TABLE foo1(a);
INSERT INTO foo1(a) VALUES(1);
CREATE TABLE foo2(b);
INSERT INTO foo2(b) VALUES(1);
SELECT * FROM foo1;
1
SELECT * FROM foo2;
1
INSERT INTO foo1(a) VALUES(2);
INSERT INTO foo2(b) VALUES(2);
SELECT * FROM foo1;
1
2
SELECT * FROM foo2;
1
2
}}

# Test with echo on and headers on using dot command and 
# multiple commands per line.
# NB. whitespace is important







|

<

|
<
|


<







132
133
134
135
136
137
138
139
140

141
142

143
144
145

146
147
148
149
150
151
152
INSERT INTO foo1(a) VALUES(2); INSERT INTO foo2(b) VALUES(2);
SELECT * FROM foo1; SELECT * FROM foo2;
}
} {0 {CREATE TABLE foo1(a);
INSERT INTO foo1(a) VALUES(1);
CREATE TABLE foo2(b);
INSERT INTO foo2(b) VALUES(1);
SELECT * FROM foo1; SELECT * FROM foo2;
1

1
INSERT INTO foo1(a) VALUES(2); INSERT INTO foo2(b) VALUES(2);

SELECT * FROM foo1; SELECT * FROM foo2;
1
2

1
2
}}

# Test with echo on and headers on using dot command and 
# multiple commands per line.
# NB. whitespace is important
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
SELECT * FROM foo1; SELECT * FROM foo2;
}
} {0 {.headers ON
CREATE TABLE foo1(a);
INSERT INTO foo1(a) VALUES(1);
CREATE TABLE foo2(b);
INSERT INTO foo2(b) VALUES(1);
SELECT * FROM foo1;
a
1
SELECT * FROM foo2;
b
1
INSERT INTO foo1(a) VALUES(2);
INSERT INTO foo2(b) VALUES(2);
SELECT * FROM foo1;
a
1
2
SELECT * FROM foo2;
b
1
2
}}

# Test for rejection of incomplete input at EOF.
# Reported at https://sqlite.org/forum/forumpost/718f489a43be3197







|


<


|
<
|



<







163
164
165
166
167
168
169
170
171
172

173
174
175

176
177
178
179

180
181
182
183
184
185
186
SELECT * FROM foo1; SELECT * FROM foo2;
}
} {0 {.headers ON
CREATE TABLE foo1(a);
INSERT INTO foo1(a) VALUES(1);
CREATE TABLE foo2(b);
INSERT INTO foo2(b) VALUES(1);
SELECT * FROM foo1; SELECT * FROM foo2;
a
1

b
1
INSERT INTO foo1(a) VALUES(2); INSERT INTO foo2(b) VALUES(2);

SELECT * FROM foo1; SELECT * FROM foo2;
a
1
2

b
1
2
}}

# Test for rejection of incomplete input at EOF.
# Reported at https://sqlite.org/forum/forumpost/718f489a43be3197
Changes to test/shell3.test.
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#
#   shell3-1.*: Basic tests for running SQL statments from command line.
#   shell3-2.*: Basic tests for running SQL file from command line.
#   shell3-3.*: Basic tests for processing odd SQL constructs.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set CLI [test_find_cli]
db close
forcedelete test.db test.db-journal test.db-wal
sqlite3 db test.db


# There are inconsistencies in command-line argument quoting on Windows.
# In particular, individual applications are responsible for command-line







|







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#
#   shell3-1.*: Basic tests for running SQL statments from command line.
#   shell3-2.*: Basic tests for running SQL file from command line.
#   shell3-3.*: Basic tests for processing odd SQL constructs.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set CLI [test_cli_invocation]
db close
forcedelete test.db test.db-journal test.db-wal
sqlite3 db test.db


# There are inconsistencies in command-line argument quoting on Windows.
# In particular, individual applications are responsible for command-line
Changes to test/shell4.test.
19
20
21
22
23
24
25
26

27
28
29
30
31
32
33
#   shell4-1.*: Basic tests specific to the "stats" command.
#   shell4-2.*: Basic tests for ".trace"
#   shell4-3.*: The ".read" command takes the shell out of interactive mode
#   shell4-4.*: Input redirects cannot recurse too much
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set CLI [test_find_cli]

db close
forcedelete test.db test.db-journal test.db-wal
sqlite3 db test.db

#----------------------------------------------------------------------------
# Test cases shell4-1.*: Tests specific to the "stats" command.
#







|
>







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#   shell4-1.*: Basic tests specific to the "stats" command.
#   shell4-2.*: Basic tests for ".trace"
#   shell4-3.*: The ".read" command takes the shell out of interactive mode
#   shell4-4.*: Input redirects cannot recurse too much
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set CLI [test_cli_invocation]
set CLI_ONLY [test_find_cli]
db close
forcedelete test.db test.db-journal test.db-wal
sqlite3 db test.db

#----------------------------------------------------------------------------
# Test cases shell4-1.*: Tests specific to the "stats" command.
#
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
} {0 {SELECT * FROM t1;}}
}

do_test shell4-3.1 {
  set fd [open t1.txt wb]
  puts $fd "SELECT 'squirrel';"
  close $fd
  exec $::CLI :memory: --interactive ".read t1.txt"
} {squirrel}
do_test shell4-3.2 {
  set fd [open t1.txt wb]
  puts $fd "SELECT 'pound: \302\243';"
  close $fd
  exec $::CLI :memory: --interactive ".read t1.txt"
} {pound: £}

do_test shell4-4.1 {
  set fd [open t1.txt wb]
  puts $fd ".read t1.txt"
  close $fd
  catchcmd ":memory:" ".read t1.txt"
} {1 {Input nesting limit (25) reached at line 1. Check recursion.}}

finish_test







|





|










127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
} {0 {SELECT * FROM t1;}}
}

do_test shell4-3.1 {
  set fd [open t1.txt wb]
  puts $fd "SELECT 'squirrel';"
  close $fd
  exec $::CLI_ONLY :memory: --interactive ".read t1.txt"
} {squirrel}
do_test shell4-3.2 {
  set fd [open t1.txt wb]
  puts $fd "SELECT 'pound: \302\243';"
  close $fd
  exec $::CLI_ONLY :memory: --interactive ".read t1.txt"
} {pound: £}

do_test shell4-4.1 {
  set fd [open t1.txt wb]
  puts $fd ".read t1.txt"
  close $fd
  catchcmd ":memory:" ".read t1.txt"
} {1 {Input nesting limit (25) reached at line 1. Check recursion.}}

finish_test
Changes to test/shell5.test.
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# Test plan:
#
#   shell5-1.*: Basic tests specific to the ".import" command.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set CLI [test_find_cli]
db close
forcedelete test.db test.db-journal test.db-wal

#----------------------------------------------------------------------------
# Test cases shell5-1.*: Basic handling of the .import and .separator commands.
#








|







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# Test plan:
#
#   shell5-1.*: Basic tests specific to the ".import" command.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set CLI [test_cli_invocation]
db close
forcedelete test.db test.db-journal test.db-wal

#----------------------------------------------------------------------------
# Test cases shell5-1.*: Basic handling of the .import and .separator commands.
#

Changes to test/shell8.test.
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix shell8

ifcapable !vtab {
  finish_test; return
}
set CLI [test_find_cli]

# Check to make sure the shell has been compiled with ".archive" support.
#
if {[string match {*unknown command*} [catchcmd :memory: .archive]]} {
  finish_test; return
}








|







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix shell8

ifcapable !vtab {
  finish_test; return
}
set CLI [test_cli_invocation]

# Check to make sure the shell has been compiled with ".archive" support.
#
if {[string match {*unknown command*} [catchcmd :memory: .archive]]} {
  finish_test; return
}

Changes to test/swarmvtab3.test.
144
145
146
147
148
149
150

151
152
153
154
155

156
157
158
159
160
161
162

catch { array unset ::dbcache }

# Set up 100 databases with filenames "remote_test.dbN", where N is a
# random integer between 0 and 1,000,000
# 0 and 99.
do_test 2.1 {

  for {set i 0} {$i < 100} {incr i} {
    while 1 {
      set ctx [expr abs(int(rand() *1000000))]
      if {[info exists ::dbcache($ctx)]==0} break
    }


    set file test_remote.db$ctx
    forcedelete $file
    forcedelete test.db$i
    sqlite3 rrr $file
    rrr eval {
      CREATE TABLE t1(a INTEGER PRIMARY KEY, b);







>



|

>







144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

catch { array unset ::dbcache }

# Set up 100 databases with filenames "remote_test.dbN", where N is a
# random integer between 0 and 1,000,000
# 0 and 99.
do_test 2.1 {
  catch { array unset ctx_used } 
  for {set i 0} {$i < 100} {incr i} {
    while 1 {
      set ctx [expr abs(int(rand() *1000000))]
      if {[info exists ctx_used($ctx)]==0} break
    }
    set ctx_used($ctx) 1

    set file test_remote.db$ctx
    forcedelete $file
    forcedelete test.db$i
    sqlite3 rrr $file
    rrr eval {
      CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
Changes to test/tester.tcl.
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
    if {[info exists ::env(ComSpec)]} {
      set comSpec $::env(ComSpec)
    } else {
      # NOTE: Hard-code the typical default value.
      set comSpec {C:\Windows\system32\cmd.exe}
    }
    return [string map [list \\ /] \
        [string trim [exec -- $comSpec /c echo %CD%]]]
  } else {
    return [pwd]
  }
}

# Copy file $from into $to. This is used because some versions of
# TCL for windows (notably the 8.4.1 binary package shipped with the







|







180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
    if {[info exists ::env(ComSpec)]} {
      set comSpec $::env(ComSpec)
    } else {
      # NOTE: Hard-code the typical default value.
      set comSpec {C:\Windows\system32\cmd.exe}
    }
    return [string map [list \\ /] \
        [string trim [exec -- $comSpec /c CD]]]
  } else {
    return [pwd]
  }
}

# Copy file $from into $to. This is used because some versions of
# TCL for windows (notably the 8.4.1 binary package shipped with the
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488































2489
2490
2491
2492
2493
2494
2495
    finish_test
    return ""
  }
  return $ret
}

# Find the name of the 'shell' executable (e.g. "sqlite3.exe") to use for
# the tests in shell[1-5].test. If no such executable can be found, invoke
# [finish_test ; return] in the callers context.
#
proc test_find_cli {} {
  set prog [test_find_binary sqlite3]
  if {$prog==""} { return -code return }
  return $prog
}
































# Find the name of the 'sqldiff' executable (e.g. "sqlite3.exe") to use for
# the tests in sqldiff tests. If no such executable can be found, invoke
# [finish_test ; return] in the callers context.
#
proc test_find_sqldiff {} {
  set prog [test_find_binary sqldiff]







|







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
    finish_test
    return ""
  }
  return $ret
}

# Find the name of the 'shell' executable (e.g. "sqlite3.exe") to use for
# the tests in shell*.test. If no such executable can be found, invoke
# [finish_test ; return] in the callers context.
#
proc test_find_cli {} {
  set prog [test_find_binary sqlite3]
  if {$prog==""} { return -code return }
  return $prog
}

# Find invocation of the 'shell' executable (e.g. "sqlite3.exe") to use
# for the tests in shell*.test with optional valgrind prefix when the
# environment variable SQLITE_CLI_VALGRIND_OPT is set. The set value
# operates as follows:
#   empty or 0 => no valgrind prefix;
#   1 => valgrind options for memory leak check;
#   other => use value as valgrind options.
# If shell not found, invoke [finish_test ; return] in callers context.
#
proc test_cli_invocation {} {
  set prog [test_find_binary sqlite3]
  if {$prog==""} { return -code return }
  set vgrun [expr {[permutation]=="valgrind"}]
  if {$vgrun || [info exists ::env(SQLITE_CLI_VALGRIND_OPT)]} {
    if {$vgrun} {
      set vgo "--quiet"
    } else {
      set vgo $::env(SQLITE_CLI_VALGRIND_OPT)
    }
    if {$vgo == 0 || $vgo eq ""} {
      return $prog
    } elseif {$vgo == 1} {
      return "valgrind --quiet --leak-check=yes $prog"
    } else {
      return "valgrind $vgo $prog"
    }
  } else {
    return $prog
  }
}

# Find the name of the 'sqldiff' executable (e.g. "sqlite3.exe") to use for
# the tests in sqldiff tests. If no such executable can be found, invoke
# [finish_test ; return] in the callers context.
#
proc test_find_sqldiff {} {
  set prog [test_find_binary sqldiff]
Added test/upfrom4.test.




































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# 2022-05-24
#
# 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.
#
#***********************************************************************
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix upfrom4

do_execsql_test 100 {
  DROP TABLE IF EXISTS t5;
  DROP TABLE IF EXISTS m1;
  DROP TABLE IF EXISTS m2;
  CREATE TABLE t5(a INTEGER PRIMARY KEY, b TEXT, c TEXT);
  CREATE TABLE m1(x INTEGER PRIMARY KEY, y TEXT);
  CREATE TABLE m2(u INTEGER PRIMARY KEY, v TEXT);

  INSERT INTO t5 VALUES(1, 'one', 'ONE');
  INSERT INTO t5 VALUES(2, 'two', 'TWO');
  INSERT INTO t5 VALUES(3, 'three', 'THREE');
  INSERT INTO t5 VALUES(4, 'four', 'FOUR');

  INSERT INTO m1 VALUES(1, 'i');
  INSERT INTO m1 VALUES(2, 'ii');
  INSERT INTO m1 VALUES(3, 'iii');

  INSERT INTO m2 VALUES(1, 'I');
  INSERT INTO m2 VALUES(3, 'II');
  INSERT INTO m2 VALUES(4, 'III');
  SELECT * FROM t5;
} {1 one ONE 2 two TWO 3 three THREE 4 four FOUR}

do_execsql_test 110 {
  BEGIN;
  UPDATE t5 SET b=y, c=v FROM m1 LEFT JOIN m2 ON (x=u) WHERE x=a;
  SELECT * FROM t5 ORDER BY a;
  ROLLBACK;
} {1 i I 2 ii {} 3 iii II 4 four FOUR}

do_execsql_test 120 {
  BEGIN;
  UPDATE t5 SET b=y, c=v FROM m2 RIGHT JOIN m1 ON (x=u) WHERE x=a;
  SELECT * FROM t5 ORDER BY a;
  ROLLBACK;
} {1 i I 2 ii {} 3 iii II 4 four FOUR}


reset_db
db null -
do_execsql_test 200 {
  CREATE TABLE t1(a INT PRIMARY KEY, b INT, c INT);
  INSERT INTO t1(a) VALUES(1),(2),(8),(19);
  CREATE TABLE c1(x INTEGER PRIMARY KEY, b INT);
  INSERT INTO c1(x,b) VALUES(1,1),(8,8),(17,17),(NULL,NULL);
  CREATE TABLE c2(x INT,c INT);
  INSERT INTO c2(x,c) VALUES(2,2),(8,8),(NULL,NULL);
  CREATE TABLE dual(dummy TEXT);
  INSERT INTO dual VALUES('X');
} {}
do_execsql_test 210 {
  BEGIN;
  SELECT * FROM t1 ORDER BY a;
  UPDATE t1 SET b=c1.b, c=c2.c
    FROM dual, c1 NATURAL RIGHT JOIN c2
   WHERE x=a;
  SELECT * FROM t1 ORDER BY a;
  ROLLBACK;
} {
  1  -  -
  2  -  -
  8  -  -
  19 -  -
  1  -  -
  2  -  2
  8  8  8
  19 -  -
}
do_execsql_test 300 {
  CREATE TABLE t2(x);
  CREATE TRIGGER AFTER INSERT ON t2 BEGIN
    UPDATE t1 SET b=c1.b, c=c2.c
      FROM dual, c1 NATURAL RIGHT JOIN c2
     WHERE x=a;
  END;
} {}
do_execsql_test 310 {
  BEGIN;
  SELECT * FROM t1 ORDER BY a;
  INSERT INTO t2(x) VALUES(1);
  SELECT * FROM t1 ORDER BY a;
  ROLLBACK;
} {
  1  -  -
  2  -  -
  8  -  -
  19 -  -
  1  -  -
  2  -  2
  8  8  8
  19 -  -
}

# 2022-05-26 dbsqlfuzz crash-9401d6ba699f1257d352a657de236286bf2b14da
#
reset_db
db null -
do_execsql_test 400 {
  CREATE TABLE t2(x,y,z PRIMARY KEY) WITHOUT ROWID;
  INSERT INTO t2 VALUES(89,-89,6);
  CREATE TABLE t1(a INT,b TEXT,c TEXT,d REAL) STRICT;
  INSERT INTO t1 VALUES(1,'xyz','def',4.5);
  CREATE TRIGGER t1tr BEFORE UPDATE ON t1 BEGIN
    INSERT INTO t1(a,b) VALUES(1000,'uvw');
    UPDATE t1 SET b=NULL FROM (SELECT CAST(a AS varchar) FROM t1 ORDER BY b) NATURAL LEFT FULL JOIN t1 AS text;
  END;
  UPDATE t1 SET b=b|100;
  SELECT * FROM t1 ORDER BY a;
} {
  1    100  def 4.5
  1000 -    -   -
}

finish_test
Changes to test/vtab6.test.
273
274
275
276
277
278
279



280
281
282
283
284

285
286
287
288
289
290
291
  catchsql { SELECT * FROM t1 USING(a) }
} {1 {a JOIN clause is required before USING}}
do_test vtab6-3.6 {
  catchsql {
    SELECT * FROM t1 JOIN t2 ON t3.a=t2.b;
  }
} {1 {no such column: t3.a}}



do_test vtab6-3.7 {
  catchsql {
    SELECT * FROM t1 INNER OUTER JOIN t2;
  }
} {1 {unknown join type: INNER OUTER}}

do_test vtab6-3.7 {
  catchsql {
    SELECT * FROM t1 LEFT BOGUS JOIN t2;
  }
} {1 {unknown join type: LEFT BOGUS}}

do_test vtab6-4.1 {







>
>
>





>







273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
  catchsql { SELECT * FROM t1 USING(a) }
} {1 {a JOIN clause is required before USING}}
do_test vtab6-3.6 {
  catchsql {
    SELECT * FROM t1 JOIN t2 ON t3.a=t2.b;
  }
} {1 {no such column: t3.a}}

# EVIDENCE-OF: R-47973-48020 you cannot say "INNER OUTER JOIN", because
# that would be contradictory.
do_test vtab6-3.7 {
  catchsql {
    SELECT * FROM t1 INNER OUTER JOIN t2;
  }
} {1 {unknown join type: INNER OUTER}}

do_test vtab6-3.7 {
  catchsql {
    SELECT * FROM t1 LEFT BOGUS JOIN t2;
  }
} {1 {unknown join type: LEFT BOGUS}}

do_test vtab6-4.1 {
Changes to test/where.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2001 September 15
#
# 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.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the use of indices in WHERE clases.
#
# $Id: where.test,v 1.50 2008/11/03 09:06:06 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Build some test data
#
do_test where-1.0 {













<







1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
# 2001 September 15
#
# 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.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the use of indices in WHERE clases.
#


set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Build some test data
#
do_test where-1.0 {
1598
1599
1600
1601
1602
1603
1604
1605















1606
    INSERT INTO t1(a) VALUES(9223372036854775807);
    SELECT 1 FROM t1 WHERE a>=(9223372036854775807+1);
  } {}
  do_execsql_test where-27.2 {
    SELECT a>=9223372036854775807+1 FROM t1;
  } {0}
}
















finish_test








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
    INSERT INTO t1(a) VALUES(9223372036854775807);
    SELECT 1 FROM t1 WHERE a>=(9223372036854775807+1);
  } {}
  do_execsql_test where-27.2 {
    SELECT a>=9223372036854775807+1 FROM t1;
  } {0}
}

# 2022-05-10 dbsqlfuzz 4c5e3e89bc251d28378be88233f531b84ec66901
# 
reset_db
do_execsql_test where-28.1 {
  CREATE TABLE t1(a INTEGER PRIMARY KEY, b INT);
  CREATE INDEX t1b ON t1(b,b,b,b,b,b,b,b,b,b,b,b,b);
  INSERT INTO t1(a,b) VALUES(1,1),(15,2),(19,5);
  UPDATE t1 SET b=999 WHERE a IN (SELECT 15) AND b IN (1,2);
  SELECT * FROM t1;
} {
 1  1
 15 999
 19 5
}

finish_test