Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1001626f85 |
-131
@@ -1512,134 +1512,3 @@ sqlite3.def: $(REAL_LIBOBJ)
|
||||
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
|
||||
sqlite3_wasm_js = $(fiddle_dir)/sqlite3.js
|
||||
sqlite3_wasm = $(fiddle_dir)/sqlite3.wasm
|
||||
#emcc_opt = -O0
|
||||
#emcc_opt = -O1
|
||||
#emcc_opt = -O2
|
||||
#emcc_opt = -O3
|
||||
emcc_opt = -Oz
|
||||
emcc_flags = $(emcc_opt) -sALLOW_TABLE_GROWTH -sSTRICT_JS \
|
||||
-sENVIRONMENT=web -sMODULARIZE \
|
||||
-sEXPORTED_RUNTIME_METHODS=@$(fiddle_dir_abs)/EXPORTED_RUNTIME_METHODS \
|
||||
-sDYNAMIC_EXECUTION=0 \
|
||||
-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) \
|
||||
-sEXPORT_NAME=initFiddleModule \
|
||||
-sEXPORTED_FUNCTIONS=@$(fiddle_dir_abs)/EXPORTED_FUNCTIONS.fiddle \
|
||||
sqlite3.c shell.c
|
||||
gzip < $@ > $@.gz
|
||||
gzip < $(fiddle_dir)/fiddle-module.wasm > $(fiddle_dir)/fiddle-module.wasm.gz
|
||||
$(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) \
|
||||
-sEXPORT_NAME=initSqlite3Module \
|
||||
-sEXPORTED_FUNCTIONS=@$(fiddle_dir_abs)/EXPORTED_FUNCTIONS.sqlite3-api \
|
||||
--post-js=$(fiddle_dir)/sqlite3-api.js \
|
||||
--no-entry \
|
||||
sqlite3.c
|
||||
gzip < $@ > $@.gz
|
||||
gzip < $(sqlite3_wasm) > $(sqlite3_wasm).gz
|
||||
gzip < $(fiddle_dir)/sqlite3-api.js > $(fiddle_dir)/sqlite3-api.js.gz
|
||||
$(fiddle_dir)/fiddle.js.gz: $(fiddle_dir)/fiddle.js
|
||||
gzip < $< > $@
|
||||
$(fiddle_dir)/sqlite3-api.js.gz: $(fiddle_dir)/sqlite3-api.js
|
||||
gzip < $< > $@
|
||||
|
||||
fiddle_generated = $(fiddle_module_js) $(fiddle_module_js).gz \
|
||||
$(fiddle_dir)/fiddle-module.wasm \
|
||||
$(fiddle_dir)/fiddle-module.wasm.gz \
|
||||
$(fiddle_dir)/fiddle.js.gz
|
||||
sqlite3_wasm_generated = \
|
||||
$(sqlite3_wasm) $(sqlite3_wasm).gz \
|
||||
$(sqlite3_wasm_js) $(sqlite3_wasm_js).gz \
|
||||
$(fiddle_dir)/sqlite3.js.gz \
|
||||
$(fiddle_dir)/sqlite3-api.js.gz
|
||||
|
||||
clean-wasm:
|
||||
rm -f $(fiddle_generated) $(sqlite3_wasm_generated)
|
||||
clean: clean-wasm
|
||||
fiddle: $(fiddle_module_js) $(fiddle_dir)/fiddle.js.gz
|
||||
sqlite3-wasm: $(sqlite3_wasm_js)
|
||||
wasm: fiddle sqlite3-wasm
|
||||
########################################################################
|
||||
# Explanation of the emcc build flags follows. Full docs for these can
|
||||
# be found at:
|
||||
#
|
||||
# https://github.com/emscripten-core/emscripten/blob/main/src/settings.js
|
||||
#
|
||||
# -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!
|
||||
#
|
||||
# -sSTRICT_JS ensures that the emitted JS code includes the 'use
|
||||
# strict' option. Note that -sSTRICT is more broadly-scoped and
|
||||
# results in build errors.
|
||||
#
|
||||
# -sALLOW_TABLE_GROWTH is required for (at a minimum) the UDF-binding
|
||||
# feature.
|
||||
#
|
||||
# -sDYNAMIC_EXECUTION=0 disables eval() and the Function constructor.
|
||||
# If the build runs without these, it's preferable to use this flag
|
||||
# because certain execution environments disallow those constructs.
|
||||
# This flag is not strictly necessary, however.
|
||||
#
|
||||
# -sWASM_BIGINT is UNTESTED but "should" allow the int64-using C APIs
|
||||
# to work with JS/wasm, insofar as the JS environment supports the
|
||||
# BigInt type. That support requires an extremely recent browser:
|
||||
# Safari didn't get that support until late 2020.
|
||||
#
|
||||
# --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.
|
||||
########################################################################
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<h1 align="center">SQLite Source Repository</h1>
|
||||
|
||||
This repository contains the complete source code for the
|
||||
[SQLite database engine](https://sqlite.org/). Some test scripts
|
||||
This repository contains the complete source code for the
|
||||
[SQLite database engine](https://sqlite.org/). Some test scripts
|
||||
are also included. However, many other test scripts
|
||||
and most of the documentation are managed separately.
|
||||
|
||||
@@ -15,7 +15,7 @@ The [Fossil repository](https://sqlite.org/src/timeline) contains the urtext.
|
||||
If you are reading this on GitHub or some other Git repository or service,
|
||||
then you are looking at a mirror. The names of check-ins and
|
||||
other artifacts in a Git mirror are different from the official
|
||||
names for those objects. The official names for check-ins are
|
||||
names for those objects. The offical names for check-ins are
|
||||
found in a footer on the check-in comment for authorized mirrors.
|
||||
The official check-in name can also be seen in the `manifest.uuid` file
|
||||
in the root of the tree. Always use the official name, not the
|
||||
@@ -30,7 +30,7 @@ verify its integrity, there are hints on how to do that in the
|
||||
If you do not want to use Fossil, you can download tarballs or ZIP
|
||||
archives or [SQLite archives](https://sqlite.org/cli.html#sqlar) as follows:
|
||||
|
||||
* Latest trunk check-in as
|
||||
* Lastest trunk check-in as
|
||||
[Tarball](https://www.sqlite.org/src/tarball/sqlite.tar.gz),
|
||||
[ZIP-archive](https://www.sqlite.org/src/zip/sqlite.zip), or
|
||||
[SQLite-archive](https://www.sqlite.org/src/sqlar/sqlite.sqlar).
|
||||
@@ -47,11 +47,11 @@ archives or [SQLite archives](https://sqlite.org/cli.html#sqlar) as follows:
|
||||
then click on the "Tarball" or "ZIP Archive" links on the information
|
||||
page.
|
||||
|
||||
If you do want to use Fossil to check out the source tree,
|
||||
If you do want to use Fossil to check out the source tree,
|
||||
first install Fossil version 2.0 or later.
|
||||
(Source tarballs and precompiled binaries available
|
||||
[here](https://www.fossil-scm.org/fossil/uv/download.html). Fossil is
|
||||
a stand-alone program. To install, simply download or build the single
|
||||
a stand-alone program. To install, simply download or build the single
|
||||
executable file and put that file someplace on your $PATH.)
|
||||
Then run commands like this:
|
||||
|
||||
@@ -61,7 +61,7 @@ Then run commands like this:
|
||||
fossil open ~/Fossils/sqlite.fossil
|
||||
|
||||
After setting up a repository using the steps above, you can always
|
||||
update to the latest version using:
|
||||
update to the lastest version using:
|
||||
|
||||
fossil update trunk ;# latest trunk check-in
|
||||
fossil update release ;# latest official release
|
||||
@@ -136,7 +136,7 @@ the "tclsqlite.c" file which implements the
|
||||
extension and only later escaped to the wild as an independent library.)
|
||||
|
||||
Test scripts and programs are found in the **test/** subdirectory.
|
||||
Additional test code is found in other source repositories.
|
||||
Addtional test code is found in other source repositories.
|
||||
See [How SQLite Is Tested](http://www.sqlite.org/testing.html) for
|
||||
additional information.
|
||||
|
||||
@@ -170,7 +170,7 @@ at just the right spots. Note that comment text in the sqlite3.h file is
|
||||
used to generate much of the SQLite API documentation. The Tcl scripts
|
||||
used to generate that documentation are in a separate source repository.
|
||||
|
||||
The SQL language parser is **parse.c** which is generated from a grammar in
|
||||
The SQL language parser is **parse.c** which is generate from a grammar in
|
||||
the src/parse.y file. The conversion of "parse.y" into "parse.c" is done
|
||||
by the [lemon](./doc/lemon.html) LALR(1) parser generator. The source code
|
||||
for lemon is at tool/lemon.c. Lemon uses the tool/lempar.c file as a
|
||||
@@ -180,7 +180,7 @@ generates parse.c.
|
||||
|
||||
The **opcodes.h** header file contains macros that define the numbers
|
||||
corresponding to opcodes in the "VDBE" virtual machine. The opcodes.h
|
||||
file is generated by scanning the src/vdbe.c source file. The
|
||||
file is generated by the scanning the src/vdbe.c source file. The
|
||||
Tcl script at ./mkopcodeh.tcl does this scan and generates opcodes.h.
|
||||
A second Tcl script, ./mkopcodec.tcl, then scans opcodes.h to generate
|
||||
the **opcodes.c** source file, which contains a reverse mapping from
|
||||
@@ -237,7 +237,7 @@ prepared statements, the description of
|
||||
[how transactions work](http://www.sqlite.org/atomiccommit.html), and
|
||||
the [overview of the query planner](http://www.sqlite.org/optoverview.html).
|
||||
|
||||
Years of effort have gone into optimizing SQLite, both
|
||||
Years of effort have gone into optimizating SQLite, both
|
||||
for small size and high performance. And optimizations tend to result in
|
||||
complex code. So there is a lot of complexity in the current SQLite
|
||||
implementation. It will not be the easiest library in the world to hack.
|
||||
@@ -294,11 +294,11 @@ Key files:
|
||||
building the "testfixture.exe" program. The testfixture.exe program is
|
||||
an enhanced Tcl shell. The testfixture.exe program runs scripts in the
|
||||
test/ folder to validate the core SQLite code. The testfixture program
|
||||
(and some other test programs too) is built and run when you type
|
||||
(and some other test programs too) is build and run when you type
|
||||
"make test".
|
||||
|
||||
* **ext/misc/json1.c** - This file implements the various JSON functions
|
||||
that are built into SQLite.
|
||||
that are build into SQLite.
|
||||
|
||||
There are many other source files. Each has a succinct header comment that
|
||||
describes its purpose and role within the larger system.
|
||||
@@ -307,7 +307,7 @@ describes its purpose and role within the larger system.
|
||||
## Verifying Code Authenticity
|
||||
|
||||
The `manifest` file at the root directory of the source tree
|
||||
contains either a SHA3-256 hash (for newer files) or a SHA1 hash (for
|
||||
contains either a SHA3-256 hash (for newer files) or a SHA1 hash (for
|
||||
older files) for every source file in the repository.
|
||||
The name of the version of the entire source tree is just the
|
||||
SHA3-256 hash of the `manifest` file itself, possibly with the
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
_fiddle_exec
|
||||
_fiddle_interrupt
|
||||
_fiddle_experiment
|
||||
_fiddle_the_db
|
||||
_fiddle_db_arg
|
||||
_fiddle_db_filename
|
||||
_fiddle_reset_db
|
||||
@@ -1,51 +0,0 @@
|
||||
_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
|
||||
@@ -1,14 +0,0 @@
|
||||
ALLOC_NORMAL
|
||||
FS
|
||||
UTF8ToString
|
||||
addFunction
|
||||
allocate
|
||||
allocateUTF8OnStack
|
||||
ccall
|
||||
cwrap
|
||||
getValue
|
||||
removeFunction
|
||||
setValue
|
||||
stackAlloc
|
||||
stackRestore
|
||||
stackSave
|
||||
@@ -1,34 +0,0 @@
|
||||
# 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 \
|
||||
$(wildcard *.wasm.gz) $(wildcard *.js.gz)
|
||||
|
||||
# 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)
|
||||
@@ -1,144 +0,0 @@
|
||||
/*
|
||||
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*/);
|
||||
@@ -1,24 +0,0 @@
|
||||
/* 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);}
|
||||
}
|
||||
@@ -1,301 +0,0 @@
|
||||
/*
|
||||
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 && oldName !== fn){
|
||||
try{fiddleModule.FS.unlink(oldName);}
|
||||
catch(e){/*ignored*/}
|
||||
}
|
||||
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');
|
||||
});
|
||||
})();
|
||||
@@ -1,264 +0,0 @@
|
||||
<!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' class='hidden'/>
|
||||
<button id='btn-load-db'>Load DB...</button>
|
||||
</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>
|
||||
@@ -1,799 +0,0 @@
|
||||
/*
|
||||
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, "&");
|
||||
//text = text.replace(/</g, "<");
|
||||
//text = text.replace(/>/g, ">");
|
||||
//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 eLoadDb = E('#load-db');
|
||||
const btnLoadDb = E('#btn-load-db');
|
||||
btnLoadDb.addEventListener('click', ()=>eLoadDb.click());
|
||||
/**
|
||||
Enables (if passed true) or disables all UI elements which
|
||||
"might," if timed "just right," interfere with an
|
||||
in-progress db import/export/exec operation.
|
||||
*/
|
||||
const enableMutatingElements = function f(enable){
|
||||
if(!f._elems){
|
||||
f._elems = [
|
||||
/* UI elements to disable while import/export are
|
||||
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, eLoadDb
|
||||
];
|
||||
}
|
||||
f._elems.forEach( enable
|
||||
? (e)=>e.removeAttribute('disabled')
|
||||
: (e)=>e.setAttribute('disabled','disabled') );
|
||||
};
|
||||
btnExport.addEventListener('click',function(){
|
||||
enableMutatingElements(false);
|
||||
SF.wMsg('db-export');
|
||||
});
|
||||
SF.addMsgHandler('db-export', function(ev){
|
||||
enableMutatingElements(true);
|
||||
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.
|
||||
*/
|
||||
eLoadDb.addEventListener('change',function(){
|
||||
const f = this.files[0];
|
||||
const r = new FileReader();
|
||||
const status = {loaded: 0, total: 0};
|
||||
enableMutatingElements(false);
|
||||
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(){
|
||||
enableMutatingElements(true);
|
||||
SF.echo("Loaded",f.name+". Opening db...");
|
||||
SF.wMsg('open',{
|
||||
filename: f.name,
|
||||
buffer: this.result
|
||||
});
|
||||
});
|
||||
r.addEventListener('error',function(){
|
||||
enableMutatingElements(true);
|
||||
SF.echo("Loading",f.name,"failed for unknown reasons.");
|
||||
});
|
||||
r.addEventListener('abort',function(){
|
||||
enableMutatingElements(true);
|
||||
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()*/;
|
||||
})();
|
||||
@@ -1,94 +0,0 @@
|
||||
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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
2022-05-23
|
||||
|
||||
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 a JS Worker file for the main sqlite3 api. It loads
|
||||
sqlite3.js, initializes the module, and postMessage()'s a message
|
||||
after the module is initialized:
|
||||
|
||||
{type: 'sqlite3-api', data: 'ready'}
|
||||
|
||||
This seemingly superfluous level of indirection is necessary when
|
||||
loading sqlite3.js via a Worker. Loading sqlite3.js from the main
|
||||
window thread elides the Worker-specific API. Instantiating a worker
|
||||
with new Worker("sqlite.js") will not (cannot) call
|
||||
initSqlite3Module() to initialize the module due to a
|
||||
timing/order-of-operations conflict (and that symbol is not exported
|
||||
in a way that a Worker loading it that way can see it). Thus JS
|
||||
code wanting to load the sqlite3 Worker-specific API needs to pass
|
||||
_this_ file (or equivalent) to the Worker constructor and then
|
||||
listen for an event in the form shown above in order to know when
|
||||
the module has completed initialization. sqlite3.js will fire a
|
||||
similar event, with data:'loaded' as the final step in its loading
|
||||
process. Whether or not we _really_ need both 'loaded' and 'ready'
|
||||
events is unclear, but they are currently separate events primarily
|
||||
for the sake of clarity in the timing of when it's okay to use the
|
||||
loaded module. At the time the 'loaded' event is fired, it's
|
||||
possible (but unknown and unknowable) that the emscripten-generated
|
||||
module-setup infrastructure still has work to do. Thus it is
|
||||
hypothesized that client code is better off waiting for the 'ready'
|
||||
even before using the API.
|
||||
*/
|
||||
"use strict";
|
||||
importScripts('sqlite3.js');
|
||||
initSqlite3Module().then(function(){
|
||||
setTimeout(()=>self.postMessage({type:'sqlite3-api',data:'ready'}), 0);
|
||||
});
|
||||
@@ -1,31 +0,0 @@
|
||||
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;
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,179 +0,0 @@
|
||||
/*
|
||||
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. This file must be run in
|
||||
main JS thread and sqlite3.js must have been loaded before it.
|
||||
*/
|
||||
(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 = [];
|
||||
list.length = 0;
|
||||
db.exec("SELECT a a, b b FROM t",{
|
||||
rowMode: 'object',
|
||||
resultRows: list,
|
||||
columnNames: colNames,
|
||||
callback: function(row,stmt){
|
||||
++counter;
|
||||
T.assert(row.a%2 && row.a<6);
|
||||
}
|
||||
});
|
||||
T.assert(2 === colNames.length)
|
||||
.assert('a' === colNames[0])
|
||||
.assert(3 === counter)
|
||||
.assert(3 === list.length);
|
||||
list.length = 0;
|
||||
db.exec("SELECT a a, b b FROM t",{
|
||||
rowMode: 'array',
|
||||
callback: function(row,stmt){
|
||||
++counter;
|
||||
T.assert(Array.isArray(row))
|
||||
.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 testAttach = function(db){
|
||||
log("Testing ATTACH...");
|
||||
db.exec({
|
||||
sql:[
|
||||
"attach 'foo.db' as foo",
|
||||
"create table foo.bar(a)",
|
||||
"insert into foo.bar(a) values(1),(2),(3)"
|
||||
].join(';'),
|
||||
multi: true
|
||||
});
|
||||
T.assert(2===db.selectValue('select a from foo.bar where a>1 order by a'));
|
||||
db.exec("detach foo");
|
||||
T.mustThrow(()=>db.exec("select * from foo.bar"));
|
||||
};
|
||||
|
||||
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, testAttach
|
||||
].forEach((f)=>{
|
||||
const t = T.counter;
|
||||
f(db, sqlite3);
|
||||
log("Test count:",T.counter - t);
|
||||
});
|
||||
}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);
|
||||
});
|
||||
})();
|
||||
@@ -1,32 +0,0 @@
|
||||
<!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-worker.js tests</title>
|
||||
<style></style>
|
||||
</head>
|
||||
<body>
|
||||
<header id='titlebar'><span>sqlite3-worker.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="testing-common.js"></script>
|
||||
<script src="testing2.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,235 +0,0 @@
|
||||
/*
|
||||
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-worker.js.
|
||||
*/
|
||||
(function(){
|
||||
const T = self.SqliteTestUtil;
|
||||
const SW = new Worker("sqlite3-worker.js");
|
||||
/** Posts a worker message as {type:type, data:data}. */
|
||||
const wMsg = function(type,data){
|
||||
SW.postMessage({type, data});
|
||||
return SW;
|
||||
};
|
||||
const log = console.log.bind(console);
|
||||
const warn = console.warn.bind(console);
|
||||
const error = console.error.bind(console);
|
||||
|
||||
SW.onerror = function(event){
|
||||
error("onerror",event);
|
||||
};
|
||||
|
||||
/**
|
||||
A queue for callbacks which are to be run in response to async
|
||||
DB commands. See the notes in runTests() for why we need
|
||||
this. The event-handling plumbing of this file requires that
|
||||
any DB command which includes a `messageId` property also have
|
||||
a queued callback entry, as the existence of that property in
|
||||
response payloads is how it knows whether or not to shift an
|
||||
entry off of the queue.
|
||||
*/
|
||||
const MsgHandlerQueue = {
|
||||
queue: [],
|
||||
id: 0,
|
||||
push: function(type,callback){
|
||||
this.queue.push(callback);
|
||||
return type + '-' + (++this.id);
|
||||
},
|
||||
shift: function(){
|
||||
return this.queue.shift();
|
||||
}
|
||||
};
|
||||
|
||||
const testCount = ()=>log("Total test count:",T.counter);
|
||||
|
||||
const runOneTest = function(eventType, eventData, callback){
|
||||
T.assert(eventData && 'object'===typeof eventData);
|
||||
/* ^^^ that is for the testing and messageId-related code, not
|
||||
a hard requirement of all of the Worker-exposed APIs. */
|
||||
eventData.messageId = MsgHandlerQueue.push(eventType,function(ev){
|
||||
log("runOneTest",eventType,"result",ev.data);
|
||||
if(callback instanceof Function){
|
||||
callback(ev);
|
||||
testCount();
|
||||
}
|
||||
});
|
||||
wMsg(eventType, eventData);
|
||||
};
|
||||
|
||||
/** Methods which map directly to onmessage() event.type keys.
|
||||
They get passed the inbound event.data. */
|
||||
const dbMsgHandler = {
|
||||
open: function(ev){
|
||||
log("open result",ev.data);
|
||||
},
|
||||
exec: function(ev){
|
||||
log("exec result",ev.data);
|
||||
},
|
||||
export: function(ev){
|
||||
log("exec result",ev.data);
|
||||
},
|
||||
error: function(ev){
|
||||
error("ERROR from the worker:",ev.data);
|
||||
},
|
||||
resultRowTest1: function f(ev){
|
||||
if(undefined === f.counter) f.counter = 0;
|
||||
if(ev.data) ++f.counter;
|
||||
//log("exec() result row:",ev.data);
|
||||
T.assert(null===ev.data || 'number' === typeof ev.data.b);
|
||||
}
|
||||
};
|
||||
|
||||
const runTests = function(){
|
||||
const mustNotReach = ()=>{
|
||||
throw new Error("This is not supposed to be reached.");
|
||||
};
|
||||
/**
|
||||
"The problem" now is that the test results are async. We
|
||||
know, however, that the messages posted to the worker will
|
||||
be processed in the order they are passed to it, so we can
|
||||
create a queue of callbacks to handle them. The problem
|
||||
with that approach is that it's not error-handling
|
||||
friendly, in that an error can cause us to bypass a result
|
||||
handler queue entry. We have to perform some extra
|
||||
acrobatics to account for that.
|
||||
*/
|
||||
runOneTest('open', {filename:'testing2.sqlite3'}, function(ev){
|
||||
//log("open result",ev);
|
||||
T.assert('testing2.sqlite3'===ev.data.filename)
|
||||
.assert(ev.data.messageId);
|
||||
});
|
||||
runOneTest('exec',{
|
||||
sql: ["create table t(a,b)",
|
||||
"insert into t(a,b) values(1,2),(3,4),(5,6)"
|
||||
].join(';'),
|
||||
multi: true,
|
||||
resultRows: [], columnNames: []
|
||||
}, function(ev){
|
||||
ev = ev.data;
|
||||
T.assert(0===ev.resultRows.length)
|
||||
.assert(0===ev.columnNames.length);
|
||||
});
|
||||
runOneTest('exec',{
|
||||
sql: 'select a a, b b from t order by a',
|
||||
resultRows: [], columnNames: [],
|
||||
}, function(ev){
|
||||
ev = ev.data;
|
||||
T.assert(3===ev.resultRows.length)
|
||||
.assert(1===ev.resultRows[0][0])
|
||||
.assert(6===ev.resultRows[2][1])
|
||||
.assert(2===ev.columnNames.length)
|
||||
.assert('b'===ev.columnNames[1]);
|
||||
});
|
||||
runOneTest('exec',{
|
||||
sql: 'select a a, b b from t order by a',
|
||||
resultRows: [], columnNames: [],
|
||||
rowMode: 'object'
|
||||
}, function(ev){
|
||||
ev = ev.data;
|
||||
T.assert(3===ev.resultRows.length)
|
||||
.assert(1===ev.resultRows[0].a)
|
||||
.assert(6===ev.resultRows[2].b)
|
||||
});
|
||||
runOneTest('exec',{sql:'intentional_error'}, mustNotReach);
|
||||
// Ensure that the message-handler queue survives ^^^ that error...
|
||||
runOneTest('exec',{
|
||||
sql:'select 1',
|
||||
resultRows: [],
|
||||
//rowMode: 'array', // array is the default in the Worker interface
|
||||
}, function(ev){
|
||||
ev = ev.data;
|
||||
T.assert(1 === ev.resultRows.length)
|
||||
.assert(1 === ev.resultRows[0][0]);
|
||||
});
|
||||
runOneTest('exec',{
|
||||
sql: 'select a a, b b from t order by a',
|
||||
callback: 'resultRowTest1',
|
||||
rowMode: 'object'
|
||||
}, function(ev){
|
||||
T.assert(3===dbMsgHandler.resultRowTest1.counter);
|
||||
dbMsgHandler.resultRowTest1.counter = 0;
|
||||
});
|
||||
runOneTest('exec',{sql: 'delete from t where a>3'});
|
||||
runOneTest('exec',{
|
||||
sql: 'select count(a) from t',
|
||||
resultRows: []
|
||||
},function(ev){
|
||||
ev = ev.data;
|
||||
T.assert(1===ev.resultRows.length)
|
||||
.assert(2===ev.resultRows[0][0]);
|
||||
});
|
||||
runOneTest('export',{}, function(ev){
|
||||
ev = ev.data;
|
||||
T.assert('string' === typeof ev.filename)
|
||||
.assert(ev.buffer instanceof Uint8Array)
|
||||
.assert(ev.buffer.length > 1024)
|
||||
.assert('application/x-sqlite3' === ev.mimetype);
|
||||
});
|
||||
|
||||
/***** close() tests must come last. *****/
|
||||
runOneTest('close',{unlink:true},function(ev){
|
||||
ev = ev.data;
|
||||
T.assert('string' === typeof ev.filename);
|
||||
});
|
||||
runOneTest('close',{unlink:true},function(ev){
|
||||
ev = ev.data;
|
||||
T.assert(undefined === ev.filename);
|
||||
});
|
||||
};
|
||||
|
||||
SW.onmessage = function(ev){
|
||||
if(!ev.data || 'object'!==typeof ev.data){
|
||||
warn("Unknown sqlite3-worker message type:",ev);
|
||||
return;
|
||||
}
|
||||
ev = ev.data/*expecting a nested object*/;
|
||||
//log("main window onmessage:",ev);
|
||||
if(ev.data && ev.data.messageId){
|
||||
/* We're expecting a queued-up callback handler. */
|
||||
const f = MsgHandlerQueue.shift();
|
||||
if('error'===ev.type){
|
||||
dbMsgHandler.error(ev);
|
||||
return;
|
||||
}
|
||||
T.assert(f instanceof Function);
|
||||
f(ev);
|
||||
return;
|
||||
}
|
||||
switch(ev.type){
|
||||
case 'sqlite3-api':
|
||||
switch(ev.data){
|
||||
case 'loaded':
|
||||
log("Message:",ev); return;
|
||||
case 'ready':
|
||||
log("Message:",ev);
|
||||
self.sqlite3TestModule.setStatus(null);
|
||||
setTimeout(runTests, 0);
|
||||
return;
|
||||
default:
|
||||
warn("Unknown sqlite3-api message type:",ev);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
if(dbMsgHandler.hasOwnProperty(ev.type)){
|
||||
try{dbMsgHandler[ev.type](ev);}
|
||||
catch(err){
|
||||
error("Exception while handling db result message",
|
||||
ev,":",err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
warn("Unknown sqlite3-api message type:",ev);
|
||||
}
|
||||
};
|
||||
|
||||
log("Init complete, but async init bits may still be running.");
|
||||
})();
|
||||
@@ -3899,8 +3899,6 @@ static int fts3IncrmergePush(
|
||||
pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nPrefix);
|
||||
}
|
||||
pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nSuffix);
|
||||
assert( nPrefix+nSuffix<=nTerm );
|
||||
assert( nPrefix>=0 );
|
||||
memcpy(&pBlk->a[pBlk->n], &zTerm[nPrefix], nSuffix);
|
||||
pBlk->n += nSuffix;
|
||||
|
||||
@@ -4023,7 +4021,6 @@ static int fts3IncrmergeAppend(
|
||||
pLeaf = &pWriter->aNodeWriter[0];
|
||||
nPrefix = fts3PrefixCompress(pLeaf->key.a, pLeaf->key.n, zTerm, nTerm);
|
||||
nSuffix = nTerm - nPrefix;
|
||||
if(nSuffix<=0 ) return FTS_CORRUPT_VTAB;
|
||||
|
||||
nSpace = sqlite3Fts3VarintLen(nPrefix);
|
||||
nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
C Sync\sw/trunk,\spickup\sfts3corrupt6.test\schange.
|
||||
D 2022-06-06T14:00:41.074
|
||||
C Fix\sanother\sproblem\swith\ssubroutine\sreuse\sin\sthe\sRIGHT\sJOIN\sno-match\scode\nfor\sthe\ssubquery\son\sthe\sright-hand\sside\sof\san\sIN\soperator.\s\sThe\scurrent\scode\nworks\sfor\sall\sknown\scases,\sbut\sseems\sunnecessarily\scomplex\sand\sin\sneed\sof\nsimplification.
|
||||
D 2022-04-30T17:22:22.048
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
F Makefile.in e45046a016985c8fedfc5e7aad88ee396033a1e9b4e929fd6e1033e4c39dba95
|
||||
F Makefile.in b210ad2733317f1a4353085dfb9d385ceec30b0e6a61d20a5accabecac6b1949
|
||||
F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241
|
||||
F Makefile.msc b28a8a7a977e7312f6859f560348e1eb110c21bd6cf9fab0d16537c0a514eef3
|
||||
F README.md 8b8df9ca852aeac4864eb1e400002633ee6db84065bd01b78c33817f97d31f5e
|
||||
F README.md 2dd87a5c1d108b224921f3dd47dea567973f706e1f6959386282a626f459a70c
|
||||
F VERSION fa8e7d2d1cc962f9e14c6d410387cf75860ee139462763fda887c1be4261f824
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
|
||||
@@ -55,23 +55,6 @@ F ext/expert/expert1.test 3c642a4e7bbb14f21ddab595436fb465a4733f47a0fe5b2855e1d5
|
||||
F ext/expert/sqlite3expert.c 6ca30d73b9ed75bd56d6e0d7f2c962d2affaa72c505458619d0ff5d9cdfac204
|
||||
F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b
|
||||
F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72
|
||||
F ext/fiddle/EXPORTED_FUNCTIONS.fiddle 7fb73f7150ab79d83bb45a67d257553c905c78cd3d693101699243f36c5ae6c3
|
||||
F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3-api 540b9dec63a3a62a256e2f030827848a92e9b9d9b6fa5c0188295a4a1c5382cd
|
||||
F ext/fiddle/EXPORTED_RUNTIME_METHODS b831017ba67ba993b34a27400cef2f6095bd6789c0fc4eba7e7a251c207be31c
|
||||
F ext/fiddle/Makefile e25d34a0e1324f771d64c09c592601b97219282011587e6ce410fa8acdedb913
|
||||
F ext/fiddle/SqliteTestUtil.js 559731c3e8e0de330ec7d292e6c1846566408caee6637acc8a119ac338a8781c
|
||||
F ext/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f
|
||||
F ext/fiddle/fiddle-worker.js 88bc2193a6cb6a3f04d8911bed50a4401fe6f277de7a71ba833865ab64a1b4ae
|
||||
F ext/fiddle/fiddle.html c44f86abf286231fccfed9fd080fd17b200f5e5c05939e8080c810b6920a9326
|
||||
F ext/fiddle/fiddle.js 6c20bf264cf26a570f9bf22e533adcc7250a6f183d482eaa725ccd0fa83a6d95
|
||||
F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf
|
||||
F ext/fiddle/sqlite3-api.js ccf4bd0c1c5bbb3be3469573423d6c53991941bec497eac63e9f17ea13bf8952
|
||||
F ext/fiddle/sqlite3-worker.js a9c2b614beca187dbdd8c053ec2770cc61ec1ac9c0ec6398ceb49a79f705a421
|
||||
F ext/fiddle/testing.css 750572dded671d2cf142bbcb27af5542522ac08db128245d0b9fe410aa1d7f2a
|
||||
F ext/fiddle/testing1.html ea1f3be727f78e420007f823912c1a03b337ecbb8e79449abc2244ad4fe15d9a
|
||||
F ext/fiddle/testing1.js 68715f4716a30aa4dab0ce954d465f662486c8bc96a19a4fc8edbea4ac211fd2
|
||||
F ext/fiddle/testing2.html 9063b2430ade2fe9da4e711addd1b51a2741cf0c7ebf6926472a5e5dd63c0bc4
|
||||
F ext/fiddle/testing2.js 7b45b4e7fddbd51dbaf89b6722c02758051b34bac5a98c11b569a7e7572f88ee
|
||||
F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e
|
||||
F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b
|
||||
F ext/fts1/ft_hash.h 06df7bba40dadd19597aa400a875dbc2fed705ea
|
||||
@@ -120,7 +103,7 @@ F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3
|
||||
F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004
|
||||
F ext/fts3/fts3_unicode.c de426ff05c1c2e7bce161cf6b706638419c3a1d9c2667de9cb9dc0458c18e226
|
||||
F ext/fts3/fts3_unicode2.c 416eb7e1e81142703520d284b768ca2751d40e31fa912cae24ba74860532bf0f
|
||||
F ext/fts3/fts3_write.c 85279b980f99253c296006503a13f92957ec49b716123083f021acc74545ecfc
|
||||
F ext/fts3/fts3_write.c 3109c1a232da86474e196cc7db754445a354409f141e08cb11c846cdb17bdf31
|
||||
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
|
||||
F ext/fts3/tool/fts3cov.sh c331d006359456cf6f8f953e37f2b9c7d568f3863f00bb5f7eb87fea4ac01b73
|
||||
F ext/fts3/tool/fts3view.c 413c346399159df81f86c4928b7c4a455caab73bfbc8cd68f950f632e5751674
|
||||
@@ -503,17 +486,17 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 0390ca1d69ec3626cfa9f153114b7ab233e6b2bada6a9eb91361ed385fe90deb
|
||||
F src/alter.c 9395ece9850ad57c6fbb453aeb5185be4bae3b159c4b37611425c565124ee849
|
||||
F src/analyze.c aabdf3769c7fd9954a8ec508eb7041ae174b66f88d12c47199fabbea9a646467
|
||||
F src/attach.c 4431f82f0247bf3aaf91589acafdff77d1882235c95407b36da1585c765fbbc8
|
||||
F src/auth.c f4fa91b6a90bbc8e0d0f738aa284551739c9543a367071f55574681e0f24f8cf
|
||||
F src/backup.c a2891172438e385fdbe97c11c9745676bec54f518d4447090af97189fd8e52d7
|
||||
F src/bitvec.c 7c849aac407230278445cb069bebc5f89bf2ddd87c5ed9459b070a9175707b3d
|
||||
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
||||
F src/btree.c 6f12c520c386fa56b16c2db67de6227786ca811d9c8b0e83b6a8829a10cb0d38
|
||||
F src/btree.c df695e953c2ce78ce4878ee5016751df9bc9a921dc0500a0f53ab3bb3196e505
|
||||
F src/btree.h 74d64b8f28cfa4a894d14d4ed64fa432cd697b98b61708d4351482ae15913e22
|
||||
F src/btreeInt.h 8ce1332edd89dfd2461d561ac10a0ab5601c8e06200cb5230596c3caaf54482e
|
||||
F src/build.c 23f874642825d7eaaeeb7a3281b2b1a75e1d4c4dd9ae4dceddcd908266634214
|
||||
F src/build.c e8e776b52bc145cbf4e9fb88b99830083880fc2b174c2f96518fff15cbc72396
|
||||
F src/callback.c 4c19af69835787bfe790ac560f3071a824eb629f34e41f97b52ce5235c77de1c
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 026dbdcdbd8c3cde98a88483ee88310ff43150ab164ad768f12cc700a11495ad
|
||||
@@ -521,10 +504,10 @@ F src/date.c 15082566229d4b1e5f24fdb490bf9bcc68824b911d70e3573ef075a1b9e2d26f
|
||||
F src/dbpage.c 90661a87e1db8bfbc8d2ebbdcd3749651ddb287c555c07a28fb17c7c591ffb68
|
||||
F src/dbstat.c 861e08690fcb0f2ee1165eff0060ea8d4f3e2ea10f80dab7d32ad70443a6ff2d
|
||||
F src/delete.c a8e844af211a48b13b5b358be77a12c860c6a557c21990ad51a548e2536500ce
|
||||
F src/expr.c 69c833a8faa081f1a97c17cc40db15fd5295647b4885fa5d3efe93a46fc21a3b
|
||||
F src/expr.c d8c520edd0edf0b9c0ca467aa44c864ff17f265fd1cebbd224b6d5c625b638c3
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c d965ede15d8360c09ed59348940649ee647b192e784466837d7aefa836d1d91e
|
||||
F src/func.c 8f72e88cccdee22185133c10f96ccd61dc34c5ea4b1fa9a73c237ef59b2e64f1
|
||||
F src/func.c a3407a6fbb0d4088d8d502e46f0ace63e0aeae7467ae23a9ca9815bbf9239761
|
||||
F src/global.c e83ee571b79ee3adc32e380cf554cf1254bc43763d23786c71721fbcdfbbb965
|
||||
F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
|
||||
F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
|
||||
@@ -533,8 +516,8 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c 173845e5a6bac96ae937409e4f876b631f26b31dabb9df8fd0eb3b130b2bb3a7
|
||||
F src/json.c 7749b98c62f691697c7ee536b570c744c0583cab4a89200fdd0fc2aa8cc8cbd6
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 853385cc7a604157e137585097949252d5d0c731768e16b044608e5c95c3614b
|
||||
F src/main.c e946f1d9e30bf49cf399ddf860cfd2319e3a97bbaabfb8e87d6ab985a20d54ad
|
||||
F src/loadext.c 0705c2747212934183398f09891415d2f7f3113d0f543ccb205640210b20e617
|
||||
F src/main.c 135858d2ede0b83d779e71b07ede9c1d6b6eaab7b77bc2a85729584152769faf
|
||||
F src/malloc.c a9127efdcef92d6934c6339ea9813075b90edc0ce2e5c723556381a3828fb720
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
||||
@@ -551,39 +534,39 @@ F src/mutex_unix.c dd2b3f1cc1863079bc1349ac0fec395a500090c4fe4e11ab775310a49f2f9
|
||||
F src/mutex_w32.c caa50e1c0258ac4443f52e00fe8aaea73b6d0728bd8856bedfff822cae418541
|
||||
F src/notify.c 89a97dc854c3aa62ad5f384ef50c5a4a11d70fcc69f86de3e991573421130ed6
|
||||
F src/os.c b1c4f2d485961e9a5b6b648c36687d25047c252222e9660b7cc25a6e1ea436ab
|
||||
F src/os.h 1ff5ae51d339d0e30d8a9d814f4b8f8e448169304d83a7ed9db66a65732f3e63
|
||||
F src/os.h 26890f540b475598cd9881dcc68931377b8d429d3ea3e2eeb64470cde64199f8
|
||||
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
|
||||
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
|
||||
F src/os_unix.c 2df2b33db88f00af13805d4573ee126bc5973f9e3b91d03c575fa7ba64e7dc41
|
||||
F src/os_unix.c 1f71ec8c87621f75c9c5ea973f5e8ce2f1d23fe760c01ed2814fe4b98b639825
|
||||
F src/os_win.c a8ea80037e81127ca01959daa87387cc135f325c88dc745376c4f760de852a10
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c 42120492784fc9bcd9082b5c9b5e329b7318c357f9f3574a1bbfcf7418910356
|
||||
F src/pager.h f82e9844166e1585f5786837ddc7709966138ced17f568c16af7ccf946c2baa3
|
||||
F src/parse.y 8e67d820030d2655b9942ffe61c1e7e6b96cea2f2f72183533299393907d0564
|
||||
F src/parse.y b86d56b446afb9c203d8354dc6c422818a62b4bbab52b76ab3da06d7b1d07e44
|
||||
F src/pcache.c 084e638432c610f95aea72b8509f0845d2791293f39d1b82f0c0a7e089c3bb6b
|
||||
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
|
||||
F src/pcache1.c 54881292a9a5db202b2c0ac541c5e3ef9a5e8c4f1c1383adb2601d5499a60e65
|
||||
F src/pragma.c d1aead03e8418ff586c7cfca344c50a914b8eb06abd841e8e91a982d823671da
|
||||
F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
|
||||
F src/prepare.c c62820c15dcb63013519c8e41d9f928d7478672cc902cfd0581c733c271dbf45
|
||||
F src/printf.c 6166a30417b05c5b2f82e1f183f75faa2926ad60531c0b688a57dbc951441a20
|
||||
F src/prepare.c fd940149c691684e7c1073c3787a7170e44852b02d1275d2e30a5b58e89cfcaf
|
||||
F src/printf.c 512574910a45341c8ad244bd3d4939968ebdfde215645b676fff01cc46e90757
|
||||
F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c
|
||||
F src/resolve.c a4eb3c617027fd049b07432f3b942ea7151fa793a332a11a7d0f58c9539e104f
|
||||
F src/resolve.c f72bb13359dd5a74d440df25f320dc2c1baff5cde4fc9f0d1bc3feba90b8932a
|
||||
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
|
||||
F src/select.c 8b98d3e5511d2789880ea4a12a4637803f69db5df04c81e1e93a5aac75c89b2a
|
||||
F src/shell.c.in 5d5f27f88c4661b2b6e6859890e9c7fe00eac9a628743a12c44632705fc38309
|
||||
F src/sqlite.h.in 172528c287399a34f188154017b7268bf82c6d5b780902e361958d2318c4e37c
|
||||
F src/select.c cc1a7581403fc074eee85283ba8d81de50a831ae175cb65a5751be00f621c0d5
|
||||
F src/shell.c.in ae0a6fae983caac6f8c824733f0599dfdf7b3a7e8efdef3cb5e3ab2e457ffc35
|
||||
F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h a988810c9b21c0dc36dc7a62735012339dc76fc7ab448fb0792721d30eacb69d
|
||||
F src/sqliteInt.h bc88540ae44fa1a88c41b94bea247ff16709e95f0a81a1382a629e71f6b28426
|
||||
F src/sqlite3ext.h f49e28c25bd941e79794db5415fdf7b202deb3bc072ed6f1ed273d578703684e
|
||||
F src/sqliteInt.h 4092f9f2395909ebf7da0a6e9907e92883cf98656bb751e1d919d2a0e475ae70
|
||||
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
|
||||
F src/status.c 4a3da6d77eeb3531cb0dbdf7047772a2a1b99f98c69e90ce009c75fe6328b2c0
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
F src/tclsqlite.c 4e64ba300a5a26e0f1170e09032429faeb65e45e8f3d1a7833e8edb69fc2979e
|
||||
F src/tclsqlite.c 1f6673991147bc2cecc08a40d22f9803b84c805b24b499fe727f392256f73474
|
||||
F src/test1.c 1356984e97bff07e4a8cc3863e892f05b3348678a74783bb6f350b76316736f1
|
||||
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
|
||||
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
|
||||
F src/test4.c 4533b76419e7feb41b40582554663ed3cd77aaa54e135cf76b3205098cd6e664
|
||||
F src/test4.c 7c4420e01c577b5c4add2cb03119743b1a357543d347773b9e717195ea967159
|
||||
F src/test5.c 328aae2c010c57a9829d255dc099d6899311672d
|
||||
F src/test6.c ae73a3a42bbc982fb9e301b84d30bda65a307be48c6dff20aba1461e17a9b0ce
|
||||
F src/test7.c 5612e9aecf934d6df7bba6ce861fdf5ba5456010
|
||||
@@ -635,18 +618,18 @@ F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c a38f52058b517929e264094abd0b5fd1e8e145a1aa43bc6f6a72ae5218f96c98
|
||||
F src/treeview.c 73facf395c8841653b9a54e789d8c80e15bc3d0d1cb9d16104c2d889c15e33cd
|
||||
F src/trigger.c 61bea163b1fa3039bc572ed8312461b978e5c527e5301f302b078f4c1ccdec6a
|
||||
F src/treeview.c 7dd99cf420137d658492bbf3601d55fce9c34d4788606f43d83937b73474769c
|
||||
F src/trigger.c 372ada38f667c6823a3db15749eb668338e65c793394e55a37e56a489f2d1b55
|
||||
F src/update.c 2cfaded82ca80ff56afb8c3ae5e88284e0824bfd86119827cc22481959f96f92
|
||||
F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937
|
||||
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
|
||||
F src/util.c 602fe229f32a96ceccae4f40824129669582096f7c355f53dbac156c9fecef23
|
||||
F src/vacuum.c bb346170b0b54c6683bba4a5983aea40485597fdf605c87ec8bc2e199fe88cd8
|
||||
F src/vdbe.c a6a20956fa128c0b8d3c5592a9a3db890a46cf626f46ffee0cab2ac5bf8d04b2
|
||||
F src/vdbe.h 07641758ca8b4f4c6d81ea667ea167c541e6ece21f5574da11e3d21ec37e2662
|
||||
F src/vacuum.c 6c38ddc52f0619865c91dae9c441d4d48bf3040d7dc1bc5b22da1e45547ed0b3
|
||||
F src/vdbe.c 9527ab7f71c5b0291e5ed7727f213f4d7f6e0a82af019da5b365fd5a0f56bb96
|
||||
F src/vdbe.h 76eb1b3d84173e7f39fa236c03537aacdb53bc0c7ce21d8fd10cf1be9830ffe6
|
||||
F src/vdbeInt.h ef43f7fdc5fde29fc3fd29c506c12830f366178fdb4edbbf0cbc3dfbd1278b5f
|
||||
F src/vdbeapi.c 354c893f1500cf524cc45c32879b9c68893a28b77e3442c24668d6afe4236217
|
||||
F src/vdbeaux.c 75c4f75ed7e1d12eb3d80093a160ec998c839f3008a1c3c967fc5acf522d0e3c
|
||||
F src/vdbeaux.c 9279cb71557235d6bf0fcda139a1c8a773ad5542bcec27c6591320cc9027970f
|
||||
F src/vdbeblob.c 5e61ce31aca17db8fb60395407457a8c1c7fb471dde405e0cd675974611dcfcd
|
||||
F src/vdbemem.c 7189090b72baa025f945a1ac8c61ee420c645254476e8a191d555db76dfea5d4
|
||||
F src/vdbesort.c 43756031ca7430f7aec3ef904824a7883c4ede783e51f280d99b9b65c0796e35
|
||||
@@ -657,11 +640,11 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d
|
||||
F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
|
||||
F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b
|
||||
F src/where.c 3a69f4403aa994cda45db8f4070d146d8f253f9850b4c827a9ade7d444f889ea
|
||||
F src/whereInt.h b48ca529ffe293c18cbfa8326af18a09e39910de66fb3e96ef788c7cbf8ef3a7
|
||||
F src/wherecode.c 0b09abfcb88c61c6a6984a3e065786631ff35495e9bdf865e6b74ab0a1299c5b
|
||||
F src/whereexpr.c 20255cf03e0b765b742301197d165511ff99e95da0d7ee9c8a2ebc1e888dd049
|
||||
F src/window.c fff1b51757438c664e471d5184634e48dcdf8ea34b640f3b1b0810b1e06de18c
|
||||
F src/where.c 43085b3a4ce2e56315fabb0b240a56e76667d9e03c79f287695bcae7b76152d5
|
||||
F src/whereInt.h 4db5a877a9d1f38b5c928c1c84297c07f30b9a3bc1f5f66214cf1a8ef90a0556
|
||||
F src/wherecode.c 96b342445146c0352a55924d9c3509b66b6284fa246dd276ca7599cf4637ab50
|
||||
F src/whereexpr.c 174d4ad5be165c610c907abb779ef4a97974d22b84e1ce7898d2d9f6947249e5
|
||||
F src/window.c 924e04fd6e0e113d4dba18b78d43fcb8e42b8ebffc8fc728da52cf3ab014cf3c
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
|
||||
F test/affinity3.test b5c19d504dec222c0dc66642673d23dce915d35737b68e74d9f237b80493eb53
|
||||
@@ -683,12 +666,11 @@ F test/alterfault.test 289067108947bedca27534edd4ff251bcd298cf84402d7b24eaa37493
|
||||
F test/alterlegacy.test f38c6d06cda39e1f7b955bbce57f2e3ef5b7cb566d3d1234502093e228c15811
|
||||
F test/altermalloc.test 167a47de41b5c638f5f5c6efb59784002b196fff70f98d9b4ed3cd74a3fb80c9
|
||||
F test/altermalloc2.test 17fb3724c4b004c469c27dc4ef181608aa644555fbd3f3236767584f73747c81
|
||||
F test/altermalloc3.test 8531b3086f0a7889f43971a579a8c81832d5123f4703d8c86b89ba1136c63b9a
|
||||
F test/altermalloc3.test 55e606edf4b0acfbbd851ddfe93cfdddfae43d103644dcfd6008ae4ab3c44adf
|
||||
F test/alterqf.test ff6c6f881485c29ed699b8ef4774864ca1b0c01a6c08f5cdd624a008e4b40fca
|
||||
F test/altertab.test 7273b8506eab46342be016af78028df49f3bd99037412f997a8f1011b37a6912
|
||||
F test/altertab2.test 62597b6fd08feaba1b6bfe7d31dac6117c67e06dc9ce9c478a3abe75b5926de0
|
||||
F test/altertab3.test 6c432fbb9963e0bd6549bf1422f6861d744ee5a80cb3298564e81e556481df16
|
||||
F test/altertrig.test fb5951d21a2c954be3b8a8cf8e10b5c0fa20687c53fd67d63cea88d08dd058d5
|
||||
F test/altertab3.test 8af5c6eb4a7dd2fc73235b865b53561bf07428d1d6a9cd59a067abf51141891e
|
||||
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
|
||||
F test/analyze.test 547bb700f903107b38611b014ca645d6b5bb819f5210d7bf39c40802aafeb7d7
|
||||
F test/analyze3.test 4440c4932247adb2b4e0c838f657c19dc7af4f56859255436dc4e855f39b9324
|
||||
@@ -697,7 +679,7 @@ F test/analyze5.test fa5131952303ac4146aba101b116b9c8cb89e2637531c334a6df7f7d19d
|
||||
F test/analyze6.test 028f5bdfc9e5b5294768fa9a7185b8cd1d019aa7aab5b2f8ee42d7271d9a3b28
|
||||
F test/analyze7.test 079d17c495e396bdbd6cc6a083112788a6fbfb3b95c42e760e4270a53c9ead8f
|
||||
F test/analyze8.test 29ef237d8a59b39cc31c3310134fefe96a690b195e3deed5ecb652839089f15c
|
||||
F test/analyze9.test 30e1cb99336045a384a11d97900720184333c88174b3b89bc07444ea39e7df19
|
||||
F test/analyze9.test 162cd40d713310fbe7a63a5ecff5d3a013777d86809618838177d9b2af4dd09c
|
||||
F test/analyzeC.test 1111830ad355d29a294a5dda654dd5f6a8622c6a223a4f7b7b3d091df7a7a42b
|
||||
F test/analyzeD.test 485f621cfd2ef0a8f8ac79672586651bfa495bd899db50461bb4b558400ab3c1
|
||||
F test/analyzeE.test 69d130f9ba78c9853dcd5a18317e81f462a72d704cec0c4c30afb220213acd29
|
||||
@@ -897,7 +879,7 @@ F test/e_fts3.test 17ba7c373aba4d4f5696ba147ee23fd1a1ef70782af050e03e262ca187c5e
|
||||
F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e
|
||||
F test/e_reindex.test 2b0e29344497d9a8a999453a003cb476b6b1d2eef2d6c120f83c2d3a429f3164
|
||||
F test/e_resolve.test a61751c368b109db73df0f20fc75fb47e166b1d8
|
||||
F test/e_select.test 89fa483f68d868f1be3d6f56180ed42d979979c266e051bf8b5e66a251e6b44a
|
||||
F test/e_select.test 9b7ca08975c5444844b35ee60e09f973787a9f3317719715e8e6669abdf6aba2
|
||||
F test/e_select2.test aceb80ab927d46fba5ce7586ebabf23e2bb0604f
|
||||
F test/e_totalchanges.test c927f7499dc3aa28b9b556b7d6d115a2f0fe41f012b128d16bf1f3b30e9b41e4
|
||||
F test/e_update.test f46c2554d915c9197548681e8d8c33a267e84528
|
||||
@@ -919,7 +901,7 @@ F test/exclusive.test 7ff63be7503990921838d5c9f77f6e33e68e48ed1a9d48cd28745bf650
|
||||
F test/exclusive2.test 984090e8e9d1b331d2e8111daf6e5d61dda0bef7
|
||||
F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
|
||||
F test/exists.test 79a75323c78f02bbe9c251ea502a092f9ef63dac
|
||||
F test/expr.test 5c06696478212e5a04e04b043f993373f6f8e5ce5a80f5548a84703b123b6caa
|
||||
F test/expr.test e1afcdb1038e4d3fa67a3df323347c38750946e2e1b4e385bdc75d26284f2dac
|
||||
F test/expr2.test c27327ae9c017a7ff6280123f67aff496f912da74d78c888926d68b46ec75fd8
|
||||
F test/exprfault.test 497cc0b8fe6a677f49b55cb485e040f709ec2834b84f25912fe9c2dfeeda33db
|
||||
F test/extension01.test 00d13cec817f331a687a243e0e5a2d87b0e358c9
|
||||
@@ -1003,12 +985,12 @@ F test/fts3b.test c15c4a9d04e210d0be67e54ce6a87b927168fbf9c1e3faec8c1a732c366fd4
|
||||
F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958
|
||||
F test/fts3comp1.test a0f5b16a2df44dd0b15751787130af2183167c0c
|
||||
F test/fts3conf.test c84bbaec81281c1788aa545ac6e78a6bd6cde2bdbbce2da261690e3659f5a76b
|
||||
F test/fts3corrupt.test 6732477c5ace050c5758a40a8b5706c8c0cccd416b9c558e0e15224805a40e57
|
||||
F test/fts3corrupt.test 43c6c89b994e90997590ece4dfa9c9325c9b61cddd7c97e158498da8b1de79f8
|
||||
F test/fts3corrupt2.test e318f0676e5e78d5a4b702637e2bb25265954c08a1b1e4aaf93c7880bb0c67d0
|
||||
F test/fts3corrupt3.test 0d5b69a0998b4adf868cc301fc78f3d0707745f1d984ce044c205cdb764b491f
|
||||
F test/fts3corrupt4.test 799ff994b964fed7201be6b6b62c7ff2ef7bb3da6c02b9eaf0d96a5a4d9b6ca3
|
||||
F test/fts3corrupt5.test 0549f85ec4bd22e992f645f13c59b99d652f2f5e643dac75568bfd23a6db7ed5
|
||||
F test/fts3corrupt6.test f417c910254f32c0bc9ead7affa991a1d5aec35b3b32a183ffb05eea78289525
|
||||
F test/fts3corrupt6.test 657b4b8e5791d8d4adc93c90588fb25f1c7346544dd877c6c298a0746749146d
|
||||
F test/fts3cov.test 7eacdbefd756cfa4dc2241974e3db2834e9b372ca215880e00032222f32194cf
|
||||
F test/fts3d.test 2bd8c97bcb9975f2334147173b4872505b6a41359a4f9068960a36afe07a679f
|
||||
F test/fts3defer.test f4c20e4c7153d20a98ee49ee5f3faef624fefc9a067f8d8d629db380c4d9f1de
|
||||
@@ -1076,7 +1058,7 @@ F test/func3.test 600a632c305a88f3946d38f9a51efe145c989b2e13bd2b2a488db47fe76bab
|
||||
F test/func4.test 2285fb5792d593fef442358763f0fd9de806eda47dbc7a5934df57ffdc484c31
|
||||
F test/func5.test 863e6d1bd0013d09c17236f8a13ea34008dd857d87d85a13a673960e4c25d82a
|
||||
F test/func6.test 9cc9b1f43b435af34fe1416eb1e318c8920448ea7a6962f2121972f5215cb9b0
|
||||
F test/func7.test adbfc910385a6ffd15dc47be3c619ef070c542fcb7488964badb17b2d9a4d080
|
||||
F test/func7.test b9e2a1a30a8562b00841b4a21a5d2d81754fa3ab99275fd71fd5279287b44b1c
|
||||
F test/fuzz-oss1.test 514dcabb24687818ea949fa6760229eaacad74ca70157743ef36d35bbe01ffb0
|
||||
F test/fuzz.test 4608c1310cff4c3014a84bcced6278139743e080046e5f6784b0de7b069371d8
|
||||
F test/fuzz2.test 76dc35b32b6d6f965259508508abce75a6c4d7e1
|
||||
@@ -1107,7 +1089,7 @@ F test/hook2.test b9ff3b8c6519fb67f33192f1afe86e7782ee4ac8
|
||||
F test/icu.test 716a6b89fbabe5cc63e0cd4c260befb08fd7b9d761f04d43669233292f0753b1
|
||||
F test/ieee754.test b0945d12be7d255f3dfa18e2511b17ca37e0edd2b803231c52d05b86c04ab26e
|
||||
F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8
|
||||
F test/in.test 55503d3633c434120d8b2d5966a34f0d9a55393a589050b1366afe4b188093c7
|
||||
F test/in.test 15de58ee017f43d36390812e9a51217d1b2db7758f97d0df48296ef178ea560b
|
||||
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
|
||||
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
|
||||
F test/in4.test fdd1d8134da8376985c2edba6035a2de1f6c731524d2ffa651419e8fe2cd1c5a
|
||||
@@ -1115,7 +1097,7 @@ F test/in5.test b32ce7f4a93f44c5dee94af16886d922cc16ebe33c8e1765c73d4049d0f4b40f
|
||||
F test/in6.test f5f40d6816a8bb7c784424b58a10ac38efb76ab29127a2c17399e0cbeeda0e4b
|
||||
F test/incrblob.test c9b96afc292aeff43d6687bcb09b0280aa599822
|
||||
F test/incrblob2.test a494c9e848560039a23974b9119cfc2cf3ad3bd15cc2694ee6367ae537ef8f1f
|
||||
F test/incrblob3.test 67621a04b3084113bf38ce03797d70eca012d9d8f948193b8f655df577b0da6f
|
||||
F test/incrblob3.test d47be78a46da142dd60b93772db6e03936a8a36a3b6129dff8d11923dfdc6d63
|
||||
F test/incrblob4.test 21a52a6843a56cdcce968c6a86b72a7066d0e6ba
|
||||
F test/incrblob_err.test 89372a28f1d98254f03fed705f9efcd34ef61a674df16d2dbb4726944a2de5e9
|
||||
F test/incrblobfault.test de274b1e329169c2c3438f9528994807ea8201ebf38ae9f157d34bf3ec0cc549
|
||||
@@ -1159,21 +1141,17 @@ F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
|
||||
F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4
|
||||
F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b
|
||||
F test/istrue.test e7f285bb70282625c258e866ce6337d4c762922f5a300e1b50f958aef6e7d9c9
|
||||
F test/join.test edeaff6edc1c1a2bcfebee343744e04d000f861c3d67cb653114f88565f8c955
|
||||
F test/join.test e5f165dfd84fd46406ddae6614b0122c3bfa23a26ef62966442e1503c40d96aa
|
||||
F test/join2.test 466b07233820f5deee66a6c3bf6e4500c8bbf7b83649e67606f5f649c07928c0
|
||||
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
|
||||
F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
|
||||
F test/join5.test d22b6cba8fb59ab3f1c82701434c360705eb12d4ce200c449f37b018fc47681a
|
||||
F test/join5.test c4df54e2e204d7f1417bfbdd21ca324b4b07415c647595cc47798eacfddc96d3
|
||||
F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c
|
||||
F test/join7.test 2268dcbb54b724391dda3748ea95c60d960607ffeed67885675998e7117697f6
|
||||
F test/join8.test 01c46c005f3cd20f530e1b7e17d003a1e6d16ae945ceca395f6c016bbee92e9f
|
||||
F test/join7.test 8e72de4b45e5e930d18c305c7efe86015fb2552731e4e03ea226353036b0dab0
|
||||
F test/join8.test 9a4b2f53d5358abb29e6356e357c0cd40f4d8f282589300dcb76728dce050b51
|
||||
F test/join9.test 9056ddd3b0c0f4f9d658f4521038d9a37dc23ead8ca9a505d0b0db2b6a471e05
|
||||
F test/joinA.test 7eab225dc1c1ab258a5e62513a4ed7cabbd3db971d59d5d92f4fb6fa14c12f6a
|
||||
F test/joinB.test 1b2ba3fc8568b49411787fccbf540570c148e9b6a53a30f80691cb6268098ded
|
||||
F test/joinC.test 1f1a602c2127f55f136e2cbd3bf2d26546614bf8cffe5902ec1ac9c07f87f207
|
||||
F test/joinD.test 1a430af8dac5b68663f13df534ffe98775e582bac2305b80f1e8eb4ab778672a
|
||||
F test/joinE.test d5d182f3812771e2c0d97c9dcf5dbe4c41c8e21c82560e59358731c4a3981d6b
|
||||
F test/joinF.test 53dd66158806823ea680dd7543b5406af151b5aafa5cd06a7f3231cd94938127
|
||||
F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497
|
||||
F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4
|
||||
F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e
|
||||
@@ -1314,7 +1292,7 @@ F test/parser1.test 6ccdf5e459a5dc4673d3273dc311a7e9742ca952dd0551a6a6320d27035c
|
||||
F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b
|
||||
F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
|
||||
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
|
||||
F test/permutations.test cf5f31bab83a452288b2a050880152cdf99d62e9aab71948268d549debcc6942
|
||||
F test/permutations.test 68b6dcd2667acdc643140d502c0b6c503abe444495cf5d16aa3a4f0391604020
|
||||
F test/pg_common.tcl 3b27542224db1e713ae387459b5d117c836a5f6e328846922993b6d2b7640d9f
|
||||
F test/pragma.test cae534c12a033a5c319ccc94f50b32811acdef9f67bf19a82ff42697caccd69f
|
||||
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
|
||||
@@ -1354,9 +1332,9 @@ F test/round1.test 768018b04522ca420b1aba8a24bd76091d269f3bce3902af3ec6ebcee41ab
|
||||
F test/rowallock.test 3f88ec6819489d0b2341c7a7528ae17c053ab7cc
|
||||
F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81
|
||||
F test/rowid.test e29025be95baf6b32f0d5edef59a7633028325896a98f1caa8019559ca910350
|
||||
F test/rowvalue.test ff1ffa31cebe12feb6f989e09263f3b1e8c560db94b40fe006126a8435fd6832
|
||||
F test/rowvalue.test 228b312f8526ed000ecda559a6a9adf30aa2d79dcb12afa5c04eebaafcf55eae
|
||||
F test/rowvalue2.test 060d238b7e5639a7c5630cb5e63e311b44efef2b
|
||||
F test/rowvalue3.test 1347e25ca11c547c5a6ff0cc5626f95aa9740e9275bfaec096029f57cb2130ce
|
||||
F test/rowvalue3.test 3068f508753af69884b12125995f023da0dbb256
|
||||
F test/rowvalue4.test 441e7e366ac6d939a3a95a574031c56ec2a854077a91d66eee5ff1d86cb5be58
|
||||
F test/rowvalue5.test 00740304ea6a53a8704640c7405690f0045d5d2a6b4b04dde7bccc14c3068ea7
|
||||
F test/rowvalue6.test d19b54feb604d5601f8614b15e214e0774c01087
|
||||
@@ -1417,14 +1395,14 @@ F test/sharedA.test 49d87ec54ab640fbbc3786ee3c01de94aaa482a3a9f834ad3fe92770eb69
|
||||
F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e
|
||||
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
|
||||
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
|
||||
F test/shell1.test e4b4de56f454708e0747b52915135baa2cbfec4965406d6eaf02a4a5c22a9880
|
||||
F test/shell2.test c536c2aab4852608f8a606262330797abc4d964a4c2c782a7760f54ea1f17a6a
|
||||
F test/shell3.test 91febeac0412812bf6370abb8ed72700e32bf8f9878849414518f662dfd55e8a
|
||||
F test/shell4.test 7dc8a515705bc093d8ffe381670e8fa7a969661e8ed177c35c847e3c6dfc35e2
|
||||
F test/shell5.test c8b6c54f26ec537f8558273d7ed293ca3725ef42e6b12b8f151718628bd1473b
|
||||
F test/shell1.test f7a2ef8260aa01f20be3185118213b1ae70518fdcd2105f3e25b021b5ca800ac
|
||||
F test/shell2.test 7a3a23a9f57b99453f1679b1fe8072cb30e382a622874c0c4d97695fadb0a787
|
||||
F test/shell3.test a50628ab1d78d90889d9d3f32fb2c084ee15674771e96afe954aaa0accd1de3c
|
||||
F test/shell4.test 8f6c0fce4abed19a8a7f7262517149812a04caa905d01bdc8f5e92573504b759
|
||||
F test/shell5.test 78a7a8516b1e7de560748881424f621321549023d3e5f7ed2e1c56497f64c06c
|
||||
F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3
|
||||
F test/shell7.test 115132f66d0463417f408562cc2cf534f6bbc6d83a6d50f0072a9eb171bae97f
|
||||
F test/shell8.test 3fd093d481aaa94dc77fb73f1044c1f19c7efe3477a395cc4f7450133bc54915
|
||||
F test/shell8.test 388471d16e4de767333107e30653983f186232c0e863f4490bb230419e830aae
|
||||
F test/shmlock.test 3dbf017d34ab0c60abe6a44e447d3552154bd0c87b41eaf5ceacd408dd13fda5
|
||||
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
|
||||
@@ -1482,7 +1460,7 @@ F test/subtype1.test 7fe09496352f97053af1437150751be2d0a0cae8
|
||||
F test/superlock.test ec94f0556b6488d97f71c79f9061ae08d9ab8f12
|
||||
F test/swarmvtab.test 250231404fcac88f61a6c147bb0e3a118ed879278cd3ccb0ae2d3a729e1e8e26
|
||||
F test/swarmvtab2.test c948cb2fdfc5b01d85e8f6d6504854202dc1a0782ab2a0ed61538f27cbd0aa5c
|
||||
F test/swarmvtab3.test 41a3ab47cb7a834d4e5336425103b617410a67bb95d335ef536f887587ece073
|
||||
F test/swarmvtab3.test 247aa38b6ebd2b99db2075847ae47e789ac34f1c2ab5c720dfcffd990004c544
|
||||
F test/swarmvtabfault.test 8a67a9f27c61073a47990829e92bc0c64420a807cb642b15a25f6c788210ed95
|
||||
F test/symlink.test 72b22238d4405ba34df8e60b335d290a3b1129fd5c260835c944c1e4e77288a9
|
||||
F test/symlink2.test 9531f475a53d8781c4f81373f87faf2e2aff4f5fb2102ec6386e0c827916a670
|
||||
@@ -1502,7 +1480,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
|
||||
F test/temptable2.test d2940417496e2b9548e01d09990763fbe88c316504033256d51493e1f1a5ce6a
|
||||
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
|
||||
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
|
||||
F test/tester.tcl 76771269dcc20b2c2d1d6f1175dd50d1eebddc004aebac865483f1829a5cd398
|
||||
F test/tester.tcl 18448c7801d44cc5f2690f54f803da49ed994b3968f73a393cff329e55926679
|
||||
F test/thread001.test b61a29dd87cf669f5f6ac96124a7c97d71b0c80d9012746072055877055cf9ef
|
||||
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
@@ -1711,7 +1689,6 @@ F test/upfrom1.tcl 8859d9d437f03b44174c4524a7a734a391fd4526fcff65be08285dafc9dc9
|
||||
F test/upfrom1.test 8cb06689e99cd707d884faa16da0e8eb26ff658bb01c47ddf72fadade666e6e1
|
||||
F test/upfrom2.test 66f3ebf721b3cebd922faee5c386bf244f816d416b57c000753ff51af62328a1
|
||||
F test/upfrom3.test 6130f24ebf97f5ea865e5d2a14a2d543fe5428a62e87cc60f62d875e45c1f5f0
|
||||
F test/upfrom4.test 1cd82e9423e02b1f63d069e8665c6c3932ec424fd0043d033cc0ba99abf33236
|
||||
F test/upfromfault.test 3a10075a0043f0c4fad6614b2c371f88a8ba5a4acab68b907438413865d6a8d6
|
||||
F test/upsert1.test b0ae2f58680c5205b4bc1cdeed3c3d444057c506f6c44494fa3eac60731d68a2
|
||||
F test/upsert2.test 720e94d09f7362a282bc69b3c6b83d51daeaaf0440eb4920a08b86518b8c7496
|
||||
@@ -1740,7 +1717,7 @@ F test/vtab2.test 14d4ab26cee13ba6cf5c5601b158e4f57552d3b055cdd9406cf7f711e9c840
|
||||
F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e
|
||||
F test/vtab4.test 8e73ed268f3d596bc3590f45fc948fb40f28e9c3
|
||||
F test/vtab5.test 889f444970393c73f1e077e2bdc5d845e157a391
|
||||
F test/vtab6.test 2525a2fe2e44ccbed1d758cb2977fb8ab8f07d5312ed8d8799d3529647d11f2f
|
||||
F test/vtab6.test fa609a4af96da30beceefa3cb624abe9be38c4747ab373d98179b24027d6b798
|
||||
F test/vtab7.test 70c6f4a1d6177144a8236e4172d5fba92e683440374664ad1f04851fbb335d3c
|
||||
F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583
|
||||
F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b
|
||||
@@ -1798,7 +1775,7 @@ F test/walthread.test 14b20fcfa6ae152f5d8e12f5dc8a8a724b7ef189f5d8ef1e2ceab79f2a
|
||||
F test/walvfs.test bccb3e0d235ef85e276f491d34db32c9ada1ea67be8d9f10aabe7b30319ec656
|
||||
F test/wapp.tcl b440cd8cf57953d3a49e7ee81e6a18f18efdaf113b69f7d8482b0710a64566ec
|
||||
F test/wapptest.tcl 899594e25684861d5b0c0880fb012364def50ef8097041b8ddf74be5ba7fa270 x
|
||||
F test/where.test d13cd7c24e80009d2b54e2f7a8893c457afa49c64f99359c9eb3fe668ba1d9d4
|
||||
F test/where.test 8c6bbd0cae8feae142a7946e3484a802fa566bacf38452b1c3e48cb77321f9a4
|
||||
F test/where2.test 03c21a11e7b90e2845fc3c8b4002fc44cc2797fa74c86ee47d70bd7ea4f29ed6
|
||||
F test/where3.test 5b4ffc0ac2ea0fe92f02b1244b7531522fe4d7bccf6fa8741d54e82c10e67753
|
||||
F test/where4.test 4a371bfcc607f41d233701bdec33ac2972908ba8
|
||||
@@ -1845,7 +1822,6 @@ F test/window9.test 349c71eab4288a1ffc19e2f65872ec2c37e6cf8a1dda2ad300364b7450ae
|
||||
F test/windowA.test 6d63dc1260daa17141a55007600581778523a8b420629f1282d2acfc36af23be
|
||||
F test/windowB.test f2fb42b864b0cf431c956407583e9478a74c3642bdf8737fdcb6ff4a40298b07
|
||||
F test/windowC.test 6fd75f5bb2f1343d34e470e36e68f0ff638d8a42f6aa7d99471261b31a0d42f2
|
||||
F test/windowD.test 65cf5a765fb8072450e8a0de2979ce7f09a38d87724fe1280c6444073e3da49b
|
||||
F test/windowerr.tcl f5acd6fbc210d7b5546c0e879d157888455cd4a17a1d3f28f07c1c8a387019e0
|
||||
F test/windowerr.test a8b752402109c15aa1c5efe1b93ccb0ce1ef84fa964ae1cd6684dd0b3cc1819b
|
||||
F test/windowfault.test 15094c1529424e62f798bc679e3fe9dfab6e8ba2f7dfe8c923b6248c31660a7c
|
||||
@@ -1975,9 +1951,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 2512d2f68dfff4d74c881a4102b63ca528e690ad93ab2b4eb1f03ce1d9ac155c f7c17449ea0685e322f50abe7a59b7afcde0f7e38e03645ec5b13753a6d0dcf3
|
||||
Q +04b2e47784238008ce9057e2761ded91d895dc16d3bc8a3a3508df98a4769602
|
||||
R 9207d306b462962d71351cad5c380553
|
||||
U larrybr
|
||||
Z bff0aa34a1a107fc43ee5c4bae4c5b52
|
||||
P a8da85c57e07721dc1c918d67433d6c99ce48421e369123cc3194d855e55f7e8
|
||||
R e3fbc3d41c1e378863d3a3844f4d4b19
|
||||
U drh
|
||||
Z 429a0d8657da0ac87e9e33fefb72e33d
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
268072f636b25c24ec47e34f2a8356f466ec200b80487b1041e89e0ae909c8bd
|
||||
ad32da8045e691372871a05ca49688032e9c2bab769a07da6b6cfd6186d25955
|
||||
+21
-36
@@ -880,7 +880,7 @@ static int renameUnmapSelectCb(Walker *pWalker, Select *p){
|
||||
if( ALWAYS(p->pEList) ){
|
||||
ExprList *pList = p->pEList;
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
if( pList->a[i].zEName && pList->a[i].fg.eEName==ENAME_NAME ){
|
||||
if( pList->a[i].zEName && pList->a[i].eEName==ENAME_NAME ){
|
||||
sqlite3RenameTokenRemap(pParse, 0, (void*)pList->a[i].zEName);
|
||||
}
|
||||
}
|
||||
@@ -929,7 +929,7 @@ void sqlite3RenameExprlistUnmap(Parse *pParse, ExprList *pEList){
|
||||
sWalker.xExprCallback = renameUnmapExprCb;
|
||||
sqlite3WalkExprList(&sWalker, pEList);
|
||||
for(i=0; i<pEList->nExpr; i++){
|
||||
if( ALWAYS(pEList->a[i].fg.eEName==ENAME_NAME) ){
|
||||
if( ALWAYS(pEList->a[i].eEName==ENAME_NAME) ){
|
||||
sqlite3RenameTokenRemap(pParse, 0, (void*)pEList->a[i].zEName);
|
||||
}
|
||||
}
|
||||
@@ -1087,7 +1087,7 @@ static void renameColumnElistNames(
|
||||
int i;
|
||||
for(i=0; i<pEList->nExpr; i++){
|
||||
const char *zName = pEList->a[i].zEName;
|
||||
if( ALWAYS(pEList->a[i].fg.eEName==ENAME_NAME)
|
||||
if( ALWAYS(pEList->a[i].eEName==ENAME_NAME)
|
||||
&& ALWAYS(zName!=0)
|
||||
&& 0==sqlite3_stricmp(zName, zOld)
|
||||
){
|
||||
@@ -1317,33 +1317,27 @@ static int renameResolveTrigger(Parse *pParse){
|
||||
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);
|
||||
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( db->mallocFailed ){
|
||||
if( rc==SQLITE_OK && db->mallocFailed ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
sNC.pSrcList = pSrc;
|
||||
@@ -1795,15 +1789,6 @@ static void renameTableFunc(
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -9165,7 +9165,7 @@ int sqlite3BtreeInsert(
|
||||
TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n",
|
||||
pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno,
|
||||
loc==0 ? "overwrite" : "new entry"));
|
||||
assert( pPage->isInit || CORRUPT_DB );
|
||||
assert( pPage->isInit );
|
||||
newCell = pBt->pTmpSpace;
|
||||
assert( newCell!=0 );
|
||||
if( flags & BTREE_PREFORMAT ){
|
||||
|
||||
+5
-5
@@ -1890,7 +1890,7 @@ void sqlite3AddPrimaryKey(
|
||||
pTab->keyConf = (u8)onError;
|
||||
assert( autoInc==0 || autoInc==1 );
|
||||
pTab->tabFlags |= autoInc*TF_Autoincrement;
|
||||
if( pList ) pParse->iPkSortOrder = pList->a[0].fg.sortFlags;
|
||||
if( pList ) pParse->iPkSortOrder = pList->a[0].sortFlags;
|
||||
(void)sqlite3HasExplicitNulls(pParse, pList);
|
||||
}else if( autoInc ){
|
||||
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
||||
@@ -2384,7 +2384,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
if( IN_RENAME_OBJECT ){
|
||||
sqlite3RenameTokenRemap(pParse, pList->a[0].pExpr, &pTab->iPKey);
|
||||
}
|
||||
pList->a[0].fg.sortFlags = pParse->iPkSortOrder;
|
||||
pList->a[0].sortFlags = pParse->iPkSortOrder;
|
||||
assert( pParse->pNewTable==pTab );
|
||||
pTab->iPKey = -1;
|
||||
sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0,
|
||||
@@ -3872,8 +3872,8 @@ int sqlite3HasExplicitNulls(Parse *pParse, ExprList *pList){
|
||||
if( pList ){
|
||||
int i;
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
if( pList->a[i].fg.bNulls ){
|
||||
u8 sf = pList->a[i].fg.sortFlags;
|
||||
if( pList->a[i].bNulls ){
|
||||
u8 sf = pList->a[i].sortFlags;
|
||||
sqlite3ErrorMsg(pParse, "unsupported use of NULLS %s",
|
||||
(sf==0 || sf==3) ? "FIRST" : "LAST"
|
||||
);
|
||||
@@ -4226,7 +4226,7 @@ void sqlite3CreateIndex(
|
||||
goto exit_create_index;
|
||||
}
|
||||
pIndex->azColl[i] = zColl;
|
||||
requestedSortOrder = pListItem->fg.sortFlags & sortOrderMask;
|
||||
requestedSortOrder = pListItem->sortFlags & sortOrderMask;
|
||||
pIndex->aSortOrder[i] = (u8)requestedSortOrder;
|
||||
}
|
||||
|
||||
|
||||
+42
-46
@@ -1069,7 +1069,6 @@ Expr *sqlite3ExprFunction(
|
||||
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]
|
||||
@@ -1348,7 +1347,7 @@ static int dupedExprStructSize(const Expr *p, int flags){
|
||||
nSize = EXPR_FULLSIZE;
|
||||
}else{
|
||||
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
|
||||
assert( !ExprHasProperty(p, EP_OuterON) );
|
||||
assert( !ExprHasProperty(p, EP_FromJoin) );
|
||||
assert( !ExprHasProperty(p, EP_MemToken) );
|
||||
assert( !ExprHasVVAProperty(p, EP_NoReduce) );
|
||||
if( p->pLeft || p->x.pList ){
|
||||
@@ -1629,8 +1628,12 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, const ExprList *p, int flags){
|
||||
}
|
||||
}
|
||||
pItem->zEName = sqlite3DbStrDup(db, pOldItem->zEName);
|
||||
pItem->fg = pOldItem->fg;
|
||||
pItem->fg.done = 0;
|
||||
pItem->sortFlags = pOldItem->sortFlags;
|
||||
pItem->eEName = pOldItem->eEName;
|
||||
pItem->done = 0;
|
||||
pItem->bNulls = pOldItem->bNulls;
|
||||
pItem->bUsed = pOldItem->bUsed;
|
||||
pItem->bSorterRef = pOldItem->bSorterRef;
|
||||
pItem->u = pOldItem->u;
|
||||
}
|
||||
return pNew;
|
||||
@@ -1930,16 +1933,16 @@ void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder, int eNulls){
|
||||
);
|
||||
|
||||
pItem = &p->a[p->nExpr-1];
|
||||
assert( pItem->fg.bNulls==0 );
|
||||
assert( pItem->bNulls==0 );
|
||||
if( iSortOrder==SQLITE_SO_UNDEFINED ){
|
||||
iSortOrder = SQLITE_SO_ASC;
|
||||
}
|
||||
pItem->fg.sortFlags = (u8)iSortOrder;
|
||||
pItem->sortFlags = (u8)iSortOrder;
|
||||
|
||||
if( eNulls!=SQLITE_SO_UNDEFINED ){
|
||||
pItem->fg.bNulls = 1;
|
||||
pItem->bNulls = 1;
|
||||
if( iSortOrder!=eNulls ){
|
||||
pItem->fg.sortFlags |= KEYINFO_ORDER_BIGNULL;
|
||||
pItem->sortFlags |= KEYINFO_ORDER_BIGNULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1965,7 +1968,7 @@ void sqlite3ExprListSetName(
|
||||
assert( pList->nExpr>0 );
|
||||
pItem = &pList->a[pList->nExpr-1];
|
||||
assert( pItem->zEName==0 );
|
||||
assert( pItem->fg.eEName==ENAME_NAME );
|
||||
assert( pItem->eEName==ENAME_NAME );
|
||||
pItem->zEName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n);
|
||||
if( dequote ){
|
||||
/* If dequote==0, then pName->z does not point to part of a DDL
|
||||
@@ -2000,7 +2003,7 @@ void sqlite3ExprListSetSpan(
|
||||
assert( pList->nExpr>0 );
|
||||
if( pItem->zEName==0 ){
|
||||
pItem->zEName = sqlite3DbSpanDup(db, zStart, zEnd);
|
||||
pItem->fg.eEName = ENAME_SPAN;
|
||||
pItem->eEName = ENAME_SPAN;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2174,7 +2177,7 @@ 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) ){
|
||||
if( pWalker->eCode==2 && ExprHasProperty(pExpr, EP_FromJoin) ){
|
||||
pWalker->eCode = 0;
|
||||
return WRC_Abort;
|
||||
}
|
||||
@@ -2321,10 +2324,10 @@ int sqlite3ExprIsTableConstraint(Expr *pExpr, const SrcItem *pSrc){
|
||||
return 0; /* rule (3) */
|
||||
}
|
||||
if( pSrc->fg.jointype & JT_LEFT ){
|
||||
if( !ExprHasProperty(pExpr, EP_OuterON) ) return 0; /* rule (4a) */
|
||||
if( !ExprHasProperty(pExpr, EP_FromJoin) ) return 0; /* rule (4a) */
|
||||
if( pExpr->w.iJoin!=pSrc->iCursor ) return 0; /* rule (4b) */
|
||||
}else{
|
||||
if( ExprHasProperty(pExpr, EP_OuterON) ) return 0; /* rule (5) */
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0; /* rule (5) */
|
||||
}
|
||||
return sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor); /* rules (1), (2) */
|
||||
}
|
||||
@@ -2656,7 +2659,7 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
|
||||
** all members of the RHS set, skipping duplicates.
|
||||
**
|
||||
** A cursor is opened on the b-tree object that is the RHS of the IN operator
|
||||
** and the *piTab parameter is set to the index of that cursor.
|
||||
** and pX->iTable is set to the index of that cursor.
|
||||
**
|
||||
** The returned value of this function indicates the b-tree type, as follows:
|
||||
**
|
||||
@@ -2676,10 +2679,7 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
|
||||
** If the RHS of the IN operator is a list or a more complex subquery, then
|
||||
** an ephemeral table might need to be generated from the RHS and then
|
||||
** pX->iTable made to point to the ephemeral table instead of an
|
||||
** existing table. In this case, the creation and initialization of the
|
||||
** ephmeral table might be put inside of a subroutine, the EP_Subrtn flag
|
||||
** will be set on pX and the pX->y.sub fields will be set to show where
|
||||
** the subroutine is coded.
|
||||
** existing table.
|
||||
**
|
||||
** The inFlags parameter must contain, at a minimum, one of the bits
|
||||
** IN_INDEX_MEMBERSHIP or IN_INDEX_LOOP but not both. If inFlags contains
|
||||
@@ -2740,13 +2740,12 @@ int sqlite3FindInIndex(
|
||||
){
|
||||
Select *p; /* SELECT to the right of IN operator */
|
||||
int eType = 0; /* Type of RHS table. IN_INDEX_* */
|
||||
int iTab; /* Cursor of the RHS table */
|
||||
int iTab = pParse->nTab++; /* 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
|
||||
@@ -2912,8 +2911,6 @@ int sqlite3FindInIndex(
|
||||
&& ExprUseXList(pX)
|
||||
&& (!sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2)
|
||||
){
|
||||
pParse->nTab--; /* Back out the allocation of the unused cursor */
|
||||
iTab = -1; /* Cursor is not allocated */
|
||||
eType = IN_INDEX_NOOP;
|
||||
}
|
||||
|
||||
@@ -3080,7 +3077,6 @@ void sqlite3CodeRhsOfIN(
|
||||
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;
|
||||
@@ -3955,17 +3951,7 @@ static int exprCodeInlineFunction(
|
||||
caseExpr.x.pList = pFarg;
|
||||
return sqlite3ExprCodeTarget(pParse, &caseExpr, target);
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
case INLINEFUNC_sqlite_offset: {
|
||||
Expr *pArg = pFarg->a[0].pExpr;
|
||||
if( pArg->op==TK_COLUMN && pArg->iTable>=0 ){
|
||||
sqlite3VdbeAddOp3(v, OP_Offset, pArg->iTable, pArg->iColumn, target);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default: {
|
||||
/* The UNLIKELY() function is a no-op. The result is the value
|
||||
** of the first argument.
|
||||
@@ -4504,8 +4490,20 @@ expr_code_doover:
|
||||
if( !pColl ) pColl = db->pDfltColl;
|
||||
sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ);
|
||||
}
|
||||
sqlite3VdbeAddFunctionCall(pParse, constMask, r1, target, nFarg,
|
||||
pDef, pExpr->op2);
|
||||
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
if( (pDef->funcFlags & SQLITE_FUNC_OFFSET)!=0 && ALWAYS(pFarg!=0) ){
|
||||
Expr *pArg = pFarg->a[0].pExpr;
|
||||
if( pArg->op==TK_COLUMN ){
|
||||
sqlite3VdbeAddOp3(v, OP_Offset, pArg->iTable, pArg->iColumn, target);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
sqlite3VdbeAddFunctionCall(pParse, constMask, r1, target, nFarg,
|
||||
pDef, pExpr->op2);
|
||||
}
|
||||
if( nFarg ){
|
||||
if( constMask==0 ){
|
||||
sqlite3ReleaseTempRange(pParse, r1, nFarg);
|
||||
@@ -4819,9 +4817,7 @@ int sqlite3ExprCodeRunJustOnce(
|
||||
struct ExprList_item *pItem;
|
||||
int i;
|
||||
for(pItem=p->a, i=p->nExpr; i>0; pItem++, i--){
|
||||
if( pItem->fg.reusable
|
||||
&& sqlite3ExprCompare(0,pItem->pExpr,pExpr,-1)==0
|
||||
){
|
||||
if( pItem->reusable && sqlite3ExprCompare(0,pItem->pExpr,pExpr,-1)==0 ){
|
||||
return pItem->u.iConstExprReg;
|
||||
}
|
||||
}
|
||||
@@ -4844,7 +4840,7 @@ int sqlite3ExprCodeRunJustOnce(
|
||||
p = sqlite3ExprListAppend(pParse, p, pExpr);
|
||||
if( p ){
|
||||
struct ExprList_item *pItem = &p->a[p->nExpr-1];
|
||||
pItem->fg.reusable = regDest<0;
|
||||
pItem->reusable = regDest<0;
|
||||
if( regDest<0 ) regDest = ++pParse->nMem;
|
||||
pItem->u.iConstExprReg = regDest;
|
||||
}
|
||||
@@ -4978,7 +4974,7 @@ int sqlite3ExprCodeExprList(
|
||||
for(pItem=pList->a, i=0; i<n; i++, pItem++){
|
||||
Expr *pExpr = pItem->pExpr;
|
||||
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
|
||||
if( pItem->fg.bSorterRef ){
|
||||
if( pItem->bSorterRef ){
|
||||
i--;
|
||||
n--;
|
||||
}else
|
||||
@@ -5072,8 +5068,8 @@ static void exprCodeBetween(
|
||||
** 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;
|
||||
** have to reuse the EP_FromJoin bit. Bummer. */
|
||||
pDel->flags |= EP_FromJoin;
|
||||
sqlite3ExprCodeTarget(pParse, &exprAnd, dest);
|
||||
}
|
||||
sqlite3ReleaseTempReg(pParse, regFree1);
|
||||
@@ -5603,7 +5599,7 @@ int sqlite3ExprListCompare(const ExprList *pA, const ExprList *pB, int iTab){
|
||||
int res;
|
||||
Expr *pExprA = pA->a[i].pExpr;
|
||||
Expr *pExprB = pB->a[i].pExpr;
|
||||
if( pA->a[i].fg.sortFlags!=pB->a[i].fg.sortFlags ) return 1;
|
||||
if( pA->a[i].sortFlags!=pB->a[i].sortFlags ) return 1;
|
||||
if( (res = sqlite3ExprCompare(0, pExprA, pExprB, iTab)) ) return res;
|
||||
}
|
||||
return 0;
|
||||
@@ -5758,7 +5754,7 @@ int sqlite3ExprImpliesExpr(
|
||||
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;
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ) return WRC_Prune;
|
||||
switch( pExpr->op ){
|
||||
case TK_ISNOT:
|
||||
case TK_ISNULL:
|
||||
@@ -5855,7 +5851,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
||||
** 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
|
||||
** 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
|
||||
|
||||
+4
-3
@@ -2098,11 +2098,11 @@ static void logFunc(
|
||||
switch( SQLITE_PTR_TO_INT(sqlite3_user_data(context)) ){
|
||||
case 1:
|
||||
/* Convert from natural logarithm to log base 10 */
|
||||
ans /= M_LN10;
|
||||
ans *= 1.0/M_LN10;
|
||||
break;
|
||||
case 2:
|
||||
/* Convert from natural logarithm to log base 2 */
|
||||
ans /= M_LN2;
|
||||
ans *= 1.0/M_LN2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -2241,7 +2241,8 @@ void sqlite3RegisterBuiltinFunctions(void){
|
||||
INLINE_FUNC(likelihood, 2, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
|
||||
INLINE_FUNC(likely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
|
||||
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
INLINE_FUNC(sqlite_offset, 1, INLINEFUNC_sqlite_offset, 0 ),
|
||||
{1, SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_FUNC_OFFSET|SQLITE_FUNC_TYPEOF,
|
||||
0, 0, noopFunc, 0, 0, 0, "sqlite_offset", {0} },
|
||||
#endif
|
||||
FUNCTION(ltrim, 1, 1, 0, trimFunc ),
|
||||
FUNCTION(ltrim, 2, 1, 0, trimFunc ),
|
||||
|
||||
+2
-3
@@ -503,12 +503,11 @@ static const sqlite3_api_routines sqlite3Apis = {
|
||||
/* Version 3.39.0 and later */
|
||||
#ifndef SQLITE_OMIT_DESERIALIZE
|
||||
sqlite3_deserialize,
|
||||
sqlite3_serialize,
|
||||
sqlite3_serialize
|
||||
#else
|
||||
0,
|
||||
0,
|
||||
0
|
||||
#endif
|
||||
sqlite3_db_name
|
||||
};
|
||||
|
||||
/* True if x is the directory separator character
|
||||
|
||||
-18
@@ -4626,24 +4626,6 @@ Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){
|
||||
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.
|
||||
|
||||
@@ -39,13 +39,6 @@
|
||||
# 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
|
||||
*/
|
||||
|
||||
+149
-103
@@ -6423,99 +6423,86 @@ static int unixAccess(
|
||||
}
|
||||
|
||||
/*
|
||||
** A pathname under construction
|
||||
** 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.
|
||||
*/
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
** Append all path elements in zPath to the DbPath under construction.
|
||||
** 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 void appendAllPathElements(
|
||||
DbPath *pPath, /* Path under construction, to which to append zName */
|
||||
const char *zPath /* Path to append to pPath. Is zero-terminated */
|
||||
static int mkFullPathname(
|
||||
const char *zPath, /* Input path */
|
||||
char *zOut, /* Output buffer */
|
||||
int nOut /* Allocated size of buffer zOut */
|
||||
){
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
do{
|
||||
while( zPath[i] && zPath[i]!='/' ){ i++; }
|
||||
if( i>j ){
|
||||
appendOnePathElement(pPath, &zPath[j], i-j);
|
||||
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);
|
||||
}
|
||||
j = i+1;
|
||||
}while( zPath[i++] );
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -6533,27 +6520,86 @@ static int unixFullPathname(
|
||||
int nOut, /* Size of output buffer in bytes */
|
||||
char *zOut /* Output buffer */
|
||||
){
|
||||
DbPath path;
|
||||
#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);
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
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;
|
||||
|
||||
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
|
||||
|
||||
+3
-34
@@ -924,18 +924,7 @@ where_opt_ret(A) ::= WHERE expr(X) RETURNING selcollist(Y).
|
||||
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);
|
||||
}
|
||||
X = sqlite3SrcListAppendList(pParse, X, F);
|
||||
sqlite3ExprListCheckLength(pParse,Y,"set list");
|
||||
#ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
||||
if( O || L ){
|
||||
@@ -951,18 +940,7 @@ 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);
|
||||
}
|
||||
X = sqlite3SrcListAppendList(pParse, X, F);
|
||||
sqlite3Update(pParse,X,Y,W,R,0,0,0);
|
||||
}
|
||||
%endif
|
||||
@@ -1240,14 +1218,6 @@ 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*/}
|
||||
@@ -1293,8 +1263,7 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
||||
** regardless of the value of expr1.
|
||||
*/
|
||||
sqlite3ExprUnmapAndDelete(pParse, A);
|
||||
A = sqlite3Expr(pParse->db, TK_STRING, N ? "true" : "false");
|
||||
if( A ) sqlite3ExprIdToTrueFalse(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 ){
|
||||
|
||||
+1
-9
@@ -663,14 +663,6 @@ void sqlite3ParseObjectInit(Parse *pParse, sqlite3 *db){
|
||||
if( db->mallocFailed ) sqlite3ErrorMsg(pParse, "out of memory");
|
||||
}
|
||||
|
||||
/*
|
||||
** Maximum number of times that we will try again to prepare a statement
|
||||
** that returns SQLITE_ERROR_RETRY.
|
||||
*/
|
||||
#ifndef SQLITE_MAX_PREPARE_RETRY
|
||||
# define SQLITE_MAX_PREPARE_RETRY 25
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Compile the UTF-8 encoded SQL statement zSql into a statement handle.
|
||||
*/
|
||||
@@ -845,7 +837,7 @@ static int sqlite3LockAndPrepare(
|
||||
rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail);
|
||||
assert( rc==SQLITE_OK || *ppStmt==0 );
|
||||
if( rc==SQLITE_OK || db->mallocFailed ) break;
|
||||
}while( (rc==SQLITE_ERROR_RETRY && (cnt++)<SQLITE_MAX_PREPARE_RETRY)
|
||||
}while( rc==SQLITE_ERROR_RETRY
|
||||
|| (rc==SQLITE_SCHEMA && (sqlite3ResetOneSchema(db,-1), cnt++)==0) );
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
|
||||
+1
-3
@@ -954,9 +954,7 @@ void sqlite3RecordErrorByteOffset(sqlite3 *db, const char *z){
|
||||
** as the error offset.
|
||||
*/
|
||||
void sqlite3RecordErrorOffsetOfExpr(sqlite3 *db, const Expr *pExpr){
|
||||
while( pExpr
|
||||
&& (ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) || pExpr->w.iOfst<=0)
|
||||
){
|
||||
while( pExpr && (ExprHasProperty(pExpr,EP_FromJoin) || pExpr->w.iOfst<=0) ){
|
||||
pExpr = pExpr->pLeft;
|
||||
}
|
||||
if( pExpr==0 ) return;
|
||||
|
||||
+9
-10
@@ -130,7 +130,7 @@ int sqlite3MatchEName(
|
||||
){
|
||||
int n;
|
||||
const char *zSpan;
|
||||
if( pItem->fg.eEName!=ENAME_TAB ) return 0;
|
||||
if( pItem->eEName!=ENAME_TAB ) return 0;
|
||||
zSpan = pItem->zEName;
|
||||
for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
|
||||
if( zDb && (sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){
|
||||
@@ -359,9 +359,8 @@ static int lookupName(
|
||||
cntTab = 2;
|
||||
pMatch = pItem;
|
||||
pExpr->iColumn = j;
|
||||
pEList->a[j].fg.bUsed = 1;
|
||||
pEList->a[j].bUsed = 1;
|
||||
hit = 1;
|
||||
if( pEList->a[j].fg.bUsingTerm ) break;
|
||||
}
|
||||
if( hit || zTab==0 ) continue;
|
||||
}
|
||||
@@ -584,7 +583,7 @@ static int lookupName(
|
||||
assert( pEList!=0 );
|
||||
for(j=0; j<pEList->nExpr; j++){
|
||||
char *zAs = pEList->a[j].zEName;
|
||||
if( pEList->a[j].fg.eEName==ENAME_NAME
|
||||
if( pEList->a[j].eEName==ENAME_NAME
|
||||
&& sqlite3_stricmp(zAs, zCol)==0
|
||||
){
|
||||
Expr *pOrig;
|
||||
@@ -928,7 +927,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
}
|
||||
sqlite3WalkExpr(pWalker, pExpr->pLeft);
|
||||
if( 0==sqlite3ExprCanBeNull(pExpr->pLeft) && !IN_RENAME_OBJECT ){
|
||||
testcase( ExprHasProperty(pExpr, EP_OuterON) );
|
||||
testcase( ExprHasProperty(pExpr, EP_FromJoin) );
|
||||
assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
||||
if( pExpr->op==TK_NOTNULL ){
|
||||
pExpr->u.zToken = "true";
|
||||
@@ -1337,7 +1336,7 @@ static int resolveAsName(
|
||||
assert( !ExprHasProperty(pE, EP_IntValue) );
|
||||
zCol = pE->u.zToken;
|
||||
for(i=0; i<pEList->nExpr; i++){
|
||||
if( pEList->a[i].fg.eEName==ENAME_NAME
|
||||
if( pEList->a[i].eEName==ENAME_NAME
|
||||
&& sqlite3_stricmp(pEList->a[i].zEName, zCol)==0
|
||||
){
|
||||
return i+1;
|
||||
@@ -1458,7 +1457,7 @@ static int resolveCompoundOrderBy(
|
||||
return 1;
|
||||
}
|
||||
for(i=0; i<pOrderBy->nExpr; i++){
|
||||
pOrderBy->a[i].fg.done = 0;
|
||||
pOrderBy->a[i].done = 0;
|
||||
}
|
||||
pSelect->pNext = 0;
|
||||
while( pSelect->pPrior ){
|
||||
@@ -1473,7 +1472,7 @@ static int resolveCompoundOrderBy(
|
||||
for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
|
||||
int iCol = -1;
|
||||
Expr *pE, *pDup;
|
||||
if( pItem->fg.done ) continue;
|
||||
if( pItem->done ) continue;
|
||||
pE = sqlite3ExprSkipCollateAndLikely(pItem->pExpr);
|
||||
if( NEVER(pE==0) ) continue;
|
||||
if( sqlite3ExprIsInteger(pE, &iCol) ){
|
||||
@@ -1526,7 +1525,7 @@ static int resolveCompoundOrderBy(
|
||||
sqlite3ExprDelete(db, pE);
|
||||
pItem->u.x.iOrderByCol = (u16)iCol;
|
||||
}
|
||||
pItem->fg.done = 1;
|
||||
pItem->done = 1;
|
||||
}else{
|
||||
moreToDo = 1;
|
||||
}
|
||||
@@ -1534,7 +1533,7 @@ static int resolveCompoundOrderBy(
|
||||
pSelect = pSelect->pNext;
|
||||
}
|
||||
for(i=0; i<pOrderBy->nExpr; i++){
|
||||
if( pOrderBy->a[i].fg.done==0 ){
|
||||
if( pOrderBy->a[i].done==0 ){
|
||||
sqlite3ErrorMsg(pParse, "%r ORDER BY term does not match any "
|
||||
"column in the result set", i+1);
|
||||
return 1;
|
||||
|
||||
+59
-129
@@ -331,7 +331,7 @@ void sqlite3SrcItemColumnUsed(SrcItem *pItem, int iCol){
|
||||
pResults = pItem->pSelect->pEList;
|
||||
assert( pResults!=0 );
|
||||
assert( iCol>=0 && iCol<pResults->nExpr );
|
||||
pResults->a[iCol].fg.bUsed = 1;
|
||||
pResults->a[iCol].bUsed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,11 +378,11 @@ static int tableAndColumnIndex(
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the EP_OuterON property on all terms of the given expression.
|
||||
** 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_OuterON property is used on terms of an expression to tell
|
||||
** 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
|
||||
@@ -404,7 +404,7 @@ static int tableAndColumnIndex(
|
||||
** the output, which is incorrect.
|
||||
*/
|
||||
void sqlite3SetJoinExpr(Expr *p, int iTable, u32 joinFlag){
|
||||
assert( joinFlag==EP_OuterON || joinFlag==EP_InnerON );
|
||||
assert( joinFlag==EP_FromJoin || joinFlag==EP_InnerJoin );
|
||||
while( p ){
|
||||
ExprSetProperty(p, joinFlag);
|
||||
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
|
||||
@@ -425,17 +425,17 @@ void sqlite3SetJoinExpr(Expr *p, int iTable, u32 joinFlag){
|
||||
}
|
||||
|
||||
/* 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.
|
||||
** 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_OuterON)
|
||||
if( ExprHasProperty(p, EP_FromJoin)
|
||||
&& (iTable<0 || p->w.iJoin==iTable) ){
|
||||
ExprClearProperty(p, EP_OuterON);
|
||||
ExprSetProperty(p, EP_InnerON);
|
||||
ExprClearProperty(p, EP_FromJoin);
|
||||
ExprSetProperty(p, EP_InnerJoin);
|
||||
}
|
||||
if( p->op==TK_COLUMN && p->iTable==iTable ){
|
||||
ExprClearProperty(p, EP_CanBeNull);
|
||||
@@ -463,8 +463,8 @@ static void unsetJoinExpr(Expr *p, int iTable){
|
||||
**
|
||||
** * 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.
|
||||
** 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
|
||||
@@ -489,7 +489,7 @@ static int sqlite3ProcessJoin(Parse *pParse, Select *p){
|
||||
u32 joinType;
|
||||
|
||||
if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue;
|
||||
joinType = (pRight->fg.jointype & JT_OUTER)!=0 ? EP_OuterON : EP_InnerON;
|
||||
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.
|
||||
@@ -999,7 +999,7 @@ static void fixDistinctOpenEph(
|
||||
** retrieved directly from table t1. If the values are very large, this
|
||||
** can be more efficient than storing them directly in the sorter records.
|
||||
**
|
||||
** The ExprList_item.fg.bSorterRef flag is set for each expression in pEList
|
||||
** The ExprList_item.bSorterRef flag is set for each expression in pEList
|
||||
** for which the sorter-reference optimization should be enabled.
|
||||
** Additionally, the pSort->aDefer[] array is populated with entries
|
||||
** for all cursors required to evaluate all selected expressions. Finally.
|
||||
@@ -1059,7 +1059,7 @@ static void selectExprDefer(
|
||||
nDefer++;
|
||||
}
|
||||
}
|
||||
pItem->fg.bSorterRef = 1;
|
||||
pItem->bSorterRef = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1190,7 +1190,7 @@ static void selectInnerLoop(
|
||||
for(i=0; i<pEList->nExpr; i++){
|
||||
if( pEList->a[i].u.x.iOrderByCol>0
|
||||
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
|
||||
|| pEList->a[i].fg.bSorterRef
|
||||
|| pEList->a[i].bSorterRef
|
||||
#endif
|
||||
){
|
||||
nResultCol--;
|
||||
@@ -1552,7 +1552,7 @@ KeyInfo *sqlite3KeyInfoFromExprList(
|
||||
assert( sqlite3KeyInfoIsWriteable(pInfo) );
|
||||
for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){
|
||||
pInfo->aColl[i-iStart] = sqlite3ExprNNCollSeq(pParse, pItem->pExpr);
|
||||
pInfo->aSortFlags[i-iStart] = pItem->fg.sortFlags;
|
||||
pInfo->aSortFlags[i-iStart] = pItem->sortFlags;
|
||||
}
|
||||
}
|
||||
return pInfo;
|
||||
@@ -1691,7 +1691,7 @@ static void generateSortTail(
|
||||
}
|
||||
for(i=0, iCol=nKey+bSeq-1; i<nColumn; i++){
|
||||
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
|
||||
if( aOutEx[i].fg.bSorterRef ) continue;
|
||||
if( aOutEx[i].bSorterRef ) continue;
|
||||
#endif
|
||||
if( aOutEx[i].u.x.iOrderByCol==0 ) iCol++;
|
||||
}
|
||||
@@ -1728,7 +1728,7 @@ static void generateSortTail(
|
||||
#endif
|
||||
for(i=nColumn-1; i>=0; i--){
|
||||
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
|
||||
if( aOutEx[i].fg.bSorterRef ){
|
||||
if( aOutEx[i].bSorterRef ){
|
||||
sqlite3ExprCode(pParse, aOutEx[i].pExpr, regRow+i);
|
||||
}else
|
||||
#endif
|
||||
@@ -2094,7 +2094,7 @@ void sqlite3GenerateColumnNames(
|
||||
assert( p->op!=TK_AGG_COLUMN ); /* Agg processing has not run yet */
|
||||
assert( p->op!=TK_COLUMN
|
||||
|| (ExprUseYTab(p) && p->y.pTab!=0) ); /* Covering idx not yet coded */
|
||||
if( pEList->a[i].zEName && pEList->a[i].fg.eEName==ENAME_NAME ){
|
||||
if( pEList->a[i].zEName && pEList->a[i].eEName==ENAME_NAME ){
|
||||
/* An AS clause always takes first priority */
|
||||
char *zName = pEList->a[i].zEName;
|
||||
sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT);
|
||||
@@ -2180,10 +2180,9 @@ int sqlite3ColumnsFromExprList(
|
||||
|
||||
for(i=0, pCol=aCol; i<nCol && !db->mallocFailed; i++, pCol++){
|
||||
struct ExprList_item *pX = &pEList->a[i];
|
||||
struct ExprList_item *pCollide;
|
||||
/* Get an appropriate name for the column
|
||||
*/
|
||||
if( (zName = pX->zEName)!=0 && pX->fg.eEName==ENAME_NAME ){
|
||||
if( (zName = pX->zEName)!=0 && pX->eEName==ENAME_NAME ){
|
||||
/* If the column contains an "AS <name>" phrase, use <name> as the name */
|
||||
}else{
|
||||
Expr *pColExpr = sqlite3ExprSkipCollateAndLikely(pX->pExpr);
|
||||
@@ -2193,11 +2192,10 @@ int sqlite3ColumnsFromExprList(
|
||||
}
|
||||
if( pColExpr->op==TK_COLUMN
|
||||
&& ALWAYS( ExprUseYTab(pColExpr) )
|
||||
&& ALWAYS( pColExpr->y.pTab!=0 )
|
||||
&& (pTab = 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 ){
|
||||
@@ -2218,10 +2216,7 @@ int sqlite3ColumnsFromExprList(
|
||||
** append an integer to the name so that it becomes unique.
|
||||
*/
|
||||
cnt = 0;
|
||||
while( zName && (pCollide = sqlite3HashFind(&ht, zName))!=0 ){
|
||||
if( pCollide->fg.bUsingTerm ){
|
||||
pCol->colFlags |= COLFLAG_NOEXPAND;
|
||||
}
|
||||
while( zName && sqlite3HashFind(&ht, zName)!=0 ){
|
||||
nName = sqlite3Strlen30(zName);
|
||||
if( nName>0 ){
|
||||
for(j=nName-1; j>0 && sqlite3Isdigit(zName[j]); j--){}
|
||||
@@ -2232,11 +2227,8 @@ int sqlite3ColumnsFromExprList(
|
||||
}
|
||||
pCol->zCnName = zName;
|
||||
pCol->hName = sqlite3StrIHash(zName);
|
||||
if( pX->fg.bNoExpand ){
|
||||
pCol->colFlags |= COLFLAG_NOEXPAND;
|
||||
}
|
||||
sqlite3ColumnPropertiesFromName(0, pCol);
|
||||
if( zName && sqlite3HashInsert(&ht, zName, pX)==pX ){
|
||||
if( zName && sqlite3HashInsert(&ht, zName, pCol)==pCol ){
|
||||
sqlite3OomFault(db);
|
||||
}
|
||||
}
|
||||
@@ -2493,7 +2485,7 @@ static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){
|
||||
}
|
||||
assert( sqlite3KeyInfoIsWriteable(pRet) );
|
||||
pRet->aColl[i] = pColl;
|
||||
pRet->aSortFlags[i] = pOrderBy->a[i].fg.sortFlags;
|
||||
pRet->aSortFlags[i] = pOrderBy->a[i].sortFlags;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3763,7 +3755,7 @@ static Expr *substExpr(
|
||||
Expr *pExpr /* Expr in which substitution occurs */
|
||||
){
|
||||
if( pExpr==0 ) return 0;
|
||||
if( ExprHasProperty(pExpr, EP_OuterON)
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin)
|
||||
&& pExpr->w.iJoin==pSubst->iTable
|
||||
){
|
||||
pExpr->w.iJoin = pSubst->iNewTable;
|
||||
@@ -3804,17 +3796,12 @@ static Expr *substExpr(
|
||||
if( pSubst->isOuterJoin ){
|
||||
ExprSetProperty(pNew, EP_CanBeNull);
|
||||
}
|
||||
if( ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) ){
|
||||
if( ExprHasProperty(pExpr,EP_FromJoin|EP_InnerJoin) ){
|
||||
sqlite3SetJoinExpr(pNew, pExpr->w.iJoin,
|
||||
pExpr->flags & (EP_OuterON|EP_InnerON));
|
||||
pExpr->flags & (EP_FromJoin|EP_InnerJoin));
|
||||
}
|
||||
sqlite3ExprDelete(db, pExpr);
|
||||
pExpr = pNew;
|
||||
if( pExpr->op==TK_TRUEFALSE ){
|
||||
pExpr->u.iValue = sqlite3ExprTruthValue(pExpr);
|
||||
pExpr->op = TK_INTEGER;
|
||||
ExprSetProperty(pExpr, EP_IntValue);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
@@ -3975,7 +3962,7 @@ static int renumberCursorsCb(Walker *pWalker, Expr *pExpr){
|
||||
if( op==TK_COLUMN || op==TK_IF_NULL_ROW ){
|
||||
renumberCursorDoMapping(pWalker, &pExpr->iTable);
|
||||
}
|
||||
if( ExprHasProperty(pExpr, EP_OuterON) ){
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ){
|
||||
renumberCursorDoMapping(pWalker, &pExpr->w.iJoin);
|
||||
}
|
||||
return WRC_Continue;
|
||||
@@ -4553,7 +4540,7 @@ static int flattenSubquery(
|
||||
pWhere = pSub->pWhere;
|
||||
pSub->pWhere = 0;
|
||||
if( isOuterJoin>0 ){
|
||||
sqlite3SetJoinExpr(pWhere, iNewParent, EP_OuterON);
|
||||
sqlite3SetJoinExpr(pWhere, iNewParent, EP_FromJoin);
|
||||
}
|
||||
if( pWhere ){
|
||||
if( pParent->pWhere ){
|
||||
@@ -4686,7 +4673,7 @@ static void constInsert(
|
||||
static void findConstInWhere(WhereConst *pConst, Expr *pExpr){
|
||||
Expr *pRight, *pLeft;
|
||||
if( NEVER(pExpr==0) ) return;
|
||||
if( ExprHasProperty(pExpr, EP_OuterON) ) return;
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ) return;
|
||||
if( pExpr->op==TK_AND ){
|
||||
findConstInWhere(pConst, pExpr->pRight);
|
||||
findConstInWhere(pConst, pExpr->pLeft);
|
||||
@@ -4722,9 +4709,9 @@ static int propagateConstantExprRewriteOne(
|
||||
int i;
|
||||
if( pConst->pOomFault[0] ) return WRC_Prune;
|
||||
if( pExpr->op!=TK_COLUMN ) return WRC_Continue;
|
||||
if( ExprHasProperty(pExpr, EP_FixedCol|EP_OuterON) ){
|
||||
if( ExprHasProperty(pExpr, EP_FixedCol|EP_FromJoin) ){
|
||||
testcase( ExprHasProperty(pExpr, EP_FixedCol) );
|
||||
testcase( ExprHasProperty(pExpr, EP_OuterON) );
|
||||
testcase( ExprHasProperty(pExpr, EP_FromJoin) );
|
||||
return WRC_Continue;
|
||||
}
|
||||
for(i=0; i<pConst->nConst; i++){
|
||||
@@ -5009,12 +4996,12 @@ static int pushDownWhereTerms(
|
||||
|
||||
#if 0 /* Legacy code. Checks now done by sqlite3ExprIsTableConstraint() */
|
||||
if( isLeftJoin
|
||||
&& (ExprHasProperty(pWhere,EP_OuterON)==0
|
||||
&& (ExprHasProperty(pWhere,EP_FromJoin)==0
|
||||
|| pWhere->w.iJoin!=iCursor)
|
||||
){
|
||||
return 0; /* restriction (4) */
|
||||
}
|
||||
if( ExprHasProperty(pWhere,EP_OuterON)
|
||||
if( ExprHasProperty(pWhere,EP_FromJoin)
|
||||
&& pWhere->w.iJoin!=iCursor
|
||||
){
|
||||
return 0; /* restriction (5) */
|
||||
@@ -5104,7 +5091,7 @@ static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){
|
||||
}
|
||||
*ppMinMax = pOrderBy = sqlite3ExprListDup(db, pEList, 0);
|
||||
assert( pOrderBy!=0 || db->mallocFailed );
|
||||
if( pOrderBy ) pOrderBy->a[0].fg.sortFlags = sortFlags;
|
||||
if( pOrderBy ) pOrderBy->a[0].sortFlags = sortFlags;
|
||||
return eRet;
|
||||
}
|
||||
|
||||
@@ -5811,7 +5798,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr);
|
||||
if( pNew ){
|
||||
pNew->a[pNew->nExpr-1].zEName = a[k].zEName;
|
||||
pNew->a[pNew->nExpr-1].fg.eEName = a[k].fg.eEName;
|
||||
pNew->a[pNew->nExpr-1].eEName = a[k].eEName;
|
||||
a[k].zEName = 0;
|
||||
}
|
||||
a[k].pExpr = 0;
|
||||
@@ -5831,7 +5818,6 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
char *zTabName; /* AS name for this data source */
|
||||
const char *zSchemaName = 0; /* Schema name for this data source */
|
||||
int iDb; /* Schema index for this data src */
|
||||
IdList *pUsing; /* USING clause for pFrom[1] */
|
||||
|
||||
if( (zTabName = pFrom->zAlias)==0 ){
|
||||
zTabName = pTab->zName;
|
||||
@@ -5851,27 +5837,6 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
zSchemaName = iDb>=0 ? db->aDb[iDb].zDbSName : "*";
|
||||
}
|
||||
if( i+1<pTabList->nSrc
|
||||
&& pFrom[1].fg.isUsing
|
||||
&& (selFlags & SF_NestedFrom)!=0
|
||||
){
|
||||
int ii;
|
||||
pUsing = pFrom[1].u3.pUsing;
|
||||
for(ii=0; ii<pUsing->nId; ii++){
|
||||
const char *zUName = pUsing->a[ii].zName;
|
||||
pRight = sqlite3Expr(db, TK_ID, zUName);
|
||||
pNew = sqlite3ExprListAppend(pParse, pNew, pRight);
|
||||
if( pNew ){
|
||||
struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];
|
||||
assert( pX->zEName==0 );
|
||||
pX->zEName = sqlite3MPrintf(db,"..%s", zUName);
|
||||
pX->fg.eEName = ENAME_TAB;
|
||||
pX->fg.bUsingTerm = 1;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
pUsing = 0;
|
||||
}
|
||||
for(j=0; j<pTab->nCol; j++){
|
||||
char *zName = pTab->aCol[j].zCnName;
|
||||
struct ExprList_item *pX; /* Newly added ExprList term */
|
||||
@@ -5893,15 +5858,9 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
){
|
||||
continue;
|
||||
}
|
||||
if( (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)!=0
|
||||
&& zTName==0
|
||||
&& (selFlags & (SF_NestedFrom))==0
|
||||
){
|
||||
continue;
|
||||
}
|
||||
tableSeen = 1;
|
||||
|
||||
if( i>0 && zTName==0 && (selFlags & SF_NestedFrom)==0 ){
|
||||
if( i>0 && zTName==0 ){
|
||||
if( pFrom->fg.isUsing
|
||||
&& sqlite3IdListIndex(pFrom->u3.pUsing, zName)>=0
|
||||
){
|
||||
@@ -5913,7 +5872,6 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
pRight = sqlite3Expr(db, TK_ID, zName);
|
||||
if( (pTabList->nSrc>1
|
||||
&& ( (pFrom->fg.jointype & JT_LTORJ)==0
|
||||
|| (selFlags & SF_NestedFrom)!=0
|
||||
|| !inAnyUsingClause(zName,pFrom,pTabList->nSrc-i-1)
|
||||
)
|
||||
)
|
||||
@@ -5947,20 +5905,13 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
zSchemaName, zTabName, zName);
|
||||
testcase( pX->zEName==0 );
|
||||
}
|
||||
pX->fg.eEName = ENAME_TAB;
|
||||
if( (pFrom->fg.isUsing
|
||||
&& sqlite3IdListIndex(pFrom->u3.pUsing, zName)>=0)
|
||||
|| (pUsing && sqlite3IdListIndex(pUsing, zName)>=0)
|
||||
|| (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)!=0
|
||||
){
|
||||
pX->fg.bNoExpand = 1;
|
||||
}
|
||||
pX->eEName = ENAME_TAB;
|
||||
}else if( longNames ){
|
||||
pX->zEName = sqlite3MPrintf(db, "%s.%s", zTabName, zName);
|
||||
pX->fg.eEName = ENAME_NAME;
|
||||
pX->eEName = ENAME_NAME;
|
||||
}else{
|
||||
pX->zEName = sqlite3DbStrDup(db, zName);
|
||||
pX->fg.eEName = ENAME_NAME;
|
||||
pX->eEName = ENAME_NAME;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6524,29 +6475,6 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
|
||||
}
|
||||
#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.
|
||||
**
|
||||
@@ -6651,12 +6579,15 @@ int sqlite3Select(
|
||||
** 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;
|
||||
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,
|
||||
@@ -6931,7 +6862,7 @@ int sqlite3Select(
|
||||
|
||||
/* Generate code to implement the subquery
|
||||
**
|
||||
** The subquery is implemented as a co-routine all if the following are
|
||||
** 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
|
||||
@@ -6989,11 +6920,11 @@ int sqlite3Select(
|
||||
** the same view can reuse the materialization. */
|
||||
int topAddr;
|
||||
int onceAddr = 0;
|
||||
int retAddr;
|
||||
|
||||
pItem->regReturn = ++pParse->nMem;
|
||||
topAddr = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
|
||||
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
|
||||
@@ -7008,9 +6939,9 @@ int sqlite3Select(
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
pItem->pTab->nRowLogEst = pSub->nSelectRow;
|
||||
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
|
||||
sqlite3VdbeAddOp2(v, OP_Return, pItem->regReturn, topAddr+1);
|
||||
retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
|
||||
VdbeComment((v, "end %!S", pItem));
|
||||
sqlite3VdbeJumpHere(v, topAddr);
|
||||
sqlite3VdbeChangeP1(v, topAddr, retAddr);
|
||||
sqlite3ClearTempRegCache(pParse);
|
||||
if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){
|
||||
CteUse *pCteUse = pItem->u2.pCteUse;
|
||||
@@ -7108,13 +7039,13 @@ int sqlite3Select(
|
||||
if( p->selFlags & SF_NestedFrom ){
|
||||
/* Delete or NULL-out result columns that will never be used */
|
||||
int ii;
|
||||
for(ii=pEList->nExpr-1; ii>0 && pEList->a[ii].fg.bUsed==0; ii--){
|
||||
for(ii=pEList->nExpr-1; ii>0 && pEList->a[ii].bUsed==0; ii--){
|
||||
sqlite3ExprDelete(db, pEList->a[ii].pExpr);
|
||||
sqlite3DbFree(db, pEList->a[ii].zEName);
|
||||
pEList->nExpr--;
|
||||
}
|
||||
for(ii=0; ii<pEList->nExpr; ii++){
|
||||
if( pEList->a[ii].fg.bUsed==0 ) pEList->a[ii].pExpr->op = TK_NULL;
|
||||
if( pEList->a[ii].bUsed==0 ) pEList->a[ii].pExpr->op = TK_NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7266,9 +7197,8 @@ int sqlite3Select(
|
||||
** ORDER BY to maximize the chances of rows being delivered in an
|
||||
** order that makes the ORDER BY redundant. */
|
||||
for(ii=0; ii<pGroupBy->nExpr; ii++){
|
||||
u8 sortFlags;
|
||||
sortFlags = sSort.pOrderBy->a[ii].fg.sortFlags & KEYINFO_ORDER_DESC;
|
||||
pGroupBy->a[ii].fg.sortFlags = sortFlags;
|
||||
u8 sortFlags = sSort.pOrderBy->a[ii].sortFlags & KEYINFO_ORDER_DESC;
|
||||
pGroupBy->a[ii].sortFlags = sortFlags;
|
||||
}
|
||||
if( sqlite3ExprListCompare(pGroupBy, sSort.pOrderBy, -1)==0 ){
|
||||
orderByGrp = 1;
|
||||
@@ -7733,7 +7663,7 @@ int sqlite3Select(
|
||||
eDist = sqlite3WhereIsDistinct(pWInfo);
|
||||
updateAccumulator(pParse, regAcc, pAggInfo, eDist);
|
||||
if( eDist!=WHERE_DISTINCT_NOOP ){
|
||||
struct AggInfo_func *pF = pAggInfo->aFunc;
|
||||
struct AggInfo_func *pF = &pAggInfo->aFunc[0];
|
||||
if( pF ){
|
||||
fixDistinctOpenEph(pParse, eDist, pF->iDistinct, pF->iDistAddr);
|
||||
}
|
||||
|
||||
+50
-323
@@ -229,16 +229,6 @@ static void setTextMode(FILE *file, int isOutput){
|
||||
# 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;
|
||||
@@ -701,7 +691,6 @@ static char *local_getline(char *zLine, FILE *in){
|
||||
** 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;
|
||||
@@ -721,7 +710,7 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
|
||||
}
|
||||
return zResult;
|
||||
}
|
||||
#endif /* !SQLITE_SHELL_WASM_MODE */
|
||||
|
||||
|
||||
/*
|
||||
** Return the value of a hexadecimal digit. Return -1 if the input
|
||||
@@ -809,7 +798,7 @@ static void freeText(ShellText *p){
|
||||
** 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){
|
||||
static void appendText(ShellText *p, char const *zAppend, char quote){
|
||||
int len;
|
||||
int i;
|
||||
int nAppend = strlen30(zAppend);
|
||||
@@ -1020,18 +1009,16 @@ 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/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
|
||||
#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
|
||||
@@ -1162,18 +1149,8 @@ struct ShellState {
|
||||
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
|
||||
*/
|
||||
@@ -1214,7 +1191,7 @@ static ShellState shellState;
|
||||
#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_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 */
|
||||
@@ -1838,11 +1815,7 @@ static int safeModeAuth(
|
||||
UNUSED_PARAMETER(zA4);
|
||||
switch( op ){
|
||||
case SQLITE_ATTACH: {
|
||||
#ifndef SQLITE_SHELL_WASM_MODE
|
||||
/* In WASM builds the filesystem is a virtual sandbox, so
|
||||
** there's no harm in using ATTACH. */
|
||||
failIfSafeMode(p, "cannot run ATTACH in safe mode");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case SQLITE_FUNCTION: {
|
||||
@@ -3847,6 +3820,11 @@ static int shell_exec(
|
||||
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;
|
||||
@@ -4245,14 +4223,13 @@ static int run_schema_dump_query(
|
||||
** Text of help messages.
|
||||
**
|
||||
** The help text for each individual command begins with a line that starts
|
||||
** with ".". Subsequent lines are supplemental information.
|
||||
** 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) \
|
||||
&& !defined(SQLITE_SHELL_WASM_MODE)
|
||||
#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",
|
||||
@@ -4278,28 +4255,20 @@ static const char *(azHelp[]) = {
|
||||
#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",
|
||||
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
|
||||
".dbinfo ?DB? Show status information about the database",
|
||||
#endif
|
||||
".dump ?OBJECTS? Render database content as SQL",
|
||||
" Options:",
|
||||
" --data-only Output only INSERT statements",
|
||||
@@ -4316,13 +4285,9 @@ static const char *(azHelp[]) = {
|
||||
" 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",
|
||||
@@ -4331,7 +4296,6 @@ static const char *(azHelp[]) = {
|
||||
".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",
|
||||
@@ -4346,7 +4310,6 @@ static const char *(azHelp[]) = {
|
||||
" 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
|
||||
@@ -4360,12 +4323,10 @@ static const char *(azHelp[]) = {
|
||||
".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)
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
".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",
|
||||
@@ -4390,23 +4351,16 @@ static const char *(azHelp[]) = {
|
||||
" --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",
|
||||
@@ -4416,14 +4370,12 @@ static const char *(azHelp[]) = {
|
||||
" --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",
|
||||
@@ -4440,11 +4392,9 @@ static const char *(azHelp[]) = {
|
||||
" --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",
|
||||
@@ -4453,10 +4403,8 @@ static const char *(azHelp[]) = {
|
||||
" --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:",
|
||||
@@ -4490,7 +4438,7 @@ static const char *(azHelp[]) = {
|
||||
" --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)
|
||||
#ifndef SQLITE_NOHAVE_SYSTEM
|
||||
".shell CMD ARGS... Run CMD ARGS... in a system shell",
|
||||
#endif
|
||||
".show Show the current values for various settings",
|
||||
@@ -4499,13 +4447,11 @@ static const char *(azHelp[]) = {
|
||||
" 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)
|
||||
#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",
|
||||
#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",
|
||||
@@ -5050,16 +4996,14 @@ static void open_db(ShellState *p, int openFlags){
|
||||
#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);
|
||||
#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
|
||||
@@ -5847,7 +5791,6 @@ static unsigned int get4byteInt(unsigned char *a){
|
||||
return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3];
|
||||
}
|
||||
|
||||
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
|
||||
/*
|
||||
** Implementation of the ".dbinfo" command.
|
||||
**
|
||||
@@ -5944,8 +5887,6 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
|
||||
utf8_printf(p->out, "%-20s %u\n", "data version", iDataVersion);
|
||||
return 0;
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE)
|
||||
&& defined(SQLITE_ENABLE_DBPAGE_VTAB) */
|
||||
|
||||
/*
|
||||
** Print the current sqlite3_errmsg() value to stderr and return 1.
|
||||
@@ -8185,8 +8126,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}else
|
||||
#endif
|
||||
|
||||
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) \
|
||||
&& !defined(SQLITE_SHELL_WASM_MODE)
|
||||
#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");
|
||||
@@ -8194,7 +8134,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}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)
|
||||
){
|
||||
@@ -8263,7 +8202,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
close_db(pDest);
|
||||
}else
|
||||
#endif /* !defined(SQLITE_SHELL_WASM_MODE) */
|
||||
|
||||
if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 ){
|
||||
if( nArg==2 ){
|
||||
@@ -8294,7 +8232,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
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 ){
|
||||
@@ -8314,7 +8251,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
rc = 1;
|
||||
}
|
||||
}else
|
||||
#endif /* !defined(SQLITE_SHELL_WASM_MODE) */
|
||||
|
||||
if( c=='c' && n>=3 && strncmp(azArg[0], "changes", n)==0 ){
|
||||
if( nArg==2 ){
|
||||
@@ -8325,7 +8261,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
}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.
|
||||
@@ -8350,9 +8285,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
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 ){
|
||||
@@ -8362,7 +8295,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
rc = 1;
|
||||
}
|
||||
}else
|
||||
#endif /* !defined(SQLITE_SHELL_WASM_MODE) */
|
||||
|
||||
if( c=='c' && strncmp(azArg[0], "connection", n)==0 ){
|
||||
if( nArg==1 ){
|
||||
@@ -8488,11 +8420,11 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
}else
|
||||
|
||||
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
|
||||
if( c=='d' && n>=3 && strncmp(azArg[0], "dbinfo", n)==0 ){
|
||||
rc = shell_dbinfo_command(p, nArg, azArg);
|
||||
}else
|
||||
|
||||
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
|
||||
if( c=='r' && strncmp(azArg[0], "recover", n)==0 ){
|
||||
open_db(p, 0);
|
||||
rc = recoverDatabaseCmd(p, nArg, azArg);
|
||||
@@ -8505,7 +8437,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
int i;
|
||||
int savedShowHeader = p->showHeader;
|
||||
int savedShellFlags = p->shellFlgs;
|
||||
ShellClearFlag(p,
|
||||
ShellClearFlag(p,
|
||||
SHFLG_PreserveRowid|SHFLG_Newlines|SHFLG_Echo
|
||||
|SHFLG_DumpDataOnly|SHFLG_DumpNoSys);
|
||||
for(i=1; i<nArg; i++){
|
||||
@@ -8651,12 +8583,10 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
}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 */
|
||||
@@ -8911,7 +8841,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
}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") */
|
||||
@@ -8933,12 +8862,16 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
|
||||
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;
|
||||
}
|
||||
rc = 1;
|
||||
for(i=1; i<nArg; i++){
|
||||
char *z = azArg[i];
|
||||
if( z[0]=='-' && z[1]=='-' ) z++;
|
||||
@@ -8950,6 +8883,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}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 ){
|
||||
@@ -8971,6 +8905,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}else{
|
||||
utf8_printf(p->out, "ERROR: unknown option: \"%s\". Usage:\n", z);
|
||||
showHelp(p->out, "import");
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
}
|
||||
@@ -8978,6 +8913,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
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;
|
||||
@@ -8989,18 +8925,21 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
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,
|
||||
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 ){
|
||||
@@ -9014,6 +8953,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
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];
|
||||
@@ -9024,6 +8964,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
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");
|
||||
@@ -9036,6 +8977,8 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
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) ){
|
||||
@@ -9049,11 +8992,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
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 ){}
|
||||
@@ -9202,7 +9140,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
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 ){
|
||||
@@ -9392,7 +9329,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
lintDotCommand(p, azArg, nArg);
|
||||
}else
|
||||
|
||||
#if !defined(SQLITE_OMIT_LOAD_EXTENSION) && !defined(SQLITE_SHELL_WASM_MODE)
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
if( c=='l' && strncmp(azArg[0], "load", n)==0 ){
|
||||
const char *zFile, *zProc;
|
||||
char *zErrMsg = 0;
|
||||
@@ -9414,7 +9351,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}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 ){
|
||||
@@ -9426,7 +9362,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
p->pLog = output_file_open(zFile, 0);
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
|
||||
if( c=='m' && strncmp(azArg[0], "mode", n)==0 ){
|
||||
const char *zMode = 0;
|
||||
@@ -9551,7 +9486,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
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");
|
||||
@@ -9566,7 +9500,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
** 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 ){
|
||||
@@ -9588,7 +9521,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
/* 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
|
||||
@@ -9609,9 +9541,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}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]=='-' ){
|
||||
}else if( z[0]=='-' ){
|
||||
utf8_printf(stderr, "unknown option: %s\n", z);
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
@@ -9638,7 +9568,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
/* 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
|
||||
@@ -9646,9 +9575,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
){
|
||||
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);
|
||||
@@ -9671,7 +9597,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
}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)
|
||||
@@ -9787,7 +9712,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
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);
|
||||
@@ -9957,13 +9881,10 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
}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;
|
||||
@@ -9998,9 +9919,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
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;
|
||||
@@ -10052,7 +9971,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
close_db(pSrc);
|
||||
}else
|
||||
#endif /* !defined(SQLITE_SHELL_WASM_MODE) */
|
||||
|
||||
if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){
|
||||
if( nArg==2 ){
|
||||
@@ -10678,7 +10596,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
sqlite3_free(zSql);
|
||||
}else
|
||||
|
||||
#if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_WASM_MODE)
|
||||
#ifndef SQLITE_NOHAVE_SYSTEM
|
||||
if( c=='s'
|
||||
&& (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0)
|
||||
){
|
||||
@@ -10699,7 +10617,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
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) */
|
||||
#endif /* !defined(SQLITE_NOHAVE_SYSTEM) */
|
||||
|
||||
if( c=='s' && strncmp(azArg[0], "show", n)==0 ){
|
||||
static const char *azBool[] = { "off", "on", "trigger", "full"};
|
||||
@@ -10711,7 +10629,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
goto meta_command_exit;
|
||||
}
|
||||
utf8_printf(p->out, "%12.12s: %s\n","echo",
|
||||
azBool[ShellHasFlag(p, SHFLG_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");
|
||||
@@ -10879,7 +10797,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
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);
|
||||
@@ -10893,7 +10810,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
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 ){
|
||||
@@ -11463,7 +11379,7 @@ static QuickScanState quickscan(char *zLine, QuickScanState qss){
|
||||
cWait = 0;
|
||||
qss = QSS_SETV(qss, 0);
|
||||
goto PlainScan;
|
||||
default: assert(0);
|
||||
default: assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11484,7 +11400,7 @@ static int line_is_command_terminator(char *zLine){
|
||||
zLine += 2; /* SQL Server */
|
||||
else
|
||||
return 0;
|
||||
return quickscan(zLine, QSS_Start)==QSS_Start;
|
||||
return quickscan(zLine,QSS_Start)==QSS_Start;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -11561,42 +11477,6 @@ static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){
|
||||
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
|
||||
@@ -11646,13 +11526,14 @@ static int process_input(ShellState *p){
|
||||
}
|
||||
qss = quickscan(zLine, qss);
|
||||
if( QSS_PLAINWHITE(qss) && nSql==0 ){
|
||||
if( ShellHasFlag(p, SHFLG_Echo) )
|
||||
printf("%s\n", zLine);
|
||||
/* 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( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zLine);
|
||||
if( zLine[0]=='.' ){
|
||||
rc = do_meta_command(zLine, p);
|
||||
if( rc==2 ){ /* exit requested */
|
||||
@@ -11685,7 +11566,6 @@ static int process_input(ShellState *p){
|
||||
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 ){
|
||||
@@ -11697,14 +11577,13 @@ static int process_input(ShellState *p){
|
||||
p->bSafeMode = p->bSafeModePersist;
|
||||
qss = QSS_Start;
|
||||
}else if( nSql && QSS_PLAINWHITE(qss) ){
|
||||
echo_group_input(p, zSql);
|
||||
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. */
|
||||
echo_group_input(p, zSql);
|
||||
errCnt += runOneSqlLine(p, zSql, p->in, startline);
|
||||
}
|
||||
free(zSql);
|
||||
@@ -11843,7 +11722,7 @@ static const char zOptions[] =
|
||||
#if !defined(SQLITE_OMIT_DESERIALIZE)
|
||||
" -deserialize open the database using sqlite3_deserialize()\n"
|
||||
#endif
|
||||
" -echo print inputs before execution\n"
|
||||
" -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)
|
||||
@@ -11979,25 +11858,14 @@ static char *cmdline_option_value(int argc, char **argv, int i){
|
||||
# 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;
|
||||
@@ -12013,13 +11881,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
|
||||
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") ){
|
||||
@@ -12275,9 +12138,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
#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
|
||||
@@ -12543,9 +12404,6 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
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 ){
|
||||
@@ -12572,136 +12430,5 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
/* 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 */
|
||||
|
||||
@@ -6276,28 +6276,6 @@ int sqlite3_get_autocommit(sqlite3*);
|
||||
*/
|
||||
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
|
||||
|
||||
@@ -356,7 +356,6 @@ struct sqlite3_api_routines {
|
||||
sqlite3_int64,sqlite3_int64,unsigned);
|
||||
unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*,
|
||||
unsigned int);
|
||||
const char *(*db_name)(sqlite3*,int);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -675,12 +674,10 @@ typedef int (*sqlite3_loadext_entry)(
|
||||
#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)
|
||||
|
||||
+32
-41
@@ -1781,7 +1781,6 @@ struct sqlite3 {
|
||||
#define SQLITE_BalancedMerge 0x00200000 /* Balance multi-way merges */
|
||||
#define SQLITE_ReleaseReg 0x00400000 /* Use OP_ReleaseReg for testing */
|
||||
#define SQLITE_FlttnUnionAll 0x00800000 /* Disable the UNION ALL flattener */
|
||||
/* TH3 expects this value ^^^^^^^^^^ See flatten04.test */
|
||||
#define SQLITE_AllOpts 0xffffffff /* All optimizations */
|
||||
|
||||
/*
|
||||
@@ -1884,7 +1883,7 @@ struct FuncDestructor {
|
||||
#define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a
|
||||
** single query - might change over time */
|
||||
#define SQLITE_FUNC_TEST 0x4000 /* Built-in testing functions */
|
||||
/* 0x8000 -- available for reuse */
|
||||
#define SQLITE_FUNC_OFFSET 0x8000 /* Built-in sqlite_offset() function */
|
||||
#define SQLITE_FUNC_WINDOW 0x00010000 /* Built-in window-only function */
|
||||
#define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */
|
||||
#define SQLITE_FUNC_DIRECT 0x00080000 /* Not for use in TRIGGERs or VIEWs */
|
||||
@@ -1901,7 +1900,6 @@ struct FuncDestructor {
|
||||
#define INLINEFUNC_expr_compare 3
|
||||
#define INLINEFUNC_affinity 4
|
||||
#define INLINEFUNC_iif 5
|
||||
#define INLINEFUNC_sqlite_offset 6
|
||||
#define INLINEFUNC_unlikely 99 /* Default case */
|
||||
|
||||
/*
|
||||
@@ -2128,7 +2126,6 @@ struct Column {
|
||||
#define COLFLAG_NOTAVAIL 0x0080 /* STORED column not yet calculated */
|
||||
#define COLFLAG_BUSY 0x0100 /* Blocks recursion on GENERATED columns */
|
||||
#define COLFLAG_HASCOLL 0x0200 /* Has collating sequence name in zCnName */
|
||||
#define COLFLAG_NOEXPAND 0x0400 /* Omit this column when expanding "*" */
|
||||
#define COLFLAG_GENERATED 0x0060 /* Combo: _STORED, _VIRTUAL */
|
||||
#define COLFLAG_NOINSERT 0x0062 /* Combo: _HIDDEN, _STORED, _VIRTUAL */
|
||||
|
||||
@@ -2848,7 +2845,7 @@ struct Expr {
|
||||
** 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 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 */
|
||||
@@ -2869,29 +2866,29 @@ struct Expr {
|
||||
** 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_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_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_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_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_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 */
|
||||
@@ -2914,8 +2911,8 @@ struct Expr {
|
||||
#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)
|
||||
#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.
|
||||
@@ -3002,18 +2999,13 @@ struct ExprList {
|
||||
struct ExprList_item { /* For each expression in the list */
|
||||
Expr *pExpr; /* The parse tree for this expression */
|
||||
char *zEName; /* Token associated with this expression */
|
||||
struct {
|
||||
u8 sortFlags; /* Mask of KEYINFO_ORDER_* flags */
|
||||
unsigned eEName :2; /* Meaning of zEName */
|
||||
unsigned done :1; /* Indicates when processing is finished */
|
||||
unsigned reusable :1; /* Constant expression is reusable */
|
||||
unsigned bSorterRef :1; /* Defer evaluation until after sorting */
|
||||
unsigned bNulls :1; /* True if explicit "NULLS FIRST/LAST" */
|
||||
unsigned bUsed :1; /* This column used in a SF_NestedFrom subquery */
|
||||
unsigned bUsingTerm:1; /* Term from the USING clause of a NestedFrom */
|
||||
unsigned bNoExpand: 1; /* Term is an auxiliary in NestedFrom and should
|
||||
** not be expanded by "*" in parent queries */
|
||||
} fg;
|
||||
u8 sortFlags; /* Mask of KEYINFO_ORDER_* flags */
|
||||
unsigned eEName :2; /* Meaning of zEName */
|
||||
unsigned done :1; /* A flag to indicate when processing is finished */
|
||||
unsigned reusable :1; /* Constant expression is reusable */
|
||||
unsigned bSorterRef :1; /* Defer evaluation until after sorting */
|
||||
unsigned bNulls: 1; /* True if explicit "NULLS FIRST/LAST" */
|
||||
unsigned bUsed: 1; /* This column used in a SF_NestedFrom subquery */
|
||||
union {
|
||||
struct { /* Used by any ExprList other than Parse.pConsExpr */
|
||||
u16 iOrderByCol; /* For ORDER BY, column number in result set */
|
||||
@@ -3094,7 +3086,6 @@ struct SrcItem {
|
||||
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 */
|
||||
|
||||
+1
-1
@@ -2965,7 +2965,7 @@ deserialize_error:
|
||||
}
|
||||
|
||||
if( objc==(6+isReadonly) ){
|
||||
zDb = Tcl_GetString(objv[2+isReadonly]);
|
||||
zDb = Tcl_GetString(objv[2]);
|
||||
}
|
||||
zTable = Tcl_GetString(objv[objc-3]);
|
||||
zColumn = Tcl_GetString(objv[objc-2]);
|
||||
|
||||
-15
@@ -60,11 +60,6 @@ struct Thread {
|
||||
#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.
|
||||
@@ -81,20 +76,16 @@ static void *test_thread_main(void *pArg){
|
||||
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);
|
||||
@@ -108,7 +99,6 @@ static void *test_thread_main(void *pArg){
|
||||
sqlite3_free(p->zErr);
|
||||
p->zErr = 0;
|
||||
}
|
||||
test_barrier();
|
||||
p->completed++;
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
sqlite3_thread_cleanup();
|
||||
@@ -176,9 +166,7 @@ static int SQLITE_TCLAPI tcl_thread_create(
|
||||
** 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();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -468,7 +456,6 @@ static int SQLITE_TCLAPI tcl_thread_compile(
|
||||
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;
|
||||
}
|
||||
@@ -520,7 +507,6 @@ static int SQLITE_TCLAPI tcl_thread_step(
|
||||
}
|
||||
test_thread_wait(&threadset[i]);
|
||||
threadset[i].xOp = do_step;
|
||||
test_barrier();
|
||||
threadset[i].opnum++;
|
||||
return TCL_OK;
|
||||
}
|
||||
@@ -565,7 +551,6 @@ static int SQLITE_TCLAPI tcl_thread_finalize(
|
||||
threadset[i].xOp = do_finalize;
|
||||
sqlite3_free(threadset[i].zArg);
|
||||
threadset[i].zArg = 0;
|
||||
test_barrier();
|
||||
threadset[i].opnum++;
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
+4
-11
@@ -397,7 +397,6 @@ void sqlite3TreeViewBound(
|
||||
*/
|
||||
void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){
|
||||
int nElement = 0;
|
||||
if( pWin==0 ) return;
|
||||
if( pWin->pFilter ){
|
||||
sqlite3TreeViewItem(pView, "FILTER", 1);
|
||||
sqlite3TreeViewExpr(pView, pWin->pFilter, 0);
|
||||
@@ -462,7 +461,6 @@ void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){
|
||||
** Generate a human-readable explanation for a Window Function object
|
||||
*/
|
||||
void sqlite3TreeViewWinFunc(TreeView *pView, const Window *pWin, u8 more){
|
||||
if( pWin==0 ) return;
|
||||
sqlite3TreeViewPush(&pView, more);
|
||||
sqlite3TreeViewLine(pView, "WINFUNC %s(%d)",
|
||||
pWin->pWFunc->zName, pWin->pWFunc->nArg);
|
||||
@@ -489,11 +487,8 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
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_FromJoin) ){
|
||||
sqlite3_str_appendf(&x, " iJoin=%d", pExpr->w.iJoin);
|
||||
}
|
||||
if( ExprHasProperty(pExpr, EP_FromDDL) ){
|
||||
sqlite3_str_appendf(&x, " DDL");
|
||||
@@ -878,15 +873,13 @@ void sqlite3TreeViewBareExprList(
|
||||
moreToFollow = 0;
|
||||
sqlite3TreeViewLine(pView, 0);
|
||||
if( zName ){
|
||||
switch( pList->a[i].fg.eEName ){
|
||||
switch( pList->a[i].eEName ){
|
||||
default:
|
||||
fprintf(stdout, "AS %s ", zName);
|
||||
break;
|
||||
case ENAME_TAB:
|
||||
fprintf(stdout, "TABLE-ALIAS-NAME(\"%s\") ", zName);
|
||||
if( pList->a[i].fg.bUsed ) fprintf(stdout, "(used) ");
|
||||
if( pList->a[i].fg.bUsingTerm ) fprintf(stdout, "(USING-term) ");
|
||||
if( pList->a[i].fg.bNoExpand ) fprintf(stdout, "(NoExpand) ");
|
||||
if( pList->a[i].bUsed==0 ) fprintf(stdout, "(unused) ");
|
||||
break;
|
||||
case ENAME_SPAN:
|
||||
fprintf(stdout, "SPAN(\"%s\") ", zName);
|
||||
|
||||
+3
-11
@@ -514,7 +514,7 @@ TriggerStep *sqlite3TriggerInsertStep(
|
||||
TriggerStep *sqlite3TriggerUpdateStep(
|
||||
Parse *pParse, /* Parser */
|
||||
Token *pTableName, /* Name of the table to be updated */
|
||||
SrcList *pFrom, /* FROM clause for an UPDATE-FROM, or NULL */
|
||||
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) */
|
||||
@@ -850,14 +850,6 @@ SrcList *sqlite3TriggerStepSrc(
|
||||
}
|
||||
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{
|
||||
@@ -913,7 +905,7 @@ static ExprList *sqlite3ExpandReturning(
|
||||
if( !db->mallocFailed ){
|
||||
struct ExprList_item *pItem = &pNew->a[pNew->nExpr-1];
|
||||
pItem->zEName = sqlite3DbStrDup(db, pTab->aCol[jj].zCnName);
|
||||
pItem->fg.eEName = ENAME_NAME;
|
||||
pItem->eEName = ENAME_NAME;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
@@ -922,7 +914,7 @@ static ExprList *sqlite3ExpandReturning(
|
||||
if( !db->mallocFailed && ALWAYS(pList->a[i].zEName!=0) ){
|
||||
struct ExprList_item *pItem = &pNew->a[pNew->nExpr-1];
|
||||
pItem->zEName = sqlite3DbStrDup(db, pList->a[i].zEName);
|
||||
pItem->fg.eEName = pList->a[i].fg.eEName;
|
||||
pItem->eEName = pList->a[i].eEName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,7 +368,6 @@ SQLITE_NOINLINE int sqlite3RunVacuum(
|
||||
|
||||
assert( rc==SQLITE_OK );
|
||||
if( pOut==0 ){
|
||||
nRes = sqlite3BtreeGetRequestedReserve(pTemp);
|
||||
rc = sqlite3BtreeSetPageSize(pMain, sqlite3BtreeGetPageSize(pTemp), nRes,1);
|
||||
}
|
||||
|
||||
|
||||
@@ -1043,8 +1043,6 @@ case OP_InitCoroutine: { /* jump */
|
||||
/* Most jump operations do a goto to this spot in order to update
|
||||
** the pOp pointer. */
|
||||
jump_to_p2:
|
||||
assert( pOp->p2>0 ); /* There are never any jumps to instruction 0 */
|
||||
assert( pOp->p2<p->nOp ); /* Jumps must be in range */
|
||||
pOp = &aOp[pOp->p2 - 1];
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -232,6 +232,7 @@ void sqlite3VdbeJumpHere(Vdbe*, int addr);
|
||||
void sqlite3VdbeJumpHereOrPopInst(Vdbe*, int addr);
|
||||
int sqlite3VdbeChangeToNoop(Vdbe*, int addr);
|
||||
int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op);
|
||||
void sqlite3VdbeUndoBackTo(Vdbe*, int addr);
|
||||
#ifdef SQLITE_DEBUG
|
||||
void sqlite3VdbeReleaseRegisters(Parse*,int addr, int n, u32 mask, int);
|
||||
#else
|
||||
|
||||
+20
-2
@@ -1303,6 +1303,22 @@ int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Undo all opcode inserts so that addr is the last opcode.
|
||||
*/
|
||||
void sqlite3VdbeUndoBackTo(Vdbe *p, int addr){
|
||||
while( p->nOp>addr ){
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( p->db->flags & SQLITE_VdbeAddopTrace ){
|
||||
printf("UNDO: ");
|
||||
sqlite3VdbePrintOp(0, p->nOp-1, &p->aOp[p->nOp-1]);
|
||||
}
|
||||
#endif
|
||||
sqlite3VdbeChangeToNoop(p, p->nOp-1);
|
||||
p->nOp--;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
** Generate an OP_ReleaseReg opcode to indicate that a range of
|
||||
@@ -1576,9 +1592,11 @@ char *sqlite3VdbeDisplayComment(
|
||||
}else if( c=='X' ){
|
||||
if( pOp->zComment && pOp->zComment[0] ){
|
||||
sqlite3_str_appendall(&x, pOp->zComment);
|
||||
seenCom = 1;
|
||||
break;
|
||||
}else{
|
||||
sqlite3_str_appendall(&x, zSynopsis+1);
|
||||
}
|
||||
seenCom = 1;
|
||||
break;
|
||||
}else{
|
||||
int v1 = translateP(c, pOp);
|
||||
int v2;
|
||||
|
||||
+23
-49
@@ -330,7 +330,7 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
|
||||
&& (iColumn!=XN_EXPR
|
||||
|| sqlite3ExprCompareSkip(pTerm->pExpr->pLeft,
|
||||
pScan->pIdxExpr,iCur)==0)
|
||||
&& (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_OuterON))
|
||||
&& (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin))
|
||||
){
|
||||
if( (pTerm->eOperator & WO_EQUIV)!=0
|
||||
&& pScan->nEquiv<ArraySize(pScan->aiCur)
|
||||
@@ -757,7 +757,7 @@ static int termCanDriveIndex(
|
||||
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)
|
||||
&& !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
|
||||
&& (pTerm->eOperator & WO_IS)
|
||||
){
|
||||
/* Cannot use an IS term from the WHERE clause as an index driver for
|
||||
@@ -1181,7 +1181,7 @@ static sqlite3_index_info *allocateIndexInfo(
|
||||
** 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)
|
||||
&& !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
|
||||
){
|
||||
continue;
|
||||
}
|
||||
@@ -1206,7 +1206,7 @@ static sqlite3_index_info *allocateIndexInfo(
|
||||
}
|
||||
|
||||
/* Virtual tables are unable to deal with NULLS FIRST */
|
||||
if( pOrderBy->a[i].fg.sortFlags & KEYINFO_ORDER_BIGNULL ) break;
|
||||
if( pOrderBy->a[i].sortFlags & KEYINFO_ORDER_BIGNULL ) break;
|
||||
|
||||
/* First case - a direct column references without a COLLATE operator */
|
||||
if( pExpr->op==TK_COLUMN && pExpr->iTable==pSrc->iCursor ){
|
||||
@@ -1318,7 +1318,7 @@ static sqlite3_index_info *allocateIndexInfo(
|
||||
|| (pExpr->op==TK_COLLATE && pExpr->pLeft->op==TK_COLUMN
|
||||
&& pExpr->iColumn==pExpr->pLeft->iColumn) );
|
||||
pIdxOrderBy[j].iColumn = pExpr->iColumn;
|
||||
pIdxOrderBy[j].desc = pOrderBy->a[i].fg.sortFlags & KEYINFO_ORDER_DESC;
|
||||
pIdxOrderBy[j].desc = pOrderBy->a[i].sortFlags & KEYINFO_ORDER_DESC;
|
||||
j++;
|
||||
}
|
||||
pIdxInfo->nOrderBy = j;
|
||||
@@ -2059,7 +2059,7 @@ void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm){
|
||||
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( 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 );
|
||||
@@ -2836,7 +2836,7 @@ static int whereLoopAddBtreeIndex(
|
||||
** 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)
|
||||
&& !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
|
||||
){
|
||||
continue;
|
||||
}
|
||||
@@ -3205,8 +3205,8 @@ static int whereUsablePartialIndex(
|
||||
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))
|
||||
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
|
||||
){
|
||||
@@ -3482,14 +3482,7 @@ static int whereLoopAddBtree(
|
||||
}
|
||||
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);
|
||||
}
|
||||
rc = whereLoopInsert(pBuilder, pNew);
|
||||
pNew->nOut = rSize;
|
||||
if( rc ) break;
|
||||
}
|
||||
@@ -3664,7 +3657,6 @@ static int whereLoopAddVirtualOne(
|
||||
*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
|
||||
@@ -4138,10 +4130,8 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
||||
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);
|
||||
@@ -4151,13 +4141,12 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
||||
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;
|
||||
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;
|
||||
}else{
|
||||
mPrereq = 0;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( IsVirtual(pItem->pTab) ){
|
||||
@@ -4468,18 +4457,16 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
/* Make sure the sort order is compatible in an ORDER BY clause.
|
||||
** Sort order is irrelevant for a GROUP BY clause. */
|
||||
if( revSet ){
|
||||
if( (rev ^ revIdx)
|
||||
!= (pOrderBy->a[i].fg.sortFlags&KEYINFO_ORDER_DESC)
|
||||
){
|
||||
if( (rev ^ revIdx)!=(pOrderBy->a[i].sortFlags&KEYINFO_ORDER_DESC) ){
|
||||
isMatch = 0;
|
||||
}
|
||||
}else{
|
||||
rev = revIdx ^ (pOrderBy->a[i].fg.sortFlags & KEYINFO_ORDER_DESC);
|
||||
rev = revIdx ^ (pOrderBy->a[i].sortFlags & KEYINFO_ORDER_DESC);
|
||||
if( rev ) *pRevMask |= MASKBIT(iLoop);
|
||||
revSet = 1;
|
||||
}
|
||||
}
|
||||
if( isMatch && (pOrderBy->a[i].fg.sortFlags & KEYINFO_ORDER_BIGNULL) ){
|
||||
if( isMatch && (pOrderBy->a[i].sortFlags & KEYINFO_ORDER_BIGNULL) ){
|
||||
if( j==pLoop->u.btree.nEq ){
|
||||
pLoop->wsFlags |= WHERE_BIGNULL_SORT;
|
||||
}else{
|
||||
@@ -5227,7 +5214,7 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin(
|
||||
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)
|
||||
if( !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
|
||||
|| pTerm->pExpr->w.iJoin!=pItem->iCursor
|
||||
){
|
||||
break;
|
||||
@@ -5853,7 +5840,6 @@ WhereInfo *sqlite3WhereBegin(
|
||||
iIndexCur = pParse->nTab++;
|
||||
}
|
||||
pLevel->iIdxCur = iIndexCur;
|
||||
assert( pIx!=0 );
|
||||
assert( pIx->pSchema==pTab->pSchema );
|
||||
assert( iIndexCur>=0 );
|
||||
if( op ){
|
||||
@@ -5929,20 +5915,9 @@ WhereInfo *sqlite3WhereBegin(
|
||||
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
|
||||
@@ -6034,7 +6009,6 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
SrcList *pTabList = pWInfo->pTabList;
|
||||
sqlite3 *db = pParse->db;
|
||||
int iEnd = sqlite3VdbeCurrentAddr(v);
|
||||
int nRJ = 0;
|
||||
|
||||
/* Generate loop termination code.
|
||||
*/
|
||||
@@ -6051,7 +6025,8 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
pRJ->endSubrtn = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp3(v, OP_Return, pRJ->regReturn, pRJ->addrSubrtn, 1);
|
||||
VdbeCoverage(v);
|
||||
nRJ++;
|
||||
assert( pParse->withinRJSubrtn>0 );
|
||||
pParse->withinRJSubrtn--;
|
||||
}
|
||||
pLoop = pLevel->pWLoop;
|
||||
if( pLevel->op!=OP_Noop ){
|
||||
@@ -6193,7 +6168,6 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -6330,8 +6304,8 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
|
||||
/* Final cleanup
|
||||
*/
|
||||
if( pWInfo->pExprMods ) whereUndoExprMods(pWInfo);
|
||||
pParse->nQueryLoop = pWInfo->savedNQueryLoop;
|
||||
whereInfoFree(db, pWInfo);
|
||||
pParse->withinRJSubrtn -= nRJ;
|
||||
return;
|
||||
}
|
||||
|
||||
+2
-3
@@ -41,7 +41,7 @@ typedef struct WhereRightJoin WhereRightJoin;
|
||||
*/
|
||||
struct WhereMemBlock {
|
||||
WhereMemBlock *pNext; /* Next block in the chain */
|
||||
u64 sz; /* Bytes of space */
|
||||
u8 sz; /* Bytes of space */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -612,9 +612,8 @@ void sqlite3WhereTabFuncArgs(Parse*, SrcItem*, WhereClause*);
|
||||
#define WO_AND 0x0400 /* Two or more AND-connected terms */
|
||||
#define WO_EQUIV 0x0800 /* Of the form A==B, both columns */
|
||||
#define WO_NOOP 0x1000 /* This term does not restrict search space */
|
||||
#define WO_ROWVAL 0x2000 /* A row-value term */
|
||||
|
||||
#define WO_ALL 0x3fff /* Mask of all possible WO_* values */
|
||||
#define WO_ALL 0x1fff /* Mask of all possible WO_* values */
|
||||
#define WO_SINGLE 0x01ff /* Mask of all non-compound WO_* values */
|
||||
|
||||
/*
|
||||
|
||||
+33
-54
@@ -350,7 +350,7 @@ 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->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
|
||||
&& (pLevel->notReady & pTerm->prereqAll)==0
|
||||
){
|
||||
if( nLoop && (pTerm->wtFlags & TERM_LIKE)!=0 ){
|
||||
@@ -612,7 +612,7 @@ static int codeEqualityTerm(
|
||||
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0, &iTab);
|
||||
}else{
|
||||
Expr *pExpr = pTerm->pExpr;
|
||||
if( pExpr->iTable==0 || !ExprHasProperty(pExpr, EP_Subrtn) ){
|
||||
if( pExpr->iTable==0 || !ExprHasProperty(pExpr, EP_Subrtn) ){
|
||||
sqlite3 *db = pParse->db;
|
||||
pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX);
|
||||
if( !db->mallocFailed ){
|
||||
@@ -622,8 +622,13 @@ static int codeEqualityTerm(
|
||||
}
|
||||
sqlite3ExprDelete(db, pX);
|
||||
}else{
|
||||
int j1;
|
||||
j1 = sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn,
|
||||
pExpr->y.sub.iAddr);
|
||||
aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
|
||||
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab);
|
||||
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap,&iTab);
|
||||
iTab = pExpr->iTable;
|
||||
sqlite3VdbeUndoBackTo(v, j1+1);
|
||||
}
|
||||
pX = pExpr;
|
||||
}
|
||||
@@ -1071,7 +1076,7 @@ static void codeCursorHint(
|
||||
*/
|
||||
if( pTabItem->fg.jointype & JT_LEFT ){
|
||||
Expr *pExpr = pTerm->pExpr;
|
||||
if( !ExprHasProperty(pExpr, EP_OuterON)
|
||||
if( !ExprHasProperty(pExpr, EP_FromJoin)
|
||||
|| pExpr->w.iJoin!=pTabItem->iCursor
|
||||
){
|
||||
sWalker.eCode = 0;
|
||||
@@ -1080,7 +1085,7 @@ static void codeCursorHint(
|
||||
if( sWalker.eCode ) continue;
|
||||
}
|
||||
}else{
|
||||
if( ExprHasProperty(pTerm->pExpr, EP_OuterON) ) continue;
|
||||
if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue;
|
||||
}
|
||||
|
||||
/* All terms in pWLoop->aLTerm[] except pEndRange are used to initialize
|
||||
@@ -1258,6 +1263,7 @@ static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
|
||||
pExpr->op = TK_COLUMN;
|
||||
pExpr->iTable = pX->iIdxCur;
|
||||
pExpr->iColumn = pX->iIdxCol;
|
||||
testcase( ExprHasProperty(pExpr, EP_Skip) );
|
||||
testcase( ExprHasProperty(pExpr, EP_Unlikely) );
|
||||
ExprClearProperty(pExpr, EP_Skip|EP_Unlikely|EP_WinFunc|EP_Subrtn);
|
||||
pExpr->y.pTab = 0;
|
||||
@@ -1411,8 +1417,6 @@ static SQLITE_NOINLINE void filterPullDown(
|
||||
/* ,--- Because sqlite3ConstructBloomFilter() has will not have set
|
||||
** vvvvv--' pLevel->regFilter if this were true. */
|
||||
if( NEVER(pLoop->prereq & notReady) ) continue;
|
||||
assert( pLevel->addrBrk==0 );
|
||||
pLevel->addrBrk = addrNxt;
|
||||
if( pLoop->wsFlags & WHERE_IPK ){
|
||||
WhereTerm *pTerm = pLoop->aLTerm[0];
|
||||
int regRowid;
|
||||
@@ -1439,7 +1443,6 @@ static SQLITE_NOINLINE void filterPullDown(
|
||||
VdbeCoverage(pParse->pVdbe);
|
||||
}
|
||||
pLevel->regFilter = 0;
|
||||
pLevel->addrBrk = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2411,7 +2414,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
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)
|
||||
&& !ExprHasProperty(pOrExpr, EP_FromJoin)
|
||||
); /* See TH3 vtab25.400 and ticket 614b25314c766238 */
|
||||
pDelete = pOrExpr = sqlite3ExprDup(db, pOrExpr, 0);
|
||||
if( db->mallocFailed ){
|
||||
@@ -2619,22 +2622,12 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
}
|
||||
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 if( (pTabItem->fg.jointype & JT_LEFT)==JT_LEFT
|
||||
&& !ExprHasProperty(pE,EP_OuterON) ){
|
||||
continue;
|
||||
}else{
|
||||
Bitmask m = sqlite3WhereGetMask(&pWInfo->sMaskSet, pE->w.iJoin);
|
||||
if( m & pLevel->notReady ){
|
||||
/* An ON clause that is not ripe */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if( (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ))
|
||||
&& !ExprHasProperty(pE,EP_FromJoin)
|
||||
){
|
||||
continue;
|
||||
}
|
||||
|
||||
if( iLoop==1 && !sqlite3ExprCoveredByIndex(pE, pLevel->iTabCur, pIdx) ){
|
||||
iNext = 2;
|
||||
continue;
|
||||
@@ -2693,7 +2686,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
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;
|
||||
if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ) ) continue;
|
||||
pE = pTerm->pExpr;
|
||||
#ifdef WHERETRACE_ENABLED /* 0x800 */
|
||||
if( sqlite3WhereTrace & 0x800 ){
|
||||
@@ -2701,7 +2694,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
sqlite3WhereTermPrint(pTerm, pWC->nTerm-j);
|
||||
}
|
||||
#endif
|
||||
assert( !ExprHasProperty(pE, EP_OuterON) );
|
||||
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,
|
||||
@@ -2772,8 +2765,18 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2789,26 +2792,6 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
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 */
|
||||
@@ -2862,13 +2845,9 @@ SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
|
||||
mAll |= pLoop->maskSelf;
|
||||
for(k=0; k<pWC->nTerm; k++){
|
||||
WhereTerm *pTerm = &pWC->a[k];
|
||||
if( (pTerm->wtFlags & (TERM_VIRTUAL|TERM_SLICE))!=0
|
||||
&& pTerm->eOperator!=WO_ROWVAL
|
||||
){
|
||||
break;
|
||||
}
|
||||
if( pTerm->wtFlags & TERM_VIRTUAL ) break;
|
||||
if( pTerm->prereqAll & ~mAll ) continue;
|
||||
if( ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON) ) continue;
|
||||
if( ExprHasProperty(pTerm->pExpr, EP_FromJoin|EP_InnerJoin) ) continue;
|
||||
pSubWhere = sqlite3ExprAnd(pParse, pSubWhere,
|
||||
sqlite3ExprDup(pParse->db, pTerm->pExpr, 0));
|
||||
}
|
||||
|
||||
+20
-28
@@ -461,8 +461,8 @@ static int isAuxiliaryVtabOperator(
|
||||
** 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);
|
||||
if( pDerived ){
|
||||
pDerived->flags |= pBase->flags & EP_FromJoin;
|
||||
pDerived->w.iJoin = pBase->w.iJoin;
|
||||
}
|
||||
}
|
||||
@@ -917,7 +917,7 @@ static int termIsEquivalence(Parse *pParse, Expr *pExpr){
|
||||
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;
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0;
|
||||
aff1 = sqlite3ExprAffinity(pExpr->pLeft);
|
||||
aff2 = sqlite3ExprAffinity(pExpr->pRight);
|
||||
if( aff1!=aff2
|
||||
@@ -1105,26 +1105,18 @@ static void exprAnalyze(
|
||||
if( prereqAll!=sqlite3WhereExprUsageNN(pMaskSet, pExpr) ){
|
||||
printf("\n*** Incorrect prereqAll computed for:\n");
|
||||
sqlite3TreeViewExpr(0,pExpr,0);
|
||||
assert( 0 );
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
if( ExprHasProperty(pExpr, EP_OuterON|EP_InnerON) ){
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ){
|
||||
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);
|
||||
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;
|
||||
@@ -1192,7 +1184,7 @@ static void exprAnalyze(
|
||||
pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask;
|
||||
}else
|
||||
if( op==TK_ISNULL
|
||||
&& !ExprHasProperty(pExpr,EP_OuterON)
|
||||
&& !ExprHasProperty(pExpr,EP_FromJoin)
|
||||
&& 0==sqlite3ExprCanBeNull(pLeft)
|
||||
){
|
||||
assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
||||
@@ -1263,7 +1255,7 @@ static void exprAnalyze(
|
||||
else if( pExpr->op==TK_NOTNULL ){
|
||||
if( pExpr->pLeft->op==TK_COLUMN
|
||||
&& pExpr->pLeft->iColumn>=0
|
||||
&& !ExprHasProperty(pExpr, EP_OuterON)
|
||||
&& !ExprHasProperty(pExpr, EP_FromJoin)
|
||||
){
|
||||
Expr *pNewExpr;
|
||||
Expr *pLeft = pExpr->pLeft;
|
||||
@@ -1411,7 +1403,7 @@ static void exprAnalyze(
|
||||
}
|
||||
pTerm = &pWC->a[idxTerm];
|
||||
pTerm->wtFlags |= TERM_CODED|TERM_VIRTUAL; /* Disable the original */
|
||||
pTerm->eOperator = WO_ROWVAL;
|
||||
pTerm->eOperator = 0;
|
||||
}
|
||||
|
||||
/* If there is a vector IN term - e.g. "(a, b) IN (SELECT ...)" - create
|
||||
@@ -1467,8 +1459,8 @@ static void exprAnalyze(
|
||||
Expr *pNewExpr;
|
||||
pNewExpr = sqlite3PExpr(pParse, TK_MATCH,
|
||||
0, sqlite3ExprDup(db, pRight, 0));
|
||||
if( ExprHasProperty(pExpr, EP_OuterON) && pNewExpr ){
|
||||
ExprSetProperty(pNewExpr, EP_OuterON);
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) && pNewExpr ){
|
||||
ExprSetProperty(pNewExpr, EP_FromJoin);
|
||||
pNewExpr->w.iJoin = pExpr->w.iJoin;
|
||||
}
|
||||
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
|
||||
@@ -1612,7 +1604,7 @@ void sqlite3WhereAddLimit(WhereClause *pWC, Select *p){
|
||||
/* This term is a vector operation that has been decomposed into
|
||||
** other, subsequent terms. It can be ignored. See tag-20220128a */
|
||||
assert( pWC->a[ii].wtFlags & TERM_VIRTUAL );
|
||||
assert( pWC->a[ii].eOperator==WO_ROWVAL );
|
||||
assert( pWC->a[ii].eOperator==0 );
|
||||
continue;
|
||||
}
|
||||
if( pWC->a[ii].leftCursor!=iCsr ) return;
|
||||
@@ -1624,7 +1616,7 @@ void sqlite3WhereAddLimit(WhereClause *pWC, Select *p){
|
||||
Expr *pExpr = pOrderBy->a[ii].pExpr;
|
||||
if( pExpr->op!=TK_COLUMN ) return;
|
||||
if( pExpr->iTable!=iCsr ) return;
|
||||
if( pOrderBy->a[ii].fg.sortFlags & KEYINFO_ORDER_BIGNULL ) return;
|
||||
if( pOrderBy->a[ii].sortFlags & KEYINFO_ORDER_BIGNULL ) return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1835,9 +1827,9 @@ void sqlite3WhereTabFuncArgs(
|
||||
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;
|
||||
joinType = EP_FromJoin;
|
||||
}else{
|
||||
joinType = EP_InnerON;
|
||||
joinType = EP_InnerJoin;
|
||||
}
|
||||
sqlite3SetJoinExpr(pTerm, pItem->iCursor, joinType);
|
||||
whereClauseInsert(pWC, pTerm, TERM_DYNAMIC);
|
||||
|
||||
+3
-3
@@ -916,7 +916,7 @@ static ExprList *exprListAppendList(
|
||||
}
|
||||
}
|
||||
pList = sqlite3ExprListAppend(pParse, pList, pDup);
|
||||
if( pList ) pList->a[nInit+i].fg.sortFlags = pAppend->a[i].fg.sortFlags;
|
||||
if( pList ) pList->a[nInit+i].sortFlags = pAppend->a[i].sortFlags;
|
||||
}
|
||||
}
|
||||
return pList;
|
||||
@@ -2117,7 +2117,7 @@ static void windowCodeRangeTest(
|
||||
|
||||
assert( op==OP_Ge || op==OP_Gt || op==OP_Le );
|
||||
assert( pOrderBy && pOrderBy->nExpr==1 );
|
||||
if( pOrderBy->a[0].fg.sortFlags & KEYINFO_ORDER_DESC ){
|
||||
if( pOrderBy->a[0].sortFlags & KEYINFO_ORDER_DESC ){
|
||||
switch( op ){
|
||||
case OP_Ge: op = OP_Le; break;
|
||||
case OP_Gt: op = OP_Lt; break;
|
||||
@@ -2150,7 +2150,7 @@ static void windowCodeRangeTest(
|
||||
** Additionally, if either reg1 or reg2 are NULL but the jump to lbl is
|
||||
** not taken, control jumps over the comparison operator coded below this
|
||||
** block. */
|
||||
if( pOrderBy->a[0].fg.sortFlags & KEYINFO_ORDER_BIGNULL ){
|
||||
if( pOrderBy->a[0].sortFlags & KEYINFO_ORDER_BIGNULL ){
|
||||
/* This block runs if reg1 contains a NULL. */
|
||||
int addr = sqlite3VdbeAddOp1(v, OP_NotNull, reg1); VdbeCoverage(v);
|
||||
switch( op ){
|
||||
|
||||
@@ -21,7 +21,6 @@ ifcapable !altertable {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
set ::TMPDBERROR [list 1 \
|
||||
{unable to open a temporary database file for storing temporary tables}
|
||||
]
|
||||
@@ -48,7 +47,6 @@ do_faultsim_test 1 -prep {
|
||||
faultsim_test_result {0 {}} $::TMPDBERROR
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# dbsqlfuzz e3dd84cda3848016a6a6024c7249d09bc2ef2615
|
||||
#
|
||||
@@ -61,11 +59,6 @@ do_execsql_test 2.0 {
|
||||
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
|
||||
|
||||
+1
-1
@@ -645,7 +645,7 @@ do_execsql_test 26.5 {
|
||||
} {}
|
||||
do_catchsql_test 26.6 {
|
||||
ALTER TABLE t1 RENAME TO t2;
|
||||
} {1 {error in trigger xx: no such column: xx}}
|
||||
} {1 {error in trigger xx: ambiguous column name: xx}}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
# 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
|
||||
|
||||
+1
-1
@@ -399,7 +399,7 @@ do_test 9.2 {
|
||||
for {set i 0} {$i < 100} {incr i} {
|
||||
execsql "INSERT INTO t1 VALUES('x', 'y', 'z', $i, [expr $i/2])"
|
||||
}
|
||||
for {set i 0} {$i < 21} {incr i} {
|
||||
for {set i 0} {$i < 20} {incr i} {
|
||||
execsql "INSERT INTO t1 VALUES('x', 'y', 'z', 101, $i)"
|
||||
}
|
||||
for {set i 102} {$i < 200} {incr i} {
|
||||
|
||||
+3
-4
@@ -618,12 +618,11 @@ foreach {tn select res} {
|
||||
} {
|
||||
do_join_test e_select-1.7.$tn $select $res
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-24610-05866 If the join-operator is a "LEFT JOIN" or
|
||||
# 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 does not match any row in the
|
||||
# right-hand dataset.
|
||||
# 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);
|
||||
|
||||
@@ -181,53 +181,29 @@ if {[working_64bit_int]} {
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -193,42 +193,4 @@ do_catchsql_test 7.10 {
|
||||
SELECT matchinfo( f , 'pcx') FROM f WHERE b MATCH x'c533';
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
reset_db
|
||||
sqlite3_fts3_may_be_corrupt 1
|
||||
do_execsql_test 8.1 {
|
||||
CREATE VIRTUAL TABLE f USING fts3(a);
|
||||
INSERT INTO f(f) VALUES('nodesize=24');
|
||||
BEGIN;
|
||||
INSERT INTO f VALUES('abcdefghijklmnopqrstuvwxyz0123456789');
|
||||
INSERT INTO f VALUES('abcdefghijklmnopqrstuvwxyz0123456789');
|
||||
INSERT INTO f VALUES('abcdefghijklmnopqrstuvwxyz0123456789');
|
||||
|
||||
INSERT INTO f VALUES('abcdefghijklmnopqrstuvwxyz012345678X');
|
||||
INSERT INTO f VALUES('abcdefghijklmnopqrstuvwxyz012345678X');
|
||||
INSERT INTO f VALUES('abcdefghijklmnopqrstuvwxyz012345678X');
|
||||
COMMIT;
|
||||
BEGIN;
|
||||
INSERT INTO f VALUES('abcdefghijklmnopqrstuvwxyz0123456789');
|
||||
INSERT INTO f VALUES('abcdefghijklmnopqrstuvwxyz0123456789');
|
||||
INSERT INTO f VALUES('abcdefghijklmnopqrstuvwxyz0123456789');
|
||||
|
||||
INSERT INTO f VALUES('abcdefghijklmnopqrstuvwxyz012345678X');
|
||||
INSERT INTO f VALUES('abcdefghijklmnopqrstuvwxyz012345678X');
|
||||
INSERT INTO f VALUES('abcdefghijklmnopqrstuvwxyz012345678X');
|
||||
COMMIT;
|
||||
|
||||
SELECT count(*) FROM f_segments;
|
||||
} {4}
|
||||
|
||||
do_execsql_test 8.2 {
|
||||
UPDATE f_segments SET block = (
|
||||
SELECT block FROM f_segments WHERE blockid=1
|
||||
) WHERE blockid=2
|
||||
}
|
||||
|
||||
do_catchsql_test 8.3 {
|
||||
INSERT INTO f(f) VALUES('merge=2,2');
|
||||
} {1 {database disk image is malformed}}
|
||||
sqlite3_fts3_may_be_corrupt 0
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -64,8 +64,7 @@ do_execsql_test 2.1 {
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
breakpoint
|
||||
do_catchsql_test 3.0 {
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE main.Table0 USING fts3();
|
||||
INSERT INTO Table0 VALUES (1), (printf('%8.1280000X') ), (1), (printf('%8.1280000X') ), (1) ;
|
||||
INSERT INTO Table0 VALUES (0), (printf('%8.1280000X%8.1280000X') ), (1), (printf('%1280000.1280000X%#1280000.1280000E%8.1280000X') ), (1) ;
|
||||
@@ -73,7 +72,7 @@ do_catchsql_test 3.0 {
|
||||
UPDATE Table0_segdir SET start_block = 1;
|
||||
INSERT INTO Table0 VALUES (1) ;
|
||||
INSERT INTO Table0(Table0) VALUES('merge=6,8');
|
||||
} {1 {database disk image is malformed}}
|
||||
}
|
||||
|
||||
set sqlite_fts3_enable_parentheses $saved_sqlite_fts3_enable_parentheses
|
||||
finish_test
|
||||
|
||||
@@ -60,12 +60,6 @@ do_execsql_test func7-pg-170 {
|
||||
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}
|
||||
|
||||
@@ -798,13 +798,4 @@ 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
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix incrblob3
|
||||
|
||||
ifcapable !incrblob {
|
||||
finish_test
|
||||
@@ -274,41 +273,4 @@ do_test incrblob3-7.2 {
|
||||
db close
|
||||
tvfs delete
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
forcedelete test.db2
|
||||
do_execsql_test 8.1 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
|
||||
ATTACH 'test.db2' AS aux;
|
||||
CREATE TABLE aux.t1(a INTEGER PRIMARY KEY, b);
|
||||
|
||||
INSERT INTO t1 VALUES(4, 'hello');
|
||||
INSERT INTO aux.t1 VALUES(4, 'world');
|
||||
}
|
||||
|
||||
do_test 8.2 {
|
||||
set ::blob [db incrblob -readonly main t1 b 4]
|
||||
read $::blob
|
||||
} {hello}
|
||||
close $::blob
|
||||
|
||||
do_test 8.3 {
|
||||
set ::blob [db incrblob -readonly aux t1 b 4]
|
||||
read $::blob
|
||||
} {world}
|
||||
close $::blob
|
||||
|
||||
do_test 8.4 {
|
||||
set ::blob [db incrblob -readonly t1 b 4]
|
||||
read $::blob
|
||||
} {hello}
|
||||
close $::blob
|
||||
|
||||
do_test 8.5 {
|
||||
list [catch { db incrblob -readonly nosuchdb t1 b 4 } msg] $msg
|
||||
} {1 {no such table: nosuchdb.t1}}
|
||||
|
||||
|
||||
db close
|
||||
finish_test
|
||||
|
||||
@@ -250,19 +250,6 @@ do_test join-2.1 {
|
||||
}
|
||||
} {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 {
|
||||
@@ -341,9 +328,6 @@ do_test join-3.6 {
|
||||
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;
|
||||
|
||||
@@ -393,38 +393,6 @@ do_execsql_test 11.4 {
|
||||
SELECT count(*) FROM t1 LEFT JOIN t2 ON c=b WHERE d>=300;
|
||||
} {2}
|
||||
|
||||
# 2022-05-03 https://sqlite.org/forum/forumpost/2482b32700384a0f
|
||||
# Bloom-filter pull-down does not handle NOT NULL constraints correctly.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 12.1 {
|
||||
CREATE TABLE t1(a INT, b INT, c INT);
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
|
||||
INSERT INTO t1(a,b,c) SELECT x, x*1000, x*1000000 FROM c;
|
||||
CREATE TABLE t2(b INT, x INT);
|
||||
INSERT INTO t2(b,x) SELECT b, a FROM t1 WHERE a%3==0;
|
||||
CREATE INDEX t2b ON t2(b);
|
||||
CREATE TABLE t3(c INT, y INT);
|
||||
INSERT INTO t3(c,y) SELECT c, a FROM t1 WHERE a%4==0;
|
||||
CREATE INDEX t3c ON t3(c);
|
||||
INSERT INTO t1(a,b,c) VALUES(200, 200000, NULL);
|
||||
ANALYZE;
|
||||
} {}
|
||||
do_execsql_test 12.2 {
|
||||
SELECT * FROM t1 NATURAL JOIN t2 NATURAL JOIN t3 WHERE x>0 AND y>0
|
||||
ORDER BY +a;
|
||||
} {
|
||||
12 12000 12000000 12 12
|
||||
24 24000 24000000 24 24
|
||||
36 36000 36000000 36 36
|
||||
48 48000 48000000 48 48
|
||||
60 60000 60000000 60 60
|
||||
72 72000 72000000 72 72
|
||||
84 84000 84000000 84 84
|
||||
96 96000 96000000 96 96
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -139,72 +139,6 @@ foreach {id schema} {
|
||||
1 3 3 33
|
||||
1 4 4 44
|
||||
}
|
||||
do_execsql_test join7-$id.32 {
|
||||
SELECT t1.*, t2.* FROM t2 FULL OUTER JOIN t1 ON b=c
|
||||
WHERE b=c
|
||||
ORDER BY +b;
|
||||
} {
|
||||
1 3 3 33
|
||||
1 4 4 44
|
||||
}
|
||||
do_execsql_test join7-$id.33 {
|
||||
SELECT t1.*, t2.* FROM t2 FULL OUTER JOIN t1 ON b=c
|
||||
WHERE b>0
|
||||
ORDER BY +b;
|
||||
} {
|
||||
1 2 NULL NULL
|
||||
1 3 3 33
|
||||
1 4 4 44
|
||||
}
|
||||
do_execsql_test join7-$id.34 {
|
||||
SELECT t1.*, t2.* FROM t2 FULL OUTER JOIN t1 ON b=c
|
||||
WHERE b>0 OR b IS NULL
|
||||
ORDER BY +b;
|
||||
} {
|
||||
NULL NULL 5 55
|
||||
1 2 NULL NULL
|
||||
1 3 3 33
|
||||
1 4 4 44
|
||||
}
|
||||
do_execsql_test join7-$id.35 {
|
||||
SELECT t1.*, t2.* FROM t2 FULL OUTER JOIN t1 ON b=c AND b>3 AND c>4
|
||||
ORDER BY coalesce(b,c,0);
|
||||
} {
|
||||
1 2 NULL NULL
|
||||
NULL NULL 3 33
|
||||
1 3 NULL NULL
|
||||
NULL NULL 4 44
|
||||
1 4 NULL NULL
|
||||
NULL NULL 5 55
|
||||
}
|
||||
do_execsql_test join7-$id.36 {
|
||||
SELECT t1.*, t2.* FROM t2 FULL OUTER JOIN t1 ON b=c AND b>3 WHERE c>4
|
||||
ORDER BY coalesce(b,c,0);
|
||||
} {
|
||||
NULL NULL 5 55
|
||||
}
|
||||
do_execsql_test join7-$id.37 {
|
||||
SELECT t1.*, t2.* FROM t2 FULL OUTER JOIN t1 ON b=c WHERE b>3 AND c>4
|
||||
ORDER BY coalesce(b,c,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test join7-$id.38 {
|
||||
SELECT t1.*, t2.* FROM t2 FULL OUTER JOIN t1 ON b=c WHERE b>3 OR c>4
|
||||
ORDER BY coalesce(b,c,0);
|
||||
} {
|
||||
1 4 4 44
|
||||
NULL NULL 5 55
|
||||
}
|
||||
do_execsql_test join7-$id.39 {
|
||||
SELECT t1.*, t2.* FROM t2 FULL OUTER JOIN t1 ON b=c AND (b>3 OR c>4)
|
||||
ORDER BY coalesce(b,c,0);
|
||||
} {
|
||||
1 2 NULL NULL
|
||||
NULL NULL 3 33
|
||||
1 3 NULL NULL
|
||||
1 4 4 44
|
||||
NULL NULL 5 55
|
||||
}
|
||||
do_execsql_test join7-$id.40 {
|
||||
SELECT * FROM t1 RIGHT OUTER JOIN t2 ON b=c ORDER BY +b;
|
||||
} {
|
||||
|
||||
-392
@@ -20,8 +20,6 @@ ifcapable !vtab {
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -182,394 +180,4 @@ do_execsql_test join8-6020 {
|
||||
WHERE (a,b) IN (SELECT rowid, b FROM t1);
|
||||
} {17 1 2}
|
||||
|
||||
# Bloom filter usage by RIGHT and FULL JOIN
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test join8-7000 {
|
||||
CREATE TABLE t1(a INT, b INT, c INT, d INT);
|
||||
WITH RECURSIVE c(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM c WHERE x<10)
|
||||
INSERT INTO t1(a,b,c,d) SELECT x, x+100, x+200, x+300 FROM c;
|
||||
CREATE TABLE t2(b INT, x INT);
|
||||
INSERT INTO t2(b,x) SELECT b, a FROM t1 WHERE a%2=0;
|
||||
CREATE INDEX t2b ON t2(b);
|
||||
CREATE TABLE t3(c INT, y INT);
|
||||
INSERT INTO t3(c,y) SELECT c, a FROM t1 WHERE a%3=0;
|
||||
CREATE INDEX t3c ON t3(c);
|
||||
CREATE TABLE t4(d INT, z INT);
|
||||
INSERT INTO t4(d,z) SELECT d, a FROM t1 WHERE a%5=0;
|
||||
CREATE INDEX t4d ON t4(d);
|
||||
INSERT INTO t1(a,b,c,d) VALUES
|
||||
(96,NULL,296,396),
|
||||
(97,197,NULL,397),
|
||||
(98,198,298,NULL),
|
||||
(99,NULL,NULL,NULL);
|
||||
ANALYZE sqlite_schema;
|
||||
INSERT INTO sqlite_stat1 VALUES('t4','t4d','20 1');
|
||||
INSERT INTO sqlite_stat1 VALUES('t3','t3c','32 1');
|
||||
INSERT INTO sqlite_stat1 VALUES('t2','t2b','48 1');
|
||||
INSERT INTO sqlite_stat1 VALUES('t1',NULL,'100');
|
||||
ANALYZE sqlite_schema;
|
||||
} {}
|
||||
db null -
|
||||
do_execsql_test join8-7010 {
|
||||
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);
|
||||
} {
|
||||
6 106 206 306 106 6 206 6 - -
|
||||
- - - - - - 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
|
||||
}
|
||||
|
||||
# 2022-05-30
|
||||
# https://sqlite.org/forum/forumpost/3902c7b833
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test join8-15000 {
|
||||
CREATE TABLE t1(x INT);
|
||||
CREATE TABLE t2(y INT);
|
||||
CREATE TABLE t3(z INT);
|
||||
INSERT INTO t1 VALUES(10);
|
||||
INSERT INTO t3 VALUES(20),(30);
|
||||
}
|
||||
do_execsql_test join8-15010 {
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON true JOIN t3 ON t2.y IS NOT NULL;
|
||||
} {}
|
||||
do_execsql_test join8-15020 {
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON true JOIN t3 ON t2.y IS NOT NULL
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600);
|
||||
} {}
|
||||
do_execsql_test join8-15100 {
|
||||
PRAGMA automatic_index = 0;
|
||||
CREATE TABLE t4(x TEXT);
|
||||
CREATE TABLE t5(y TEXT);
|
||||
CREATE TABLE t6(z TEXT);
|
||||
INSERT INTO t4 VALUES('a'), ('b');
|
||||
INSERT INTO t5 VALUES('b'), ('c');
|
||||
INSERT INTO t6 VALUES('a'), ('d');
|
||||
} {}
|
||||
db null -
|
||||
do_execsql_test join8-15110 {
|
||||
SELECT * FROM t4 LEFT JOIN t5 ON x=y LEFT JOIN t6 ON (x=z) ORDER BY +x;
|
||||
} {a - a b b -}
|
||||
do_execsql_test join8-15120 {
|
||||
SELECT * FROM t4 LEFT JOIN t5 ON x=y LEFT JOIN t6 ON (x=z)
|
||||
WHERE t5.y!='x' AND t4.x!='x';
|
||||
} {b b -}
|
||||
|
||||
# 2022-05-31
|
||||
# https://sqlite.org/forum/forumpost/c2554d560b
|
||||
reset_db
|
||||
do_execsql_test join8-16000 {
|
||||
CREATE TABLE t1(a TEXT);
|
||||
CREATE TABLE t2(b TEXT);
|
||||
CREATE TABLE t3(c TEXT);
|
||||
INSERT INTO t2(b) VALUES ('x');
|
||||
INSERT INTO t3(c) VALUES ('y'), ('z');
|
||||
} {}
|
||||
db null -
|
||||
do_execsql_test join8-16010 {
|
||||
SELECT * FROM t1 RIGHT JOIN t2 ON true LEFT JOIN t3 ON a<>'';
|
||||
} {- x -}
|
||||
do_execsql_test join8-16020 {
|
||||
SELECT * FROM t1 RIGHT JOIN t2 ON true LEFT JOIN t3 ON a<>'' WHERE c IS NULL;
|
||||
} {- x -}
|
||||
do_execsql_test join8-16020 {
|
||||
SELECT * FROM t1 RIGHT JOIN t2 ON true JOIN t3 ON a<>'' WHERE c IS NULL;
|
||||
} {}
|
||||
do_execsql_test join8-16030 {
|
||||
SELECT * FROM t1 RIGHT JOIN t2 ON true JOIN t3 ON a<>'';
|
||||
} {}
|
||||
do_execsql_test join8-16040 {
|
||||
SELECT * FROM t1 RIGHT JOIN t2 ON true LEFT JOIN t3 ON a<>'' WHERE c<>'';
|
||||
} {}
|
||||
do_execsql_test join8-16050 {
|
||||
SELECT * FROM t1 RIGHT JOIN t2 ON true LEFT JOIN t3 ON a<>'' WHERE c IS NOT NULL;
|
||||
} {}
|
||||
do_execsql_test join8-16060 {
|
||||
SELECT * FROM t1 RIGHT JOIN t2 ON true JOIN t3 ON a<>'' WHERE c<>'';
|
||||
} {}
|
||||
do_execsql_test join8-16070 {
|
||||
SELECT * FROM t1 RIGHT JOIN t2 ON true JOIN t3 ON a<>'' WHERE c IS NOT NULL;
|
||||
} {}
|
||||
|
||||
# 2022-06-01
|
||||
# https://sqlite.org/forum/forumpost/087de2d9ec
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test join8-17000 {
|
||||
CREATE TABLE t1(id INTEGER PRIMARY KEY, x INT, y INT);
|
||||
CREATE TABLE t2(z INT);
|
||||
INSERT INTO t1(id,x,y) VALUES(1, 0, 0);
|
||||
} {}
|
||||
db null NULL
|
||||
do_execsql_test join8-17010 {
|
||||
SELECT * FROM t2 RIGHT JOIN t1 ON true;
|
||||
} {NULL 1 0 0}
|
||||
do_execsql_test join8-17020 {
|
||||
SELECT 99=id AND 0=y AS "truth" FROM t2 RIGHT JOIN t1 ON true;
|
||||
} {0}
|
||||
do_execsql_test join8-17030 {
|
||||
SELECT (99, 0)==(id, y) AS "truth" FROM t2 RIGHT JOIN t1;
|
||||
} {0}
|
||||
do_execsql_test join8-17040 {
|
||||
SELECT * FROM t2 RIGHT JOIN t1 WHERE 99=id AND 0=y;
|
||||
} {}
|
||||
do_execsql_test join8-17041 {
|
||||
SELECT * FROM t2 RIGHT JOIN t1 WHERE 99=+id AND 0=y;
|
||||
} {}
|
||||
do_execsql_test join8-17050 {
|
||||
SELECT * FROM t2 RIGHT JOIN t1 WHERE (99, 0)==(id,y);
|
||||
} {}
|
||||
do_execsql_test join8-17051 {
|
||||
SELECT * FROM t2 RIGHT JOIN t1 WHERE (99, 0)==(+id,y);
|
||||
} {}
|
||||
do_execsql_test join8-17060 {
|
||||
SELECT * FROM t2 RIGHT JOIN t1 WHERE 1=id AND 0=y;
|
||||
} {NULL 1 0 0}
|
||||
do_execsql_test join8-17061 {
|
||||
SELECT * FROM t2 RIGHT JOIN t1 WHERE 1=+id AND 0=y;
|
||||
} {NULL 1 0 0}
|
||||
do_execsql_test join8-17070 {
|
||||
SELECT * FROM t2 RIGHT JOIN t1 WHERE (1, 0)==(id,y);
|
||||
} {NULL 1 0 0}
|
||||
do_execsql_test join8-17071 {
|
||||
SELECT * FROM t2 RIGHT JOIN t1 WHERE (1, 0)==(+id,y);
|
||||
} {NULL 1 0 0}
|
||||
do_execsql_test join8-17080 {
|
||||
CREATE TABLE t3(a INTEGER PRIMARY KEY, b INT);
|
||||
CREATE TABLE t4(x INT, y INT);
|
||||
INSERT INTO t3(a,b) VALUES(1, 3);
|
||||
} {}
|
||||
do_execsql_test join8-17090 {
|
||||
SELECT t3.a FROM t4 RIGHT JOIN t3 ON (x=a) WHERE (b, 4)=(SELECT 3, 4);
|
||||
} {1}
|
||||
do_execsql_test join8-17091 {
|
||||
SELECT t3.a FROM t4 RIGHT JOIN t3 ON (x=a) WHERE (b, 4) IS (SELECT 3, 4);
|
||||
} {1}
|
||||
|
||||
finish_test
|
||||
|
||||
-4594
File diff suppressed because it is too large
Load Diff
-35134
File diff suppressed because it is too large
Load Diff
-443
@@ -1,443 +0,0 @@
|
||||
# 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 " "\}"
|
||||
#
|
||||
# }
|
||||
# }
|
||||
-613
@@ -1,613 +0,0 @@
|
||||
# 2022-05-31
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# A few extra tests that were not generated from postgresql output are
|
||||
# added at the end.
|
||||
#
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
db nullvalue -
|
||||
db eval {
|
||||
CREATE TABLE t1(x INT);
|
||||
CREATE TABLE t2(y INT);
|
||||
CREATE TABLE t3(z INT);
|
||||
CREATE TABLE t4(w INT);
|
||||
INSERT INTO t1 VALUES(10);
|
||||
INSERT INTO t3 VALUES(20),(30);
|
||||
INSERT INTO t4 VALUES(50);
|
||||
}
|
||||
do_execsql_test joinF-1 {
|
||||
SELECT *
|
||||
FROM t1 INNER JOIN t2 ON true
|
||||
INNER JOIN t3 ON t2.y IS NOT NULL
|
||||
INNER JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-2 {
|
||||
SELECT *
|
||||
FROM t1 INNER JOIN t2 ON true
|
||||
INNER JOIN t3 ON t2.y IS NOT NULL
|
||||
INNER JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-3 {
|
||||
SELECT *
|
||||
FROM t1 INNER JOIN t2 ON true
|
||||
INNER JOIN t3 ON t2.y IS NOT NULL
|
||||
LEFT JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-4 {
|
||||
SELECT *
|
||||
FROM t1 INNER JOIN t2 ON true
|
||||
INNER JOIN t3 ON t2.y IS NOT NULL
|
||||
LEFT JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-5 {
|
||||
SELECT *
|
||||
FROM t1 INNER JOIN t2 ON true
|
||||
INNER JOIN t3 ON t2.y IS NOT NULL
|
||||
RIGHT JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
- - - 50
|
||||
}
|
||||
do_execsql_test joinF-6 {
|
||||
SELECT *
|
||||
FROM t1 INNER JOIN t2 ON true
|
||||
INNER JOIN t3 ON t2.y IS NOT NULL
|
||||
RIGHT JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-7 {
|
||||
SELECT *
|
||||
FROM t1 INNER JOIN t2 ON true
|
||||
LEFT JOIN t3 ON t2.y IS NOT NULL
|
||||
INNER JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-8 {
|
||||
SELECT *
|
||||
FROM t1 INNER JOIN t2 ON true
|
||||
LEFT JOIN t3 ON t2.y IS NOT NULL
|
||||
INNER JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-9 {
|
||||
SELECT *
|
||||
FROM t1 INNER JOIN t2 ON true
|
||||
LEFT JOIN t3 ON t2.y IS NOT NULL
|
||||
LEFT JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-10 {
|
||||
SELECT *
|
||||
FROM t1 INNER JOIN t2 ON true
|
||||
LEFT JOIN t3 ON t2.y IS NOT NULL
|
||||
LEFT JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-11 {
|
||||
SELECT *
|
||||
FROM t1 INNER JOIN t2 ON true
|
||||
LEFT JOIN t3 ON t2.y IS NOT NULL
|
||||
RIGHT JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
- - - 50
|
||||
}
|
||||
do_execsql_test joinF-12 {
|
||||
SELECT *
|
||||
FROM t1 INNER JOIN t2 ON true
|
||||
LEFT JOIN t3 ON t2.y IS NOT NULL
|
||||
RIGHT JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-13 {
|
||||
SELECT *
|
||||
FROM t1 INNER JOIN t2 ON true
|
||||
RIGHT JOIN t3 ON t2.y IS NOT NULL
|
||||
INNER JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
- - 20 50
|
||||
- - 30 50
|
||||
}
|
||||
do_execsql_test joinF-14 {
|
||||
SELECT *
|
||||
FROM t1 INNER JOIN t2 ON true
|
||||
RIGHT JOIN t3 ON t2.y IS NOT NULL
|
||||
INNER JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
- - 20 50
|
||||
- - 30 50
|
||||
}
|
||||
do_execsql_test joinF-15 {
|
||||
SELECT *
|
||||
FROM t1 INNER JOIN t2 ON true
|
||||
RIGHT JOIN t3 ON t2.y IS NOT NULL
|
||||
LEFT JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
- - 20 50
|
||||
- - 30 50
|
||||
}
|
||||
do_execsql_test joinF-16 {
|
||||
SELECT *
|
||||
FROM t1 INNER JOIN t2 ON true
|
||||
RIGHT JOIN t3 ON t2.y IS NOT NULL
|
||||
LEFT JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
- - 20 50
|
||||
- - 30 50
|
||||
}
|
||||
do_execsql_test joinF-17 {
|
||||
SELECT *
|
||||
FROM t1 INNER JOIN t2 ON true
|
||||
RIGHT JOIN t3 ON t2.y IS NOT NULL
|
||||
RIGHT JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
- - 20 50
|
||||
- - 30 50
|
||||
}
|
||||
do_execsql_test joinF-18 {
|
||||
SELECT *
|
||||
FROM t1 INNER JOIN t2 ON true
|
||||
RIGHT JOIN t3 ON t2.y IS NOT NULL
|
||||
RIGHT JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
- - 20 50
|
||||
- - 30 50
|
||||
}
|
||||
do_execsql_test joinF-19 {
|
||||
SELECT *
|
||||
FROM t1 LEFT JOIN t2 ON true
|
||||
INNER JOIN t3 ON t2.y IS NOT NULL
|
||||
INNER JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-20 {
|
||||
SELECT *
|
||||
FROM t1 LEFT JOIN t2 ON true
|
||||
INNER JOIN t3 ON t2.y IS NOT NULL
|
||||
INNER JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-21 {
|
||||
SELECT *
|
||||
FROM t1 LEFT JOIN t2 ON true
|
||||
INNER JOIN t3 ON t2.y IS NOT NULL
|
||||
LEFT JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-22 {
|
||||
SELECT *
|
||||
FROM t1 LEFT JOIN t2 ON true
|
||||
INNER JOIN t3 ON t2.y IS NOT NULL
|
||||
LEFT JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-23 {
|
||||
SELECT *
|
||||
FROM t1 LEFT JOIN t2 ON true
|
||||
INNER JOIN t3 ON t2.y IS NOT NULL
|
||||
RIGHT JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
- - - 50
|
||||
}
|
||||
do_execsql_test joinF-24 {
|
||||
SELECT *
|
||||
FROM t1 LEFT JOIN t2 ON true
|
||||
INNER JOIN t3 ON t2.y IS NOT NULL
|
||||
RIGHT JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-25 {
|
||||
SELECT *
|
||||
FROM t1 LEFT JOIN t2 ON true
|
||||
LEFT JOIN t3 ON t2.y IS NOT NULL
|
||||
INNER JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
10 - - 50
|
||||
}
|
||||
do_execsql_test joinF-26 {
|
||||
SELECT *
|
||||
FROM t1 LEFT JOIN t2 ON true
|
||||
LEFT JOIN t3 ON t2.y IS NOT NULL
|
||||
INNER JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-27 {
|
||||
SELECT *
|
||||
FROM t1 LEFT JOIN t2 ON true
|
||||
LEFT JOIN t3 ON t2.y IS NOT NULL
|
||||
LEFT JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
10 - - 50
|
||||
}
|
||||
do_execsql_test joinF-28 {
|
||||
SELECT *
|
||||
FROM t1 LEFT JOIN t2 ON true
|
||||
LEFT JOIN t3 ON t2.y IS NOT NULL
|
||||
LEFT JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-29 {
|
||||
SELECT *
|
||||
FROM t1 LEFT JOIN t2 ON true
|
||||
LEFT JOIN t3 ON t2.y IS NOT NULL
|
||||
RIGHT JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
10 - - 50
|
||||
}
|
||||
do_execsql_test joinF-30 {
|
||||
SELECT *
|
||||
FROM t1 LEFT JOIN t2 ON true
|
||||
LEFT JOIN t3 ON t2.y IS NOT NULL
|
||||
RIGHT JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-31 {
|
||||
SELECT *
|
||||
FROM t1 LEFT JOIN t2 ON true
|
||||
RIGHT JOIN t3 ON t2.y IS NOT NULL
|
||||
INNER JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
- - 20 50
|
||||
- - 30 50
|
||||
}
|
||||
do_execsql_test joinF-32 {
|
||||
SELECT *
|
||||
FROM t1 LEFT JOIN t2 ON true
|
||||
RIGHT JOIN t3 ON t2.y IS NOT NULL
|
||||
INNER JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
- - 20 50
|
||||
- - 30 50
|
||||
}
|
||||
do_execsql_test joinF-33 {
|
||||
SELECT *
|
||||
FROM t1 LEFT JOIN t2 ON true
|
||||
RIGHT JOIN t3 ON t2.y IS NOT NULL
|
||||
LEFT JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
- - 20 50
|
||||
- - 30 50
|
||||
}
|
||||
do_execsql_test joinF-34 {
|
||||
SELECT *
|
||||
FROM t1 LEFT JOIN t2 ON true
|
||||
RIGHT JOIN t3 ON t2.y IS NOT NULL
|
||||
LEFT JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
- - 20 50
|
||||
- - 30 50
|
||||
}
|
||||
do_execsql_test joinF-35 {
|
||||
SELECT *
|
||||
FROM t1 LEFT JOIN t2 ON true
|
||||
RIGHT JOIN t3 ON t2.y IS NOT NULL
|
||||
RIGHT JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
- - 20 50
|
||||
- - 30 50
|
||||
}
|
||||
do_execsql_test joinF-36 {
|
||||
SELECT *
|
||||
FROM t1 LEFT JOIN t2 ON true
|
||||
RIGHT JOIN t3 ON t2.y IS NOT NULL
|
||||
RIGHT JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
- - 20 50
|
||||
- - 30 50
|
||||
}
|
||||
do_execsql_test joinF-37 {
|
||||
SELECT *
|
||||
FROM t1 RIGHT JOIN t2 ON true
|
||||
INNER JOIN t3 ON t2.y IS NOT NULL
|
||||
INNER JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-38 {
|
||||
SELECT *
|
||||
FROM t1 RIGHT JOIN t2 ON true
|
||||
INNER JOIN t3 ON t2.y IS NOT NULL
|
||||
INNER JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-39 {
|
||||
SELECT *
|
||||
FROM t1 RIGHT JOIN t2 ON true
|
||||
INNER JOIN t3 ON t2.y IS NOT NULL
|
||||
LEFT JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-40 {
|
||||
SELECT *
|
||||
FROM t1 RIGHT JOIN t2 ON true
|
||||
INNER JOIN t3 ON t2.y IS NOT NULL
|
||||
LEFT JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-41 {
|
||||
SELECT *
|
||||
FROM t1 RIGHT JOIN t2 ON true
|
||||
INNER JOIN t3 ON t2.y IS NOT NULL
|
||||
RIGHT JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
- - - 50
|
||||
}
|
||||
do_execsql_test joinF-42 {
|
||||
SELECT *
|
||||
FROM t1 RIGHT JOIN t2 ON true
|
||||
INNER JOIN t3 ON t2.y IS NOT NULL
|
||||
RIGHT JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-43 {
|
||||
SELECT *
|
||||
FROM t1 RIGHT JOIN t2 ON true
|
||||
LEFT JOIN t3 ON t2.y IS NOT NULL
|
||||
INNER JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-44 {
|
||||
SELECT *
|
||||
FROM t1 RIGHT JOIN t2 ON true
|
||||
LEFT JOIN t3 ON t2.y IS NOT NULL
|
||||
INNER JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-45 {
|
||||
SELECT *
|
||||
FROM t1 RIGHT JOIN t2 ON true
|
||||
LEFT JOIN t3 ON t2.y IS NOT NULL
|
||||
LEFT JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-46 {
|
||||
SELECT *
|
||||
FROM t1 RIGHT JOIN t2 ON true
|
||||
LEFT JOIN t3 ON t2.y IS NOT NULL
|
||||
LEFT JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-47 {
|
||||
SELECT *
|
||||
FROM t1 RIGHT JOIN t2 ON true
|
||||
LEFT JOIN t3 ON t2.y IS NOT NULL
|
||||
RIGHT JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
- - - 50
|
||||
}
|
||||
do_execsql_test joinF-48 {
|
||||
SELECT *
|
||||
FROM t1 RIGHT JOIN t2 ON true
|
||||
LEFT JOIN t3 ON t2.y IS NOT NULL
|
||||
RIGHT JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
}
|
||||
do_execsql_test joinF-49 {
|
||||
SELECT *
|
||||
FROM t1 RIGHT JOIN t2 ON true
|
||||
RIGHT JOIN t3 ON t2.y IS NOT NULL
|
||||
INNER JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
- - 20 50
|
||||
- - 30 50
|
||||
}
|
||||
do_execsql_test joinF-50 {
|
||||
SELECT *
|
||||
FROM t1 RIGHT JOIN t2 ON true
|
||||
RIGHT JOIN t3 ON t2.y IS NOT NULL
|
||||
INNER JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
- - 20 50
|
||||
- - 30 50
|
||||
}
|
||||
do_execsql_test joinF-51 {
|
||||
SELECT *
|
||||
FROM t1 RIGHT JOIN t2 ON true
|
||||
RIGHT JOIN t3 ON t2.y IS NOT NULL
|
||||
LEFT JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
- - 20 50
|
||||
- - 30 50
|
||||
}
|
||||
do_execsql_test joinF-52 {
|
||||
SELECT *
|
||||
FROM t1 RIGHT JOIN t2 ON true
|
||||
RIGHT JOIN t3 ON t2.y IS NOT NULL
|
||||
LEFT JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
- - 20 50
|
||||
- - 30 50
|
||||
}
|
||||
do_execsql_test joinF-53 {
|
||||
SELECT *
|
||||
FROM t1 RIGHT JOIN t2 ON true
|
||||
RIGHT JOIN t3 ON t2.y IS NOT NULL
|
||||
RIGHT JOIN t4 ON true
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
- - 20 50
|
||||
- - 30 50
|
||||
}
|
||||
do_execsql_test joinF-54 {
|
||||
SELECT *
|
||||
FROM t1 RIGHT JOIN t2 ON true
|
||||
RIGHT JOIN t3 ON t2.y IS NOT NULL
|
||||
RIGHT JOIN t4 ON true
|
||||
WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)
|
||||
ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);
|
||||
} {
|
||||
- - 20 50
|
||||
- - 30 50
|
||||
}
|
||||
finish_test
|
||||
|
||||
############################################################################
|
||||
# This is the TCL script used to generate the psql script that generated
|
||||
# the data above.
|
||||
#
|
||||
# puts "
|
||||
# \\pset border off
|
||||
# \\pset tuples_only on
|
||||
# \\pset null -
|
||||
#
|
||||
# DROP TABLE IF EXISTS t1;
|
||||
# DROP TABLE IF EXISTS t2;
|
||||
# DROP TABLE IF EXISTS t3;
|
||||
# DROP TABLE IF EXISTS t4;
|
||||
# CREATE TABLE t1(x INT);
|
||||
# CREATE TABLE t2(y INT);
|
||||
# CREATE TABLE t3(z INT);
|
||||
# CREATE TABLE t4(w INT);
|
||||
# INSERT INTO t1 VALUES(10);
|
||||
# INSERT INTO t3 VALUES(20),(30);
|
||||
# INSERT INTO t4 VALUES(50);
|
||||
# "
|
||||
#
|
||||
# proc echo {prefix txt} {
|
||||
# regsub -all {\n} $txt \n$prefix txt
|
||||
# puts "$prefix$txt"
|
||||
# }
|
||||
#
|
||||
# set n 0
|
||||
# foreach j1 {INNER LEFT RIGHT} {
|
||||
# foreach j2 {INNER LEFT RIGHT} {
|
||||
# foreach j3 {INNER LEFT RIGHT} {
|
||||
#
|
||||
# incr n
|
||||
# set q1 ""
|
||||
# append q1 "SELECT *\n"
|
||||
# append q1 " FROM t1 $j1 JOIN t2 ON true\n"
|
||||
# append q1 " $j2 JOIN t3 ON t2.y IS NOT NULL\n"
|
||||
# append q1 " $j3 JOIN t4 ON true\n"
|
||||
# append q1 " ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);"
|
||||
#
|
||||
# echo "\\qecho " "do_execsql_test joinF-$n \{"
|
||||
# echo "\\qecho X " $q1
|
||||
# echo "\\qecho " "\} \{"
|
||||
# puts $q1
|
||||
# echo "\\qecho " "\}"
|
||||
#
|
||||
# incr n
|
||||
# set q1 ""
|
||||
# append q1 "SELECT *\n"
|
||||
# append q1 " FROM t1 $j1 JOIN t2 ON true\n"
|
||||
# append q1 " $j2 JOIN t3 ON t2.y IS NOT NULL\n"
|
||||
# append q1 " $j3 JOIN t4 ON true\n"
|
||||
# append q1 " WHERE (t3.z!=400 AND t3.z!=500 AND t3.z!=600)\n"
|
||||
# append q1 " ORDER BY coalesce(t1.x,t2.y,t3.z,t4.w,0);"
|
||||
#
|
||||
# echo "\\qecho " "do_execsql_test joinF-$n \{"
|
||||
# echo "\\qecho X " $q1
|
||||
# echo "\\qecho " "\} \{"
|
||||
# puts $q1
|
||||
# echo "\\qecho " "\}"
|
||||
#
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
#
|
||||
@@ -217,8 +217,7 @@ test_suite "valgrind" -prefix "" -description {
|
||||
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 \
|
||||
shell*.test crash8.test atof1.test selectG.test \
|
||||
tkt-fc62af4523.test numindex1.test corruptK.test
|
||||
] -initialize {
|
||||
set ::G(valgrind) 1
|
||||
|
||||
+3
-27
@@ -260,23 +260,11 @@ do_catchsql_test 11.8 {
|
||||
#
|
||||
do_execsql_test 12.1 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(a INT,b INT); INSERT INTO t1 VALUES(1,2);
|
||||
CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(1,2);
|
||||
DROP TABLE IF EXISTS t2;
|
||||
CREATE TABLE t2(x INT,y INT); INSERT INTO t2 VALUES(3,4);
|
||||
CREATE TABLE t2(x,y); INSERT INTO t2 VALUES(3,4);
|
||||
SELECT *,'x' FROM t1 LEFT JOIN t2 ON (a,b)=(x,y);
|
||||
} {1 2 {} {} x}
|
||||
db null -
|
||||
do_execsql_test 12.2 {
|
||||
SELECT t1.*, t2.* FROM t2 RIGHT JOIN t1 ON (a,b)=(x,y);
|
||||
} {1 2 - -}
|
||||
do_execsql_test 12.3 {
|
||||
SELECT t1.*, t2.* FROM t1 FULL JOIN t2 ON (a,b)=(x,y)
|
||||
ORDER BY coalesce(a,x);
|
||||
} {
|
||||
1 2 - -
|
||||
- - 3 4
|
||||
}
|
||||
db null {}
|
||||
|
||||
|
||||
foreach {tn sql} {
|
||||
@@ -552,7 +540,7 @@ do_execsql_test 19.36 {
|
||||
SELECT * FROM t1 WHERE (3,32)>=(a,b) ORDER BY a DESC;
|
||||
} {2 22 1 11}
|
||||
|
||||
# 2018-02-18: Memory leak nested row-value. Detected by OSSFuzz.
|
||||
# 2018-02-18: Memory leak nexted row-value. Detected by OSSFuzz.
|
||||
#
|
||||
do_catchsql_test 20.1 {
|
||||
SELECT 1 WHERE (2,(2,0)) IS (2,(2,0));
|
||||
@@ -644,15 +632,9 @@ do_execsql_test 26.10 {
|
||||
do_execsql_test 26.20 {
|
||||
SELECT 2 FROM t1 LEFT JOIN t0 ON (c0, x'') != (NULL, 0);
|
||||
} {2}
|
||||
do_execsql_test 26.21 {
|
||||
SELECT 21 FROM t0 RIGHT JOIN t1 ON (c0, x'') != (NULL, 0);
|
||||
} {21}
|
||||
do_execsql_test 26.30 {
|
||||
SELECT 3 FROM t1 LEFT JOIN t0 WHERE (c0, x'') != (NULL, 0);
|
||||
} {3}
|
||||
do_execsql_test 26.31 {
|
||||
SELECT 31 FROM t0 RIGHT JOIN t1 WHERE (c0, x'') != (NULL, 0);
|
||||
} {31}
|
||||
|
||||
# 2019-12-30 ticket 892575cdba4e1e36
|
||||
#
|
||||
@@ -718,9 +700,6 @@ do_execsql_test 31.1 {
|
||||
CREATE TABLE b(b1 UNIQUE,b2);
|
||||
SELECT * FROM a LEFT JOIN b ON b2=NULL AND b2=5 WHERE (b1,substr(b.b1,1,1))==(SELECT 1024,'b');
|
||||
} {}
|
||||
do_execsql_test 31.1b {
|
||||
SELECT * FROM b RIGHT JOIN a ON b2=NULL AND b2=5 WHERE (b1,substr(b.b1,1,1))==(SELECT 1024,'b');
|
||||
} {}
|
||||
do_execsql_test 31.2 {
|
||||
CREATE TABLE t1(a);
|
||||
INSERT INTO t1 VALUES(0);
|
||||
@@ -728,9 +707,6 @@ do_execsql_test 31.2 {
|
||||
INSERT INTO t2 VALUES(NULL,123,456);
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON b=NULL WHERE (c,d)==(SELECT 123, 456+a);
|
||||
} {}
|
||||
do_execsql_test 31.2b {
|
||||
SELECT * FROM t2 RIGHT JOIN t1 ON b=NULL WHERE (c,d)==(SELECT 123, 456+a);
|
||||
} {}
|
||||
|
||||
# 2022-02-03 dbsqlfuzz 80a9fade844b4fb43564efc972bcb2c68270f5d1
|
||||
reset_db
|
||||
|
||||
+1
-2
@@ -213,8 +213,7 @@ do_execsql_test 5.0 {
|
||||
CREATE TABLE T2(a TEXT PRIMARY KEY,n INT);
|
||||
INSERT INTO T2(a, n) VALUES('aaa',0);
|
||||
SELECT * FROM T2
|
||||
WHERE (a,n) IN (SELECT T1.a, V.n
|
||||
FROM T1, (SELECT * FROM (SELECT 0 n) T3) V);
|
||||
WHERE (a,n) IN (SELECT T1.a, V.n FROM T1, (SELECT * FROM (SELECT 0 n)) V);
|
||||
} {aaa 0}
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
#
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set CLI [test_cli_invocation]
|
||||
set CLI [test_find_cli]
|
||||
db close
|
||||
forcedelete test.db test.db-journal test.db-wal
|
||||
sqlite3 db test.db
|
||||
|
||||
+12
-6
@@ -136,13 +136,16 @@ SELECT * FROM foo1; SELECT * FROM foo2;
|
||||
INSERT INTO foo1(a) VALUES(1);
|
||||
CREATE TABLE foo2(b);
|
||||
INSERT INTO foo2(b) VALUES(1);
|
||||
SELECT * FROM foo1; SELECT * FROM foo2;
|
||||
SELECT * FROM foo1;
|
||||
1
|
||||
SELECT * FROM foo2;
|
||||
1
|
||||
INSERT INTO foo1(a) VALUES(2); INSERT INTO foo2(b) VALUES(2);
|
||||
SELECT * FROM foo1; SELECT * FROM foo2;
|
||||
INSERT INTO foo1(a) VALUES(2);
|
||||
INSERT INTO foo2(b) VALUES(2);
|
||||
SELECT * FROM foo1;
|
||||
1
|
||||
2
|
||||
SELECT * FROM foo2;
|
||||
1
|
||||
2
|
||||
}}
|
||||
@@ -167,16 +170,19 @@ 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;
|
||||
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; SELECT * FROM foo2;
|
||||
INSERT INTO foo1(a) VALUES(2);
|
||||
INSERT INTO foo2(b) VALUES(2);
|
||||
SELECT * FROM foo1;
|
||||
a
|
||||
1
|
||||
2
|
||||
SELECT * FROM foo2;
|
||||
b
|
||||
1
|
||||
2
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@
|
||||
#
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set CLI [test_cli_invocation]
|
||||
set CLI [test_find_cli]
|
||||
db close
|
||||
forcedelete test.db test.db-journal test.db-wal
|
||||
sqlite3 db test.db
|
||||
|
||||
+3
-4
@@ -23,8 +23,7 @@
|
||||
#
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set CLI [test_cli_invocation]
|
||||
set CLI_ONLY [test_find_cli]
|
||||
set CLI [test_find_cli]
|
||||
db close
|
||||
forcedelete test.db test.db-journal test.db-wal
|
||||
sqlite3 db test.db
|
||||
@@ -131,13 +130,13 @@ 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"
|
||||
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_ONLY :memory: --interactive ".read t1.txt"
|
||||
exec $::CLI :memory: --interactive ".read t1.txt"
|
||||
} {pound: £}
|
||||
|
||||
do_test shell4-4.1 {
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@
|
||||
#
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set CLI [test_cli_invocation]
|
||||
set CLI [test_find_cli]
|
||||
db close
|
||||
forcedelete test.db test.db-journal test.db-wal
|
||||
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ set testprefix shell8
|
||||
ifcapable !vtab {
|
||||
finish_test; return
|
||||
}
|
||||
set CLI [test_cli_invocation]
|
||||
set CLI [test_find_cli]
|
||||
|
||||
# Check to make sure the shell has been compiled with ".archive" support.
|
||||
#
|
||||
|
||||
@@ -148,13 +148,11 @@ catch { array unset ::dbcache }
|
||||
# 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
|
||||
if {[info exists ::dbcache($ctx)]==0} break
|
||||
}
|
||||
set ctx_used($ctx) 1
|
||||
|
||||
set file test_remote.db$ctx
|
||||
forcedelete $file
|
||||
|
||||
+2
-33
@@ -184,7 +184,7 @@ proc get_pwd {} {
|
||||
set comSpec {C:\Windows\system32\cmd.exe}
|
||||
}
|
||||
return [string map [list \\ /] \
|
||||
[string trim [exec -- $comSpec /c CD]]]
|
||||
[string trim [exec -- $comSpec /c echo %CD%]]]
|
||||
} else {
|
||||
return [pwd]
|
||||
}
|
||||
@@ -2478,7 +2478,7 @@ proc test_find_binary {nm} {
|
||||
}
|
||||
|
||||
# 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
|
||||
# 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 {} {
|
||||
@@ -2487,37 +2487,6 @@ proc test_find_cli {} {
|
||||
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.
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
# 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
|
||||
@@ -277,15 +277,11 @@ do_test vtab6-3.6 {
|
||||
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
-15
@@ -11,6 +11,7 @@
|
||||
# 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
|
||||
@@ -1602,19 +1603,4 @@ if {[permutation]!="valgrind"} {
|
||||
} {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
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
# 2022 June 2
|
||||
#
|
||||
# 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 windowD
|
||||
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t0(c0 TEXT);
|
||||
CREATE VIEW v0(c0, c1)
|
||||
AS SELECT CUME_DIST() OVER (PARTITION BY t0.c0), TRUE FROM t0;
|
||||
INSERT INTO t0 VALUES ('x');
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
SELECT ('500') IS (v0.c1) FROM v0;
|
||||
} {
|
||||
0
|
||||
}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
SELECT (('500') IS (v0.c1)) FROM v0, t0;
|
||||
} {
|
||||
0
|
||||
}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
SELECT (('500') IS (v0.c1)) IS FALSE FROM v0;
|
||||
} {
|
||||
1
|
||||
}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
SELECT * FROM v0;
|
||||
} {
|
||||
1.0 1
|
||||
}
|
||||
|
||||
do_execsql_test 1.4 {
|
||||
SELECT * FROM v0 WHERE ('500' IS v0.c1) IS FALSE;
|
||||
} {
|
||||
1.0 1
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
reset_db
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1 VALUES('value');
|
||||
CREATE VIEW v1(a, b, c, d) AS SELECT 1, 2, TRUE, FALSE FROM t1;
|
||||
}
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
SELECT 500 IS a, 500 IS b, 500 IS c, 500 IS d FROM v1
|
||||
} {0 0 0 0}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
SELECT * FROM v1 WHERE 500 IS c;
|
||||
} {}
|
||||
|
||||
do_execsql_test 2.3 {
|
||||
SELECT * FROM v1 WHERE 500 IS d;
|
||||
} {}
|
||||
|
||||
do_execsql_test 2.4 {
|
||||
CREATE VIEW v2 AS SELECT max(x) OVER () AS a, TRUE AS c FROM t1;
|
||||
}
|
||||
|
||||
do_execsql_test 2.5 {
|
||||
SELECT 500 IS c FROM v2;
|
||||
} 0
|
||||
|
||||
do_execsql_test 2.6 {
|
||||
SELECT * FROM v2 WHERE 500 IS c;
|
||||
} {}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
Reference in New Issue
Block a user