Compare commits
229 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6d52725e87 | |||
| bf20a35d5f | |||
| f7da5555da | |||
| 85462ed939 | |||
| 853546d047 | |||
| 1fb6a11072 | |||
| 8daefc2af0 | |||
| 6b5d4759ce | |||
| 1aca5caa88 | |||
| c438df1be0 | |||
| 8930c2ab0c | |||
| 831116d164 | |||
| 6e4cc55e1f | |||
| a634fb1577 | |||
| 54d0d2dd9a | |||
| ac4f0039c0 | |||
| dd95d30f82 | |||
| 8d8f56296b | |||
| fad9f9a8a6 | |||
| 578e1ca8d7 | |||
| 38fdead890 | |||
| d3c156638a | |||
| b3f56fdb69 | |||
| 3fb183d2f7 | |||
| 53cd10afcd | |||
| b663587890 | |||
| 7a4b1642a7 | |||
| 853c4a7621 | |||
| e7c84cc7e3 | |||
| ff9fce4d60 | |||
| 2f17001521 | |||
| 7c8e9c78c8 | |||
| 70c93204ea | |||
| 36ed03428d | |||
| a1f7c0a21c | |||
| 6971952c65 | |||
| 27de5c5cb6 | |||
| face087212 | |||
| 382bdeabef | |||
| bfa463696b | |||
| 664eb14d8e | |||
| 68916c9fd3 | |||
| d9c131c366 | |||
| 182ea4e324 | |||
| e2ac506704 | |||
| 5e8980ddb1 | |||
| e6c7b09df6 | |||
| c872966ef4 | |||
| ab1dcc1a4b | |||
| 78d5843245 | |||
| 0c60c1fe66 | |||
| 3c863634ef | |||
| 5c2b314222 | |||
| 86dd3716b9 | |||
| dd23c6bfb4 | |||
| fd0a2f9756 | |||
| b22f38a779 | |||
| 3d1d90a13d | |||
| 4979088506 | |||
| 3f802ebce2 | |||
| 83553eefaf | |||
| 70f624c3a9 | |||
| d345a66428 | |||
| f45f2326a2 | |||
| 323913c880 | |||
| dbfca2b7f8 | |||
| c83a6bed04 | |||
| 59b8f2e108 | |||
| 9a4444778f | |||
| 8e1ee88c88 | |||
| 9afccba269 | |||
| cc08fa48b8 | |||
| a22a75e5ca | |||
| e99b9cdc70 | |||
| f9f1bdb0c8 | |||
| 5b1420e046 | |||
| 8ad0de3f72 | |||
| fbb24d1092 | |||
| 4ef7efad5e | |||
| 0a8d14261c | |||
| 2b59b3a4c8 | |||
| 0c8a934cb4 | |||
| bc76063cd2 | |||
| 781e34cde3 | |||
| db1cc09c72 | |||
| 6284db908a | |||
| 344510e62b | |||
| 65ea12cb4a | |||
| 26d7e7c6b7 | |||
| ba194369ad | |||
| ea6c36e204 | |||
| 079a307259 | |||
| ddba0c227e | |||
| d2de861cbe | |||
| 0401acec91 | |||
| f87684189d | |||
| 0e682099a1 | |||
| a70a073b3f | |||
| 18c7e40ca3 | |||
| c625ba7f4f | |||
| d88e521f59 | |||
| 82d25da5b0 | |||
| 87af14a639 | |||
| 468108628c | |||
| 8073c70b33 | |||
| 3afca7d18c | |||
| 89212fb9f9 | |||
| b06a4ec1f0 | |||
| 55aeee4b48 | |||
| b72cad14d0 | |||
| f3ccc38a69 | |||
| eb443925ef | |||
| 8879481868 | |||
| f0ec2a5ea7 | |||
| fe70510aa7 | |||
| 0df163a9f0 | |||
| 378d01aa94 | |||
| b6e8fd105c | |||
| 62117159d0 | |||
| 0d71d121ae | |||
| dc90d3d8af | |||
| a6eaa635cc | |||
| fc5717cc99 | |||
| 03af2168db | |||
| 13ef14afc1 | |||
| 6d1626eb7c | |||
| 1496566560 | |||
| 817492630a | |||
| b1a1c29a07 | |||
| ef4668bc05 | |||
| d520041bc0 | |||
| afc14f72ef | |||
| 19c6d96aec | |||
| 052c6784ee | |||
| d1053a4314 | |||
| ed79b45cf7 | |||
| a4660bd695 | |||
| 5f1d536b53 | |||
| b64fa0adf7 | |||
| ad4b262545 | |||
| 5810d0315b | |||
| 9d42cc994c | |||
| ffe6bc2b93 | |||
| d34ab07507 | |||
| f926d1ea47 | |||
| a9e0aeb552 | |||
| f2c135fabd | |||
| 13a747e5e4 | |||
| 9b8afef260 | |||
| 5668969a69 | |||
| 295aedf097 | |||
| 80b2f97234 | |||
| 6295524e3d | |||
| dea63f24e1 | |||
| fcb44a89f2 | |||
| 900defa07a | |||
| fbf0f0e1f6 | |||
| f21fa489b1 | |||
| 7e065fcf7d | |||
| 3833e934d3 | |||
| c91b2fd310 | |||
| 75fd054201 | |||
| defbd9dade | |||
| efbf3b1a10 | |||
| 07901eb8c3 | |||
| 597515d70c | |||
| 063d4a041a | |||
| a6efad8a97 | |||
| 3b9330f83c | |||
| 69b30abd59 | |||
| c718190768 | |||
| 7e4efaecad | |||
| 3852b68edd | |||
| 434a93147c | |||
| 0baa035a1e | |||
| 1fed5dab0d | |||
| e8c1eba9a9 | |||
| 5e990bea51 | |||
| 151d05cd39 | |||
| edb4ece65e | |||
| 1925a2e6f8 | |||
| 98c91905c9 | |||
| 9d41bc105d | |||
| 15ab9418d9 | |||
| 5b4627e957 | |||
| 4d87aaed56 | |||
| 06280ee582 | |||
| 4300c1ae3b | |||
| 5655c549aa | |||
| 3d77dee935 | |||
| c0bf493ea5 | |||
| 49d9ba6354 | |||
| f4345e40a0 | |||
| 7d1761059b | |||
| 552fd45441 | |||
| bb13813ed1 | |||
| 688852ab15 | |||
| 8be09304b7 | |||
| 7591051a73 | |||
| 57bf4a8eeb | |||
| 2926f9694f | |||
| 65acf373c9 | |||
| 05a86c5c0f | |||
| cfc6ca4179 | |||
| a7b3b63524 | |||
| f78da0e6af | |||
| 4a1d365903 | |||
| 2953ba9e20 | |||
| 3f40d40ad9 | |||
| dd973548f1 | |||
| 56e3767eb4 | |||
| e5b6ea797e | |||
| 962f9669b6 | |||
| fe48599294 | |||
| e0670b6220 | |||
| 784156f84c | |||
| c5185cd845 | |||
| 39a3088dc4 | |||
| aaa21b41e8 | |||
| 7c3280649a | |||
| a6e3a8c9d5 | |||
| 8af9ad951d | |||
| 6ddecb753a | |||
| daa3ce4b08 | |||
| e22724ee54 | |||
| a806475f86 | |||
| 572df3b1e4 | |||
| da0e47109e | |||
| f51446a38c |
+5
-1
@@ -177,7 +177,7 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
|
||||
notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \
|
||||
pager.lo parse.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \
|
||||
random.lo resolve.lo rowset.lo rtree.lo select.lo status.lo \
|
||||
table.lo tokenize.lo trigger.lo \
|
||||
table.lo threads.lo tokenize.lo trigger.lo \
|
||||
update.lo util.lo vacuum.lo \
|
||||
vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \
|
||||
vdbetrace.lo wal.lo walker.lo where.lo utf.lo vtab.lo
|
||||
@@ -261,6 +261,7 @@ SRC = \
|
||||
$(TOP)/src/sqliteInt.h \
|
||||
$(TOP)/src/sqliteLimit.h \
|
||||
$(TOP)/src/table.c \
|
||||
$(TOP)/src/threads.c \
|
||||
$(TOP)/src/tclsqlite.c \
|
||||
$(TOP)/src/tokenize.c \
|
||||
$(TOP)/src/trigger.c \
|
||||
@@ -732,6 +733,9 @@ status.lo: $(TOP)/src/status.c $(HDR)
|
||||
table.lo: $(TOP)/src/table.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/table.c
|
||||
|
||||
threads.lo: $(TOP)/src/threads.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/threads.c
|
||||
|
||||
tokenize.lo: $(TOP)/src/tokenize.c keywordhash.h $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/tokenize.c
|
||||
|
||||
|
||||
+18
-3
@@ -214,7 +214,7 @@ NLTLIBPATHS = "/LIBPATH:$(NCRTLIBPATH)" "/LIBPATH:$(NSDKLIBPATH)"
|
||||
# will run on the target platform. (BCC and TCC are usually the
|
||||
# same unless your are cross-compiling.)
|
||||
#
|
||||
TCC = $(CC) -W3 -DSQLITE_OS_WIN=1 -I$(TOP) -I$(TOP)\src -fp:precise
|
||||
TCC = $(CC) -W3 -DSQLITE_OS_WIN=1 -I. -I$(TOP) -I$(TOP)\src -fp:precise
|
||||
RCC = $(RC) -DSQLITE_OS_WIN=1 -I$(TOP) -I$(TOP)\src
|
||||
|
||||
# Check if assembly code listings should be generated for the source
|
||||
@@ -564,7 +564,7 @@ LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.lo \
|
||||
notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \
|
||||
pager.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \
|
||||
random.lo resolve.lo rowset.lo rtree.lo select.lo status.lo \
|
||||
table.lo tokenize.lo trigger.lo \
|
||||
table.lo threads.o tokenize.lo trigger.lo \
|
||||
update.lo util.lo vacuum.lo \
|
||||
vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \
|
||||
vdbetrace.lo wal.lo walker.lo where.lo utf.lo vtab.lo
|
||||
@@ -659,6 +659,7 @@ SRC = \
|
||||
$(TOP)\src\sqliteInt.h \
|
||||
$(TOP)\src\sqliteLimit.h \
|
||||
$(TOP)\src\table.c \
|
||||
$(TOP)\src\threads.c \
|
||||
$(TOP)\src\tclsqlite.c \
|
||||
$(TOP)\src\tokenize.c \
|
||||
$(TOP)\src\trigger.c \
|
||||
@@ -1139,6 +1140,9 @@ status.lo: $(TOP)\src\status.c $(HDR)
|
||||
table.lo: $(TOP)\src\table.c $(HDR)
|
||||
$(LTCOMPILE) -c $(TOP)\src\table.c
|
||||
|
||||
threads.lo: $(TOP)\src\threads.c $(HDR)
|
||||
$(LTCOMPILE) -c $(TOP)\src\threads.c
|
||||
|
||||
tokenize.lo: $(TOP)\src\tokenize.c keywordhash.h $(HDR)
|
||||
$(LTCOMPILE) -c $(TOP)\src\tokenize.c
|
||||
|
||||
@@ -1219,7 +1223,7 @@ parse.c: $(TOP)\src\parse.y lemon.exe $(TOP)\addopcodes.awk
|
||||
$(NAWK) -f $(TOP)\addopcodes.awk parse.h.temp > parse.h
|
||||
|
||||
sqlite3.h: $(TOP)\src\sqlite.h.in $(TOP)\manifest.uuid $(TOP)\VERSION
|
||||
$(TCLSH_CMD) $(TOP)\tool\mksqlite3h.tcl $(TOP) > sqlite3.h
|
||||
$(TCLSH_CMD) $(TOP)\tool\mksqlite3h.tcl $(TOP:\=/) > sqlite3.h
|
||||
|
||||
mkkeywordhash.exe: $(TOP)\tool\mkkeywordhash.c
|
||||
$(BCC) -Fe$@ $(OPT_FEATURE_FLAGS) $(OPTS) $(TOP)\tool\mkkeywordhash.c /link $(NLTLIBPATHS)
|
||||
@@ -1319,6 +1323,9 @@ testfixture.exe: $(TESTFIXTURE_SRC) $(LIBRESOBJS) $(HDR)
|
||||
$(TESTFIXTURE_SRC) \
|
||||
/link $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS) $(TLIBS)
|
||||
|
||||
extensiontest: testfixture.exe testloadext.dll
|
||||
.\testfixture.exe $(TOP)\test\loadext.test
|
||||
|
||||
fulltest: testfixture.exe sqlite3.exe
|
||||
.\testfixture.exe $(TOP)\test\all.test
|
||||
|
||||
@@ -1345,6 +1352,12 @@ sqlite3_analyzer.exe: sqlite3_analyzer.c $(LIBRESOBJS)
|
||||
$(LTLINK) -DBUILD_sqlite -DTCLSH=2 -I$(TCLINCDIR) sqlite3_analyzer.c \
|
||||
/link $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS) $(TLIBS)
|
||||
|
||||
testloadext.lo: $(TOP)\src\test_loadext.c
|
||||
$(LTCOMPILE) -c $(TOP)\src\test_loadext.c
|
||||
|
||||
testloadext.dll: testloadext.lo
|
||||
$(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL /OUT:$@ testloadext.lo
|
||||
|
||||
showdb.exe: $(TOP)\tool\showdb.c $(SQLITE3C)
|
||||
$(LTLINK) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \
|
||||
$(TOP)\tool\showdb.c $(SQLITE3C)
|
||||
@@ -1363,6 +1376,7 @@ clean:
|
||||
del /Q sqlite3.h opcodes.c opcodes.h
|
||||
del /Q lemon.exe lempar.c parse.*
|
||||
del /Q mkkeywordhash.exe keywordhash.h
|
||||
del /Q notasharedlib.*
|
||||
-rmdir /Q/S .deps
|
||||
-rmdir /Q/S .libs
|
||||
-rmdir /Q/S quota2a
|
||||
@@ -1371,6 +1385,7 @@ clean:
|
||||
-rmdir /Q/S tsrc
|
||||
del /Q .target_source
|
||||
del /Q tclsqlite3.exe tclsqlite3.exp
|
||||
del /Q testloadext.dll testloadext.exp
|
||||
del /Q testfixture.exe testfixture.exp test.db
|
||||
del /Q sqlite3.dll sqlite3.lib sqlite3.exp sqlite3.def
|
||||
del /Q sqlite3.c sqlite3-*.c
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
This directory contains source code to
|
||||
|
||||
SQLite: An Embeddable SQL Database Engine
|
||||
|
||||
To compile the project, first create a directory in which to place
|
||||
the build products. It is recommended, but not required, that the
|
||||
build directory be separate from the source directory. Cd into the
|
||||
build directory and then from the build directory run the configure
|
||||
script found at the root of the source tree. Then run "make".
|
||||
|
||||
For example:
|
||||
|
||||
tar xzf sqlite.tar.gz ;# Unpack the source tree into "sqlite"
|
||||
mkdir bld ;# Build will occur in a sibling directory
|
||||
cd bld ;# Change to the build directory
|
||||
../sqlite/configure ;# Run the configure script
|
||||
make ;# Run the makefile.
|
||||
make install ;# (Optional) Install the build products
|
||||
|
||||
The configure script uses autoconf 2.61 and libtool. If the configure
|
||||
script does not work out for you, there is a generic makefile named
|
||||
"Makefile.linux-gcc" in the top directory of the source tree that you
|
||||
can copy and edit to suit your needs. Comments on the generic makefile
|
||||
show what changes are needed.
|
||||
|
||||
The linux binaries on the website are created using the generic makefile,
|
||||
not the configure script. The windows binaries on the website are created
|
||||
using MinGW32 configured as a cross-compiler running under Linux. For
|
||||
details, see the ./publish.sh script at the top-level of the source tree.
|
||||
The developers do not use teh configure script.
|
||||
|
||||
SQLite does not require TCL to run, but a TCL installation is required
|
||||
by the makefiles. SQLite contains a lot of generated code and TCL is
|
||||
used to do much of that code generation. The makefile also requires
|
||||
AWK.
|
||||
|
||||
Contacts:
|
||||
|
||||
http://www.sqlite.org/
|
||||
@@ -0,0 +1,215 @@
|
||||
<h1 align="center">SQLite Source Repository</h1>
|
||||
|
||||
This repository contains the complete source code for the SQLite database
|
||||
engine. Some test scripts are also include. However, many other test scripts
|
||||
and most of the documentation are managed separately.
|
||||
|
||||
## Compiling
|
||||
|
||||
First create a directory in which to place
|
||||
the build products. It is recommended, but not required, that the
|
||||
build directory be separate from the source directory. Cd into the
|
||||
build directory and then from the build directory run the configure
|
||||
script found at the root of the source tree. Then run "make".
|
||||
|
||||
For example:
|
||||
|
||||
tar xzf sqlite.tar.gz ;# Unpack the source tree into "sqlite"
|
||||
mkdir bld ;# Build will occur in a sibling directory
|
||||
cd bld ;# Change to the build directory
|
||||
../sqlite/configure ;# Run the configure script
|
||||
make ;# Run the makefile.
|
||||
make sqlite3.c ;# Build the "amalgamation" source file
|
||||
make test ;# Run some tests (requires Tcl)
|
||||
|
||||
See the makefile for additional targets.
|
||||
|
||||
The configure script uses autoconf 2.61 and libtool. If the configure
|
||||
script does not work out for you, there is a generic makefile named
|
||||
"Makefile.linux-gcc" in the top directory of the source tree that you
|
||||
can copy and edit to suit your needs. Comments on the generic makefile
|
||||
show what changes are needed.
|
||||
|
||||
## Using MSVC
|
||||
|
||||
On Windows, all applicable build products can be compiled with MSVC.
|
||||
First open the command prompt window associated with the desired compiler
|
||||
version (e.g. "Developer Command Prompt for VS2013"). Next, use NMAKE
|
||||
with the provided "Makefile.msc" to build one of the supported targets.
|
||||
|
||||
For example:
|
||||
|
||||
mkdir bld
|
||||
cd bld
|
||||
nmake /f Makefile.msc TOP=..\sqlite
|
||||
nmake /f Makefile.msc sqlite3.c TOP=..\sqlite
|
||||
nmake /f Makefile.msc sqlite3.dll TOP=..\sqlite
|
||||
nmake /f Makefile.msc sqlite3.exe TOP=..\sqlite
|
||||
nmake /f Makefile.msc test TOP=..\sqlite
|
||||
|
||||
There are several build options that can be set via the NMAKE command
|
||||
line. For example, to build for WinRT, simply add "FOR_WINRT=1" argument
|
||||
to the "sqlite3.dll" command line above. When debugging into the SQLite
|
||||
code, adding the "DEBUG=1" argument to one of the above command lines is
|
||||
recommended.
|
||||
|
||||
SQLite does not require Tcl to run, but a Tcl installation is required
|
||||
by the makefiles (including those for MSVC). SQLite contains a lot of
|
||||
generated code and Tcl is used to do much of that code generation. The
|
||||
makefiles also require AWK.
|
||||
|
||||
## Source Code Tour
|
||||
|
||||
Most of the core source files are in the **src/** subdirectory. But
|
||||
src/ also contains files used to build the "testfixture" test harness;
|
||||
those file all begin with "test". And src/ contains the "shell.c" file
|
||||
which is the main program for the "sqlite3.exe" command-line shell and
|
||||
the "tclsqlite.c" file which implements the bindings to SQLite from the
|
||||
Tcl programming language. (Historical note: SQLite began as a Tcl
|
||||
extension and only later escaped to the wild as an independent library.)
|
||||
|
||||
Test scripts and programs are found in the **test/** subdirectory.
|
||||
There are other test suites for SQLite (see
|
||||
[How SQLite Is Tested](http://www.sqlite.org/testing.html))
|
||||
but those other test suites are
|
||||
in separate source repositories.
|
||||
|
||||
The **ext/** subdirectory contains code for extensions. The
|
||||
Full-text search engine is in **ext/fts3**. The R-Tree engine is in
|
||||
**ext/rtree**. The **ext/misc** subdirectory contains a number of
|
||||
smaller, single-file extensions, such as a REGEXP operator.
|
||||
|
||||
The **tool/** subdirectory contains various scripts and programs used
|
||||
for building generated source code files or for testing or for generating
|
||||
accessory programs such as "sqlite3_analyzer(.exe)".
|
||||
|
||||
### Generated Source Code Files
|
||||
|
||||
Several of the C-language source files used by SQLite are generated from
|
||||
other sources rather than being typed in manually by a programmer. This
|
||||
section will summarize those automatically-generated files. To create all
|
||||
of the automatically-generated files, simply run "make target_source".
|
||||
The "target_source" make target will create a subdirectory "tsrc/" and
|
||||
fill it with all the source files needed to build SQLite, both
|
||||
manually-edited files and automatically-generated files.
|
||||
|
||||
The SQLite interface is defined by the **sqlite3.h** header file, which is
|
||||
generated from src/sqlite.h.in, ./manifest.uuid, and ./VERSION. The
|
||||
Tcl script at tool/mksqlite3h.tcl does the conversion. The manifest.uuid
|
||||
file contains the SHA1 hash of the particular check-in and is used to generate
|
||||
the SQLITE_SOURCE_ID macro. The VERSION file contains the current SQLite
|
||||
version number. The sqlite3.h header is really just a copy of src/sqlite.h.in
|
||||
with the source-id and version number inserted 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 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 a
|
||||
template for generating its parser. A generic template is in tool/lempar.c,
|
||||
but SQLite uses a slightly modified template found in src/lempar.c.
|
||||
|
||||
Lemon also generates the **parse.h** header file, at the same time it
|
||||
generates parse.c. But the parse.h header file is
|
||||
modified further (to add additional symbols) using the ./addopcodes.awk
|
||||
AWK script.
|
||||
|
||||
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 the scanning the src/vdbe.c source file. The
|
||||
AWK script at ./mkopcodeh.awk does this scan and generates opcodes.h.
|
||||
A second AWK script, ./mkopcodec.awk, then scans opcodes.h to generate
|
||||
the **opcodes.c** source file, which contains a reverse mapping from
|
||||
opcode-number to opcode-name that is used for EXPLAIN output.
|
||||
|
||||
The **keywordhash.h** header file contains the definition of a hash table
|
||||
that maps SQL language keywords (ex: "CREATE", "SELECT", "INDEX", etc.) into
|
||||
the numeric codes used by the parse.c parser. The keywordhash.h file is
|
||||
generated by a C-language program at tool mkkeywordhash.c.
|
||||
|
||||
### The Amalgamation
|
||||
|
||||
All of the individual C source code and header files (both manually-edited
|
||||
and automatically-generated) can be combined into a single big source file
|
||||
**sqlite3.c** called "the amalgamation". The amalgamation is the recommended
|
||||
way of using SQLite in a larger application. Combining all individual
|
||||
source code files into a single big source code file allows the C compiler
|
||||
to perform more cross-procedure analysis and generate better code. SQLite
|
||||
runs about 5% faster when compiled from the amalgamation versus when compiled
|
||||
from individual source files.
|
||||
|
||||
The amalgamation is generated from the tool/mksqlite3c.tcl Tcl script.
|
||||
First, all of the individual source files must be gathered into the tsrc/
|
||||
subdirectory (using the equivalent of "make target_source") then the
|
||||
tool/mksqlite3c.tcl script is run to copy them all together in just the
|
||||
right order while resolving internal "#include" references.
|
||||
|
||||
The amalgamation source file is more than 100K lines long. Some symbolic
|
||||
debuggers (most notably MSVC) are unable to deal with files longer than 64K
|
||||
lines. To work around this, a separate Tcl script, tool/split-sqlite3c.tcl,
|
||||
can be run on the amalgamation to break it up into a single small C file
|
||||
called **sqlite3-all.c** that does #include on about five other files
|
||||
named **sqlite3-1.c**, **sqlite3-2.c**, ..., **sqlite3-5.c**. In this way,
|
||||
all of the source code is contained within a single translation unit so
|
||||
that the compiler can do extra cross-procedure optimization, but no
|
||||
individual source file exceeds 32K lines in length.
|
||||
|
||||
## How It All Fits Together
|
||||
|
||||
SQLite is modular in design.
|
||||
See the [architectural description](http://www.sqlite.org/arch.html)
|
||||
for details. Other documents that are useful in
|
||||
(helping to understand how SQLite works include the
|
||||
[file format](http://www.sqlite.org/fileformat2.html) description,
|
||||
the [virtual machine](http://www.sqlite.org/vdbe.html) that runs
|
||||
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).
|
||||
|
||||
Unfortunately, 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 SQLite implementation.
|
||||
|
||||
Key files:
|
||||
|
||||
* **sqlite3.h** - This file defines the public interface to the SQLite
|
||||
library. Readers will need to be familiar with this interface before
|
||||
trying to understand how the library works internally.
|
||||
|
||||
* **sqliteInt.h** - this header file defines many of the data objects
|
||||
used internally by SQLite.
|
||||
|
||||
* **parse.y** - This file describes the LALR(1) grammer that SQLite uses
|
||||
to parse SQL statements, and the actions that are taken at each stop
|
||||
in the parsing process.
|
||||
|
||||
* **vdbe.c** - This file implements the virtual machine that runs
|
||||
prepared statements. There are various helper files whose names
|
||||
begin with "vdbe". The VDBE has access to the vdbeInt.h header file
|
||||
which defines internal data objects. The rest of SQLite interacts
|
||||
with the VDBE through an interface defined by vdbe.h.
|
||||
|
||||
* **where.c** - This file analyzes the WHERE clause and generates
|
||||
virtual machine code to run queries efficiently. This file is
|
||||
sometimes called the "query optimizer". It has its own private
|
||||
header file, whereInt.h, that defines data objects used internally.
|
||||
|
||||
* **btree.c** - This file contains the implementation of the B-Tree
|
||||
storage engine used by SQLite.
|
||||
|
||||
* **pager.c** - This file contains the "pager" implementation, the
|
||||
module that implements transactions.
|
||||
|
||||
* **os_unix.c** and **os_win.c** - These two files implement the interface
|
||||
between SQLite and the underlying operating system using the run-time
|
||||
pluggable VFS interface.
|
||||
|
||||
|
||||
## Contacts
|
||||
|
||||
The main SQLite webpage is [http://www.sqlite.org/](http://www.sqlite.org/)
|
||||
with geographically distributed backup servers at
|
||||
[http://www2.sqlite.org/](http://www2.sqlite.org) and
|
||||
[http://www3.sqlite.org/](http://www3.sqlite.org).
|
||||
@@ -1,119 +1,528 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# install - install a program, script, or datafile
|
||||
# This comes from X11R5; it is not part of GNU.
|
||||
|
||||
scriptversion=2011-04-20.01; # UTC
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
# following copyright and license.
|
||||
#
|
||||
# $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $
|
||||
# Copyright (C) 1994 X Consortium
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Except as contained in this notice, the name of the X Consortium shall not
|
||||
# be used in advertising or otherwise to promote the sale, use or other deal-
|
||||
# ings in this Software without prior written authorization from the X Consor-
|
||||
# tium.
|
||||
#
|
||||
#
|
||||
# FSF changes to this file are in the public domain.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# `make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
#
|
||||
|
||||
nl='
|
||||
'
|
||||
IFS=" "" $nl"
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit="${DOITPROG-}"
|
||||
doit=${DOITPROG-}
|
||||
if test -z "$doit"; then
|
||||
doit_exec=exec
|
||||
else
|
||||
doit_exec=$doit
|
||||
fi
|
||||
|
||||
# Put in absolute file names if you don't have them in your path;
|
||||
# or use environment vars.
|
||||
|
||||
# put in absolute paths if you don't have them in your path; or use env. vars.
|
||||
chgrpprog=${CHGRPPROG-chgrp}
|
||||
chmodprog=${CHMODPROG-chmod}
|
||||
chownprog=${CHOWNPROG-chown}
|
||||
cmpprog=${CMPPROG-cmp}
|
||||
cpprog=${CPPROG-cp}
|
||||
mkdirprog=${MKDIRPROG-mkdir}
|
||||
mvprog=${MVPROG-mv}
|
||||
rmprog=${RMPROG-rm}
|
||||
stripprog=${STRIPPROG-strip}
|
||||
|
||||
mvprog="${MVPROG-mv}"
|
||||
cpprog="${CPPROG-cp}"
|
||||
chmodprog="${CHMODPROG-chmod}"
|
||||
chownprog="${CHOWNPROG-chown}"
|
||||
chgrpprog="${CHGRPPROG-chgrp}"
|
||||
stripprog="${STRIPPROG-strip}"
|
||||
rmprog="${RMPROG-rm}"
|
||||
posix_glob='?'
|
||||
initialize_posix_glob='
|
||||
test "$posix_glob" != "?" || {
|
||||
if (set -f) 2>/dev/null; then
|
||||
posix_glob=
|
||||
else
|
||||
posix_glob=:
|
||||
fi
|
||||
}
|
||||
'
|
||||
|
||||
instcmd="$mvprog"
|
||||
chmodcmd=""
|
||||
chowncmd=""
|
||||
chgrpcmd=""
|
||||
stripcmd=""
|
||||
posix_mkdir=
|
||||
|
||||
# Desired mode of installed file.
|
||||
mode=0755
|
||||
|
||||
chgrpcmd=
|
||||
chmodcmd=$chmodprog
|
||||
chowncmd=
|
||||
mvcmd=$mvprog
|
||||
rmcmd="$rmprog -f"
|
||||
mvcmd="$mvprog"
|
||||
src=""
|
||||
dst=""
|
||||
stripcmd=
|
||||
|
||||
while [ x"$1" != x ]; do
|
||||
case $1 in
|
||||
-c) instcmd="$cpprog"
|
||||
shift
|
||||
continue;;
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
dst_arg=
|
||||
|
||||
-m) chmodcmd="$chmodprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
copy_on_change=false
|
||||
no_target_directory=
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
usage="\
|
||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||
or: $0 [OPTION]... -d DIRECTORIES...
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
In the 1st form, copy SRCFILE to DSTFILE.
|
||||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
||||
In the 4th, create DIRECTORIES.
|
||||
|
||||
-s) stripcmd="$stripprog"
|
||||
shift
|
||||
continue;;
|
||||
Options:
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
*) if [ x"$src" = x ]
|
||||
then
|
||||
src=$1
|
||||
else
|
||||
dst=$1
|
||||
fi
|
||||
shift
|
||||
continue;;
|
||||
esac
|
||||
-c (ignored)
|
||||
-C install only if different (preserve the last data modification time)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-s $stripprog installed files.
|
||||
-S $stripprog installed files.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
||||
RMPROG STRIPPROG
|
||||
"
|
||||
|
||||
while test $# -ne 0; do
|
||||
case $1 in
|
||||
-c) ;;
|
||||
|
||||
-C) copy_on_change=true;;
|
||||
|
||||
-d) dir_arg=true;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *' '* | *'
|
||||
'* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-S) stripcmd="$stripprog $2"
|
||||
shift;;
|
||||
|
||||
-t) dst_arg=$2
|
||||
shift;;
|
||||
|
||||
-T) no_target_directory=true;;
|
||||
|
||||
--version) echo "$0 $scriptversion"; exit $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ x"$src" = x ]
|
||||
then
|
||||
echo "install: no input file specified"
|
||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
||||
# When -d is used, all remaining arguments are directories to create.
|
||||
# When -t is used, the destination is already specified.
|
||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||
for arg
|
||||
do
|
||||
if test -n "$dst_arg"; then
|
||||
# $@ is not empty: it contains at least $arg.
|
||||
set fnord "$@" "$dst_arg"
|
||||
shift # fnord
|
||||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
done
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
if test -z "$dir_arg"; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
# It's OK to call `install-sh -d' without argument.
|
||||
# This can happen when creating conditional directories.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
do_exit='(exit $ret); exit $ret'
|
||||
trap "ret=129; $do_exit" 1
|
||||
trap "ret=130; $do_exit" 2
|
||||
trap "ret=141; $do_exit" 13
|
||||
trap "ret=143; $do_exit" 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
case $mode in
|
||||
# Optimize common cases.
|
||||
*644) cp_umask=133;;
|
||||
*755) cp_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for src
|
||||
do
|
||||
# Protect names starting with `-'.
|
||||
case $src in
|
||||
-*) src=./$src;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
dst=$src
|
||||
dstdir=$dst
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
if test ! -f "$src" && test ! -d "$src"; then
|
||||
echo "$0: $src does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$dst_arg"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dst=$dst_arg
|
||||
# Protect names starting with `-'.
|
||||
case $dst in
|
||||
-*) dst=./$dst;;
|
||||
esac
|
||||
|
||||
# If destination is a directory, append the input filename; won't work
|
||||
# if double slashes aren't ignored.
|
||||
if test -d "$dst"; then
|
||||
if test -n "$no_target_directory"; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
dstdir=$dst
|
||||
dst=$dstdir/`basename "$src"`
|
||||
dstdir_status=0
|
||||
else
|
||||
# Prefer dirname, but fall back on a substitute if dirname fails.
|
||||
dstdir=`
|
||||
(dirname "$dst") 2>/dev/null ||
|
||||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
|
||||
X"$dst" : 'X\(//\)[^/]' \| \
|
||||
X"$dst" : 'X\(//\)$' \| \
|
||||
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
|
||||
echo X"$dst" |
|
||||
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\/\)[^/].*/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\/\)$/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\).*/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
s/.*/./; q'
|
||||
`
|
||||
|
||||
if [ x"$dst" = x ]
|
||||
then
|
||||
echo "install: no destination specified"
|
||||
exit 1
|
||||
fi
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
obsolete_mkdir_used=false
|
||||
|
||||
# If destination is a directory, append the input filename; if your system
|
||||
# does not like double slashes in filenames, you may need to add some logic
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# Create intermediate dirs using mode 755 as modified by the umask.
|
||||
# This is like FreeBSD 'install' as of 1997-10-28.
|
||||
umask=`umask`
|
||||
case $stripcmd.$umask in
|
||||
# Optimize common cases.
|
||||
*[2367][2367]) mkdir_umask=$umask;;
|
||||
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
|
||||
|
||||
if [ -d $dst ]
|
||||
then
|
||||
dst="$dst"/`basename $src`
|
||||
fi
|
||||
*[0-7])
|
||||
mkdir_umask=`expr $umask + 22 \
|
||||
- $umask % 100 % 40 + $umask % 20 \
|
||||
- $umask % 10 % 4 + $umask % 2
|
||||
`;;
|
||||
*) mkdir_umask=$umask,go-w;;
|
||||
esac
|
||||
|
||||
# Make a temp file name in the proper directory.
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
|
||||
dstdir=`dirname $dst`
|
||||
dsttmp=$dstdir/#inst.$$#
|
||||
posix_mkdir=false
|
||||
case $umask in
|
||||
*[123567][0-7][0-7])
|
||||
# POSIX mkdir -p sets u+wx bits regardless of umask, which
|
||||
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
|
||||
;;
|
||||
*)
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
|
||||
|
||||
# Move or copy the file name to the temp name
|
||||
if (umask $mkdir_umask &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writeable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
ls_ld_tmpdir=`ls -ld "$tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/d" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
$doit $instcmd $src $dsttmp
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits
|
||||
# The umask is ridiculous, or mkdir does not conform to POSIX,
|
||||
# or it failed possibly due to a race condition. Create the
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
-*) prefix='./';;
|
||||
*) prefix='';;
|
||||
esac
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
eval "$initialize_posix_glob"
|
||||
|
||||
$doit $rmcmd $dst
|
||||
$doit $mvcmd $dsttmp $dst
|
||||
oIFS=$IFS
|
||||
IFS=/
|
||||
$posix_glob set -f
|
||||
set fnord $dstdir
|
||||
shift
|
||||
$posix_glob set +f
|
||||
IFS=$oIFS
|
||||
|
||||
prefixes=
|
||||
|
||||
exit 0
|
||||
for d
|
||||
do
|
||||
test -z "$d" && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask=$mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
|
||||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
|
||||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
|
||||
else
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=$dstdir/_inst.$$_
|
||||
rmtmp=$dstdir/_rm.$$_
|
||||
|
||||
# Trap to clean up those temp files at exit.
|
||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||
|
||||
# Copy the file name to the temp name.
|
||||
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits.
|
||||
#
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||
#
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
if $copy_on_change &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
|
||||
eval "$initialize_posix_glob" &&
|
||||
$posix_glob set -f &&
|
||||
set X $old && old=:$2:$4:$5:$6 &&
|
||||
set X $new && new=:$2:$4:$5:$6 &&
|
||||
$posix_glob set +f &&
|
||||
|
||||
test "$old" = "$new" &&
|
||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
||||
then
|
||||
rm -f "$dsttmp"
|
||||
else
|
||||
# Rename the file to the real destination.
|
||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
||||
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd -f "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
|
||||
trap '' 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
||||
|
||||
+313
-145
@@ -8,8 +8,6 @@
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
# RCS: @(#) $Id: tcl.m4,v 1.145 2010/08/17 00:33:40 hobbs Exp $
|
||||
|
||||
AC_PREREQ(2.57)
|
||||
|
||||
@@ -140,6 +138,8 @@ AC_DEFUN([TEA_PATH_TCLCONFIG], [
|
||||
`ls -d /usr/contrib/lib 2>/dev/null` \
|
||||
`ls -d /usr/lib 2>/dev/null` \
|
||||
`ls -d /usr/lib64 2>/dev/null` \
|
||||
`ls -d /usr/lib/tcl8.6 2>/dev/null` \
|
||||
`ls -d /usr/lib/tcl8.5 2>/dev/null` \
|
||||
; do
|
||||
if test -f "$i/tclConfig.sh" ; then
|
||||
ac_cv_c_tclconfig="`(cd $i; pwd)`"
|
||||
@@ -170,7 +170,7 @@ AC_DEFUN([TEA_PATH_TCLCONFIG], [
|
||||
|
||||
if test x"${ac_cv_c_tclconfig}" = x ; then
|
||||
TCL_BIN_DIR="# no Tcl configs found"
|
||||
AC_MSG_ERROR([Can't find Tcl configuration definitions])
|
||||
AC_MSG_ERROR([Can't find Tcl configuration definitions. Use --with-tcl to specify a directory containing tclConfig.sh])
|
||||
else
|
||||
no_tcl=
|
||||
TCL_BIN_DIR="${ac_cv_c_tclconfig}"
|
||||
@@ -323,7 +323,7 @@ AC_DEFUN([TEA_PATH_TKCONFIG], [
|
||||
|
||||
if test x"${ac_cv_c_tkconfig}" = x ; then
|
||||
TK_BIN_DIR="# no Tk configs found"
|
||||
AC_MSG_ERROR([Can't find Tk configuration definitions])
|
||||
AC_MSG_ERROR([Can't find Tk configuration definitions. Use --with-tk to specify a directory containing tkConfig.sh])
|
||||
else
|
||||
no_tk=
|
||||
TK_BIN_DIR="${ac_cv_c_tkconfig}"
|
||||
@@ -344,11 +344,10 @@ AC_DEFUN([TEA_PATH_TKCONFIG], [
|
||||
#
|
||||
# Results:
|
||||
#
|
||||
# Subst the following vars:
|
||||
# Substitutes the following vars:
|
||||
# TCL_BIN_DIR
|
||||
# TCL_SRC_DIR
|
||||
# TCL_LIB_FILE
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
AC_DEFUN([TEA_LOAD_TCLCONFIG], [
|
||||
@@ -417,32 +416,26 @@ AC_DEFUN([TEA_LOAD_TCLCONFIG], [
|
||||
AC_SUBST(TCL_STUB_LIB_FLAG)
|
||||
AC_SUBST(TCL_STUB_LIB_SPEC)
|
||||
|
||||
case "`uname -s`" in
|
||||
*CYGWIN_*)
|
||||
AC_MSG_CHECKING([for cygwin variant])
|
||||
case ${TCL_EXTRA_CFLAGS} in
|
||||
*-mwin32*|*-mno-cygwin*)
|
||||
TEA_PLATFORM="windows"
|
||||
CFLAGS="$CFLAGS -mwin32"
|
||||
AC_MSG_RESULT([win32])
|
||||
;;
|
||||
*)
|
||||
TEA_PLATFORM="unix"
|
||||
AC_MSG_RESULT([unix])
|
||||
;;
|
||||
esac
|
||||
EXEEXT=".exe"
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
AC_MSG_CHECKING([platform])
|
||||
hold_cc=$CC; CC="$TCL_CC"
|
||||
AC_TRY_COMPILE(,[
|
||||
#ifdef _WIN32
|
||||
#error win32
|
||||
#endif
|
||||
], TEA_PLATFORM="unix",
|
||||
TEA_PLATFORM="windows"
|
||||
)
|
||||
CC=$hold_cc
|
||||
AC_MSG_RESULT($TEA_PLATFORM)
|
||||
|
||||
# The BUILD_$pkg is to define the correct extern storage class
|
||||
# handling when making this package
|
||||
AC_DEFINE_UNQUOTED(BUILD_${PACKAGE_NAME}, [],
|
||||
[Building extension source?])
|
||||
# Do this here as we have fully defined TEA_PLATFORM now
|
||||
if test "${TEA_PLATFORM}" = "windows" ; then
|
||||
# The BUILD_$pkg is to define the correct extern storage class
|
||||
# handling when making this package
|
||||
AC_DEFINE_UNQUOTED(BUILD_${PACKAGE_NAME})
|
||||
CLEANFILES="$CLEANFILES *.lib *.dll *.pdb"
|
||||
EXEEXT=".exe"
|
||||
CLEANFILES="$CLEANFILES *.lib *.dll *.pdb *.exp"
|
||||
fi
|
||||
|
||||
# TEA specific:
|
||||
@@ -566,11 +559,11 @@ AC_DEFUN([TEA_LOAD_TKCONFIG], [
|
||||
# only for running extension test cases. It should never be
|
||||
# or generation of files (like pkgIndex.tcl) at build time.
|
||||
#
|
||||
# Arguments
|
||||
# Arguments:
|
||||
# none
|
||||
#
|
||||
# Results
|
||||
# Subst's the following values:
|
||||
# Results:
|
||||
# Substitutes the following vars:
|
||||
# TCLSH_PROG
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
@@ -616,11 +609,11 @@ AC_DEFUN([TEA_PROG_TCLSH], [
|
||||
# only for running extension test cases. It should never be
|
||||
# or generation of files (like pkgIndex.tcl) at build time.
|
||||
#
|
||||
# Arguments
|
||||
# Arguments:
|
||||
# none
|
||||
#
|
||||
# Results
|
||||
# Subst's the following values:
|
||||
# Results:
|
||||
# Substitutes the following vars:
|
||||
# WISH_PROG
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
@@ -731,7 +724,6 @@ AC_DEFUN([TEA_ENABLE_SHARED], [
|
||||
# TCL_THREADS
|
||||
# _REENTRANT
|
||||
# _THREAD_SAFE
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
AC_DEFUN([TEA_ENABLE_THREADS], [
|
||||
@@ -855,12 +847,11 @@ AC_DEFUN([TEA_ENABLE_THREADS], [
|
||||
#
|
||||
# Defines the following vars:
|
||||
# CFLAGS_DEFAULT Sets to $(CFLAGS_DEBUG) if true
|
||||
# Sets to $(CFLAGS_OPTIMIZE) if false
|
||||
# Sets to "$(CFLAGS_OPTIMIZE) -DNDEBUG" if false
|
||||
# LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true
|
||||
# Sets to $(LDFLAGS_OPTIMIZE) if false
|
||||
# DBGX Formerly used as debug library extension;
|
||||
# always blank now.
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
AC_DEFUN([TEA_ENABLE_SYMBOLS], [
|
||||
@@ -873,7 +864,7 @@ AC_DEFUN([TEA_ENABLE_SYMBOLS], [
|
||||
[tcl_ok=$enableval], [tcl_ok=no])
|
||||
DBGX=""
|
||||
if test "$tcl_ok" = "no"; then
|
||||
CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE}"
|
||||
CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE} -DNDEBUG"
|
||||
LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}"
|
||||
AC_MSG_RESULT([no])
|
||||
else
|
||||
@@ -920,7 +911,6 @@ AC_DEFUN([TEA_ENABLE_SYMBOLS], [
|
||||
#
|
||||
# Defines the following vars:
|
||||
# HAVE_LANGINFO Triggers use of nl_langinfo if defined.
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
AC_DEFUN([TEA_ENABLE_LANGINFO], [
|
||||
@@ -961,7 +951,6 @@ AC_DEFUN([TEA_ENABLE_LANGINFO], [
|
||||
# Defines the following var:
|
||||
#
|
||||
# system - System/platform/version identification code.
|
||||
#
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
AC_DEFUN([TEA_CONFIG_SYSTEM], [
|
||||
@@ -1030,21 +1019,20 @@ AC_DEFUN([TEA_CONFIG_SYSTEM], [
|
||||
# extensions. An empty string means we don't know how
|
||||
# to use shared libraries on this platform.
|
||||
# LIB_SUFFIX - Specifies everything that comes after the "libfoo"
|
||||
# in a static or shared library name, using the $VERSION variable
|
||||
# in a static or shared library name, using the $PACKAGE_VERSION variable
|
||||
# to put the version in the right place. This is used
|
||||
# by platforms that need non-standard library names.
|
||||
# Examples: ${VERSION}.so.1.1 on NetBSD, since it needs
|
||||
# to have a version after the .so, and ${VERSION}.a
|
||||
# Examples: ${PACKAGE_VERSION}.so.1.1 on NetBSD, since it needs
|
||||
# to have a version after the .so, and ${PACKAGE_VERSION}.a
|
||||
# on AIX, since a shared library needs to have
|
||||
# a .a extension whereas shared objects for loadable
|
||||
# extensions have a .so extension. Defaults to
|
||||
# ${VERSION}${SHLIB_SUFFIX}.
|
||||
# ${PACKAGE_VERSION}${SHLIB_SUFFIX}.
|
||||
# CFLAGS_DEBUG -
|
||||
# Flags used when running the compiler in debug mode
|
||||
# CFLAGS_OPTIMIZE -
|
||||
# Flags used when running the compiler in optimize mode
|
||||
# CFLAGS - Additional CFLAGS added as necessary (usually 64-bit)
|
||||
#
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
AC_DEFUN([TEA_CONFIG_CFLAGS], [
|
||||
@@ -1086,6 +1074,7 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
|
||||
AC_DEFINE(MODULE_SCOPE,
|
||||
[extern __attribute__((__visibility__("hidden")))],
|
||||
[Compiler support for module scope symbols])
|
||||
AC_DEFINE(HAVE_HIDDEN, [1], [Compiler support for module scope symbols])
|
||||
])
|
||||
|
||||
# Step 0.d: Disable -rpath support?
|
||||
@@ -1134,15 +1123,14 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
|
||||
ECHO_VERSION='`echo ${PACKAGE_VERSION}`'
|
||||
TCL_LIB_VERSIONS_OK=ok
|
||||
CFLAGS_DEBUG=-g
|
||||
CFLAGS_OPTIMIZE=-O
|
||||
AS_IF([test "$GCC" = yes], [
|
||||
# TEA specific:
|
||||
CFLAGS_OPTIMIZE=-O2
|
||||
CFLAGS_WARNING="-Wall"
|
||||
], [CFLAGS_WARNING=""])
|
||||
dnl FIXME: Replace AC_CHECK_PROG with AC_CHECK_TOOL once cross compiling is fixed.
|
||||
dnl AC_CHECK_TOOL(AR, ar)
|
||||
AC_CHECK_PROG(AR, ar, ar)
|
||||
], [
|
||||
CFLAGS_OPTIMIZE=-O
|
||||
CFLAGS_WARNING=""
|
||||
])
|
||||
AC_CHECK_TOOL(AR, ar)
|
||||
STLIB_LD='${AR} cr'
|
||||
LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH"
|
||||
AS_IF([test "x$SHLIB_VERSION" = x],[SHLIB_VERSION="1.0"])
|
||||
@@ -1171,7 +1159,7 @@ dnl AC_CHECK_TOOL(AR, ar)
|
||||
PATH64="${MSSDK}/Bin/Win64"
|
||||
;;
|
||||
esac
|
||||
if test ! -d "${PATH64}" ; then
|
||||
if test "$GCC" != "yes" -a ! -d "${PATH64}" ; then
|
||||
AC_MSG_WARN([Could not find 64-bit $MACHINE SDK to enable 64bit mode])
|
||||
AC_MSG_WARN([Ensure latest Platform SDK is installed])
|
||||
do64bit="no"
|
||||
@@ -1288,7 +1276,7 @@ dnl AC_CHECK_TOOL(AR, ar)
|
||||
else
|
||||
RC="rc"
|
||||
lflags="-nologo"
|
||||
LINKBIN="link"
|
||||
LINKBIN="link"
|
||||
CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d"
|
||||
CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}"
|
||||
fi
|
||||
@@ -1296,13 +1284,43 @@ dnl AC_CHECK_TOOL(AR, ar)
|
||||
|
||||
if test "$GCC" = "yes"; then
|
||||
# mingw gcc mode
|
||||
RC="windres"
|
||||
AC_CHECK_TOOL(RC, windres)
|
||||
CFLAGS_DEBUG="-g"
|
||||
CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer"
|
||||
SHLIB_LD="$CC -shared"
|
||||
SHLIB_LD='${CC} -shared'
|
||||
UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a'
|
||||
LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}"
|
||||
LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}"
|
||||
|
||||
AC_CACHE_CHECK(for cross-compile version of gcc,
|
||||
ac_cv_cross,
|
||||
AC_TRY_COMPILE([
|
||||
#ifdef _WIN32
|
||||
#error cross-compiler
|
||||
#endif
|
||||
], [],
|
||||
ac_cv_cross=yes,
|
||||
ac_cv_cross=no)
|
||||
)
|
||||
if test "$ac_cv_cross" = "yes"; then
|
||||
case "$do64bit" in
|
||||
amd64|x64|yes)
|
||||
CC="x86_64-w64-mingw32-gcc"
|
||||
LD="x86_64-w64-mingw32-ld"
|
||||
AR="x86_64-w64-mingw32-ar"
|
||||
RANLIB="x86_64-w64-mingw32-ranlib"
|
||||
RC="x86_64-w64-mingw32-windres"
|
||||
;;
|
||||
*)
|
||||
CC="i686-w64-mingw32-gcc"
|
||||
LD="i686-w64-mingw32-ld"
|
||||
AR="i686-w64-mingw32-ar"
|
||||
RANLIB="i686-w64-mingw32-ranlib"
|
||||
RC="i686-w64-mingw32-windres"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
else
|
||||
SHLIB_LD="${LINKBIN} -dll ${lflags}"
|
||||
# link -lib only works when -lib is the first arg
|
||||
@@ -1409,7 +1427,8 @@ dnl AC_CHECK_TOOL(AR, ar)
|
||||
SHLIB_CFLAGS=""
|
||||
SHLIB_LD='${CC} -shared'
|
||||
SHLIB_SUFFIX=".dll"
|
||||
EXE_SUFFIX=".exe"
|
||||
EXEEXT=".exe"
|
||||
do64bit_ok=yes
|
||||
CC_SEARCH_FLAGS=""
|
||||
LD_SEARCH_FLAGS=""
|
||||
;;
|
||||
@@ -1438,7 +1457,7 @@ dnl AC_CHECK_TOOL(AR, ar)
|
||||
])
|
||||
AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no)
|
||||
AS_IF([test "$tcl_ok" = yes], [
|
||||
LDFLAGS="$LDFLAGS -E"
|
||||
LDFLAGS="$LDFLAGS -Wl,-E"
|
||||
CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.'
|
||||
LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.'
|
||||
LD_LIBRARY_PATH_VAR="SHLIB_PATH"
|
||||
@@ -1520,7 +1539,7 @@ dnl AC_CHECK_TOOL(AR, ar)
|
||||
])
|
||||
])
|
||||
;;
|
||||
Linux*)
|
||||
Linux*|GNU*|NetBSD-Debian)
|
||||
SHLIB_CFLAGS="-fPIC"
|
||||
SHLIB_SUFFIX=".so"
|
||||
|
||||
@@ -1553,17 +1572,6 @@ dnl AC_CHECK_TOOL(AR, ar)
|
||||
# files in compat/*.c is being linked in.
|
||||
|
||||
AS_IF([test x"${USE_COMPAT}" != x],[CFLAGS="$CFLAGS -fno-inline"])
|
||||
|
||||
;;
|
||||
GNU*)
|
||||
SHLIB_CFLAGS="-fPIC"
|
||||
SHLIB_SUFFIX=".so"
|
||||
|
||||
SHLIB_LD='${CC} -shared'
|
||||
LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
|
||||
CC_SEARCH_FLAGS=""
|
||||
LD_SEARCH_FLAGS=""
|
||||
AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"])
|
||||
;;
|
||||
Lynx*)
|
||||
SHLIB_CFLAGS="-fPIC"
|
||||
@@ -1576,35 +1584,44 @@ dnl AC_CHECK_TOOL(AR, ar)
|
||||
LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'])
|
||||
;;
|
||||
OpenBSD-*)
|
||||
SHLIB_CFLAGS="-fPIC"
|
||||
SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}'
|
||||
SHLIB_SUFFIX=".so"
|
||||
AS_IF([test $doRpath = yes], [
|
||||
CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'])
|
||||
LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
|
||||
SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.${SHLIB_VERSION}'
|
||||
AC_CACHE_CHECK([for ELF], tcl_cv_ld_elf, [
|
||||
AC_EGREP_CPP(yes, [
|
||||
#ifdef __ELF__
|
||||
yes
|
||||
#endif
|
||||
], tcl_cv_ld_elf=yes, tcl_cv_ld_elf=no)])
|
||||
AS_IF([test $tcl_cv_ld_elf = yes], [
|
||||
LDFLAGS=-Wl,-export-dynamic
|
||||
], [LDFLAGS=""])
|
||||
arch=`arch -s`
|
||||
case "$arch" in
|
||||
vax)
|
||||
SHLIB_SUFFIX=""
|
||||
SHARED_LIB_SUFFIX=""
|
||||
LDFLAGS=""
|
||||
;;
|
||||
*)
|
||||
SHLIB_CFLAGS="-fPIC"
|
||||
SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}'
|
||||
SHLIB_SUFFIX=".so"
|
||||
AS_IF([test $doRpath = yes], [
|
||||
CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'])
|
||||
LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
|
||||
SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.${SHLIB_VERSION}'
|
||||
LDFLAGS="-Wl,-export-dynamic"
|
||||
;;
|
||||
esac
|
||||
case "$arch" in
|
||||
vax)
|
||||
CFLAGS_OPTIMIZE="-O1"
|
||||
;;
|
||||
*)
|
||||
CFLAGS_OPTIMIZE="-O2"
|
||||
;;
|
||||
esac
|
||||
AS_IF([test "${TCL_THREADS}" = "1"], [
|
||||
# OpenBSD builds and links with -pthread, never -lpthread.
|
||||
# On OpenBSD: Compile with -pthread
|
||||
# Don't link with -lpthread
|
||||
LIBS=`echo $LIBS | sed s/-lpthread//`
|
||||
CFLAGS="$CFLAGS -pthread"
|
||||
SHLIB_CFLAGS="$SHLIB_CFLAGS -pthread"
|
||||
])
|
||||
# OpenBSD doesn't do version numbers with dots.
|
||||
UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a'
|
||||
TCL_LIB_VERSIONS_OK=nodots
|
||||
;;
|
||||
NetBSD-*|FreeBSD-[[3-4]].*)
|
||||
# FreeBSD 3.* and greater have ELF.
|
||||
# NetBSD 2.* has ELF and can use 'cc -shared' to build shared libs
|
||||
NetBSD-*)
|
||||
# NetBSD has ELF and can use 'cc -shared' to build shared libs
|
||||
SHLIB_CFLAGS="-fPIC"
|
||||
SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}'
|
||||
SHLIB_SUFFIX=".so"
|
||||
@@ -1618,32 +1635,24 @@ dnl AC_CHECK_TOOL(AR, ar)
|
||||
CFLAGS="$CFLAGS -pthread"
|
||||
LDFLAGS="$LDFLAGS -pthread"
|
||||
])
|
||||
case $system in
|
||||
FreeBSD-3.*)
|
||||
# FreeBSD-3 doesn't handle version numbers with dots.
|
||||
UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a'
|
||||
SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so'
|
||||
TCL_LIB_VERSIONS_OK=nodots
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
FreeBSD-*)
|
||||
# This configuration from FreeBSD Ports.
|
||||
SHLIB_CFLAGS="-fPIC"
|
||||
SHLIB_LD="${CC} -shared"
|
||||
TCL_SHLIB_LD_EXTRAS="-soname \$[@]"
|
||||
TCL_SHLIB_LD_EXTRAS="-Wl,-soname=\$[@]"
|
||||
SHLIB_SUFFIX=".so"
|
||||
LDFLAGS=""
|
||||
AS_IF([test $doRpath = yes], [
|
||||
CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
|
||||
LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'])
|
||||
LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'])
|
||||
AS_IF([test "${TCL_THREADS}" = "1"], [
|
||||
# The -pthread needs to go in the LDFLAGS, not LIBS
|
||||
LIBS=`echo $LIBS | sed s/-pthread//`
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
LDFLAGS="$LDFLAGS $PTHREAD_LIBS"])
|
||||
# Version numbers are dot-stripped by system policy.
|
||||
TCL_TRIM_DOTS=`echo ${VERSION} | tr -d .`
|
||||
TCL_TRIM_DOTS=`echo ${PACKAGE_VERSION} | tr -d .`
|
||||
UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a'
|
||||
SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1'
|
||||
TCL_LIB_VERSIONS_OK=nodots
|
||||
@@ -1705,7 +1714,7 @@ dnl AC_CHECK_TOOL(AR, ar)
|
||||
AS_IF([test $tcl_cv_ld_single_module = yes], [
|
||||
SHLIB_LD="${SHLIB_LD} -Wl,-single_module"
|
||||
])
|
||||
# TEA specific: link shlib with current and compatiblity version flags
|
||||
# TEA specific: link shlib with current and compatibility version flags
|
||||
vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([[0-9]]\{1,5\}\)\(\(\.[[0-9]]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d`
|
||||
SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}"
|
||||
SHLIB_SUFFIX=".dylib"
|
||||
@@ -1941,6 +1950,24 @@ dnl AC_CHECK_TOOL(AR, ar)
|
||||
LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}'
|
||||
])
|
||||
;;
|
||||
UNIX_SV* | UnixWare-5*)
|
||||
SHLIB_CFLAGS="-KPIC"
|
||||
SHLIB_LD='${CC} -G'
|
||||
SHLIB_LD_LIBS=""
|
||||
SHLIB_SUFFIX=".so"
|
||||
# Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers
|
||||
# that don't grok the -Bexport option. Test that it does.
|
||||
AC_CACHE_CHECK([for ld accepts -Bexport flag], tcl_cv_ld_Bexport, [
|
||||
hold_ldflags=$LDFLAGS
|
||||
LDFLAGS="$LDFLAGS -Wl,-Bexport"
|
||||
AC_TRY_LINK(, [int i;], tcl_cv_ld_Bexport=yes, tcl_cv_ld_Bexport=no)
|
||||
LDFLAGS=$hold_ldflags])
|
||||
AS_IF([test $tcl_cv_ld_Bexport = yes], [
|
||||
LDFLAGS="$LDFLAGS -Wl,-Bexport"
|
||||
])
|
||||
CC_SEARCH_FLAGS=""
|
||||
LD_SEARCH_FLAGS=""
|
||||
;;
|
||||
esac
|
||||
|
||||
AS_IF([test "$do64bit" = yes -a "$do64bit_ok" = no], [
|
||||
@@ -1965,7 +1992,7 @@ dnl # preprocessing tests use only CPPFLAGS.
|
||||
case $system in
|
||||
AIX-*) ;;
|
||||
BSD/OS*) ;;
|
||||
CYGWIN_*) ;;
|
||||
CYGWIN_*|MINGW32_*) ;;
|
||||
IRIX*) ;;
|
||||
NetBSD-*|FreeBSD-*|OpenBSD-*) ;;
|
||||
Darwin-*) ;;
|
||||
@@ -1977,15 +2004,109 @@ dnl # preprocessing tests use only CPPFLAGS.
|
||||
AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [
|
||||
AC_DEFINE(MODULE_SCOPE, [extern],
|
||||
[No Compiler support for module scope symbols])
|
||||
AC_DEFINE(NO_VIZ)
|
||||
])
|
||||
|
||||
AS_IF([test "$SHARED_LIB_SUFFIX" = ""], [
|
||||
# TEA specific: use PACKAGE_VERSION instead of VERSION
|
||||
SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}'])
|
||||
# TEA specific: use PACKAGE_VERSION instead of VERSION
|
||||
SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}'])
|
||||
AS_IF([test "$UNSHARED_LIB_SUFFIX" = ""], [
|
||||
# TEA specific: use PACKAGE_VERSION instead of VERSION
|
||||
UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a'])
|
||||
# TEA specific: use PACKAGE_VERSION instead of VERSION
|
||||
UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a'])
|
||||
|
||||
if test "${GCC}" = "yes" -a ${SHLIB_SUFFIX} = ".dll"; then
|
||||
AC_CACHE_CHECK(for SEH support in compiler,
|
||||
tcl_cv_seh,
|
||||
AC_TRY_RUN([
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int a, b = 0;
|
||||
__try {
|
||||
a = 666 / b;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
],
|
||||
tcl_cv_seh=yes,
|
||||
tcl_cv_seh=no,
|
||||
tcl_cv_seh=no)
|
||||
)
|
||||
if test "$tcl_cv_seh" = "no" ; then
|
||||
AC_DEFINE(HAVE_NO_SEH, 1,
|
||||
[Defined when mingw does not support SEH])
|
||||
fi
|
||||
|
||||
#
|
||||
# Check to see if the excpt.h include file provided contains the
|
||||
# definition for EXCEPTION_DISPOSITION; if not, which is the case
|
||||
# with Cygwin's version as of 2002-04-10, define it to be int,
|
||||
# sufficient for getting the current code to work.
|
||||
#
|
||||
AC_CACHE_CHECK(for EXCEPTION_DISPOSITION support in include files,
|
||||
tcl_cv_eh_disposition,
|
||||
AC_TRY_COMPILE([
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# undef WIN32_LEAN_AND_MEAN
|
||||
],[
|
||||
EXCEPTION_DISPOSITION x;
|
||||
],
|
||||
tcl_cv_eh_disposition=yes,
|
||||
tcl_cv_eh_disposition=no)
|
||||
)
|
||||
if test "$tcl_cv_eh_disposition" = "no" ; then
|
||||
AC_DEFINE(EXCEPTION_DISPOSITION, int,
|
||||
[Defined when cygwin/mingw does not support EXCEPTION DISPOSITION])
|
||||
fi
|
||||
|
||||
# Check to see if winnt.h defines CHAR, SHORT, and LONG
|
||||
# even if VOID has already been #defined. The win32api
|
||||
# used by mingw and cygwin is known to do this.
|
||||
|
||||
AC_CACHE_CHECK(for winnt.h that ignores VOID define,
|
||||
tcl_cv_winnt_ignore_void,
|
||||
AC_TRY_COMPILE([
|
||||
#define VOID void
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
], [
|
||||
CHAR c;
|
||||
SHORT s;
|
||||
LONG l;
|
||||
],
|
||||
tcl_cv_winnt_ignore_void=yes,
|
||||
tcl_cv_winnt_ignore_void=no)
|
||||
)
|
||||
if test "$tcl_cv_winnt_ignore_void" = "yes" ; then
|
||||
AC_DEFINE(HAVE_WINNT_IGNORE_VOID, 1,
|
||||
[Defined when cygwin/mingw ignores VOID define in winnt.h])
|
||||
fi
|
||||
fi
|
||||
|
||||
# See if the compiler supports casting to a union type.
|
||||
# This is used to stop gcc from printing a compiler
|
||||
# warning when initializing a union member.
|
||||
|
||||
AC_CACHE_CHECK(for cast to union support,
|
||||
tcl_cv_cast_to_union,
|
||||
AC_TRY_COMPILE([],
|
||||
[
|
||||
union foo { int i; double d; };
|
||||
union foo f = (union foo) (int) 0;
|
||||
],
|
||||
tcl_cv_cast_to_union=yes,
|
||||
tcl_cv_cast_to_union=no)
|
||||
)
|
||||
if test "$tcl_cv_cast_to_union" = "yes"; then
|
||||
AC_DEFINE(HAVE_CAST_TO_UNION, 1,
|
||||
[Defined when compiler supports casting to union type.])
|
||||
fi
|
||||
|
||||
AC_SUBST(CFLAGS_DEBUG)
|
||||
AC_SUBST(CFLAGS_OPTIMIZE)
|
||||
@@ -2024,7 +2145,6 @@ dnl # preprocessing tests use only CPPFLAGS.
|
||||
# USE_TERMIOS
|
||||
# USE_TERMIO
|
||||
# USE_SGTTY
|
||||
#
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
AC_DEFUN([TEA_SERIAL_PORT], [
|
||||
@@ -2236,7 +2356,6 @@ closedir(d);
|
||||
# XINCLUDES
|
||||
# XLIBSW
|
||||
# PKG_LIBS (appends to)
|
||||
#
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
AC_DEFUN([TEA_PATH_X], [
|
||||
@@ -2250,9 +2369,9 @@ AC_DEFUN([TEA_PATH_UNIX_X], [
|
||||
not_really_there=""
|
||||
if test "$no_x" = ""; then
|
||||
if test "$x_includes" = ""; then
|
||||
AC_TRY_CPP([#include <X11/XIntrinsic.h>], , not_really_there="yes")
|
||||
AC_TRY_CPP([#include <X11/Xlib.h>], , not_really_there="yes")
|
||||
else
|
||||
if test ! -r $x_includes/X11/Intrinsic.h; then
|
||||
if test ! -r $x_includes/X11/Xlib.h; then
|
||||
not_really_there="yes"
|
||||
fi
|
||||
fi
|
||||
@@ -2260,11 +2379,11 @@ AC_DEFUN([TEA_PATH_UNIX_X], [
|
||||
if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then
|
||||
AC_MSG_CHECKING([for X11 header files])
|
||||
found_xincludes="no"
|
||||
AC_TRY_CPP([#include <X11/Intrinsic.h>], found_xincludes="yes", found_xincludes="no")
|
||||
AC_TRY_CPP([#include <X11/Xlib.h>], found_xincludes="yes", found_xincludes="no")
|
||||
if test "$found_xincludes" = "no"; then
|
||||
dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include"
|
||||
for i in $dirs ; do
|
||||
if test -r $i/X11/Intrinsic.h; then
|
||||
if test -r $i/X11/Xlib.h; then
|
||||
AC_MSG_RESULT([$i])
|
||||
XINCLUDES=" -I$i"
|
||||
found_xincludes="yes"
|
||||
@@ -2332,7 +2451,6 @@ AC_DEFUN([TEA_PATH_UNIX_X], [
|
||||
# HAVE_SYS_FILIO_H
|
||||
# USE_FIONBIO
|
||||
# O_NONBLOCK
|
||||
#
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
AC_DEFUN([TEA_BLOCKING_STYLE], [
|
||||
@@ -2367,7 +2485,6 @@ AC_DEFUN([TEA_BLOCKING_STYLE], [
|
||||
# HAVE_TM_GMTOFF
|
||||
# HAVE_TM_TZADJ
|
||||
# HAVE_TIMEZONE_VAR
|
||||
#
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
AC_DEFUN([TEA_TIME_HANDLER], [
|
||||
@@ -2436,7 +2553,6 @@ AC_DEFUN([TEA_TIME_HANDLER], [
|
||||
#
|
||||
# Might defines some of the following vars:
|
||||
# strtod (=fixstrtod)
|
||||
#
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
AC_DEFUN([TEA_BUGGY_STRTOD], [
|
||||
@@ -2487,7 +2603,7 @@ AC_DEFUN([TEA_BUGGY_STRTOD], [
|
||||
#
|
||||
# Results:
|
||||
#
|
||||
# Subst's the following var:
|
||||
# Substitutes the following vars:
|
||||
# TCL_LIBS
|
||||
# MATH_LIBS
|
||||
#
|
||||
@@ -2496,7 +2612,6 @@ AC_DEFUN([TEA_BUGGY_STRTOD], [
|
||||
#
|
||||
# Might define the following vars:
|
||||
# HAVE_NET_ERRNO_H
|
||||
#
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
AC_DEFUN([TEA_TCL_LINK_LIBS], [
|
||||
@@ -2574,7 +2689,6 @@ AC_DEFUN([TEA_TCL_LINK_LIBS], [
|
||||
# _ISOC99_SOURCE
|
||||
# _LARGEFILE64_SOURCE
|
||||
# _LARGEFILE_SOURCE64
|
||||
#
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
AC_DEFUN([TEA_TCL_EARLY_FLAG],[
|
||||
@@ -2622,7 +2736,6 @@ AC_DEFUN([TEA_TCL_EARLY_FLAGS],[
|
||||
# HAVE_STRUCT_DIRENT64
|
||||
# HAVE_STRUCT_STAT64
|
||||
# HAVE_TYPE_OFF64_T
|
||||
#
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
AC_DEFUN([TEA_TCL_64BIT_FLAGS], [
|
||||
@@ -2654,7 +2767,7 @@ AC_DEFUN([TEA_TCL_64BIT_FLAGS], [
|
||||
# Now check for auxiliary declarations
|
||||
AC_CACHE_CHECK([for struct dirent64], tcl_cv_struct_dirent64,[
|
||||
AC_TRY_COMPILE([#include <sys/types.h>
|
||||
#include <sys/dirent.h>],[struct dirent64 p;],
|
||||
#include <dirent.h>],[struct dirent64 p;],
|
||||
tcl_cv_struct_dirent64=yes,tcl_cv_struct_dirent64=no)])
|
||||
if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then
|
||||
AC_DEFINE(HAVE_STRUCT_DIRENT64, 1, [Is 'struct dirent64' in <sys/types.h>?])
|
||||
@@ -2739,6 +2852,13 @@ TEA version not specified.])
|
||||
else
|
||||
AC_MSG_RESULT([ok (TEA ${TEA_VERSION})])
|
||||
fi
|
||||
|
||||
# If the user did not set CFLAGS, set it now to keep macros
|
||||
# like AC_PROG_CC and AC_TRY_COMPILE from adding "-g -O2".
|
||||
if test "${CFLAGS+set}" != "set" ; then
|
||||
CFLAGS=""
|
||||
fi
|
||||
|
||||
case "`uname -s`" in
|
||||
*win32*|*WIN32*|*MINGW32_*)
|
||||
AC_CHECK_PROG(CYGPATH, cygpath, cygpath -w, echo)
|
||||
@@ -2752,8 +2872,17 @@ TEA version not specified.])
|
||||
;;
|
||||
*)
|
||||
CYGPATH=echo
|
||||
EXEEXT=""
|
||||
TEA_PLATFORM="unix"
|
||||
# Maybe we are cross-compiling....
|
||||
case ${host_alias} in
|
||||
*mingw32*)
|
||||
EXEEXT=".exe"
|
||||
TEA_PLATFORM="windows"
|
||||
;;
|
||||
*)
|
||||
EXEEXT=""
|
||||
TEA_PLATFORM="unix"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -2766,6 +2895,8 @@ TEA version not specified.])
|
||||
exec_prefix=$prefix
|
||||
fi
|
||||
|
||||
AC_MSG_NOTICE([configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}])
|
||||
|
||||
AC_SUBST(EXEEXT)
|
||||
AC_SUBST(CYGPATH)
|
||||
|
||||
@@ -3001,6 +3132,22 @@ AC_DEFUN([TEA_ADD_CFLAGS], [
|
||||
AC_SUBST(PKG_CFLAGS)
|
||||
])
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
# TEA_ADD_CLEANFILES --
|
||||
#
|
||||
# Specify one or more CLEANFILES.
|
||||
#
|
||||
# Arguments:
|
||||
# one or more file names to clean target
|
||||
#
|
||||
# Results:
|
||||
#
|
||||
# Appends to CLEANFILES, already defined for subst in LOAD_TCLCONFIG
|
||||
#------------------------------------------------------------------------
|
||||
AC_DEFUN([TEA_ADD_CLEANFILES], [
|
||||
CLEANFILES="$CLEANFILES $@"
|
||||
])
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
# TEA_PREFIX --
|
||||
#
|
||||
@@ -3055,16 +3202,17 @@ AC_DEFUN([TEA_SETUP_COMPILER_CC], [
|
||||
# Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE)
|
||||
# in this macro, they need to go into TEA_SETUP_COMPILER instead.
|
||||
|
||||
# If the user did not set CFLAGS, set it now to keep
|
||||
# the AC_PROG_CC macro from adding "-g -O2".
|
||||
if test "${CFLAGS+set}" != "set" ; then
|
||||
CFLAGS=""
|
||||
fi
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_CPP
|
||||
|
||||
AC_PROG_INSTALL
|
||||
INSTALL="\$(SHELL) \$(srcdir)/tclconfig/install-sh -c"
|
||||
AC_SUBST(INSTALL)
|
||||
INSTALL_DATA="\${INSTALL} -m 644"
|
||||
AC_SUBST(INSTALL_DATA)
|
||||
INSTALL_PROGRAM="\${INSTALL}"
|
||||
AC_SUBST(INSTALL_PROGRAM)
|
||||
INSTALL_SCRIPT="\${INSTALL}"
|
||||
AC_SUBST(INSTALL_SCRIPT)
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Checks to see if the make program sets the $MAKE variable.
|
||||
@@ -3076,7 +3224,7 @@ AC_DEFUN([TEA_SETUP_COMPILER_CC], [
|
||||
# Find ranlib
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
AC_PROG_RANLIB
|
||||
AC_CHECK_TOOL(RANLIB, ranlib)
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Determines the correct binary file extension (.o, .obj, .exe etc.)
|
||||
@@ -3155,13 +3303,26 @@ AC_DEFUN([TEA_SETUP_COMPILER], [
|
||||
# MAKE_SHARED_LIB Makefile rule for building a shared library
|
||||
# MAKE_STATIC_LIB Makefile rule for building a static library
|
||||
# MAKE_STUB_LIB Makefile rule for building a stub library
|
||||
# VC_MANIFEST_EMBED_DLL Makefile rule for embedded VC manifest in DLL
|
||||
# VC_MANIFEST_EMBED_EXE Makefile rule for embedded VC manifest in EXE
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
AC_DEFUN([TEA_MAKE_LIB], [
|
||||
if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then
|
||||
MAKE_STATIC_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_OBJECTS)"
|
||||
MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LD_LIBS} \${LDFLAGS_DEFAULT} -out:\[$]@ \$(PKG_OBJECTS)"
|
||||
MAKE_STUB_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_STUB_OBJECTS)"
|
||||
AC_EGREP_CPP([manifest needed], [
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||
print("manifest needed")
|
||||
#endif
|
||||
], [
|
||||
# Could do a CHECK_PROG for mt, but should always be with MSVC8+
|
||||
VC_MANIFEST_EMBED_DLL="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;2 ; fi"
|
||||
VC_MANIFEST_EMBED_EXE="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;1 ; fi"
|
||||
MAKE_SHARED_LIB="${MAKE_SHARED_LIB} ; ${VC_MANIFEST_EMBED_DLL}"
|
||||
TEA_ADD_CLEANFILES([*.manifest])
|
||||
])
|
||||
MAKE_STUB_LIB="\${STLIB_LD} -nodefaultlib -out:\[$]@ \$(PKG_STUB_OBJECTS)"
|
||||
else
|
||||
MAKE_STATIC_LIB="\${STLIB_LD} \[$]@ \$(PKG_OBJECTS)"
|
||||
MAKE_SHARED_LIB="\${SHLIB_LD} -o \[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}"
|
||||
@@ -3184,13 +3345,19 @@ AC_DEFUN([TEA_MAKE_LIB], [
|
||||
if test "${SHARED_BUILD}" = "1" ; then
|
||||
# We force the unresolved linking of symbols that are really in
|
||||
# the private libraries of Tcl and Tk.
|
||||
SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\""
|
||||
if test x"${TK_BIN_DIR}" != x ; then
|
||||
SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\""
|
||||
fi
|
||||
SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\""
|
||||
if test "$GCC" = "yes"; then
|
||||
SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -static-libgcc"
|
||||
fi
|
||||
eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
|
||||
else
|
||||
eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
|
||||
if test "$GCC" = "yes"; then
|
||||
PKG_LIB_FILE=lib${PKG_LIB_FILE}
|
||||
fi
|
||||
fi
|
||||
# Some packages build their own stubs libraries
|
||||
eval eval "PKG_STUB_LIB_FILE=${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}"
|
||||
@@ -3228,6 +3395,8 @@ AC_DEFUN([TEA_MAKE_LIB], [
|
||||
AC_SUBST(MAKE_STATIC_LIB)
|
||||
AC_SUBST(MAKE_STUB_LIB)
|
||||
AC_SUBST(RANLIB_STUB)
|
||||
AC_SUBST(VC_MANIFEST_EMBED_DLL)
|
||||
AC_SUBST(VC_MANIFEST_EMBED_EXE)
|
||||
])
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
@@ -3316,7 +3485,7 @@ AC_DEFUN([TEA_LIB_SPEC], [
|
||||
#
|
||||
# Results:
|
||||
#
|
||||
# Substs the following vars:
|
||||
# Substitutes the following vars:
|
||||
# TCL_TOP_DIR_NATIVE
|
||||
# TCL_INCLUDES
|
||||
#------------------------------------------------------------------------
|
||||
@@ -3394,7 +3563,7 @@ AC_DEFUN([TEA_PRIVATE_TCL_HEADERS], [
|
||||
# Adds a --with-tclinclude switch to configure.
|
||||
# Result is cached.
|
||||
#
|
||||
# Substs the following vars:
|
||||
# Substitutes the following vars:
|
||||
# TCL_INCLUDES
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
@@ -3484,7 +3653,7 @@ AC_DEFUN([TEA_PUBLIC_TCL_HEADERS], [
|
||||
#
|
||||
# Results:
|
||||
#
|
||||
# Substs the following vars:
|
||||
# Substitutes the following vars:
|
||||
# TK_INCLUDES
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
@@ -3573,7 +3742,7 @@ AC_DEFUN([TEA_PRIVATE_TK_HEADERS], [
|
||||
# Adds a --with-tkinclude switch to configure.
|
||||
# Result is cached.
|
||||
#
|
||||
# Substs the following vars:
|
||||
# Substitutes the following vars:
|
||||
# TK_INCLUDES
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
@@ -3791,11 +3960,10 @@ AC_DEFUN([TEA_PATH_CONFIG], [
|
||||
#
|
||||
# Results:
|
||||
#
|
||||
# Subst the following vars:
|
||||
# Substitutes the following vars:
|
||||
# $1_SRC_DIR
|
||||
# $1_LIB_FILE
|
||||
# $1_LIB_SPEC
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
AC_DEFUN([TEA_LOAD_CONFIG], [
|
||||
@@ -3822,6 +3990,8 @@ AC_DEFUN([TEA_LOAD_CONFIG], [
|
||||
$1_LIB_SPEC=${$1_BUILD_LIB_SPEC}
|
||||
$1_STUB_LIB_SPEC=${$1_BUILD_STUB_LIB_SPEC}
|
||||
$1_STUB_LIB_PATH=${$1_BUILD_STUB_LIB_PATH}
|
||||
$1_INCLUDE_SPEC=${$1_BUILD_INCLUDE_SPEC}
|
||||
$1_LIBRARY_PATH=${$1_LIBRARY_PATH}
|
||||
fi
|
||||
|
||||
AC_SUBST($1_VERSION)
|
||||
@@ -3854,7 +4024,6 @@ AC_DEFUN([TEA_LOAD_CONFIG], [
|
||||
#
|
||||
# Results:
|
||||
# Adds to LIBS the appropriate extension library
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
AC_DEFUN([TEA_LOAD_CONFIG_LIB], [
|
||||
AC_MSG_CHECKING([For $1 library for LIBS])
|
||||
@@ -3886,11 +4055,10 @@ AC_DEFUN([TEA_LOAD_CONFIG_LIB], [
|
||||
# $1
|
||||
#
|
||||
# Results:
|
||||
# Subst the following vars:
|
||||
#
|
||||
# Substitutes the following vars:
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
AC_DEFUN(TEA_EXPORT_CONFIG, [
|
||||
AC_DEFUN([TEA_EXPORT_CONFIG], [
|
||||
#--------------------------------------------------------------------
|
||||
# These are for $1Config.sh
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.62 for sqlite 3.8.3.
|
||||
# Generated by GNU Autoconf 2.62 for sqlite 3.8.5.
|
||||
#
|
||||
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
|
||||
@@ -743,8 +743,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='sqlite'
|
||||
PACKAGE_TARNAME='sqlite'
|
||||
PACKAGE_VERSION='3.8.3'
|
||||
PACKAGE_STRING='sqlite 3.8.3'
|
||||
PACKAGE_VERSION='3.8.5'
|
||||
PACKAGE_STRING='sqlite 3.8.5'
|
||||
PACKAGE_BUGREPORT=''
|
||||
|
||||
# Factoring default headers for most tests.
|
||||
@@ -1483,7 +1483,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures sqlite 3.8.3 to adapt to many kinds of systems.
|
||||
\`configure' configures sqlite 3.8.5 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1548,7 +1548,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlite 3.8.3:";;
|
||||
short | recursive ) echo "Configuration of sqlite 3.8.5:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1664,7 +1664,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlite configure 3.8.3
|
||||
sqlite configure 3.8.5
|
||||
generated by GNU Autoconf 2.62
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
@@ -1678,7 +1678,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by sqlite $as_me 3.8.3, which was
|
||||
It was created by sqlite $as_me 3.8.5, which was
|
||||
generated by GNU Autoconf 2.62. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -14021,7 +14021,7 @@ exec 6>&1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by sqlite $as_me 3.8.3, which was
|
||||
This file was extended by sqlite $as_me 3.8.5, which was
|
||||
generated by GNU Autoconf 2.62. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -14074,7 +14074,7 @@ Report bugs to <bug-autoconf@gnu.org>."
|
||||
_ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_version="\\
|
||||
sqlite config.status 3.8.3
|
||||
sqlite config.status 3.8.5
|
||||
configured by $0, generated by GNU Autoconf 2.62,
|
||||
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
|
||||
|
||||
|
||||
+37
-7
@@ -1410,10 +1410,7 @@ static int fts3InitVtab(
|
||||
** addition of a %_stat table so that it can use incremental merge.
|
||||
*/
|
||||
if( !isFts4 && !isCreate ){
|
||||
int rc2 = SQLITE_OK;
|
||||
fts3DbExec(&rc2, db, "SELECT 1 FROM %Q.'%q_stat' WHERE id=2",
|
||||
p->zDb, p->zName);
|
||||
if( rc2==SQLITE_OK ) p->bHasStat = 1;
|
||||
p->bHasStat = 2;
|
||||
}
|
||||
|
||||
/* Figure out the page-size for the database. This is required in order to
|
||||
@@ -3320,7 +3317,34 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of xBegin() method. This is a no-op.
|
||||
** If it is currently unknown whether or not the FTS table has an %_stat
|
||||
** table (if p->bHasStat==2), attempt to determine this (set p->bHasStat
|
||||
** to 0 or 1). Return SQLITE_OK if successful, or an SQLite error code
|
||||
** if an error occurs.
|
||||
*/
|
||||
static int fts3SetHasStat(Fts3Table *p){
|
||||
int rc = SQLITE_OK;
|
||||
if( p->bHasStat==2 ){
|
||||
const char *zFmt ="SELECT 1 FROM %Q.sqlite_master WHERE tbl_name='%q_stat'";
|
||||
char *zSql = sqlite3_mprintf(zFmt, p->zDb, p->zName);
|
||||
if( zSql ){
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
int bHasStat = (sqlite3_step(pStmt)==SQLITE_ROW);
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
if( rc==SQLITE_OK ) p->bHasStat = bHasStat;
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of xBegin() method.
|
||||
*/
|
||||
static int fts3BeginMethod(sqlite3_vtab *pVtab){
|
||||
Fts3Table *p = (Fts3Table*)pVtab;
|
||||
@@ -3331,7 +3355,7 @@ static int fts3BeginMethod(sqlite3_vtab *pVtab){
|
||||
TESTONLY( p->inTransaction = 1 );
|
||||
TESTONLY( p->mxSavepoint = -1; );
|
||||
p->nLeafAdd = 0;
|
||||
return SQLITE_OK;
|
||||
return fts3SetHasStat(p);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3580,6 +3604,10 @@ static int fts3RenameMethod(
|
||||
sqlite3 *db = p->db; /* Database connection */
|
||||
int rc; /* Return Code */
|
||||
|
||||
/* At this point it must be known if the %_stat table exists or not.
|
||||
** So bHasStat may not be 2. */
|
||||
rc = fts3SetHasStat(p);
|
||||
|
||||
/* As it happens, the pending terms table is always empty here. This is
|
||||
** because an "ALTER TABLE RENAME TABLE" statement inside a transaction
|
||||
** always opens a savepoint transaction. And the xSavepoint() method
|
||||
@@ -3587,7 +3615,9 @@ static int fts3RenameMethod(
|
||||
** PendingTermsFlush() in in case that changes.
|
||||
*/
|
||||
assert( p->nPendingData==0 );
|
||||
rc = sqlite3Fts3PendingTermsFlush(p);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts3PendingTermsFlush(p);
|
||||
}
|
||||
|
||||
if( p->zContentTbl==0 ){
|
||||
fts3DbExec(&rc, db,
|
||||
|
||||
+1
-1
@@ -223,7 +223,7 @@ struct Fts3Table {
|
||||
|
||||
int nNodeSize; /* Soft limit for node size */
|
||||
u8 bFts4; /* True for FTS4, false for FTS3 */
|
||||
u8 bHasStat; /* True if %_stat table exists */
|
||||
u8 bHasStat; /* True if %_stat table exists (2==unknown) */
|
||||
u8 bHasDocsize; /* True if %_docsize table exists */
|
||||
u8 bDescIdx; /* True if doclists are in reverse order */
|
||||
u8 bIgnoreSavepoint; /* True to ignore xSavepoint invocations */
|
||||
|
||||
@@ -5271,6 +5271,10 @@ int sqlite3Fts3UpdateMethod(
|
||||
int nChng = 0; /* Net change in number of documents */
|
||||
int bInsertDone = 0;
|
||||
|
||||
/* At this point it must be known if the %_stat table exists or not.
|
||||
** So bHasStat may not be 2. */
|
||||
assert( p->bHasStat==0 || p->bHasStat==1 );
|
||||
|
||||
assert( p->pSegments==0 );
|
||||
assert(
|
||||
nArg==1 /* DELETE operations */
|
||||
|
||||
+1
-1
@@ -26,8 +26,8 @@ SQLITE_EXTENSION_INIT1
|
||||
# define NEVER(X) 0
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
# include <ctype.h>
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
|
||||
+23
-15
@@ -2947,26 +2947,32 @@ static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){
|
||||
** on sqlite_stat1 data. Otherwise, use RTREE_DEFAULT_ROWEST.
|
||||
*/
|
||||
static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
|
||||
const char *zSql = "SELECT stat FROM sqlite_stat1 WHERE tbl= ? || '_rowid'";
|
||||
const char *zFmt = "SELECT stat FROM %Q.sqlite_stat1 WHERE tbl = '%q_rowid'";
|
||||
char *zSql;
|
||||
sqlite3_stmt *p;
|
||||
int rc;
|
||||
i64 nRow = 0;
|
||||
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_bind_text(p, 1, pRtree->zName, -1, SQLITE_STATIC);
|
||||
if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0);
|
||||
rc = sqlite3_finalize(p);
|
||||
}else if( rc!=SQLITE_NOMEM ){
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
if( nRow==0 ){
|
||||
pRtree->nRowEst = RTREE_DEFAULT_ROWEST;
|
||||
}else{
|
||||
pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST);
|
||||
zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName);
|
||||
if( zSql==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0);
|
||||
rc = sqlite3_finalize(p);
|
||||
}else if( rc!=SQLITE_NOMEM ){
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
if( nRow==0 ){
|
||||
pRtree->nRowEst = RTREE_DEFAULT_ROWEST;
|
||||
}else{
|
||||
pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST);
|
||||
}
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
|
||||
return rc;
|
||||
@@ -3235,6 +3241,8 @@ static int rtreeInit(
|
||||
if( rc==SQLITE_OK ){
|
||||
*ppVtab = (sqlite3_vtab *)pRtree;
|
||||
}else{
|
||||
assert( *ppVtab==0 );
|
||||
assert( pRtree->nBusy==1 );
|
||||
rtreeRelease(pRtree);
|
||||
}
|
||||
return rc;
|
||||
|
||||
@@ -158,5 +158,117 @@ do_execsql_test 4.3 {
|
||||
SELECT b, a FROM t2 LEFT JOIN t1 ON (+a = +b);
|
||||
} {1 1 3 {}}
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Test that the sqlite_stat1 data is used correctly.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 5.1 {
|
||||
CREATE TABLE t1(x PRIMARY KEY, y);
|
||||
CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2);
|
||||
|
||||
INSERT INTO t1(x) VALUES(1);
|
||||
INSERT INTO t1(x) SELECT x+1 FROM t1; -- 2
|
||||
INSERT INTO t1(x) SELECT x+2 FROM t1; -- 4
|
||||
INSERT INTO t1(x) SELECT x+4 FROM t1; -- 8
|
||||
INSERT INTO t1(x) SELECT x+8 FROM t1; -- 16
|
||||
INSERT INTO t1(x) SELECT x+16 FROM t1; -- 32
|
||||
INSERT INTO t1(x) SELECT x+32 FROM t1; -- 64
|
||||
INSERT INTO t1(x) SELECT x+64 FROM t1; -- 128
|
||||
INSERT INTO t1(x) SELECT x+128 FROM t1; -- 256
|
||||
INSERT INTO t1(x) SELECT x+256 FROM t1; -- 512
|
||||
INSERT INTO t1(x) SELECT x+512 FROM t1; --1024
|
||||
|
||||
INSERT INTO rt SELECT x, x, x+1 FROM t1 WHERE x<=5;
|
||||
}
|
||||
|
||||
# First test a query with no ANALYZE data at all. The outer loop is
|
||||
# real table "t1".
|
||||
#
|
||||
do_eqp_test 5.2 {
|
||||
SELECT * FROM t1, rt WHERE x==id;
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 1:}
|
||||
}
|
||||
|
||||
# Now create enough ANALYZE data to tell SQLite that virtual table "rt"
|
||||
# contains very few rows. This causes it to move "rt" to the outer loop.
|
||||
#
|
||||
do_execsql_test 5.3 {
|
||||
ANALYZE;
|
||||
DELETE FROM sqlite_stat1 WHERE tbl='t1';
|
||||
}
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_eqp_test 5.4 {
|
||||
SELECT * FROM t1, rt WHERE x==id;
|
||||
} {
|
||||
0 0 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:}
|
||||
0 1 0 {SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (x=?)}
|
||||
}
|
||||
|
||||
# Delete the ANALYZE data. "t1" should be the outer loop again.
|
||||
#
|
||||
do_execsql_test 5.5 { DROP TABLE sqlite_stat1; }
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_eqp_test 5.6 {
|
||||
SELECT * FROM t1, rt WHERE x==id;
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 1:}
|
||||
}
|
||||
|
||||
# This time create and attach a database that contains ANALYZE data for
|
||||
# tables of the same names as those used internally by virtual table
|
||||
# "rt". Check that the rtree module is not fooled into using this data.
|
||||
# Table "t1" should remain the outer loop.
|
||||
#
|
||||
do_test 5.7 {
|
||||
db backup test.db2
|
||||
sqlite3 db2 test.db2
|
||||
db2 eval {
|
||||
ANALYZE;
|
||||
DELETE FROM sqlite_stat1 WHERE tbl='t1';
|
||||
}
|
||||
db2 close
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
execsql { ATTACH 'test.db2' AS aux; }
|
||||
} {}
|
||||
do_eqp_test 5.8 {
|
||||
SELECT * FROM t1, rt WHERE x==id;
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 1:}
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Test that having a second connection drop the sqlite_stat1 table
|
||||
# before it is required by rtreeConnect() does not cause problems.
|
||||
#
|
||||
ifcapable rtree {
|
||||
reset_db
|
||||
do_execsql_test 6.1 {
|
||||
CREATE TABLE t1(x);
|
||||
CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2);
|
||||
INSERT INTO t1 VALUES(1);
|
||||
INSERT INTO rt VALUES(1,2,3);
|
||||
ANALYZE;
|
||||
}
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 6.2 { SELECT * FROM t1 } {1}
|
||||
|
||||
do_test 6.3 {
|
||||
sqlite3 db2 test.db
|
||||
db2 eval { DROP TABLE sqlite_stat1 }
|
||||
db2 close
|
||||
execsql { SELECT * FROM rt }
|
||||
} {1 2.0 3.0}
|
||||
db close
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# 2014 March 11
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Miscellaneous tests for errors in the rtree constructor.
|
||||
#
|
||||
|
||||
|
||||
if {![info exists testdir]} {
|
||||
set testdir [file join [file dirname [info script]] .. .. test]
|
||||
}
|
||||
source [file join [file dirname [info script]] rtree_util.tcl]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/lock_common.tcl
|
||||
ifcapable !rtree {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
set testprefix rtreeD
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that if an SQLITE_BUSY is encountered within the vtable
|
||||
# constructor, a relevant error message is returned.
|
||||
#
|
||||
do_multiclient_test tn {
|
||||
do_test 1.$tn.1 {
|
||||
sql1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1,2);
|
||||
CREATE VIRTUAL TABLE rt USING rtree(id, minx, maxx, miny, maxy);
|
||||
INSERT INTO rt VALUES(1,2,3,4,5);
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test 1.$tn.2 {
|
||||
sql2 { SELECT * FROM t1; }
|
||||
} {1 2}
|
||||
|
||||
do_test 1.$tn.3 {
|
||||
sql1 { BEGIN EXCLUSIVE; INSERT INTO t1 VALUES(3, 4); }
|
||||
} {}
|
||||
|
||||
do_test 1.$tn.4 {
|
||||
list [catch { sql2 { SELECT * FROM rt } } msg] $msg
|
||||
} {1 {database is locked}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ LIBOBJ+= vdbe.o parse.o \
|
||||
notify.o opcodes.o os.o os_unix.o os_win.o \
|
||||
pager.o pcache.o pcache1.o pragma.o prepare.o printf.o \
|
||||
random.o resolve.o rowset.o rtree.o select.o status.o \
|
||||
table.o tokenize.o trigger.o \
|
||||
table.o threads.o tokenize.o trigger.o \
|
||||
update.o util.o vacuum.o \
|
||||
vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbesort.o \
|
||||
vdbetrace.o wal.o walker.o where.o utf.o vtab.o
|
||||
@@ -144,6 +144,7 @@ SRC = \
|
||||
$(TOP)/src/sqliteLimit.h \
|
||||
$(TOP)/src/table.c \
|
||||
$(TOP)/src/tclsqlite.c \
|
||||
$(TOP)/src/threads.c \
|
||||
$(TOP)/src/tokenize.c \
|
||||
$(TOP)/src/trigger.c \
|
||||
$(TOP)/src/utf.c \
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
C Add\sthe\s".save"\scommand\sas\san\salias\sfor\s".backup".\s\sImprovements\sto\sthe\nway\sfont\schanges\sare\simplemented\son\sthe\sin-memory\sdatabase\swarning.
|
||||
D 2014-02-10T19:59:27.437
|
||||
C Experimental\smulti-threaded\ssorting\schanges\sto\sbegin\smerging\sPMAs\sbefore\sSorterRewind()\sis\scalled.
|
||||
D 2014-04-07T18:44:00.443
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81
|
||||
F Makefile.in ad0921c4b2780d01868cf69b419a4f102308d125
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
F Makefile.msc 6ff3ff2eef45c7dd309a8626ff7947b20bd387e7
|
||||
F Makefile.msc 153eb9b9725bc7b8e4dbe963219298e0c4a644b0
|
||||
F Makefile.vxworks db21ed42a01d5740e656b16f92cb5d8d5e5dd315
|
||||
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
|
||||
F VERSION 8ed548d87d0a27fd7d7620476f9e25f9fa742d73
|
||||
F README.md 64f270c43c38c46de749e419c22f0ae2f4499fe8
|
||||
F VERSION 9f823c026c6a32fc5f84d212a8aae0a221dba45c
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F addopcodes.awk 9eb448a552d5c0185cf62c463f9c173cedae3811
|
||||
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
|
||||
@@ -30,15 +30,15 @@ F autoconf/tea/configure.in e0466b881b53f31f5a4a69e7a91ad130902fb359
|
||||
F autoconf/tea/doc/sqlite3.n e1fe45d4f5286ee3d0ccc877aca2a0def488e9bb
|
||||
F autoconf/tea/license.terms 13bd403c9610fd2b76ece0ab50c4c5eda933d523
|
||||
F autoconf/tea/pkgIndex.tcl.in 3ef61715cf1c7bdcff56947ffadb26bc991ca39d
|
||||
F autoconf/tea/tclconfig/install-sh b087e5c4b92820c60bffb74acc1d9c2d40d80b8f
|
||||
F autoconf/tea/tclconfig/tcl.m4 a68179d7cc45524fa59db428a36610e20bdba808
|
||||
F autoconf/tea/tclconfig/install-sh bdd5e293591621ae60d9824d86a4b1c5f22c3d00
|
||||
F autoconf/tea/tclconfig/tcl.m4 f035b86539a5ab30689e997a11ae9e7fd2e65570
|
||||
F autoconf/tea/win/makefile.vc f89d0184d0eee5f7e356ea407964dcd139939928
|
||||
F autoconf/tea/win/nmakehlp.c 2070e086f39866b353a482d3a14dedaf26196506
|
||||
F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63
|
||||
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
|
||||
F config.h.in 0921066a13130082764ab4ab6456f7b5bebe56de
|
||||
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
|
||||
F configure 1673bc402f8fc95015f72c279adc5a9a668ee237 x
|
||||
F configure 5de98fac90452f876511fee8a35565a55dfb191f x
|
||||
F configure.ac 4cf9f60785143fa141b10962ccc885d973792e9a
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/lemon.html 334dbf6621b8fb8790297ec1abf3cfa4621709d1
|
||||
@@ -78,9 +78,9 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
|
||||
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
|
||||
F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314
|
||||
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
||||
F ext/fts3/fts3.c 3fe91e36a0304ad4b35020f0e22ff37e95873166
|
||||
F ext/fts3/fts3.c 41b1920b9a8657963f09cb93b208c2671c5568db
|
||||
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
||||
F ext/fts3/fts3Int.h eb5f8029589f3d8f1dc7fd50c773326a640388b1
|
||||
F ext/fts3/fts3Int.h bdeb9015405e8facffb8fc7e09174521a2a780f4
|
||||
F ext/fts3/fts3_aux.c 5c211e17a64885faeb16b9ba7772f9d5445c2365
|
||||
F ext/fts3/fts3_expr.c 5165c365cb5a035f5be8bb296f7aa3211d43e4ac
|
||||
F ext/fts3/fts3_hash.c 29b986e43f4e9dd40110eafa377dc0d63c422c60
|
||||
@@ -96,7 +96,7 @@ F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3
|
||||
F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004
|
||||
F ext/fts3/fts3_unicode.c 92391b4b4fb043564c6539ea9b8661e3bcba47b9
|
||||
F ext/fts3/fts3_unicode2.c 0113d3acf13429e6dc38e0647d1bc71211c31a4d
|
||||
F ext/fts3/fts3_write.c cdebe72171a217b1465032dec103f8d17f7dad4d
|
||||
F ext/fts3/fts3_write.c 74c00329006c3ed6325ba4e5ab7c9b5fc99c8934
|
||||
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
|
||||
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
|
||||
F ext/fts3/tool/fts3view.c 6cfc5b67a5f0e09c0d698f9fd012c784bfaa9197
|
||||
@@ -114,13 +114,13 @@ F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
|
||||
F ext/misc/percentile.c bcbee3c061b884eccb80e21651daaae8e1e43c63
|
||||
F ext/misc/regexp.c af92cdaa5058fcec1451e49becc7ba44dba023dc
|
||||
F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a
|
||||
F ext/misc/spellfix.c 3548c433f473c2054e080b6382771636fcaa2c4c
|
||||
F ext/misc/spellfix.c 93f3961074cebe63c31fcefe62ca2a032ee8dfed
|
||||
F ext/misc/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512
|
||||
F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
|
||||
F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
|
||||
F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/rtree.c a4e18b2c150adad20aecbeb3408cd235a0a57441
|
||||
F ext/rtree/rtree.c 2d9f95da404d850474e628c720c5ce15d29b47de
|
||||
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
||||
F ext/rtree/rtree1.test cf679265ecafff494a768ac9c2f43a70915a6290
|
||||
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
|
||||
@@ -133,7 +133,8 @@ F ext/rtree/rtree8.test db79c812f9e4a11f9b1f3f9934007884610a713a
|
||||
F ext/rtree/rtree9.test d86ebf08ff6328895613ed577dd8a2a37c472c34
|
||||
F ext/rtree/rtreeA.test ace05e729a36e342d40cf94e9efc7b4723d9dcdf
|
||||
F ext/rtree/rtreeB.test 983e567b49b5dca165940f66b87e161aa30e82b2
|
||||
F ext/rtree/rtreeC.test 03975565f40a0bee165f613143e4dec716dd5a59
|
||||
F ext/rtree/rtreeC.test 16d7aa86ecb6a876d2a38cf590a1471a41b3a46d
|
||||
F ext/rtree/rtreeD.test 636630357638f5983701550b37f0f5867130d2ca
|
||||
F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
|
||||
F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
|
||||
F ext/rtree/sqlite3rtree.h c34c1e41d1ab80bb8ad09aae402c9c956871a765
|
||||
@@ -142,10 +143,7 @@ F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt f439556c5ce01ced70987e5ee86549a45165d9ff
|
||||
F main.mk 3ae543fa446525c1dec55f58de67f41b78651812
|
||||
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
|
||||
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
|
||||
F mkextw.sh d2a981497b404d6498f5ff3e3b1f3816bdfcb338
|
||||
F main.mk 4b30dd2a6cb441db688972496b45a6c3abef8b20
|
||||
F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
|
||||
F mkopcodeh.awk c6b3fa301db6ef7ac916b14c60868aeaec1337b5
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
@@ -159,42 +157,42 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 3d8b83c91651f53472ca17599dae3457b8b89494
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c d5348d0f86a5fc8fb3987727402f023953c021cf
|
||||
F src/analyze.c 581d5c18ce89c6f45d4dca65914d0de5b4dad41f
|
||||
F src/alter.c 5d99edbac5bc416032772b723ee30182ee6e5de0
|
||||
F src/analyze.c 663e0b291d27eb03c9fd6b421e2d61ba348a2389
|
||||
F src/attach.c 3801129015ef59d76bf23c95ef9b0069d18a0c52
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53
|
||||
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
|
||||
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||
F src/btree.c 7b2c3cd16deedff7f4904f2e871e7b77328b9872
|
||||
F src/btree.h a61ddebc78c66795a2b93181321a116746302cc9
|
||||
F src/btreeInt.h f038e818bfadf75afbd09819ed93c26a333d39e0
|
||||
F src/build.c 13b9d82181d95af7b00ec8a8e1304bac096432d4
|
||||
F src/btree.c 0d1be67448c45eccc40114556186397eb9da7f7d
|
||||
F src/btree.h 232836cb51753f2e96aa8ce0f052c6df850f76ba
|
||||
F src/btreeInt.h 0be66063468a520e4d66b80c7a1dc26d04ee6ea4
|
||||
F src/build.c e120a3693ac78ab3e74048205f07a3a522d9b982
|
||||
F src/callback.c 174e3c8656bc29f91d710ab61550d16eea34be98
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c 77779efbe78dd678d84bfb4fc2e87b6b6ad8dccd
|
||||
F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a
|
||||
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
|
||||
F src/delete.c 6765a421f08adbedc5d52d21760ec6dbe5123fd3
|
||||
F src/expr.c 9bea427f95665c1aa8fdc87b7678546eef50c296
|
||||
F src/delete.c cdd57149543bb28304d8f717c243f2a86b1fc280
|
||||
F src/expr.c da2b3cb41081af6b56e95e7c9e95949564ce2e21
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 2ab0f5384b70594468ef3ac5c7ed8ca24bfd17d5
|
||||
F src/func.c f4499b39d66b71825514334ce67b32ff14bd19f5
|
||||
F src/global.c 1d7bb7ea8254ae6a68ed9bfaf65fcb3d1690b486
|
||||
F src/fkey.c 5269ef07b100763134f71b889327c333bd0989cf
|
||||
F src/func.c 2945bb2c4cdc0ac43733046285a4434310be1811
|
||||
F src/global.c deadd872189b92aca4ee2566332a86315839f811
|
||||
F src/hash.c d139319967164f139c8d1bb8a11b14db9c4ba3cd
|
||||
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c 89526b031cf8f0e2306f02099a73cee56110c580
|
||||
F src/insert.c d8bb30535c8c0785876025a4a07f9074640a15d1
|
||||
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
||||
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
|
||||
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
|
||||
F src/loadext.c 867c7b330b740c6c917af9956b13b81d0a048303
|
||||
F src/main.c 07225af6a00be0b7f34ac52e60f99cf5cbb2a475
|
||||
F src/main.c fcceb01d74a79c2d7984f33545b35b06da3bb1e8
|
||||
F src/malloc.c 0203ebce9152c6a0e5de520140b8ba65187350be
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c0c990fcaddff810ea277b4fb5d9138603dd5d4b
|
||||
F src/mem2.c dce31758da87ec2cfa52ba4c5df1aed6e07d8e8f
|
||||
F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534
|
||||
F src/mem5.c 19d9271cb936742707b6118ed44d779657c7c511
|
||||
F src/mem5.c 74670012946c4adc8a6ad84d03acc80959c3e529
|
||||
F src/memjournal.c 0683aac6cab6ec2b5374c0db37c0deb2436a3785
|
||||
F src/mutex.c d3b66a569368015e0fcb1ac15f81c119f504d3bc
|
||||
F src/mutex.h 5bc526e19dccc412b7ff04642f6fdad3fdfdabea
|
||||
@@ -205,35 +203,35 @@ F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
|
||||
F src/os.c 1b147e4cf7cc39e618115c14a086aed44bc91ace
|
||||
F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f
|
||||
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
|
||||
F src/os_unix.c 18f7f95dc6bcb9cf4d4a238d8e2de96611bc2ae5
|
||||
F src/os_win.c d4284f003445054a26689f1264b1b9bf7261bd1b
|
||||
F src/pager.c 0ffa313a30ed6d061d9c6601b7b175cc50a1cab7
|
||||
F src/os_unix.c ae4b5240af4619d711301d7992396e182585269f
|
||||
F src/os_win.c 8245fe9184300e641d02e29a8ca95cefe0cb0fd0
|
||||
F src/pager.c ab62a24218d87dda1be641f6c5ad291bff78fd94
|
||||
F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428
|
||||
F src/parse.y cce844ccb80b5f969b04c25100c8d94338488efb
|
||||
F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0
|
||||
F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2
|
||||
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
|
||||
F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c
|
||||
F src/pragma.c ed409ce4104cf4d9de6ead40ace70974f124853b
|
||||
F src/pragma.c 10f169b9650f0930a7a6df67e1387a4c2c449f38
|
||||
F src/prepare.c 677521ab7132615a8a26107a1d1c3132f44ae337
|
||||
F src/printf.c 85d07756e45d7496d19439dcae3e6e9e0090f269
|
||||
F src/printf.c e5a0005f8b3de21f85da6a709d2fbee76775bf4b
|
||||
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
|
||||
F src/resolve.c 7eda9097b29fcf3d2b42fdc17d1de672134e09b6
|
||||
F src/resolve.c 273d5f47c4e2c05b2d3d2bffeda939551ab59e66
|
||||
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
||||
F src/select.c c055a9fa25a4e7fc8c1652c44a31d6382dbb1e8a
|
||||
F src/shell.c cb8d19594483d23d6e35244bb043cf0cd1816a52
|
||||
F src/sqlite.h.in eed7f7d66a60daaa7b4a597dcd9bad87aad9611b
|
||||
F src/select.c 20055cf917222e660c4222fea306bd13a0623caa
|
||||
F src/shell.c b44c3f17f0bf41b3431e9cc171706251156ae85f
|
||||
F src/sqlite.h.in 81221c50addbf698c3247154d92efd1095bfd885
|
||||
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
|
||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||
F src/sqliteInt.h 5b1f4e30c8332270e4c14254ef1fbcbd92a4a4c7
|
||||
F src/sqliteInt.h 533154bf9d8401ff3e6f8030f4373774c0a6ad41
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c 649d373f2a3cfbefe8e935a8dec83686616f9a85
|
||||
F src/test1.c 2401eee14a4309a7cfe2aeb2f30ad517a1d9c299
|
||||
F src/tclsqlite.c e87c99e28a145943666b51b212dacae35fcea0bd
|
||||
F src/test1.c 0cd73ae82fdf7add76ca603e3575380ae7539ae2
|
||||
F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35
|
||||
F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
|
||||
F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
|
||||
F src/test5.c 41e6e732f14a54c7b47f753e364700760f6521b0
|
||||
F src/test5.c 5a34feec76d9b3a86aab30fd4f6cc9c48cbab4c1
|
||||
F src/test6.c 41cacf3b0dd180823919bf9e1fbab287c9266723
|
||||
F src/test7.c 72b732baa5642f795655ba1126ea032af46ecfd2
|
||||
F src/test8.c 54ccd7b1df5062f0ecbf50a8f7b618f8b1f13b20
|
||||
@@ -242,18 +240,18 @@ F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8
|
||||
F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12
|
||||
F src/test_backup.c 3875e899222b651e18b662f86e0e50daa946344e
|
||||
F src/test_btree.c 5b89601dcb42a33ba8b820a6b763cc9cb48bac16
|
||||
F src/test_config.c 0336e0bdbe541b4af89d7e3dd0656e8e6b51e585
|
||||
F src/test_config.c ebd0a42983b696f2b121515d577753cf2afdc9b0
|
||||
F src/test_demovfs.c 69b2085076654ebc18014cbc6386f04409c959a9
|
||||
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
|
||||
F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f
|
||||
F src/test_func.c f8235719dff4bf9ffee04c55a190af8782ce9ab5
|
||||
F src/test_func.c d3013ce36f19ac72a99c73864930fd1fa41832f8
|
||||
F src/test_hexio.c abfdecb6fa58c354623978efceb088ca18e379cd
|
||||
F src/test_init.c 66b33120ffe9cd853b5a905ec850d51151337b32
|
||||
F src/test_intarray.c 87847c71c3c36889c0bcc9c4baf9d31881665d61
|
||||
F src/test_intarray.h 2ece66438cfd177b78d1bfda7a4180cd3a10844d
|
||||
F src/test_journal.c f5c0a05b7b3d5930db769b5ee6c3766dc2221a64
|
||||
F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e
|
||||
F src/test_malloc.c 1ff5b1243d96124c9a180f3b89424820a1f337f3
|
||||
F src/test_loadext.c a5251f956ab6af21e138dc1f9c0399394a510cb4
|
||||
F src/test_malloc.c 27047a841f5bff1cb638123806a2c30714771307
|
||||
F src/test_multiplex.c 9f304bf04170c91c0318238d512df2da039eb1c8
|
||||
F src/test_multiplex.h 110a8c4d356e0aa464ca8730375608a9a0b61ae1
|
||||
F src/test_mutex.c 293042d623ebba969160f471a82aa1551626454f
|
||||
@@ -268,33 +266,34 @@ F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe
|
||||
F src/test_sqllog.c c1c1bbedbcaf82b93d83e4f9dd990e62476a680e
|
||||
F src/test_stat.c 9898687a6c2beca733b0dd6fe19163d987826d31
|
||||
F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
|
||||
F src/test_syscall.c 16dbe79fb320fadb5acd7a0a59f49e52ab2d2091
|
||||
F src/test_syscall.c 2e21ca7f7dc54a028f1967b63f1e76155c356f9b
|
||||
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
||||
F src/test_thread.c 1e133a40b50e9c035b00174035b846e7eef481cb
|
||||
F src/test_vfs.c e72f555ef7a59080f898fcf1a233deb9eb704ea9
|
||||
F src/test_vfstrace.c 3a0ab304682fecbceb689e7d9b904211fde11d78
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c b8e7232f2b9c9d148d6886117160de394d172f85
|
||||
F src/tokenize.c 6da2de6e12218ccb0aea5184b56727d011f4bee7
|
||||
F src/trigger.c a417d386e214f0abd2e0f756b834b4d9f4d3368a
|
||||
F src/update.c a7df6fffce6bfedc578fda6136dd33e34a63f8ee
|
||||
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
|
||||
F src/trigger.c 66f3470b03b52b395e839155786966e3e037fddb
|
||||
F src/update.c 5b3e74a03b3811e586b4f2b4cbd7c49f01c93115
|
||||
F src/utf.c 6dc9ec9f1b3db43ae8ba0365377f11df1ee4c01c
|
||||
F src/util.c c46c90459ef9bdc0c6c73803cf4c55425b4771cf
|
||||
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
|
||||
F src/vdbe.c e5c87476d717aebef5dafceab11417ebf2730554
|
||||
F src/vdbe.h e6c4c610fcabad4fa80ebb1efc6822a9367e2b26
|
||||
F src/vdbeInt.h 5286af9067cabdb8ba57b87c0c988a931be6c6c8
|
||||
F src/vdbeapi.c 5bc41aaea448a7fc250902c418f1795859be3820
|
||||
F src/vdbeaux.c dac6e571262a322b2f889752a8dd36549bdacd2b
|
||||
F src/vdbeblob.c 9542e116c1db5ed813977581d506c176e117c0ec
|
||||
F src/vdbemem.c 06603e8e9d2f3247b68c6bbe4bd37fb6721b5bda
|
||||
F src/vdbesort.c 9d83601f9d6243fe70dd0169a2820c5ddfd48147
|
||||
F src/vdbe.c 9f3d1b35b5fe8c7f3a4f734bd524d0df844a2576
|
||||
F src/vdbe.h 394464909ed682334aa3d5831aae0c2fe2abef94
|
||||
F src/vdbeInt.h ba1069627d0ab75e9ddb8f9c10958b86cdbd333d
|
||||
F src/vdbeapi.c 0ed6053f947edd0b30f64ce5aeb811872a3450a4
|
||||
F src/vdbeaux.c d8dc38965507a34b0e150c0d7fc82b02f8cf25ea
|
||||
F src/vdbeblob.c 15377abfb59251bccedd5a9c7d014a895f0c04aa
|
||||
F src/vdbemem.c 6fc77594c60f6155404f3f8d71bf36d1fdeb4447
|
||||
F src/vdbesort.c 07c29a5a61e041eeb1c366eefef9e99dfe5e2174
|
||||
F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767
|
||||
F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
|
||||
F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
|
||||
F src/wal.c 76e7fc6de229bea8b30bb2539110f03a494dc3a8
|
||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||
F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45
|
||||
F src/where.c 90fef20dd178db262ecd522a214a4eee6f76a44b
|
||||
F src/whereInt.h 921f935af8b684ffb49705610bda7284db1db138
|
||||
F src/where.c 70eb10da08cebbd6a576ced18edb7c8f79d41597
|
||||
F src/whereInt.h 2564055b440e44ebec8b47f237bbccae6719b7af
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
|
||||
@@ -303,7 +302,7 @@ F test/all.test 6ff7b43c2b4b905c74dc4a813d201d0fa64c5783
|
||||
F test/alter.test e88dfa77e020c2b48e52a8020c70171ab828e079
|
||||
F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060
|
||||
F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d
|
||||
F test/alter4.test 8e93bf7a7e6919b14b0c9a6c1e4908bcf21b0165
|
||||
F test/alter4.test d6c011fa0d6227abba762498cafbb607c9609e93
|
||||
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
|
||||
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
|
||||
F test/analyze.test 1772936d66471c65221e437b6d1999c3a03166c4
|
||||
@@ -313,7 +312,7 @@ F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4
|
||||
F test/analyze6.test d31defa011a561b938b4608d3538c1b4e0b5e92c
|
||||
F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f
|
||||
F test/analyze8.test 093d15c1c888eed5034304a98c992f7360130b88
|
||||
F test/analyze9.test 339e87723cd4dc158dc5e9095acd8df9e87faf79
|
||||
F test/analyze9.test e072a5172d55afcba98d6ca6a219ce8878c2f5c9
|
||||
F test/analyzeA.test 1a5c40079894847976d983ca39c707aaa44b6944
|
||||
F test/analyzeB.test 8bf35ee0a548aea831bf56762cb8e7fdb1db083d
|
||||
F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b
|
||||
@@ -364,11 +363,11 @@ F test/btreefault.test c2bcb542685eea44621275cfedbd8a13f65201e3
|
||||
F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0
|
||||
F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de
|
||||
F test/capi2.test 011c16da245fdc0106a2785035de6b242c05e738
|
||||
F test/capi3.test 6cdd49656bd62a296924f4d2fcfd05cd2a298369
|
||||
F test/capi3.test 71bcf2fbd36a9732f617766dfd752552c8e491b5
|
||||
F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4
|
||||
F test/capi3c.test a21869e4d50d5dbb7e566e328fc0bc7c2efa6a32
|
||||
F test/capi3d.test 6d0fc0a86d73f42dd19a7d8b7761ab9bc02277d0
|
||||
F test/capi3e.test ad90088b18b0367125ff2d4b5400153fd2f99aab
|
||||
F test/capi3e.test 3d49c01ef2a1a55f41d73cba2b23b5059ec460fe
|
||||
F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3
|
||||
F test/check.test 5831ddb6f2c687782eaf2e1a07b6e17f24c4f763
|
||||
F test/close.test 340bd24cc58b16c6bc01967402755027c37eb815
|
||||
@@ -405,8 +404,9 @@ F test/corruptC.test 02405cf7ed0c1e989060e1aab6d02ffbc3906fbb
|
||||
F test/corruptD.test b3c205fac7952b1de645ce44bb02335cd9e3e040
|
||||
F test/corruptE.test 193b4ca4e927e77c1d5f4f56203ddc998432a7ee
|
||||
F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4
|
||||
F test/corruptG.test c150f156dace653c00a121ad0f5772a0568c41ba
|
||||
F test/corruptH.test 9d8186f6f8751efdfd445d8546fd98f073499039
|
||||
F test/corruptG.test 1ab3bf97ee7bdba70e0ff3ba2320657df55d1804
|
||||
F test/corruptH.test 88ed71a086e13591c917aac6de32750e7c7281cb
|
||||
F test/corruptI.test b3e4203d420490fc3d3062711597bc1dea06a789
|
||||
F test/count.test 42a251178e32f617eda33f76236a7f79825a50b5
|
||||
F test/coveridxscan.test cdb47d01acc4a634a34fd25abe85189e0d0f1e62
|
||||
F test/crash.test fb9dc4a02dcba30d4aa5c2c226f98b220b2b959f
|
||||
@@ -432,7 +432,7 @@ F test/descidx1.test 6d03b44c8538fe0eb4924e19fba10cdd8f3c9240
|
||||
F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d
|
||||
F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2
|
||||
F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
|
||||
F test/distinct.test c7b194ef95dbddb32d77acbbab2e023c6eed0cb2
|
||||
F test/distinct.test 086e70c765f172e8974e9f83b9ac5ca03c154e77
|
||||
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
|
||||
F test/e_createtable.test ee95d48664503d40f6cc9ef4a7d03216188e2ada
|
||||
F test/e_delete.test d5186e2f5478b659f16a2c8b66c09892823e542a
|
||||
@@ -524,7 +524,7 @@ F test/fts3ak.test bd14deafe9d1586e8e9bf032411026ac4f8c925d
|
||||
F test/fts3al.test 07d64326e79bbdbab20ee87fc3328fbf01641c9f
|
||||
F test/fts3am.test 218aa6ba0dfc50c7c16b2022aac5c6be593d08d8
|
||||
F test/fts3an.test a49ccadc07a2f7d646ec1b81bc09da2d85a85b18
|
||||
F test/fts3ao.test 71b0675e3df5c512a5a03daaa95ee1916de23dda
|
||||
F test/fts3ao.test 3e4e3d5e75c076520341d0bdf4eb17c00e8cbde2
|
||||
F test/fts3atoken.test fca30fd86db9241d571c637751e9a8a2f50f1451
|
||||
F test/fts3auto.test b981fea19b132b4e6878f50d7c1f369b28f68eb9
|
||||
F test/fts3aux1.test f8f287a4a73f381f8fa15b6a70f36245f903d221
|
||||
@@ -536,7 +536,7 @@ F test/fts3conf.test ee8500c86dd58ec075e8831a1e216a79989436de
|
||||
F test/fts3corrupt.test 2710b77983cc7789295ddbffea52c1d3b7506dbb
|
||||
F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba
|
||||
F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7
|
||||
F test/fts3d.test c8a193513a269ec4c205ca09645e26e0bc71b860
|
||||
F test/fts3d.test 597b0b76e41f0d672e2731c4d7b631d628efd13f
|
||||
F test/fts3defer.test 0be4440b73a2e651fc1e472066686d6ada4b9963
|
||||
F test/fts3defer2.test a3b6cbeabaf28c9398652a4d101ea224d9358479
|
||||
F test/fts3defer3.test dd53fc13223c6d8264a98244e9b19abd35ed71cd
|
||||
@@ -575,7 +575,7 @@ F test/fts4merge4.test c19c85ca1faa7b6d536832b49c12e1867235f584
|
||||
F test/fts4noti.test aed33ba44808852dcb24bf70fa132e7bf530f057
|
||||
F test/fts4unicode.test 01ec3fe2a7c3cfff3b4c0581b83caa11b33efa36
|
||||
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
|
||||
F test/func.test 00667bbeac044d007f6f021af1b9f6150f0c7ff8
|
||||
F test/func.test a21814945d32137412b553d98ad2107f9b2173a9
|
||||
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
|
||||
F test/func3.test dbccee9133cfef1473c59ec07b5f0262b9d72f9a
|
||||
F test/func4.test 6beacdfcb0e18c358e6c2dcacf1b65d1fa80955f
|
||||
@@ -594,7 +594,7 @@ F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
|
||||
F test/in.test 047c4671328e9032ab95666a67021adbbd36e98e
|
||||
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
|
||||
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
|
||||
F test/in4.test 64f3cc1acde1b9161ccdd8e5bde3daefdb5b2617
|
||||
F test/in4.test 41c1c031aa46b1eb4411df2687ed2ed498da23b5
|
||||
F test/in5.test 99f9a40af01711b06d2d614ecfe96129f334fba3
|
||||
F test/incrblob.test e81846d214f3637622620fbde7cd526781cfe328
|
||||
F test/incrblob2.test bf4d549aa4a466d7fbe3e3a3693d3861263d5600
|
||||
@@ -616,10 +616,10 @@ F test/index7.test a3baf9a625bda7fd49471e99aeae04095fbfeecf
|
||||
F test/indexedby.test b2f22f3e693a53813aa3f50b812eb609ba6df1ec
|
||||
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
|
||||
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
|
||||
F test/insert.test 489aa12a027c83d291f5034a83c8c32e6be1dca2
|
||||
F test/insert.test acf909b067b838eb55338d619e800e148c17f1f5
|
||||
F test/insert2.test 4f3a04d168c728ed5ec2c88842e772606c7ce435
|
||||
F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30
|
||||
F test/insert4.test b00ddf82d6d4f0a6f3999f42bb6a3c813ea70707
|
||||
F test/insert4.test 4791662c50518bdd37d394cae9a7a8014e845bb3
|
||||
F test/insert5.test 394f96728d1258f406fe5f5aeb0aaf29487c39a6
|
||||
F test/instr.test 737bbf80685232033f3abedc6ae92f75860b5dd2
|
||||
F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4
|
||||
@@ -632,7 +632,7 @@ F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd
|
||||
F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
|
||||
F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4
|
||||
F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b
|
||||
F test/join.test 8d63cc4d230a7affafa4b6ab0b97c49b8ccb365c
|
||||
F test/join.test 559b81eb56ae350246f9c25986aa52c81c725c7e
|
||||
F test/join2.test f2171c265e57ee298a27e57e7051d22962f9f324
|
||||
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
|
||||
F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
|
||||
@@ -649,8 +649,8 @@ F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63
|
||||
F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
|
||||
F test/like.test e191e536d0fcd722a6b965e7cd1ee0bfd12a5991
|
||||
F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da
|
||||
F test/limit.test cc0ab63385239b63c72452b0e93700bf5e8f0b99
|
||||
F test/loadext.test 92e6dfefd1229c3ef4aaabd87419efd8fa57a7a5
|
||||
F test/limit.test 3d7df19c35ac672a11f7de406cd3205d592babbb
|
||||
F test/loadext.test 648cb95f324d1775c54a55c12271b2d1156b633b
|
||||
F test/loadext2.test 0408380b57adca04004247179837a18e866a74f7
|
||||
F test/lock.test 87af515b0c4cf928576d0f89946d67d7c265dfb4
|
||||
F test/lock2.test 5242d8ac4e2d59c403aebff606af449b455aceff
|
||||
@@ -663,7 +663,7 @@ F test/lock_common.tcl 0c270b121d40959fa2f3add382200c27045b3d95
|
||||
F test/lookaside.test 93f07bac140c5bb1d49f3892d2684decafdc7af2
|
||||
F test/main.test 39c4bb8a157f57298ed1659d6df89d9f35aaf2c8
|
||||
F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
|
||||
F test/malloc.test fd368e31fe98d4779ed80442f311ed9f03bcd1f7
|
||||
F test/malloc.test 26ae08a09cc15a98d147ee63925e3a66048e71c9
|
||||
F test/malloc3.test e3b32c724b5a124b57cb0ed177f675249ad0c66a
|
||||
F test/malloc4.test 957337613002b7058a85116493a262f679f3a261
|
||||
F test/malloc5.test fafce0aa9157060445cd1a56ad50fc79d82f28c3
|
||||
@@ -671,7 +671,7 @@ F test/malloc6.test 2f039d9821927eacae43e1831f815e157659a151
|
||||
F test/malloc7.test 7c68a32942858bc715284856c5507446bba88c3a
|
||||
F test/malloc8.test 9b7a3f8cb9cf0b12fff566e80a980b1767bd961d
|
||||
F test/malloc9.test 2307c6ee3703b0a21391f3ea92388b4b73f9105e
|
||||
F test/mallocA.test 1ba0367fb5434e7bc2fa4afcb30b14174d91b160
|
||||
F test/mallocA.test c049224adeb0244b8f6eb770c1fa6ac40f9b3518
|
||||
F test/mallocAll.test 98f1be74bc9f49a858bc4f361fc58e26486798be
|
||||
F test/mallocB.test bc475ab850cda896142ab935bbfbc74c24e51ed6
|
||||
F test/mallocC.test 3dffe16532f109293ce1ccecd0c31dca55ef08c4
|
||||
@@ -723,7 +723,8 @@ F test/orderby1.test 9b524aff9147288da43a6d7ddfdcff47fa2303c6
|
||||
F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04
|
||||
F test/orderby3.test 8619d06a3debdcd80a27c0fdea5c40b468854b99
|
||||
F test/orderby4.test 4d39bfbaaa3ae64d026ca2ff166353d2edca4ba4
|
||||
F test/orderby5.test 0eb82d5890c3f3d0563966560cfdc984ea69e30c
|
||||
F test/orderby5.test 2490183fef54417209d1df253633a605d46bd350
|
||||
F test/orderby6.test 8b38138ab0972588240b3fca0985d2e400432859
|
||||
F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3
|
||||
F test/pager1.test 1acbdb14c5952a72dd43129cabdbf69aaa3ed1fa
|
||||
F test/pager2.test 67b8f40ae98112bcdba1f2b2d03ea83266418c71
|
||||
@@ -737,8 +738,8 @@ F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0
|
||||
F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d
|
||||
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
|
||||
F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54
|
||||
F test/permutations.test 40add071ba71aefe1c04f5845308cf46f7de8d04
|
||||
F test/pragma.test e882183ecd21d064cec5c7aaea174fbd36293429
|
||||
F test/permutations.test a214a42b4767bbbc7cd0fd965ea6198044ab414d
|
||||
F test/pragma.test adb21a90875bc54a880fa939c4d7c46598905aa0
|
||||
F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13
|
||||
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
|
||||
F test/printf2.test bed79b4c3e5da08ba88ad637c0bf62586843cfb1
|
||||
@@ -780,17 +781,18 @@ F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5
|
||||
F test/select1.test fc2a61f226a649393664ad54bc5376631801517c
|
||||
F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56
|
||||
F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054
|
||||
F test/select4.test 00179be44e531fe04c1c3f15df216439dff2519d
|
||||
F test/select4.test 8c5a60d439e2df824aed56223566877a883c5c84
|
||||
F test/select5.test e758b8ef94f69b111df4cb819008856655dcd535
|
||||
F test/select6.test e76bd10a56988f15726c097a5d5a7966fe82d3b2
|
||||
F test/select7.test 7fd2ef598cfabb6b9ff6ac13973b91d0527df49d
|
||||
F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d
|
||||
F test/select9.test aebc2bb0c3bc44606125033cbcaac2c8d1f33a95
|
||||
F test/selectA.test 99cf21df033b93033ea4f34aba14a500f48f04fe
|
||||
F test/selectA.test 77adaffe9704cb80e301ebaeff4b107b58d435c5
|
||||
F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25
|
||||
F test/selectC.test 871fb55d884d3de5943c4057ebd22c2459e71977
|
||||
F test/selectD.test b0f02a04ef7737decb24e08be2c39b9664b43394
|
||||
F test/selectE.test fc02a1eb04c8eb537091482644b7d778ae8759b7
|
||||
F test/selectF.test 21c94e6438f76537b72532fa9fd4710cdd455fc3
|
||||
F test/server1.test 46803bd3fe8b99b30dbc5ff38ffc756f5c13a118
|
||||
F test/shared.test 1da9dbad400cee0d93f252ccf76e1ae007a63746
|
||||
F test/shared2.test 03eb4a8d372e290107d34b6ce1809919a698e879
|
||||
@@ -803,19 +805,21 @@ F test/shared9.test 5f2a8f79b4d6c7d107a01ffa1ed05ae7e6333e21
|
||||
F test/sharedA.test 0cdf1a76dfa00e6beee66af5b534b1e8df2720f5
|
||||
F test/shared_err.test 0079c05c97d88cfa03989b7c20a8b266983087aa
|
||||
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
|
||||
F test/shell1.test e7c0b9ebda25d5e78f0a3ea0dc4e31bb6d8098c0
|
||||
F test/shell1.test f2a1d471e5cd2b42f7a65b166dc1ace2b8d11583
|
||||
F test/shell2.test c57da3a381c099b02c813ba156298d5c2f5c93a3
|
||||
F test/shell3.test 5e8545ec72c4413a0e8d4c6be56496e3c257ca29
|
||||
F test/shell4.test aa4eef8118b412d1a01477a53426ece169ea86a9
|
||||
F test/shell5.test cee83b4385f842fec1f2a0bec9ea811f35386edf
|
||||
F test/shell5.test bb755ea9144b8078a752fc56223582627070b5f1
|
||||
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/shrink.test 8c70f62b6e8eb4d54533de6d65bd06b1b9a17868
|
||||
F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329
|
||||
F test/skipscan1.test 8c777ffd9dad6ee6d2568160cb2158f0b5cd9dd2
|
||||
F test/skipscan1.test bed8cbe9d554c8c27afb6c88500f704c86a9196f
|
||||
F test/skipscan2.test 5a4db0799c338ddbacb154aaa5589c0254b36a8d
|
||||
F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f
|
||||
F test/softheap1.test 40562fe6cac6d9827b7b42b86d45aedf12c15e24
|
||||
F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
|
||||
F test/sort.test 79dc647c4e9b123a64e57b7080b7f9a2df43f87a
|
||||
F test/sort2.test 21cd865e31adecdc8fc81c8d95431e629676a8d8
|
||||
F test/sort3.test c3f88d233452a129de519de311d109a0ad0da0af
|
||||
F test/speed1.test f2974a91d79f58507ada01864c0e323093065452
|
||||
F test/speed1p.explain d841e650a04728b39e6740296b852dccdca9b2cb
|
||||
F test/speed1p.test b180e98609c7677382cf618c0ec9b69f789033a8
|
||||
@@ -824,7 +828,7 @@ F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523
|
||||
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
|
||||
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
|
||||
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
|
||||
F test/speedtest1.c 1603da7b4897716f9df15bd71b0310f56ec3181e
|
||||
F test/speedtest1.c 90446861e566a9965a8d005381a3c964ff333646
|
||||
F test/spellfix.test 61309f5efbec53603b3f86457d34a504f80abafe
|
||||
F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298
|
||||
F test/stat.test 76fd746b85459e812a0193410fb599f0531f22de
|
||||
@@ -835,7 +839,7 @@ F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
|
||||
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
|
||||
F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2
|
||||
F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85
|
||||
F test/syscall.test a653783d985108c4912cc64d341ffbbb55ad2806
|
||||
F test/syscall.test d2fdaad713f103ac611fe7ef9b724c7b69f8149c
|
||||
F test/sysfault.test fa776e60bf46bdd3ae69f0b73e46ee3977a58ae6
|
||||
F test/table.test 580d23530187026d4502fae74a490f0408cf2cc7
|
||||
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
|
||||
@@ -844,7 +848,7 @@ F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43
|
||||
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
|
||||
F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
|
||||
F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1
|
||||
F test/tester.tcl 9bd04481b8b0ef1f2049ad01f28e175ee9a14f7b
|
||||
F test/tester.tcl bc0889a2f86d9c17307992ca1e70391794780265
|
||||
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
|
||||
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
@@ -869,7 +873,9 @@ F test/tkt-3998683a16.test 6d1d04d551ed1704eb3396ca87bb9ccc8c5c1eb7
|
||||
F test/tkt-3a77c9714e.test b08bca26de1140bdf004a37716582a43d7bd8be8
|
||||
F test/tkt-3fe897352e.test 27e26eb0f1811aeba4d65aba43a4c52e99da5e70
|
||||
F test/tkt-4a03edc4c8.test 91c0e135888cdc3d4eea82406a44b05c8c1648d0
|
||||
F test/tkt-4c86b126f2.test cbcc611becd0396890169ab23102dd70048bbc9a
|
||||
F test/tkt-4dd95f6943.test 3d0ce415d2ee15d3d564121960016b9c7be79407
|
||||
F test/tkt-4ef7e3cfca.test 3965ae11cc9cf6e334f9d7d3c1e20bf8d56254b1
|
||||
F test/tkt-54844eea3f.test a12b851128f46a695e4e378cca67409b9b8f5894
|
||||
F test/tkt-5d863f876e.test c9f36ca503fa154a3655f92a69d2c30da1747bfa
|
||||
F test/tkt-5e10420e8d.test 904d1687b3c06d43e5b3555bbcf6802e7c0ffd84
|
||||
@@ -883,11 +889,13 @@ F test/tkt-80ba201079.test 105a721e6aad0ae3c5946d7615d1e4d03f6145b8
|
||||
F test/tkt-80e031a00f.test 9a154173461a4dbe2de49cda73963e04842d52f7
|
||||
F test/tkt-8454a207b9.test c583a9f814a82a2b5ba95207f55001c9f0cd816c
|
||||
F test/tkt-868145d012.test a5f941107ece6a64410ca4755c6329b7eb57a356
|
||||
F test/tkt-8c63ff0ec.test 258b7fc8d7e4e1cb5362c7d65c143528b9c4cbed
|
||||
F test/tkt-91e2e8ba6f.test 08c4f94ae07696b05c9b822da0b4e5337a2f54c5
|
||||
F test/tkt-94c04eaadb.test f738c57c7f68ab8be1c054415af7774617cb6223
|
||||
F test/tkt-9d68c883.test 458f7d82a523d7644b54b497c986378a7d8c8b67
|
||||
F test/tkt-9f2eb3abac.test 85bc63e749f050e6a61c8f9207f1eee65c9d3395
|
||||
F test/tkt-a7b7803e.test 159ef554234fa1f9fb318c751b284bd1cf858da4
|
||||
F test/tkt-a8a0d2996a.test eb597379dbcefa24765763d7f682c00cb5924fa9
|
||||
F test/tkt-b1d3a2e531.test 8f7576e41ca179289ee1a8fee28386fd8e4b0550
|
||||
F test/tkt-b351d95f9.test d14a503c414c5c58fdde3e80f9a3cfef986498c0
|
||||
F test/tkt-b72787b1.test a95e8cdad0b98af1853ac7f0afd4ab27b77bf5f3
|
||||
@@ -1015,10 +1023,10 @@ F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
|
||||
F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
|
||||
F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a
|
||||
F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264
|
||||
F test/unixexcl.test a9870e46cc6f8390a494513d4f2bf55b5a8b3e46
|
||||
F test/unixexcl.test cd6c765f75e50e8e2c2ba763149e5d340ea19825
|
||||
F test/unordered.test ef85ac8f2f3c93ed2b9e811b684de73175fc464c
|
||||
F test/update.test 1b6c488a8f993d090b7ee9ad0e234faa161b3aeb
|
||||
F test/uri.test 63e03df051620a18f794b4f4adcdefb3c23b6751
|
||||
F test/uri.test 23662b7b61958b0f0e47082de7d06341ccf85d5b
|
||||
F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
|
||||
F test/vacuum.test ce91c39f7f91a4273bf620efad21086b5aa6ef1d
|
||||
F test/vacuum2.test af432e6e3bfc0ea20a80cb86a03c7d9876d38324
|
||||
@@ -1026,7 +1034,7 @@ F test/vacuum3.test 77ecdd54592b45a0bcb133339f99f1ae0ae94d0d
|
||||
F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9
|
||||
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
|
||||
F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
|
||||
F test/view.test 4057630287bfa5955628fe90a13d4c225d1c7352
|
||||
F test/view.test f311691d696a5cc27e3c1b875cec1b0866b4ccd9
|
||||
F test/vtab1.test b631d147b198cfd7903ab5fed028eb2a3d321dc6
|
||||
F test/vtab2.test 7bcffc050da5c68f4f312e49e443063e2d391c0d
|
||||
F test/vtab3.test baad99fd27217f5d6db10660522e0b7192446de1
|
||||
@@ -1044,13 +1052,14 @@ F test/vtabE.test 7c4693638d7797ce2eda17af74292b97e705cc61
|
||||
F test/vtabF.test fd5ad376f5a34fe0891df1f3cddb4fe7c3eb077e
|
||||
F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
|
||||
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
|
||||
F test/vtab_shared.test 6acafaae7126c9f49be72c2f57eb8bef3024f1cb
|
||||
F test/wal.test 40073e54359d43354925b2b700b7eebd5e207285
|
||||
F test/vtab_shared.test ea8778d5b0df200adef2ca7c00c3c37d4375f772
|
||||
F test/wal.test 885f32b2b390b30b4aa3dbb0e568f8f78d40f5cc
|
||||
F test/wal2.test a8e3963abf6b232cf0b852b09b53665ef34007af
|
||||
F test/wal3.test b22eb662bcbc148c5f6d956eaf94b047f7afe9c0
|
||||
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
|
||||
F test/wal5.test 8f888b50f66b78821e61ed0e233ded5de378224b
|
||||
F test/wal6.test 527581f5527bf9c24394991e2be83000aace5f9e
|
||||
F test/wal64k.test 163655ecd2cb8afef4737cac2a40fdd2eeaf20b8
|
||||
F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd
|
||||
F test/wal8.test 75c42e1bc4545c277fed212f8fc9b7723cd02216
|
||||
F test/wal9.test 378e76a9ad09cd9bee06c172ad3547b0129a6750
|
||||
@@ -1066,18 +1075,18 @@ F test/walhook.test ed00a40ba7255da22d6b66433ab61fab16a63483
|
||||
F test/walmode.test 4022fe03ae6e830583672caa101f046438a0473c
|
||||
F test/walnoshm.test 84ca10c544632a756467336b7c3b864d493ee496
|
||||
F test/walpersist.test 8c6b7e3ec1ba91b5e4dc4e0921d6d3f87cd356a6
|
||||
F test/walro.test 6cc247a0cc9b36aeea2057dd28a922a1cdfbd630
|
||||
F test/walro.test 34422d1d95aaff0388f0791ec20edb34e2a3ed57
|
||||
F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417
|
||||
F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a
|
||||
F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e
|
||||
F test/where.test 701a633ed16c661cd597b9d504b485197a0f49d7
|
||||
F test/where2.test ed6baa9420a109d8be683dbef5d153d186f3690b
|
||||
F test/where.test 28b64e93428961b07b0d486778d63fd672948f6b
|
||||
F test/where2.test 455a2eb2666e66c1e84e2cb5815173a85e6237db
|
||||
F test/where3.test d28c51f257e60be30f74308fa385ceeddfb54a6e
|
||||
F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
|
||||
F test/where4.test d8420ceeb8323a41ceff1f1841fc528e824e1ecf
|
||||
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
|
||||
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
|
||||
F test/where7.test 5a4b0abc207d71da4deecd734ad8579e8dd40aa8
|
||||
F test/where8.test d2b4fd6d7b7c5d44f590182a05033d78a14c00a1
|
||||
F test/where8.test 806f1dcec4088be2b826b33f757fe6e17c3236a1
|
||||
F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739
|
||||
F test/where9.test 4f3eab951353a3ae164befc521c777dfa903e46c
|
||||
F test/whereA.test 4d253178d135ec46d1671e440cd8f2b916aa6e6b
|
||||
@@ -1086,23 +1095,24 @@ F test/whereC.test d6f4ecd4fa2d9429681a5b22a25d2bda8e86ab8a
|
||||
F test/whereD.test 6c2feb79ef1f68381b07f39017fe5f9b96da8d62
|
||||
F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f
|
||||
F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7
|
||||
F test/whereG.test 2a3d5181decc801b36600fa1c40b0dad2ccc267f
|
||||
F test/whereG.test 2533b72ed4a31fd1687230a499b557b911525344
|
||||
F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
|
||||
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
|
||||
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
|
||||
F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c
|
||||
F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361
|
||||
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
|
||||
F test/with1.test 268081a6b14817a262ced4d0ee34d4d2a1dd2068
|
||||
F test/with2.test 2fe78fcd8deef2a0f9cfc49bfc755911d0b3fd64
|
||||
F test/with2.test ee227a663586aa09771cafd4fa269c5217eaf775
|
||||
F test/withM.test e97f2a8c506ab3ea9eab94e6f6072f6cc924c991
|
||||
F test/without_rowid1.test aaa26da19d543cd8d3d2d0e686dfa255556c15c8
|
||||
F test/without_rowid1.test e00a0a9dc9f0be651f011d61e8a32b7add5afb30
|
||||
F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
|
||||
F test/without_rowid3.test eac3d5c8a1924725b58503a368f2cbd24fd6c8a0
|
||||
F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a
|
||||
F test/without_rowid5.test b4a639a367f04d382d20e8f44fc1be4f2d57d107
|
||||
F test/wordcount.c 9915e06cb33d8ca8109b8700791afe80d305afda
|
||||
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
|
||||
F test/zerodamage.test 209d7ed441f44cc5299e4ebffbef06fd5aabfefd
|
||||
F test/zerodamage.test cf6748bad89553cc1632be51a6f54e487e4039ac
|
||||
F tool/build-all-msvc.bat e0917e787df675b020d250d60a00de8abaa4e30a x
|
||||
F tool/build-shell.sh 950f47c6174f1eea171319438b93ba67ff5bf367
|
||||
F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2
|
||||
@@ -1115,14 +1125,14 @@ F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
|
||||
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
|
||||
F tool/lemon.c 07aba6270d5a5016ba8107b09e431eea4ecdc123
|
||||
F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc
|
||||
F tool/logest.c 7ad625cac3d54012b27d468b7af6612f78b9ba75
|
||||
F tool/logest.c 388c318c7ac8b52b7c08ca1e2de0f4ca9a8f7e81
|
||||
F tool/mkautoconfamal.sh f8d8dbf7d62f409ebed5134998bf5b51d7266383
|
||||
F tool/mkkeywordhash.c c9e05e4a7bcab8fab9f583d5b321fb72f565ad97
|
||||
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
|
||||
F tool/mkpragmatab.tcl 78a77b2c554d534c6f2dc903130186ed15715460
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
F tool/mksqlite3c-noext.tcl 8bce31074e4cbe631bb7676526a048335f4c9f02
|
||||
F tool/mksqlite3c.tcl e2ba20d3f690990079d17f3e5a7417dfb7ada543
|
||||
F tool/mksqlite3c-noext.tcl 752f1a9d3287f6c0ef5738b1c4add0b96fbe0854
|
||||
F tool/mksqlite3c.tcl 8da823522f27608494997e1dba19cd426572ba80
|
||||
F tool/mksqlite3h.tcl ba24038056f51fde07c0079c41885ab85e2cff12
|
||||
F tool/mksqlite3internalh.tcl 3dca7bb5374cee003379b8cbac73714f610ef795
|
||||
F tool/mkvsix.tcl 6477fb9dab838b7eea1eed50658ff1cda04850b5
|
||||
@@ -1149,10 +1159,14 @@ F tool/symbols-mingw.sh 4dbcea7e74768305384c9fd2ed2b41bbf9f0414d
|
||||
F tool/symbols.sh fec58532668296d7c7dc48be9c87f75ccdb5814f
|
||||
F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
|
||||
F tool/vdbe-compress.tcl 0cf56e9263a152b84da86e75a5c0cdcdb7a47891
|
||||
F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
|
||||
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
||||
P c9eba2f7be468ae7fc843ffd5b09bd062ee311c3
|
||||
R 5e3b4e27dbbde8802d4b99c9e620e482
|
||||
U drh
|
||||
Z be8b5d9bf50fdc639aa9aecf25f98639
|
||||
P e54dded2012f0ab486ee138e9bd57c528af33980
|
||||
R 020c9d4d2bbea35c99aea5cfddab0eac
|
||||
T *branch * threads-experimental
|
||||
T *sym-threads-experimental *
|
||||
T -sym-threads *
|
||||
U dan
|
||||
Z 16c0542d21b377d284993b464ea194ff
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
fe284afe739c497e153ac2bc0275f7c9e862c824
|
||||
cbfc0f6d49b6607bb4eb45bfe4c258e39ac27403
|
||||
@@ -1,49 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# This script is used to compile SQLite into a DLL.
|
||||
#
|
||||
# Two separate DLLs are generated. "sqlite3.dll" is the core
|
||||
# library. "tclsqlite3.dll" contains the TCL bindings and is the
|
||||
# library that is loaded into TCL in order to run SQLite.
|
||||
#
|
||||
make sqlite3.c
|
||||
PATH=$PATH:/opt/mingw/bin
|
||||
TCLDIR=/home/drh/tcltk/846/win/846win
|
||||
TCLSTUBLIB=$TCLDIR/libtcl84stub.a
|
||||
OPTS='-DUSE_TCL_STUBS=1 -DBUILD_sqlite=1 -DSQLITE_OS_WIN=1'
|
||||
OPTS="$OPTS -DSQLITE_THREADSAFE=1"
|
||||
OPTS="$OPTS -DSQLITE_ENABLE_FTS3=1"
|
||||
OPTS="$OPTS -DSQLITE_ENABLE_RTREE=1"
|
||||
OPTS="$OPTS -DSQLITE_ENABLE_COLUMN_METADATA=1"
|
||||
CC="i386-mingw32msvc-gcc -Os $OPTS -Itsrc -I$TCLDIR"
|
||||
NM="i386-mingw32msvc-nm"
|
||||
CMD="$CC -c sqlite3.c"
|
||||
echo $CMD
|
||||
$CMD
|
||||
CMD="$CC -c tclsqlite3.c"
|
||||
echo $CMD
|
||||
$CMD
|
||||
echo 'EXPORTS' >tclsqlite3.def
|
||||
$NM tclsqlite3.o | grep ' T ' >temp1
|
||||
grep '_Init$' temp1 >temp2
|
||||
grep '_SafeInit$' temp1 >>temp2
|
||||
grep ' T _sqlite3_' temp1 >>temp2
|
||||
echo 'EXPORTS' >tclsqlite3.def
|
||||
sed 's/^.* T _//' temp2 | sort | uniq >>tclsqlite3.def
|
||||
i386-mingw32msvc-dllwrap \
|
||||
--def tclsqlite3.def -v --export-all \
|
||||
--driver-name i386-mingw32msvc-gcc \
|
||||
--dlltool-name i386-mingw32msvc-dlltool \
|
||||
--as i386-mingw32msvc-as \
|
||||
--target i386-mingw32 \
|
||||
-dllname tclsqlite3.dll -lmsvcrt tclsqlite3.o $TCLSTUBLIB
|
||||
$NM sqlite3.o | grep ' T ' >temp1
|
||||
echo 'EXPORTS' >sqlite3.def
|
||||
grep ' _sqlite3_' temp1 | sed 's/^.* _//' >>sqlite3.def
|
||||
i386-mingw32msvc-dllwrap \
|
||||
--def sqlite3.def -v --export-all \
|
||||
--driver-name i386-mingw32msvc-gcc \
|
||||
--dlltool-name i386-mingw32msvc-dlltool \
|
||||
--as i386-mingw32msvc-as \
|
||||
--target i386-mingw32 \
|
||||
-dllname sqlite3.dll -lmsvcrt sqlite3.o
|
||||
@@ -1,13 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# This script is used to compile SQLite into a shared library on Linux.
|
||||
#
|
||||
# Two separate shared libraries are generated. "sqlite3.so" is the core
|
||||
# library. "tclsqlite3.so" contains the TCL bindings and is the
|
||||
# library that is loaded into TCL in order to run SQLite.
|
||||
#
|
||||
CFLAGS=-O2 -Wall
|
||||
make fts2amal.c
|
||||
echo gcc $CFLAGS -shared fts2amal.c -o fts2.so
|
||||
gcc $CFLAGS -shared fts2amal.c -o fts2.so
|
||||
strip fts2.so
|
||||
@@ -1,22 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# This script is used to compile SQLite extensions into DLLs.
|
||||
#
|
||||
make fts2amal.c
|
||||
PATH=$PATH:/opt/mingw/bin
|
||||
OPTS='-DTHREADSAFE=1 -DBUILD_sqlite=1 -DSQLITE_OS_WIN=1'
|
||||
CC="i386-mingw32msvc-gcc -O2 $OPTS -Itsrc"
|
||||
NM="i386-mingw32msvc-nm"
|
||||
CMD="$CC -c fts2amal.c"
|
||||
echo $CMD
|
||||
$CMD
|
||||
echo 'EXPORTS' >fts2.def
|
||||
echo 'sqlite3_fts2_init' >>fts2.def
|
||||
i386-mingw32msvc-dllwrap \
|
||||
--def fts2.def -v --export-all \
|
||||
--driver-name i386-mingw32msvc-gcc \
|
||||
--dlltool-name i386-mingw32msvc-dlltool \
|
||||
--as i386-mingw32msvc-as \
|
||||
--target i386-mingw32 \
|
||||
-dllname fts2.dll -lmsvcrt fts2amal.o
|
||||
zip fts2dll.zip fts2.dll fts2.def
|
||||
+6
-5
@@ -77,8 +77,8 @@ static void renameTableFunc(
|
||||
assert( len>0 );
|
||||
} while( token!=TK_LP && token!=TK_USING );
|
||||
|
||||
zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", ((u8*)tname.z) - zSql, zSql,
|
||||
zTableName, tname.z+tname.n);
|
||||
zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", (int)(((u8*)tname.z) - zSql),
|
||||
zSql, zTableName, tname.z+tname.n);
|
||||
sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC);
|
||||
}
|
||||
}
|
||||
@@ -130,7 +130,7 @@ static void renameParentFunc(
|
||||
sqlite3Dequote(zParent);
|
||||
if( 0==sqlite3StrICmp((const char *)zOld, zParent) ){
|
||||
char *zOut = sqlite3MPrintf(db, "%s%.*s\"%w\"",
|
||||
(zOutput?zOutput:""), z-zInput, zInput, (const char *)zNew
|
||||
(zOutput?zOutput:""), (int)(z-zInput), zInput, (const char *)zNew
|
||||
);
|
||||
sqlite3DbFree(db, zOutput);
|
||||
zOutput = zOut;
|
||||
@@ -216,8 +216,8 @@ static void renameTriggerFunc(
|
||||
/* Variable tname now contains the token that is the old table-name
|
||||
** in the CREATE TRIGGER statement.
|
||||
*/
|
||||
zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", ((u8*)tname.z) - zSql, zSql,
|
||||
zTableName, tname.z+tname.n);
|
||||
zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", (int)(((u8*)tname.z) - zSql),
|
||||
zSql, zTableName, tname.z+tname.n);
|
||||
sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC);
|
||||
}
|
||||
}
|
||||
@@ -605,6 +605,7 @@ void sqlite3MinimumFileFormat(Parse *pParse, int iDb, int minFormat){
|
||||
sqlite3VdbeUsesBtree(v, iDb);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, minFormat, r2);
|
||||
j1 = sqlite3VdbeAddOp3(v, OP_Ge, r2, 0, r1);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, r2);
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
|
||||
+11
-4
@@ -1077,6 +1077,7 @@ static void analyzeOneTable(
|
||||
**
|
||||
*/
|
||||
addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng);
|
||||
addrGotoChng0 = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
|
||||
@@ -1098,6 +1099,7 @@ static void analyzeOneTable(
|
||||
aGotoChng[i] =
|
||||
sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, regPrev+i, pColl, P4_COLLSEQ);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, nCol, regChng);
|
||||
aGotoChng[nCol] = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
@@ -1144,7 +1146,7 @@ static void analyzeOneTable(
|
||||
sqlite3VdbeAddOp3(v, OP_Function, 1, regStat4, regTemp);
|
||||
sqlite3VdbeChangeP4(v, -1, (char*)&statPushFuncdef, P4_FUNCDEF);
|
||||
sqlite3VdbeChangeP5(v, 2+IsStat34);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
|
||||
|
||||
/* Add the entry to the stat1 table. */
|
||||
callStatGet(v, regStat4, STAT_GET_STAT1, regStat1);
|
||||
@@ -1171,10 +1173,15 @@ static void analyzeOneTable(
|
||||
addrNext = sqlite3VdbeCurrentAddr(v);
|
||||
callStatGet(v, regStat4, STAT_GET_ROWID, regSampleRowid);
|
||||
addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regSampleRowid);
|
||||
VdbeCoverage(v);
|
||||
callStatGet(v, regStat4, STAT_GET_NEQ, regEq);
|
||||
callStatGet(v, regStat4, STAT_GET_NLT, regLt);
|
||||
callStatGet(v, regStat4, STAT_GET_NDLT, regDLt);
|
||||
sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0);
|
||||
/* We know that the regSampleRowid row exists because it was read by
|
||||
** the previous loop. Thus the not-found jump of seekOp will never
|
||||
** be taken */
|
||||
VdbeCoverageNeverTaken(v);
|
||||
#ifdef SQLITE_ENABLE_STAT3
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur,
|
||||
pIdx->aiColumn[0], regSample);
|
||||
@@ -1185,10 +1192,10 @@ static void analyzeOneTable(
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, nCol+1, regSample);
|
||||
#endif
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 6, regTemp, "bbbbbb", 0);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regTabname, 6, regTemp);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur+1, regNewRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur+1, regTemp, regNewRowid);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNext);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 1, addrNext); /* P1==1 for end-of-loop */
|
||||
sqlite3VdbeJumpHere(v, addrIsNull);
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
|
||||
@@ -1205,7 +1212,7 @@ static void analyzeOneTable(
|
||||
if( pOnlyIdx==0 && needTableCnt ){
|
||||
VdbeComment((v, "%s", pTab->zName));
|
||||
sqlite3VdbeAddOp2(v, OP_Count, iTabCur, regStat1);
|
||||
jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, regStat1);
|
||||
jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, regStat1); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname);
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "aaa", 0);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
|
||||
|
||||
+62
-45
@@ -746,20 +746,32 @@ static int btreeRestoreCursorPosition(BtCursor *pCur){
|
||||
** at is deleted out from under them.
|
||||
**
|
||||
** This routine returns an error code if something goes wrong. The
|
||||
** integer *pHasMoved is set to one if the cursor has moved and 0 if not.
|
||||
** integer *pHasMoved is set as follows:
|
||||
**
|
||||
** 0: The cursor is unchanged
|
||||
** 1: The cursor is still pointing at the same row, but the pointers
|
||||
** returned by sqlite3BtreeKeyFetch() or sqlite3BtreeDataFetch()
|
||||
** might now be invalid because of a balance() or other change to the
|
||||
** b-tree.
|
||||
** 2: The cursor is no longer pointing to the row. The row might have
|
||||
** been deleted out from under the cursor.
|
||||
*/
|
||||
int sqlite3BtreeCursorHasMoved(BtCursor *pCur, int *pHasMoved){
|
||||
int rc;
|
||||
|
||||
if( pCur->eState==CURSOR_VALID ){
|
||||
*pHasMoved = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
rc = restoreCursorPosition(pCur);
|
||||
if( rc ){
|
||||
*pHasMoved = 1;
|
||||
*pHasMoved = 2;
|
||||
return rc;
|
||||
}
|
||||
if( pCur->eState!=CURSOR_VALID || NEVER(pCur->skipNext!=0) ){
|
||||
*pHasMoved = 1;
|
||||
*pHasMoved = 2;
|
||||
}else{
|
||||
*pHasMoved = 0;
|
||||
*pHasMoved = 1;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -1542,13 +1554,12 @@ static void zeroPage(MemPage *pPage, int flags){
|
||||
memset(&data[hdr], 0, pBt->usableSize - hdr);
|
||||
}
|
||||
data[hdr] = (char)flags;
|
||||
first = hdr + 8 + 4*((flags&PTF_LEAF)==0 ?1:0);
|
||||
first = hdr + ((flags&PTF_LEAF)==0 ? 12 : 8);
|
||||
memset(&data[hdr+1], 0, 4);
|
||||
data[hdr+7] = 0;
|
||||
put2byte(&data[hdr+5], pBt->usableSize);
|
||||
pPage->nFree = (u16)(pBt->usableSize - first);
|
||||
decodeFlags(pPage, flags);
|
||||
pPage->hdrOffset = hdr;
|
||||
pPage->cellOffset = first;
|
||||
pPage->aDataEnd = &data[pBt->usableSize];
|
||||
pPage->aCellIdx = &data[first];
|
||||
@@ -2162,6 +2173,7 @@ int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
/*
|
||||
** Change the limit on the amount of the database file that may be
|
||||
** memory mapped.
|
||||
@@ -2174,6 +2186,7 @@ int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 szMmap){
|
||||
sqlite3BtreeLeave(p);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#endif /* SQLITE_MAX_MMAP_SIZE>0 */
|
||||
|
||||
/*
|
||||
** Change the way data is synced to disk in order to increase or decrease
|
||||
@@ -3632,7 +3645,6 @@ static int btreeCursor(
|
||||
}
|
||||
pBt->pCursor = pCur;
|
||||
pCur->eState = CURSOR_INVALID;
|
||||
pCur->cachedRowid = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
int sqlite3BtreeCursor(
|
||||
@@ -3673,36 +3685,6 @@ void sqlite3BtreeCursorZero(BtCursor *p){
|
||||
memset(p, 0, offsetof(BtCursor, iPage));
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the cached rowid value of every cursor in the same database file
|
||||
** as pCur and having the same root page number as pCur. The value is
|
||||
** set to iRowid.
|
||||
**
|
||||
** Only positive rowid values are considered valid for this cache.
|
||||
** The cache is initialized to zero, indicating an invalid cache.
|
||||
** A btree will work fine with zero or negative rowids. We just cannot
|
||||
** cache zero or negative rowids, which means tables that use zero or
|
||||
** negative rowids might run a little slower. But in practice, zero
|
||||
** or negative rowids are very uncommon so this should not be a problem.
|
||||
*/
|
||||
void sqlite3BtreeSetCachedRowid(BtCursor *pCur, sqlite3_int64 iRowid){
|
||||
BtCursor *p;
|
||||
for(p=pCur->pBt->pCursor; p; p=p->pNext){
|
||||
if( p->pgnoRoot==pCur->pgnoRoot ) p->cachedRowid = iRowid;
|
||||
}
|
||||
assert( pCur->cachedRowid==iRowid );
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the cached rowid for the given cursor. A negative or zero
|
||||
** return value indicates that the rowid cache is invalid and should be
|
||||
** ignored. If the rowid cache has never before been set, then a
|
||||
** zero is returned.
|
||||
*/
|
||||
sqlite3_int64 sqlite3BtreeGetCachedRowid(BtCursor *pCur){
|
||||
return pCur->cachedRowid;
|
||||
}
|
||||
|
||||
/*
|
||||
** Close a cursor. The read lock on the database file is released
|
||||
** when the last cursor is closed.
|
||||
@@ -4218,10 +4200,13 @@ static const void *fetchPayload(
|
||||
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
|
||||
assert( pCur->info.nSize>0 );
|
||||
#if 0
|
||||
if( pCur->info.nSize==0 ){
|
||||
btreeParseCell(pCur->apPage[pCur->iPage], pCur->aiIdx[pCur->iPage],
|
||||
&pCur->info);
|
||||
}
|
||||
#endif
|
||||
*pAmt = pCur->info.nLocal;
|
||||
return (void*)(pCur->info.pCell + pCur->info.nHeader);
|
||||
}
|
||||
@@ -4579,6 +4564,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
int *pRes /* Write search results here */
|
||||
){
|
||||
int rc;
|
||||
RecordCompare xRecordCompare;
|
||||
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
||||
@@ -4600,6 +4586,17 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
}
|
||||
}
|
||||
|
||||
if( pIdxKey ){
|
||||
xRecordCompare = sqlite3VdbeFindCompare(pIdxKey);
|
||||
pIdxKey->errCode = 0;
|
||||
assert( pIdxKey->default_rc==1
|
||||
|| pIdxKey->default_rc==0
|
||||
|| pIdxKey->default_rc==-1
|
||||
);
|
||||
}else{
|
||||
xRecordCompare = 0; /* All keys are integers */
|
||||
}
|
||||
|
||||
rc = moveToRoot(pCur);
|
||||
if( rc ){
|
||||
return rc;
|
||||
@@ -4632,7 +4629,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
assert( biasRight==0 || biasRight==1 );
|
||||
idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
if( pPage->intKey ){
|
||||
if( xRecordCompare==0 ){
|
||||
for(;;){
|
||||
i64 nCellKey;
|
||||
pCell = findCell(pPage, idx) + pPage->childPtrSize;
|
||||
@@ -4684,14 +4681,14 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
** single byte varint and the record fits entirely on the main
|
||||
** b-tree page. */
|
||||
testcase( pCell+nCell+1==pPage->aDataEnd );
|
||||
c = sqlite3VdbeRecordCompare(nCell, (void*)&pCell[1], pIdxKey);
|
||||
c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey, 0);
|
||||
}else if( !(pCell[1] & 0x80)
|
||||
&& (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal
|
||||
){
|
||||
/* The record-size field is a 2 byte varint and the record
|
||||
** fits entirely on the main b-tree page. */
|
||||
testcase( pCell+nCell+2==pPage->aDataEnd );
|
||||
c = sqlite3VdbeRecordCompare(nCell, (void*)&pCell[2], pIdxKey);
|
||||
c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey, 0);
|
||||
}else{
|
||||
/* The record flows over onto one or more overflow pages. In
|
||||
** this case the whole cell needs to be parsed, a buffer allocated
|
||||
@@ -4712,9 +4709,13 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
sqlite3_free(pCellKey);
|
||||
goto moveto_finish;
|
||||
}
|
||||
c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey);
|
||||
c = xRecordCompare(nCell, pCellKey, pIdxKey, 0);
|
||||
sqlite3_free(pCellKey);
|
||||
}
|
||||
assert(
|
||||
(pIdxKey->errCode!=SQLITE_CORRUPT || c==0)
|
||||
&& (pIdxKey->errCode!=SQLITE_NOMEM || !pCur->pBtree->db->mallocFailed)
|
||||
);
|
||||
if( c<0 ){
|
||||
lwr = idx+1;
|
||||
}else if( c>0 ){
|
||||
@@ -4724,6 +4725,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
*pRes = 0;
|
||||
rc = SQLITE_OK;
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
if( pIdxKey->errCode ) rc = SQLITE_CORRUPT;
|
||||
goto moveto_finish;
|
||||
}
|
||||
if( lwr>upr ) break;
|
||||
@@ -6986,11 +6988,17 @@ int sqlite3BtreeInsert(
|
||||
rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur);
|
||||
if( rc ) return rc;
|
||||
|
||||
/* If this is an insert into a table b-tree, invalidate any incrblob
|
||||
** cursors open on the row being replaced (assuming this is a replace
|
||||
** operation - if it is not, the following is a no-op). */
|
||||
if( pCur->pKeyInfo==0 ){
|
||||
/* If this is an insert into a table b-tree, invalidate any incrblob
|
||||
** cursors open on the row being replaced */
|
||||
invalidateIncrblobCursors(p, nKey, 0);
|
||||
|
||||
/* If the cursor is currently on the last row and we are appending a
|
||||
** new row onto the end, set the "loc" to avoid an unnecessary btreeMoveto()
|
||||
** call */
|
||||
if( pCur->validNKey && nKey>0 && pCur->info.nKey==nKey-1 ){
|
||||
loc = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if( !loc ){
|
||||
@@ -7060,8 +7068,8 @@ int sqlite3BtreeInsert(
|
||||
** row without seeking the cursor. This can be a big performance boost.
|
||||
*/
|
||||
pCur->info.nSize = 0;
|
||||
pCur->validNKey = 0;
|
||||
if( rc==SQLITE_OK && pPage->nOverflow ){
|
||||
pCur->validNKey = 0;
|
||||
rc = balance(pCur);
|
||||
|
||||
/* Must make sure nOverflow is reset to zero even if the balance()
|
||||
@@ -7438,6 +7446,15 @@ int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete all information from the single table that pCur is open on.
|
||||
**
|
||||
** This routine only work for pCur on an ephemeral table.
|
||||
*/
|
||||
int sqlite3BtreeClearTableOfCursor(BtCursor *pCur){
|
||||
return sqlite3BtreeClearTable(pCur->pBtree, pCur->pgnoRoot, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Erase all information in a table and add the root of the table to
|
||||
** the freelist. Except, the root of the principle table (the one on
|
||||
|
||||
+4
-3
@@ -63,7 +63,9 @@ int sqlite3BtreeOpen(
|
||||
|
||||
int sqlite3BtreeClose(Btree*);
|
||||
int sqlite3BtreeSetCacheSize(Btree*,int);
|
||||
int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
|
||||
#endif
|
||||
int sqlite3BtreeSetPagerFlags(Btree*,unsigned);
|
||||
int sqlite3BtreeSyncDisabled(Btree*);
|
||||
int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
|
||||
@@ -113,6 +115,7 @@ int sqlite3BtreeIncrVacuum(Btree *);
|
||||
|
||||
int sqlite3BtreeDropTable(Btree*, int, int*);
|
||||
int sqlite3BtreeClearTable(Btree*, int, int*);
|
||||
int sqlite3BtreeClearTableOfCursor(BtCursor*);
|
||||
void sqlite3BtreeTripAllCursors(Btree*, int);
|
||||
|
||||
void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue);
|
||||
@@ -182,8 +185,6 @@ const void *sqlite3BtreeKeyFetch(BtCursor*, u32 *pAmt);
|
||||
const void *sqlite3BtreeDataFetch(BtCursor*, u32 *pAmt);
|
||||
int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
|
||||
int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);
|
||||
void sqlite3BtreeSetCachedRowid(BtCursor*, sqlite3_int64);
|
||||
sqlite3_int64 sqlite3BtreeGetCachedRowid(BtCursor*);
|
||||
|
||||
char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
|
||||
struct Pager *sqlite3BtreePager(Btree*);
|
||||
|
||||
@@ -500,7 +500,6 @@ struct BtCursor {
|
||||
Pgno *aOverflow; /* Cache of overflow page locations */
|
||||
#endif
|
||||
Pgno pgnoRoot; /* The root page of this tree */
|
||||
sqlite3_int64 cachedRowid; /* Next rowid cache. 0 means not valid */
|
||||
CellInfo info; /* A parse of the cell we are pointing at */
|
||||
i64 nKey; /* Size of pKey, or last integer key */
|
||||
void *pKey; /* Saved key that was cursor's last known position */
|
||||
|
||||
+11
-11
@@ -948,7 +948,7 @@ void sqlite3StartTable(
|
||||
reg3 = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, reg3, BTREE_FILE_FORMAT);
|
||||
sqlite3VdbeUsesBtree(v, iDb);
|
||||
j1 = sqlite3VdbeAddOp1(v, OP_If, reg3);
|
||||
j1 = sqlite3VdbeAddOp1(v, OP_If, reg3); VdbeCoverage(v);
|
||||
fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ?
|
||||
1 : SQLITE_MAX_FILE_FORMAT;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, fileFormat, reg3);
|
||||
@@ -2669,33 +2669,33 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
|
||||
/* Open the sorter cursor if we are to use one. */
|
||||
iSorter = pParse->nTab++;
|
||||
sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, 0, (char*)
|
||||
sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, pIndex->nKeyCol, (char*)
|
||||
sqlite3KeyInfoRef(pKey), P4_KEYINFO);
|
||||
|
||||
/* Open the table. Loop through all rows of the table, inserting index
|
||||
** records into the sorter. */
|
||||
sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0);
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); VdbeCoverage(v);
|
||||
regRecord = sqlite3GetTempReg(pParse);
|
||||
|
||||
sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0);
|
||||
sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord);
|
||||
sqlite3VdbeResolveLabel(v, iPartIdxLabel);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb);
|
||||
sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb,
|
||||
(char *)pKey, P4_KEYINFO);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0));
|
||||
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0);
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v);
|
||||
assert( pKey!=0 || db->mallocFailed || pParse->nErr );
|
||||
if( pIndex->onError!=OE_None && pKey!=0 ){
|
||||
int j2 = sqlite3VdbeCurrentAddr(v) + 3;
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, j2);
|
||||
addr2 = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord,
|
||||
pKey->nField - pIndex->nKeyCol);
|
||||
pKey->nField - pIndex->nKeyCol); VdbeCoverage(v);
|
||||
sqlite3UniqueConstraint(pParse, OE_Abort, pIndex);
|
||||
}else{
|
||||
addr2 = sqlite3VdbeCurrentAddr(v);
|
||||
@@ -2704,7 +2704,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 1);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
||||
sqlite3ReleaseTempReg(pParse, regRecord);
|
||||
sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2);
|
||||
sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
|
||||
sqlite3VdbeAddOp1(v, OP_Close, iTab);
|
||||
@@ -3018,7 +3018,7 @@ Index *sqlite3CreateIndex(
|
||||
pParse->checkSchema = 1;
|
||||
goto exit_create_index;
|
||||
}
|
||||
assert( pTab->nCol<=0x7fff && j<=0x7fff );
|
||||
assert( j<=0x7fff );
|
||||
pIndex->aiColumn[i] = (i16)j;
|
||||
if( pListItem->pExpr ){
|
||||
int nColl;
|
||||
@@ -3473,7 +3473,7 @@ SrcList *sqlite3SrcListEnlarge(
|
||||
assert( iStart<=pSrc->nSrc );
|
||||
|
||||
/* Allocate additional space if needed */
|
||||
if( pSrc->nSrc+nExtra>pSrc->nAlloc ){
|
||||
if( (u32)pSrc->nSrc+nExtra>pSrc->nAlloc ){
|
||||
SrcList *pNew;
|
||||
int nAlloc = pSrc->nSrc+nExtra;
|
||||
int nGot;
|
||||
@@ -3485,7 +3485,7 @@ SrcList *sqlite3SrcListEnlarge(
|
||||
}
|
||||
pSrc = pNew;
|
||||
nGot = (sqlite3DbMallocSize(db, pNew) - sizeof(*pSrc))/sizeof(pSrc->a[0])+1;
|
||||
pSrc->nAlloc = (u8)nGot;
|
||||
pSrc->nAlloc = nGot;
|
||||
}
|
||||
|
||||
/* Move existing slots that come after the newly inserted slots
|
||||
@@ -3493,7 +3493,7 @@ SrcList *sqlite3SrcListEnlarge(
|
||||
for(i=pSrc->nSrc-1; i>=iStart; i--){
|
||||
pSrc->a[i+nExtra] = pSrc->a[i];
|
||||
}
|
||||
pSrc->nSrc += (i8)nExtra;
|
||||
pSrc->nSrc += nExtra;
|
||||
|
||||
/* Zero the newly allocated slots */
|
||||
memset(&pSrc->a[iStart], 0, sizeof(pSrc->a[0])*nExtra);
|
||||
|
||||
@@ -215,6 +215,9 @@ static const char * const azCompileOpt[] = {
|
||||
#ifdef SQLITE_OMIT_COMPOUND_SELECT
|
||||
"OMIT_COMPOUND_SELECT",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_CTE
|
||||
"OMIT_CTE",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_DATETIME_FUNCS
|
||||
"OMIT_DATETIME_FUNCS",
|
||||
#endif
|
||||
|
||||
+12
-4
@@ -443,7 +443,7 @@ void sqlite3DeleteFrom(
|
||||
iKey = ++pParse->nMem;
|
||||
nKey = 0; /* Zero tells OP_Found to use a composite key */
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey,
|
||||
sqlite3IndexAffinityStr(v, pPk), P4_TRANSIENT);
|
||||
sqlite3IndexAffinityStr(v, pPk), nPk);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iEphCur, iKey);
|
||||
}else{
|
||||
/* Get the rowid of the row to be deleted and remember it in the RowSet */
|
||||
@@ -481,13 +481,15 @@ void sqlite3DeleteFrom(
|
||||
if( aToOpen[iDataCur-iTabCur] ){
|
||||
assert( pPk!=0 );
|
||||
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, addrBypass, iKey, nKey);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
}else if( pPk ){
|
||||
addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur);
|
||||
addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_RowKey, iEphCur, iKey);
|
||||
assert( nKey==0 ); /* OP_Found will use a composite key */
|
||||
}else{
|
||||
addrLoop = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, 0, iKey);
|
||||
VdbeCoverage(v);
|
||||
assert( nKey==1 );
|
||||
}
|
||||
|
||||
@@ -511,7 +513,7 @@ void sqlite3DeleteFrom(
|
||||
if( okOnePass ){
|
||||
sqlite3VdbeResolveLabel(v, addrBypass);
|
||||
}else if( pPk ){
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iEphCur, addrLoop+1);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iEphCur, addrLoop+1); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, addrLoop);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrLoop);
|
||||
@@ -609,7 +611,11 @@ void sqlite3GenerateRowDelete(
|
||||
** not attempt to delete it or fire any DELETE triggers. */
|
||||
iLabel = sqlite3VdbeMakeLabel(v);
|
||||
opSeek = HasRowid(pTab) ? OP_NotExists : OP_NotFound;
|
||||
if( !bNoSeek ) sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk);
|
||||
if( !bNoSeek ){
|
||||
sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk);
|
||||
VdbeCoverageIf(v, opSeek==OP_NotExists);
|
||||
VdbeCoverageIf(v, opSeek==OP_NotFound);
|
||||
}
|
||||
|
||||
/* If there are any triggers to fire, allocate a range of registers to
|
||||
** use for the old.* references in the triggers. */
|
||||
@@ -651,6 +657,8 @@ void sqlite3GenerateRowDelete(
|
||||
*/
|
||||
if( addrStart<sqlite3VdbeCurrentAddr(v) ){
|
||||
sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk);
|
||||
VdbeCoverageIf(v, opSeek==OP_NotExists);
|
||||
VdbeCoverageIf(v, opSeek==OP_NotFound);
|
||||
}
|
||||
|
||||
/* Do FK processing. This call checks that any FK constraints that
|
||||
|
||||
+107
-132
@@ -33,6 +33,7 @@
|
||||
char sqlite3ExprAffinity(Expr *pExpr){
|
||||
int op;
|
||||
pExpr = sqlite3ExprSkipCollate(pExpr);
|
||||
if( pExpr->flags & EP_Generic ) return SQLITE_AFF_NONE;
|
||||
op = pExpr->op;
|
||||
if( op==TK_SELECT ){
|
||||
assert( pExpr->flags&EP_xIsSelect );
|
||||
@@ -65,7 +66,11 @@ char sqlite3ExprAffinity(Expr *pExpr){
|
||||
** If a memory allocation error occurs, that fact is recorded in pParse->db
|
||||
** and the pExpr parameter is returned unchanged.
|
||||
*/
|
||||
Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr *pExpr, Token *pCollName){
|
||||
Expr *sqlite3ExprAddCollateToken(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Expr *pExpr, /* Add the "COLLATE" clause to this expression */
|
||||
const Token *pCollName /* Name of collating sequence */
|
||||
){
|
||||
if( pCollName->n>0 ){
|
||||
Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, 1);
|
||||
if( pNew ){
|
||||
@@ -118,6 +123,7 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
||||
Expr *p = pExpr;
|
||||
while( p ){
|
||||
int op = p->op;
|
||||
if( p->flags & EP_Generic ) break;
|
||||
if( op==TK_CAST || op==TK_UPLUS ){
|
||||
p = p->pLeft;
|
||||
continue;
|
||||
@@ -949,7 +955,6 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
|
||||
if( p==0 ) return 0;
|
||||
pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
|
||||
if( pNew==0 ) return 0;
|
||||
pNew->iECursor = 0;
|
||||
pNew->nExpr = i = p->nExpr;
|
||||
if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; i<p->nExpr; i+=i){}
|
||||
pNew->a = pItem = sqlite3DbMallocRaw(db, i*sizeof(p->a[0]) );
|
||||
@@ -1062,7 +1067,6 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
|
||||
pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
|
||||
pNew->addrOpenEphm[0] = -1;
|
||||
pNew->addrOpenEphm[1] = -1;
|
||||
pNew->addrOpenEphm[2] = -1;
|
||||
pNew->nSelectRow = p->nSelectRow;
|
||||
pNew->pWith = withDup(db, p->pWith);
|
||||
return pNew;
|
||||
@@ -1369,24 +1373,6 @@ int sqlite3ExprCanBeNull(const Expr *p){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate an OP_IsNull instruction that tests register iReg and jumps
|
||||
** to location iDest if the value in iReg is NULL. The value in iReg
|
||||
** was computed by pExpr. If we can look at pExpr at compile-time and
|
||||
** determine that it can never generate a NULL, then the OP_IsNull operation
|
||||
** can be omitted.
|
||||
*/
|
||||
void sqlite3ExprCodeIsNullJump(
|
||||
Vdbe *v, /* The VDBE under construction */
|
||||
const Expr *pExpr, /* Only generate OP_IsNull if this expr can be NULL */
|
||||
int iReg, /* Test the value in this register for NULL */
|
||||
int iDest /* Jump here if the value is null */
|
||||
){
|
||||
if( sqlite3ExprCanBeNull(pExpr) ){
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iDest);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the given expression is a constant which would be
|
||||
** unchanged by OP_Affinity with the affinity given in the second
|
||||
@@ -1594,9 +1580,8 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
*/
|
||||
assert(v);
|
||||
if( iCol<0 ){
|
||||
int iAddr;
|
||||
|
||||
iAddr = sqlite3CodeOnce(pParse);
|
||||
int iAddr = sqlite3CodeOnce(pParse);
|
||||
VdbeCoverage(v);
|
||||
|
||||
sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
|
||||
eType = IN_INDEX_ROWID;
|
||||
@@ -1621,18 +1606,18 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
&& sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], 0)==pReq
|
||||
&& (!mustBeUnique || (pIdx->nKeyCol==1 && pIdx->onError!=OE_None))
|
||||
){
|
||||
int iAddr = sqlite3CodeOnce(pParse);
|
||||
int iAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb);
|
||||
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
|
||||
VdbeComment((v, "%s", pIdx->zName));
|
||||
assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
|
||||
eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
|
||||
|
||||
sqlite3VdbeJumpHere(v, iAddr);
|
||||
if( prNotFound && !pTab->aCol[iCol].notNull ){
|
||||
*prNotFound = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, iAddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1649,7 +1634,6 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
*prNotFound = rMayHaveNull = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
|
||||
}else{
|
||||
testcase( pParse->nQueryLoop>0 );
|
||||
pParse->nQueryLoop = 0;
|
||||
if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){
|
||||
eType = IN_INDEX_ROWID;
|
||||
@@ -1721,7 +1705,7 @@ int sqlite3CodeSubselect(
|
||||
** save the results, and reuse the same result on subsequent invocations.
|
||||
*/
|
||||
if( !ExprHasProperty(pExpr, EP_VarSelect) ){
|
||||
testAddr = sqlite3CodeOnce(pParse);
|
||||
testAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
@@ -1837,6 +1821,7 @@ int sqlite3CodeSubselect(
|
||||
if( isRowid ){
|
||||
sqlite3VdbeAddOp2(v, OP_MustBeInt, r3,
|
||||
sqlite3VdbeCurrentAddr(v)+2);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, pExpr->iTable, r2, r3);
|
||||
}else{
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1);
|
||||
@@ -1960,10 +1945,11 @@ static void sqlite3ExprCodeIN(
|
||||
if( destIfNull==destIfFalse ){
|
||||
/* Shortcut for the common case where the false and NULL outcomes are
|
||||
** the same. */
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull);
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull); VdbeCoverage(v);
|
||||
}else{
|
||||
int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1);
|
||||
int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
}
|
||||
@@ -1971,8 +1957,9 @@ static void sqlite3ExprCodeIN(
|
||||
if( eType==IN_INDEX_ROWID ){
|
||||
/* In this case, the RHS is the ROWID of table b-tree
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, destIfFalse);
|
||||
sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, destIfFalse); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, destIfFalse, r1);
|
||||
VdbeCoverage(v);
|
||||
}else{
|
||||
/* In this case, the RHS is an index b-tree.
|
||||
*/
|
||||
@@ -1993,19 +1980,20 @@ static void sqlite3ExprCodeIN(
|
||||
** for this particular IN operator.
|
||||
*/
|
||||
sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse, r1, 1);
|
||||
|
||||
VdbeCoverage(v);
|
||||
}else{
|
||||
/* In this branch, the RHS of the IN might contain a NULL and
|
||||
** the presence of a NULL on the RHS makes a difference in the
|
||||
** outcome.
|
||||
*/
|
||||
int j1, j2, j3;
|
||||
int j1, j2;
|
||||
|
||||
/* First check to see if the LHS is contained in the RHS. If so,
|
||||
** then the presence of NULLs in the RHS does not matter, so jump
|
||||
** over all of the code that follows.
|
||||
*/
|
||||
j1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1);
|
||||
VdbeCoverage(v);
|
||||
|
||||
/* Here we begin generating code that runs if the LHS is not
|
||||
** contained within the RHS. Generate additional code that
|
||||
@@ -2013,18 +2001,15 @@ static void sqlite3ExprCodeIN(
|
||||
** jump to destIfNull. If there are no NULLs in the RHS then
|
||||
** jump to destIfFalse.
|
||||
*/
|
||||
j2 = sqlite3VdbeAddOp1(v, OP_NotNull, rRhsHasNull);
|
||||
j3 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, rRhsHasNull, 1);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, -1, rRhsHasNull);
|
||||
sqlite3VdbeJumpHere(v, j3);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, rRhsHasNull, 1);
|
||||
sqlite3VdbeJumpHere(v, j2);
|
||||
|
||||
/* Jump to the appropriate target depending on whether or not
|
||||
** the RHS contains a NULL
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_If, rRhsHasNull, destIfNull);
|
||||
sqlite3VdbeAddOp2(v, OP_If, rRhsHasNull, destIfNull); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_IfNot, rRhsHasNull, destIfFalse); VdbeCoverage(v);
|
||||
j2 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, rRhsHasNull, 1);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, rRhsHasNull);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse);
|
||||
sqlite3VdbeJumpHere(v, j2);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, rRhsHasNull);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull);
|
||||
|
||||
/* The OP_Found at the top of this branch jumps here when true,
|
||||
** causing the overall IN expression evaluation to fall through.
|
||||
@@ -2353,7 +2338,7 @@ void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
|
||||
int i;
|
||||
struct yColCache *p;
|
||||
assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo );
|
||||
sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg-1);
|
||||
sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg);
|
||||
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||
int x = p->iReg;
|
||||
if( x>=iFrom && x<iFrom+nReg ){
|
||||
@@ -2545,22 +2530,16 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
case TK_GE:
|
||||
case TK_NE:
|
||||
case TK_EQ: {
|
||||
assert( TK_LT==OP_Lt );
|
||||
assert( TK_LE==OP_Le );
|
||||
assert( TK_GT==OP_Gt );
|
||||
assert( TK_GE==OP_Ge );
|
||||
assert( TK_EQ==OP_Eq );
|
||||
assert( TK_NE==OP_Ne );
|
||||
testcase( op==TK_LT );
|
||||
testcase( op==TK_LE );
|
||||
testcase( op==TK_GT );
|
||||
testcase( op==TK_GE );
|
||||
testcase( op==TK_EQ );
|
||||
testcase( op==TK_NE );
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
|
||||
r1, r2, inReg, SQLITE_STOREP2);
|
||||
assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
|
||||
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
|
||||
assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
|
||||
assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
|
||||
assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
|
||||
assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
|
||||
testcase( regFree1==0 );
|
||||
testcase( regFree2==0 );
|
||||
break;
|
||||
@@ -2574,6 +2553,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
op = (op==TK_IS) ? TK_EQ : TK_NE;
|
||||
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
|
||||
r1, r2, inReg, SQLITE_STOREP2 | SQLITE_NULLEQ);
|
||||
VdbeCoverageIf(v, op==TK_EQ);
|
||||
VdbeCoverageIf(v, op==TK_NE);
|
||||
testcase( regFree1==0 );
|
||||
testcase( regFree2==0 );
|
||||
break;
|
||||
@@ -2590,28 +2571,17 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
case TK_LSHIFT:
|
||||
case TK_RSHIFT:
|
||||
case TK_CONCAT: {
|
||||
assert( TK_AND==OP_And );
|
||||
assert( TK_OR==OP_Or );
|
||||
assert( TK_PLUS==OP_Add );
|
||||
assert( TK_MINUS==OP_Subtract );
|
||||
assert( TK_REM==OP_Remainder );
|
||||
assert( TK_BITAND==OP_BitAnd );
|
||||
assert( TK_BITOR==OP_BitOr );
|
||||
assert( TK_SLASH==OP_Divide );
|
||||
assert( TK_LSHIFT==OP_ShiftLeft );
|
||||
assert( TK_RSHIFT==OP_ShiftRight );
|
||||
assert( TK_CONCAT==OP_Concat );
|
||||
testcase( op==TK_AND );
|
||||
testcase( op==TK_OR );
|
||||
testcase( op==TK_PLUS );
|
||||
testcase( op==TK_MINUS );
|
||||
testcase( op==TK_REM );
|
||||
testcase( op==TK_BITAND );
|
||||
testcase( op==TK_BITOR );
|
||||
testcase( op==TK_SLASH );
|
||||
testcase( op==TK_LSHIFT );
|
||||
testcase( op==TK_RSHIFT );
|
||||
testcase( op==TK_CONCAT );
|
||||
assert( TK_AND==OP_And ); testcase( op==TK_AND );
|
||||
assert( TK_OR==OP_Or ); testcase( op==TK_OR );
|
||||
assert( TK_PLUS==OP_Add ); testcase( op==TK_PLUS );
|
||||
assert( TK_MINUS==OP_Subtract ); testcase( op==TK_MINUS );
|
||||
assert( TK_REM==OP_Remainder ); testcase( op==TK_REM );
|
||||
assert( TK_BITAND==OP_BitAnd ); testcase( op==TK_BITAND );
|
||||
assert( TK_BITOR==OP_BitOr ); testcase( op==TK_BITOR );
|
||||
assert( TK_SLASH==OP_Divide ); testcase( op==TK_SLASH );
|
||||
assert( TK_LSHIFT==OP_ShiftLeft ); testcase( op==TK_LSHIFT );
|
||||
assert( TK_RSHIFT==OP_ShiftRight ); testcase( op==TK_RSHIFT );
|
||||
assert( TK_CONCAT==OP_Concat ); testcase( op==TK_CONCAT );
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||
sqlite3VdbeAddOp3(v, op, r2, r1, target);
|
||||
@@ -2643,10 +2613,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
}
|
||||
case TK_BITNOT:
|
||||
case TK_NOT: {
|
||||
assert( TK_BITNOT==OP_BitNot );
|
||||
assert( TK_NOT==OP_Not );
|
||||
testcase( op==TK_BITNOT );
|
||||
testcase( op==TK_NOT );
|
||||
assert( TK_BITNOT==OP_BitNot ); testcase( op==TK_BITNOT );
|
||||
assert( TK_NOT==OP_Not ); testcase( op==TK_NOT );
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
testcase( regFree1==0 );
|
||||
inReg = target;
|
||||
@@ -2656,14 +2624,14 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
case TK_ISNULL:
|
||||
case TK_NOTNULL: {
|
||||
int addr;
|
||||
assert( TK_ISNULL==OP_IsNull );
|
||||
assert( TK_NOTNULL==OP_NotNull );
|
||||
testcase( op==TK_ISNULL );
|
||||
testcase( op==TK_NOTNULL );
|
||||
assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL );
|
||||
assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL );
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, target);
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
testcase( regFree1==0 );
|
||||
addr = sqlite3VdbeAddOp1(v, op, r1);
|
||||
VdbeCoverageIf(v, op==TK_ISNULL);
|
||||
VdbeCoverageIf(v, op==TK_NOTNULL);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, target, -1);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
break;
|
||||
@@ -2715,6 +2683,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target);
|
||||
for(i=1; i<nFarg; i++){
|
||||
sqlite3VdbeAddOp2(v, OP_NotNull, target, endCoalesce);
|
||||
VdbeCoverage(v);
|
||||
sqlite3ExprCacheRemove(pParse, target, 1);
|
||||
sqlite3ExprCachePush(pParse);
|
||||
sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target);
|
||||
@@ -2770,7 +2739,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
}
|
||||
|
||||
sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */
|
||||
sqlite3ExprCodeExprList(pParse, pFarg, r1,
|
||||
sqlite3ExprCodeExprList(pParse, pFarg, r1,
|
||||
SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR);
|
||||
sqlite3ExprCachePop(pParse, 1); /* Ticket 2ea2425d34be */
|
||||
}else{
|
||||
@@ -2852,13 +2821,14 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
r3 = sqlite3GetTempReg(pParse);
|
||||
r4 = sqlite3GetTempReg(pParse);
|
||||
codeCompare(pParse, pLeft, pRight, OP_Ge,
|
||||
r1, r2, r3, SQLITE_STOREP2);
|
||||
r1, r2, r3, SQLITE_STOREP2); VdbeCoverage(v);
|
||||
pLItem++;
|
||||
pRight = pLItem->pExpr;
|
||||
sqlite3ReleaseTempReg(pParse, regFree2);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pRight, ®Free2);
|
||||
testcase( regFree2==0 );
|
||||
codeCompare(pParse, pLeft, pRight, OP_Le, r1, r2, r4, SQLITE_STOREP2);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_And, r3, r4, target);
|
||||
sqlite3ReleaseTempReg(pParse, r3);
|
||||
sqlite3ReleaseTempReg(pParse, r4);
|
||||
@@ -3025,6 +2995,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
if( pExpr->affinity==OE_Ignore ){
|
||||
sqlite3VdbeAddOp4(
|
||||
v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0);
|
||||
VdbeCoverage(v);
|
||||
}else{
|
||||
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_TRIGGER,
|
||||
pExpr->affinity, pExpr->u.zToken, 0, 0);
|
||||
@@ -3112,7 +3083,7 @@ int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){
|
||||
** results in register target. The results are guaranteed to appear
|
||||
** in register target.
|
||||
*/
|
||||
int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
||||
void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
||||
int inReg;
|
||||
|
||||
assert( target>0 && target<=pParse->nMem );
|
||||
@@ -3125,7 +3096,20 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
||||
sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target);
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code that will evaluate expression pExpr and store the
|
||||
** results in register target. The results are guaranteed to appear
|
||||
** in register target. If the expression is constant, then this routine
|
||||
** might choose to code the expression at initialization time.
|
||||
*/
|
||||
void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){
|
||||
if( pParse->okConstFactor && sqlite3ExprIsConstant(pExpr) ){
|
||||
sqlite3ExprCodeAtInit(pParse, pExpr, target, 0);
|
||||
}else{
|
||||
sqlite3ExprCode(pParse, pExpr, target);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3140,25 +3124,16 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
||||
** times. They are evaluated once and the results of the expression
|
||||
** are reused.
|
||||
*/
|
||||
int sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){
|
||||
void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
int inReg;
|
||||
inReg = sqlite3ExprCode(pParse, pExpr, target);
|
||||
int iMem;
|
||||
|
||||
assert( target>0 );
|
||||
/* The only place, other than this routine, where expressions can be
|
||||
** converted to TK_REGISTER is internal subexpressions in BETWEEN and
|
||||
** CASE operators. Neither ever calls this routine. And this routine
|
||||
** is never called twice on the same expression. Hence it is impossible
|
||||
** for the input to this routine to already be a register. Nevertheless,
|
||||
** it seems prudent to keep the ALWAYS() in case the conditions above
|
||||
** change with future modifications or enhancements. */
|
||||
if( ALWAYS(pExpr->op!=TK_REGISTER) ){
|
||||
int iMem;
|
||||
iMem = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, inReg, iMem);
|
||||
exprToRegister(pExpr, iMem);
|
||||
}
|
||||
return inReg;
|
||||
assert( pExpr->op!=TK_REGISTER );
|
||||
sqlite3ExprCode(pParse, pExpr, target);
|
||||
iMem = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, target, iMem);
|
||||
exprToRegister(pExpr, iMem);
|
||||
}
|
||||
|
||||
#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
|
||||
@@ -3593,23 +3568,17 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
case TK_GE:
|
||||
case TK_NE:
|
||||
case TK_EQ: {
|
||||
assert( TK_LT==OP_Lt );
|
||||
assert( TK_LE==OP_Le );
|
||||
assert( TK_GT==OP_Gt );
|
||||
assert( TK_GE==OP_Ge );
|
||||
assert( TK_EQ==OP_Eq );
|
||||
assert( TK_NE==OP_Ne );
|
||||
testcase( op==TK_LT );
|
||||
testcase( op==TK_LE );
|
||||
testcase( op==TK_GT );
|
||||
testcase( op==TK_GE );
|
||||
testcase( op==TK_EQ );
|
||||
testcase( op==TK_NE );
|
||||
testcase( jumpIfNull==0 );
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
|
||||
r1, r2, dest, jumpIfNull);
|
||||
assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
|
||||
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
|
||||
assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
|
||||
assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
|
||||
assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
|
||||
assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
|
||||
testcase( regFree1==0 );
|
||||
testcase( regFree2==0 );
|
||||
break;
|
||||
@@ -3623,18 +3592,20 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
op = (op==TK_IS) ? TK_EQ : TK_NE;
|
||||
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
|
||||
r1, r2, dest, SQLITE_NULLEQ);
|
||||
VdbeCoverageIf(v, op==TK_EQ);
|
||||
VdbeCoverageIf(v, op==TK_NE);
|
||||
testcase( regFree1==0 );
|
||||
testcase( regFree2==0 );
|
||||
break;
|
||||
}
|
||||
case TK_ISNULL:
|
||||
case TK_NOTNULL: {
|
||||
assert( TK_ISNULL==OP_IsNull );
|
||||
assert( TK_NOTNULL==OP_NotNull );
|
||||
testcase( op==TK_ISNULL );
|
||||
testcase( op==TK_NOTNULL );
|
||||
assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL );
|
||||
assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL );
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
sqlite3VdbeAddOp2(v, op, r1, dest);
|
||||
VdbeCoverageIf(v, op==TK_ISNULL);
|
||||
VdbeCoverageIf(v, op==TK_NOTNULL);
|
||||
testcase( regFree1==0 );
|
||||
break;
|
||||
}
|
||||
@@ -3661,6 +3632,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
}else{
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1);
|
||||
sqlite3VdbeAddOp3(v, OP_If, r1, dest, jumpIfNull!=0);
|
||||
VdbeCoverage(v);
|
||||
testcase( regFree1==0 );
|
||||
testcase( jumpIfNull==0 );
|
||||
}
|
||||
@@ -3752,17 +3724,17 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
case TK_GE:
|
||||
case TK_NE:
|
||||
case TK_EQ: {
|
||||
testcase( op==TK_LT );
|
||||
testcase( op==TK_LE );
|
||||
testcase( op==TK_GT );
|
||||
testcase( op==TK_GE );
|
||||
testcase( op==TK_EQ );
|
||||
testcase( op==TK_NE );
|
||||
testcase( jumpIfNull==0 );
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
|
||||
r1, r2, dest, jumpIfNull);
|
||||
assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
|
||||
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
|
||||
assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
|
||||
assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
|
||||
assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
|
||||
assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
|
||||
testcase( regFree1==0 );
|
||||
testcase( regFree2==0 );
|
||||
break;
|
||||
@@ -3776,16 +3748,18 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
|
||||
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
|
||||
r1, r2, dest, SQLITE_NULLEQ);
|
||||
VdbeCoverageIf(v, op==TK_EQ);
|
||||
VdbeCoverageIf(v, op==TK_NE);
|
||||
testcase( regFree1==0 );
|
||||
testcase( regFree2==0 );
|
||||
break;
|
||||
}
|
||||
case TK_ISNULL:
|
||||
case TK_NOTNULL: {
|
||||
testcase( op==TK_ISNULL );
|
||||
testcase( op==TK_NOTNULL );
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
sqlite3VdbeAddOp2(v, op, r1, dest);
|
||||
testcase( op==TK_ISNULL ); VdbeCoverageIf(v, op==TK_ISNULL);
|
||||
testcase( op==TK_NOTNULL ); VdbeCoverageIf(v, op==TK_NOTNULL);
|
||||
testcase( regFree1==0 );
|
||||
break;
|
||||
}
|
||||
@@ -3814,6 +3788,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
}else{
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1);
|
||||
sqlite3VdbeAddOp3(v, OP_IfNot, r1, dest, jumpIfNull!=0);
|
||||
VdbeCoverage(v);
|
||||
testcase( regFree1==0 );
|
||||
testcase( jumpIfNull==0 );
|
||||
}
|
||||
|
||||
+14
-9
@@ -340,10 +340,11 @@ static void fkLookupParent(
|
||||
** search for a matching row in the parent table. */
|
||||
if( nIncr<0 ){
|
||||
sqlite3VdbeAddOp2(v, OP_FkIfZero, pFKey->isDeferred, iOk);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
for(i=0; i<pFKey->nCol; i++){
|
||||
int iReg = aiCol[i] + regData + 1;
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iOk);
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iOk); VdbeCoverage(v);
|
||||
}
|
||||
|
||||
if( isIgnore==0 ){
|
||||
@@ -360,17 +361,19 @@ static void fkLookupParent(
|
||||
** will have INTEGER affinity applied to it, which may not be correct. */
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, aiCol[0]+1+regData, regTemp);
|
||||
iMustBeInt = sqlite3VdbeAddOp2(v, OP_MustBeInt, regTemp, 0);
|
||||
VdbeCoverage(v);
|
||||
|
||||
/* If the parent table is the same as the child table, and we are about
|
||||
** to increment the constraint-counter (i.e. this is an INSERT operation),
|
||||
** then check if the row being inserted matches itself. If so, do not
|
||||
** increment the constraint-counter. */
|
||||
if( pTab==pFKey->pFrom && nIncr==1 ){
|
||||
sqlite3VdbeAddOp3(v, OP_Eq, regData, iOk, regTemp);
|
||||
sqlite3VdbeAddOp3(v, OP_Eq, regData, iOk, regTemp); VdbeCoverage(v);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
|
||||
}
|
||||
|
||||
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
|
||||
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regTemp);
|
||||
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regTemp); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, iOk);
|
||||
sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
|
||||
sqlite3VdbeJumpHere(v, iMustBeInt);
|
||||
@@ -406,15 +409,15 @@ static void fkLookupParent(
|
||||
/* The parent key is a composite key that includes the IPK column */
|
||||
iParent = regData;
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_Ne, iChild, iJump, iParent);
|
||||
sqlite3VdbeAddOp3(v, OP_Ne, iChild, iJump, iParent); VdbeCoverage(v);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, iOk);
|
||||
}
|
||||
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regTemp, nCol, regRec);
|
||||
sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v,pIdx), P4_TRANSIENT);
|
||||
sqlite3VdbeAddOp4Int(v, OP_Found, iCur, iOk, regRec, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTemp, nCol, regRec,
|
||||
sqlite3IndexAffinityStr(v,pIdx), nCol);
|
||||
sqlite3VdbeAddOp4Int(v, OP_Found, iCur, iOk, regRec, 0); VdbeCoverage(v);
|
||||
|
||||
sqlite3ReleaseTempReg(pParse, regRec);
|
||||
sqlite3ReleaseTempRange(pParse, regTemp, nCol);
|
||||
@@ -552,6 +555,7 @@ static void fkScanChildren(
|
||||
|
||||
if( nIncr<0 ){
|
||||
iFkIfZero = sqlite3VdbeAddOp2(v, OP_FkIfZero, pFKey->isDeferred, 0);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
|
||||
/* Create an Expr object representing an SQL expression like:
|
||||
@@ -714,7 +718,7 @@ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
|
||||
}
|
||||
if( !p ) return;
|
||||
iSkip = sqlite3VdbeMakeLabel(v);
|
||||
sqlite3VdbeAddOp2(v, OP_FkIfZero, 1, iSkip);
|
||||
sqlite3VdbeAddOp2(v, OP_FkIfZero, 1, iSkip); VdbeCoverage(v);
|
||||
}
|
||||
|
||||
pParse->disableTriggers = 1;
|
||||
@@ -732,6 +736,7 @@ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
|
||||
*/
|
||||
if( (db->flags & SQLITE_DeferFKs)==0 ){
|
||||
sqlite3VdbeAddOp2(v, OP_FkIfZero, 0, sqlite3VdbeCurrentAddr(v)+2);
|
||||
VdbeCoverage(v);
|
||||
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY,
|
||||
OE_Abort, 0, P4_STATIC, P5_ConstraintFK);
|
||||
}
|
||||
@@ -891,7 +896,7 @@ void sqlite3FkCheck(
|
||||
int iJump = sqlite3VdbeCurrentAddr(v) + pFKey->nCol + 1;
|
||||
for(i=0; i<pFKey->nCol; i++){
|
||||
int iReg = pFKey->aCol[i].iFrom + regOld + 1;
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iJump);
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iJump); VdbeCoverage(v);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, -1);
|
||||
}
|
||||
|
||||
+1
-1
@@ -1017,7 +1017,7 @@ static void charFunc(
|
||||
){
|
||||
unsigned char *z, *zOut;
|
||||
int i;
|
||||
zOut = z = sqlite3_malloc( argc*4 );
|
||||
zOut = z = sqlite3_malloc( argc*4+1 );
|
||||
if( z==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
return;
|
||||
|
||||
@@ -167,6 +167,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
|
||||
0, /* nPage */
|
||||
0, /* mxParserStack */
|
||||
0, /* sharedCacheEnabled */
|
||||
0, /* nWorker */
|
||||
/* All the rest should always be initialized to zero */
|
||||
0, /* isInit */
|
||||
0, /* inProgress */
|
||||
|
||||
+193
-238
@@ -98,10 +98,16 @@ const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
|
||||
}
|
||||
|
||||
/*
|
||||
** Set P4 of the most recently inserted opcode to a column affinity
|
||||
** string for table pTab. A column affinity string has one character
|
||||
** for each column indexed by the index, according to the affinity of the
|
||||
** column:
|
||||
** Compute the affinity string for table pTab, if it has not already been
|
||||
** computed. As an optimization, omit trailing SQLITE_AFF_NONE affinities.
|
||||
**
|
||||
** If the affinity exists (if it is no entirely SQLITE_AFF_NONE values) and
|
||||
** if iReg>0 then code an OP_Affinity opcode that will set the affinities
|
||||
** for register iReg and following. Or if affinities exists and iReg==0,
|
||||
** then just set the P4 operand of the previous opcode (which should be
|
||||
** an OP_MakeRecord) to the affinity string.
|
||||
**
|
||||
** A column affinity string has one character per column:
|
||||
**
|
||||
** Character Column affinity
|
||||
** ------------------------------
|
||||
@@ -111,19 +117,11 @@ const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
|
||||
** 'd' INTEGER
|
||||
** 'e' REAL
|
||||
*/
|
||||
void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){
|
||||
/* The first time a column affinity string for a particular table
|
||||
** is required, it is allocated and populated here. It is then
|
||||
** stored as a member of the Table structure for subsequent use.
|
||||
**
|
||||
** The column affinity string will eventually be deleted by
|
||||
** sqlite3DeleteTable() when the Table structure itself is cleaned up.
|
||||
*/
|
||||
if( !pTab->zColAff ){
|
||||
char *zColAff;
|
||||
int i;
|
||||
void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
|
||||
int i;
|
||||
char *zColAff = pTab->zColAff;
|
||||
if( zColAff==0 ){
|
||||
sqlite3 *db = sqlite3VdbeDb(v);
|
||||
|
||||
zColAff = (char *)sqlite3DbMallocRaw(0, pTab->nCol+1);
|
||||
if( !zColAff ){
|
||||
db->mallocFailed = 1;
|
||||
@@ -133,22 +131,28 @@ void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
zColAff[i] = pTab->aCol[i].affinity;
|
||||
}
|
||||
zColAff[pTab->nCol] = '\0';
|
||||
|
||||
do{
|
||||
zColAff[i--] = 0;
|
||||
}while( i>=0 && zColAff[i]==SQLITE_AFF_NONE );
|
||||
pTab->zColAff = zColAff;
|
||||
}
|
||||
|
||||
sqlite3VdbeChangeP4(v, -1, pTab->zColAff, P4_TRANSIENT);
|
||||
i = sqlite3Strlen30(zColAff);
|
||||
if( i ){
|
||||
if( iReg ){
|
||||
sqlite3VdbeAddOp4(v, OP_Affinity, iReg, i, 0, zColAff, i);
|
||||
}else{
|
||||
sqlite3VdbeChangeP4(v, -1, zColAff, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return non-zero if the table pTab in database iDb or any of its indices
|
||||
** have been opened at any point in the VDBE program beginning at location
|
||||
** iStartAddr throught the end of the program. This is used to see if
|
||||
** have been opened at any point in the VDBE program. This is used to see if
|
||||
** a statement of the form "INSERT INTO <iDb, pTab> SELECT ..." can
|
||||
** run without using temporary table for the results of the SELECT.
|
||||
** run without using a temporary table for the results of the SELECT.
|
||||
*/
|
||||
static int readsTable(Parse *p, int iStartAddr, int iDb, Table *pTab){
|
||||
static int readsTable(Parse *p, int iDb, Table *pTab){
|
||||
Vdbe *v = sqlite3GetVdbe(p);
|
||||
int i;
|
||||
int iEnd = sqlite3VdbeCurrentAddr(v);
|
||||
@@ -156,7 +160,7 @@ static int readsTable(Parse *p, int iStartAddr, int iDb, Table *pTab){
|
||||
VTable *pVTab = IsVirtual(pTab) ? sqlite3GetVTable(p->db, pTab) : 0;
|
||||
#endif
|
||||
|
||||
for(i=iStartAddr; i<iEnd; i++){
|
||||
for(i=1; i<iEnd; i++){
|
||||
VdbeOp *pOp = sqlite3VdbeGetOp(v, i);
|
||||
assert( pOp!=0 );
|
||||
if( pOp->opcode==OP_OpenRead && pOp->p3==iDb ){
|
||||
@@ -257,14 +261,14 @@ void sqlite3AutoincrementBegin(Parse *pParse){
|
||||
sqlite3VdbeAddOp3(v, OP_Null, 0, memId, memId+1);
|
||||
addr = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, memId-1, 0, p->pTab->zName, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, 0, addr+9);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, 0, addr+9); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, 0, 0, memId);
|
||||
sqlite3VdbeAddOp3(v, OP_Ne, memId-1, addr+7, memId);
|
||||
sqlite3VdbeAddOp3(v, OP_Ne, memId-1, addr+7, memId); VdbeCoverage(v);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, 0, memId+1);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, 0, 1, memId);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addr+9);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, 0, addr+2);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, 0, addr+2); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, memId);
|
||||
sqlite3VdbeAddOp0(v, OP_Close);
|
||||
}
|
||||
@@ -299,25 +303,16 @@ void sqlite3AutoincrementEnd(Parse *pParse){
|
||||
assert( v );
|
||||
for(p = pParse->pAinc; p; p = p->pNext){
|
||||
Db *pDb = &db->aDb[p->iDb];
|
||||
int j1, j2, j3, j4, j5;
|
||||
int j1;
|
||||
int iRec;
|
||||
int memId = p->regCtr;
|
||||
|
||||
iRec = sqlite3GetTempReg(pParse);
|
||||
assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
|
||||
sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
|
||||
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1);
|
||||
j2 = sqlite3VdbeAddOp0(v, OP_Rewind);
|
||||
j3 = sqlite3VdbeAddOp3(v, OP_Column, 0, 0, iRec);
|
||||
j4 = sqlite3VdbeAddOp3(v, OP_Eq, memId-1, 0, iRec);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, 0, j3);
|
||||
sqlite3VdbeJumpHere(v, j2);
|
||||
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, 0, memId+1);
|
||||
j5 = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
sqlite3VdbeJumpHere(v, j4);
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, 0, memId+1);
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
sqlite3VdbeJumpHere(v, j5);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, memId-1, 2, iRec);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, 0, iRec, memId+1);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
||||
@@ -335,79 +330,6 @@ void sqlite3AutoincrementEnd(Parse *pParse){
|
||||
#endif /* SQLITE_OMIT_AUTOINCREMENT */
|
||||
|
||||
|
||||
/*
|
||||
** Generate code for a co-routine that will evaluate a subquery one
|
||||
** row at a time.
|
||||
**
|
||||
** The pSelect parameter is the subquery that the co-routine will evaluation.
|
||||
** Information about the location of co-routine and the registers it will use
|
||||
** is returned by filling in the pDest object.
|
||||
**
|
||||
** Registers are allocated as follows:
|
||||
**
|
||||
** pDest->iSDParm The register holding the next entry-point of the
|
||||
** co-routine. Run the co-routine to its next breakpoint
|
||||
** by calling "OP_Yield $X" where $X is pDest->iSDParm.
|
||||
**
|
||||
** pDest->iSdst First result register.
|
||||
**
|
||||
** pDest->nSdst Number of result registers.
|
||||
**
|
||||
** At EOF the first result register will be marked as "undefined" so that
|
||||
** the caller can know when to stop reading results.
|
||||
**
|
||||
** This routine handles all of the register allocation and fills in the
|
||||
** pDest structure appropriately.
|
||||
**
|
||||
** Here is a schematic of the generated code assuming that X is the
|
||||
** co-routine entry-point register reg[pDest->iSDParm], that EOF is the
|
||||
** completed flag reg[pDest->iSDParm+1], and R and S are the range of
|
||||
** registers that hold the result set, reg[pDest->iSdst] through
|
||||
** reg[pDest->iSdst+pDest->nSdst-1]:
|
||||
**
|
||||
** X <- A
|
||||
** goto B
|
||||
** A: setup for the SELECT
|
||||
** loop rows in the SELECT
|
||||
** load results into registers R..S
|
||||
** yield X
|
||||
** end loop
|
||||
** cleanup after the SELECT
|
||||
** end co-routine R
|
||||
** B:
|
||||
**
|
||||
** To use this subroutine, the caller generates code as follows:
|
||||
**
|
||||
** [ Co-routine generated by this subroutine, shown above ]
|
||||
** S: yield X, at EOF goto E
|
||||
** if skip this row, goto C
|
||||
** if terminate loop, goto E
|
||||
** deal with this row
|
||||
** C: goto S
|
||||
** E:
|
||||
*/
|
||||
int sqlite3CodeCoroutine(Parse *pParse, Select *pSelect, SelectDest *pDest){
|
||||
int regYield; /* Register holding co-routine entry-point */
|
||||
int addrTop; /* Top of the co-routine */
|
||||
int rc; /* Result code */
|
||||
Vdbe *v; /* VDBE under construction */
|
||||
|
||||
regYield = ++pParse->nMem;
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
addrTop = sqlite3VdbeCurrentAddr(v) + 1;
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
|
||||
sqlite3SelectDestInit(pDest, SRT_Coroutine, regYield);
|
||||
rc = sqlite3Select(pParse, pSelect, pDest);
|
||||
assert( pParse->nErr==0 || rc );
|
||||
if( pParse->db->mallocFailed && rc==SQLITE_OK ) rc = SQLITE_NOMEM;
|
||||
if( rc ) return rc;
|
||||
sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
|
||||
sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Forward declaration */
|
||||
static int xferOptimization(
|
||||
Parse *pParse, /* Parser context */
|
||||
@@ -531,16 +453,16 @@ void sqlite3Insert(
|
||||
int iIdxCur = 0; /* First index cursor */
|
||||
int ipkColumn = -1; /* Column that is the INTEGER PRIMARY KEY */
|
||||
int endOfLoop; /* Label for the end of the insertion loop */
|
||||
int useTempTable = 0; /* Store SELECT results in intermediate table */
|
||||
int srcTab = 0; /* Data comes from this temporary cursor if >=0 */
|
||||
int addrInsTop = 0; /* Jump to label "D" */
|
||||
int addrCont = 0; /* Top of insert loop. Label "C" in templates 3 and 4 */
|
||||
int addrSelect = 0; /* Address of coroutine that implements the SELECT */
|
||||
SelectDest dest; /* Destination for SELECT on rhs of INSERT */
|
||||
int iDb; /* Index of database holding TABLE */
|
||||
Db *pDb; /* The database containing table being inserted into */
|
||||
int appendFlag = 0; /* True if the insert is likely to be an append */
|
||||
int withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */
|
||||
u8 useTempTable = 0; /* Store SELECT results in intermediate table */
|
||||
u8 appendFlag = 0; /* True if the insert is likely to be an append */
|
||||
u8 withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */
|
||||
u8 bIdListInOrder = 1; /* True if IDLIST is in table order */
|
||||
ExprList *pList = 0; /* List of VALUES() to be inserted */
|
||||
|
||||
/* Register allocations */
|
||||
@@ -652,97 +574,16 @@ void sqlite3Insert(
|
||||
*/
|
||||
regAutoinc = autoIncBegin(pParse, iDb, pTab);
|
||||
|
||||
/* Figure out how many columns of data are supplied. If the data
|
||||
** is coming from a SELECT statement, then generate a co-routine that
|
||||
** produces a single row of the SELECT on each invocation. The
|
||||
** co-routine is the common header to the 3rd and 4th templates.
|
||||
*/
|
||||
if( pSelect ){
|
||||
/* Data is coming from a SELECT. Generate a co-routine to run the SELECT */
|
||||
int rc = sqlite3CodeCoroutine(pParse, pSelect, &dest);
|
||||
if( rc ) goto insert_cleanup;
|
||||
|
||||
regFromSelect = dest.iSdst;
|
||||
assert( pSelect->pEList );
|
||||
nColumn = pSelect->pEList->nExpr;
|
||||
assert( dest.nSdst==nColumn );
|
||||
|
||||
/* Set useTempTable to TRUE if the result of the SELECT statement
|
||||
** should be written into a temporary table (template 4). Set to
|
||||
** FALSE if each output row of the SELECT can be written directly into
|
||||
** the destination table (template 3).
|
||||
**
|
||||
** A temp table must be used if the table being updated is also one
|
||||
** of the tables being read by the SELECT statement. Also use a
|
||||
** temp table in the case of row triggers.
|
||||
*/
|
||||
if( pTrigger || readsTable(pParse, addrSelect, iDb, pTab) ){
|
||||
useTempTable = 1;
|
||||
}
|
||||
|
||||
if( useTempTable ){
|
||||
/* Invoke the coroutine to extract information from the SELECT
|
||||
** and add it to a transient table srcTab. The code generated
|
||||
** here is from the 4th template:
|
||||
**
|
||||
** B: open temp table
|
||||
** L: yield X, goto M at EOF
|
||||
** insert row from R..R+n into temp table
|
||||
** goto L
|
||||
** M: ...
|
||||
*/
|
||||
int regRec; /* Register to hold packed record */
|
||||
int regTempRowid; /* Register to hold temp table ROWID */
|
||||
int addrTop; /* Label "L" */
|
||||
|
||||
srcTab = pParse->nTab++;
|
||||
regRec = sqlite3GetTempReg(pParse);
|
||||
regTempRowid = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, srcTab, nColumn);
|
||||
addrTop = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect, nColumn, regRec);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regTempRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, srcTab, regRec, regTempRowid);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop);
|
||||
sqlite3VdbeJumpHere(v, addrTop);
|
||||
sqlite3ReleaseTempReg(pParse, regRec);
|
||||
sqlite3ReleaseTempReg(pParse, regTempRowid);
|
||||
}
|
||||
}else{
|
||||
/* This is the case if the data for the INSERT is coming from a VALUES
|
||||
** clause
|
||||
*/
|
||||
NameContext sNC;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = pParse;
|
||||
srcTab = -1;
|
||||
assert( useTempTable==0 );
|
||||
nColumn = pList ? pList->nExpr : 0;
|
||||
for(i=0; i<nColumn; i++){
|
||||
if( sqlite3ResolveExprNames(&sNC, pList->a[i].pExpr) ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure the number of columns in the source data matches the number
|
||||
** of columns to be inserted into the table.
|
||||
/* Allocate registers for holding the rowid of the new row,
|
||||
** the content of the new row, and the assemblied row record.
|
||||
*/
|
||||
regRowid = regIns = pParse->nMem+1;
|
||||
pParse->nMem += pTab->nCol + 1;
|
||||
if( IsVirtual(pTab) ){
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
nHidden += (IsHiddenColumn(&pTab->aCol[i]) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
if( pColumn==0 && nColumn && nColumn!=(pTab->nCol-nHidden) ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"table %S has %d columns but %d values were supplied",
|
||||
pTabList, 0, pTab->nCol-nHidden, nColumn);
|
||||
goto insert_cleanup;
|
||||
}
|
||||
if( pColumn!=0 && nColumn!=pColumn->nId ){
|
||||
sqlite3ErrorMsg(pParse, "%d values for %d columns", nColumn, pColumn->nId);
|
||||
goto insert_cleanup;
|
||||
regRowid++;
|
||||
pParse->nMem++;
|
||||
}
|
||||
regData = regRowid+1;
|
||||
|
||||
/* If the INSERT statement included an IDLIST term, then make sure
|
||||
** all elements of the IDLIST really are columns of the table and
|
||||
@@ -763,6 +604,7 @@ void sqlite3Insert(
|
||||
for(j=0; j<pTab->nCol; j++){
|
||||
if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){
|
||||
pColumn->a[i].idx = j;
|
||||
if( i!=j ) bIdListInOrder = 0;
|
||||
if( j==pTab->iPKey ){
|
||||
ipkColumn = i; assert( !withoutRowid );
|
||||
}
|
||||
@@ -782,6 +624,90 @@ void sqlite3Insert(
|
||||
}
|
||||
}
|
||||
|
||||
/* Figure out how many columns of data are supplied. If the data
|
||||
** is coming from a SELECT statement, then generate a co-routine that
|
||||
** produces a single row of the SELECT on each invocation. The
|
||||
** co-routine is the common header to the 3rd and 4th templates.
|
||||
*/
|
||||
if( pSelect ){
|
||||
/* Data is coming from a SELECT. Generate a co-routine to run the SELECT */
|
||||
int regYield; /* Register holding co-routine entry-point */
|
||||
int addrTop; /* Top of the co-routine */
|
||||
int rc; /* Result code */
|
||||
|
||||
regYield = ++pParse->nMem;
|
||||
addrTop = sqlite3VdbeCurrentAddr(v) + 1;
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
|
||||
sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
|
||||
dest.iSdst = bIdListInOrder ? regData : 0;
|
||||
dest.nSdst = pTab->nCol;
|
||||
rc = sqlite3Select(pParse, pSelect, &dest);
|
||||
regFromSelect = dest.iSdst;
|
||||
assert( pParse->nErr==0 || rc );
|
||||
if( rc || db->mallocFailed ) goto insert_cleanup;
|
||||
sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
|
||||
sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
|
||||
assert( pSelect->pEList );
|
||||
nColumn = pSelect->pEList->nExpr;
|
||||
|
||||
/* Set useTempTable to TRUE if the result of the SELECT statement
|
||||
** should be written into a temporary table (template 4). Set to
|
||||
** FALSE if each output row of the SELECT can be written directly into
|
||||
** the destination table (template 3).
|
||||
**
|
||||
** A temp table must be used if the table being updated is also one
|
||||
** of the tables being read by the SELECT statement. Also use a
|
||||
** temp table in the case of row triggers.
|
||||
*/
|
||||
if( pTrigger || readsTable(pParse, iDb, pTab) ){
|
||||
useTempTable = 1;
|
||||
}
|
||||
|
||||
if( useTempTable ){
|
||||
/* Invoke the coroutine to extract information from the SELECT
|
||||
** and add it to a transient table srcTab. The code generated
|
||||
** here is from the 4th template:
|
||||
**
|
||||
** B: open temp table
|
||||
** L: yield X, goto M at EOF
|
||||
** insert row from R..R+n into temp table
|
||||
** goto L
|
||||
** M: ...
|
||||
*/
|
||||
int regRec; /* Register to hold packed record */
|
||||
int regTempRowid; /* Register to hold temp table ROWID */
|
||||
int addrL; /* Label "L" */
|
||||
|
||||
srcTab = pParse->nTab++;
|
||||
regRec = sqlite3GetTempReg(pParse);
|
||||
regTempRowid = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, srcTab, nColumn);
|
||||
addrL = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect, nColumn, regRec);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regTempRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, srcTab, regRec, regTempRowid);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrL);
|
||||
sqlite3VdbeJumpHere(v, addrL);
|
||||
sqlite3ReleaseTempReg(pParse, regRec);
|
||||
sqlite3ReleaseTempReg(pParse, regTempRowid);
|
||||
}
|
||||
}else{
|
||||
/* This is the case if the data for the INSERT is coming from a VALUES
|
||||
** clause
|
||||
*/
|
||||
NameContext sNC;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = pParse;
|
||||
srcTab = -1;
|
||||
assert( useTempTable==0 );
|
||||
nColumn = pList ? pList->nExpr : 0;
|
||||
for(i=0; i<nColumn; i++){
|
||||
if( sqlite3ResolveExprNames(&sNC, pList->a[i].pExpr) ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If there is no IDLIST term but the table has an integer primary
|
||||
** key, the set the ipkColumn variable to the integer primary key
|
||||
** column index in the original table definition.
|
||||
@@ -789,6 +715,25 @@ void sqlite3Insert(
|
||||
if( pColumn==0 && nColumn>0 ){
|
||||
ipkColumn = pTab->iPKey;
|
||||
}
|
||||
|
||||
/* Make sure the number of columns in the source data matches the number
|
||||
** of columns to be inserted into the table.
|
||||
*/
|
||||
if( IsVirtual(pTab) ){
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
nHidden += (IsHiddenColumn(&pTab->aCol[i]) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
if( pColumn==0 && nColumn && nColumn!=(pTab->nCol-nHidden) ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"table %S has %d columns but %d values were supplied",
|
||||
pTabList, 0, pTab->nCol-nHidden, nColumn);
|
||||
goto insert_cleanup;
|
||||
}
|
||||
if( pColumn!=0 && nColumn!=pColumn->nId ){
|
||||
sqlite3ErrorMsg(pParse, "%d values for %d columns", nColumn, pColumn->nId);
|
||||
goto insert_cleanup;
|
||||
}
|
||||
|
||||
/* Initialize the count of rows to be inserted
|
||||
*/
|
||||
@@ -822,7 +767,7 @@ void sqlite3Insert(
|
||||
** end loop
|
||||
** D: ...
|
||||
*/
|
||||
addrInsTop = sqlite3VdbeAddOp1(v, OP_Rewind, srcTab);
|
||||
addrInsTop = sqlite3VdbeAddOp1(v, OP_Rewind, srcTab); VdbeCoverage(v);
|
||||
addrCont = sqlite3VdbeCurrentAddr(v);
|
||||
}else if( pSelect ){
|
||||
/* This block codes the top of loop only. The complete loop is the
|
||||
@@ -834,19 +779,9 @@ void sqlite3Insert(
|
||||
** D: ...
|
||||
*/
|
||||
addrInsTop = addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
|
||||
/* Allocate registers for holding the rowid of the new row,
|
||||
** the content of the new row, and the assemblied row record.
|
||||
*/
|
||||
regRowid = regIns = pParse->nMem+1;
|
||||
pParse->nMem += pTab->nCol + 1;
|
||||
if( IsVirtual(pTab) ){
|
||||
regRowid++;
|
||||
pParse->nMem++;
|
||||
}
|
||||
regData = regRowid+1;
|
||||
|
||||
/* Run the BEFORE and INSTEAD OF triggers, if there are any
|
||||
*/
|
||||
endOfLoop = sqlite3VdbeMakeLabel(v);
|
||||
@@ -870,10 +805,10 @@ void sqlite3Insert(
|
||||
assert( pSelect==0 ); /* Otherwise useTempTable is true */
|
||||
sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regCols);
|
||||
}
|
||||
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols);
|
||||
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols);
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols);
|
||||
sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols); VdbeCoverage(v);
|
||||
}
|
||||
|
||||
/* Cannot have triggers on a virtual table. If it were possible,
|
||||
@@ -907,8 +842,7 @@ void sqlite3Insert(
|
||||
** table column affinities.
|
||||
*/
|
||||
if( !isView ){
|
||||
sqlite3VdbeAddOp2(v, OP_Affinity, regCols+1, pTab->nCol);
|
||||
sqlite3TableAffinityStr(v, pTab);
|
||||
sqlite3TableAffinity(v, pTab, regCols+1);
|
||||
}
|
||||
|
||||
/* Fire BEFORE or INSTEAD OF triggers */
|
||||
@@ -930,7 +864,7 @@ void sqlite3Insert(
|
||||
if( useTempTable ){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, srcTab, ipkColumn, regRowid);
|
||||
}else if( pSelect ){
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+ipkColumn, regRowid);
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, regFromSelect+ipkColumn, regRowid);
|
||||
}else{
|
||||
VdbeOp *pOp;
|
||||
sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regRowid);
|
||||
@@ -949,14 +883,14 @@ void sqlite3Insert(
|
||||
if( !appendFlag ){
|
||||
int j1;
|
||||
if( !IsVirtual(pTab) ){
|
||||
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid);
|
||||
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc);
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
}else{
|
||||
j1 = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regRowid, j1+2);
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regRowid, j1+2); VdbeCoverage(v);
|
||||
}
|
||||
sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid);
|
||||
sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid); VdbeCoverage(v);
|
||||
}
|
||||
}else if( IsVirtual(pTab) || withoutRowid ){
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid);
|
||||
@@ -976,8 +910,9 @@ void sqlite3Insert(
|
||||
/* The value of the INTEGER PRIMARY KEY column is always a NULL.
|
||||
** Whenever this column is read, the rowid will be substituted
|
||||
** in its place. Hence, fill this column with a NULL to avoid
|
||||
** taking up data space with information that will never be used. */
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, iRegStore);
|
||||
** taking up data space with information that will never be used.
|
||||
** As there may be shallow copies of this value, make it a soft-NULL */
|
||||
sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore);
|
||||
continue;
|
||||
}
|
||||
if( pColumn==0 ){
|
||||
@@ -994,11 +929,13 @@ void sqlite3Insert(
|
||||
}
|
||||
}
|
||||
if( j<0 || nColumn==0 || (pColumn && j>=pColumn->nId) ){
|
||||
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, iRegStore);
|
||||
sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore);
|
||||
}else if( useTempTable ){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, iRegStore);
|
||||
}else if( pSelect ){
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+j, iRegStore);
|
||||
if( regFromSelect!=regData ){
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+j, iRegStore);
|
||||
}
|
||||
}else{
|
||||
sqlite3ExprCode(pParse, pList->a[j].pExpr, iRegStore);
|
||||
}
|
||||
@@ -1044,7 +981,7 @@ void sqlite3Insert(
|
||||
*/
|
||||
sqlite3VdbeResolveLabel(v, endOfLoop);
|
||||
if( useTempTable ){
|
||||
sqlite3VdbeAddOp2(v, OP_Next, srcTab, addrCont);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, srcTab, addrCont); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, addrInsTop);
|
||||
sqlite3VdbeAddOp1(v, OP_Close, srcTab);
|
||||
}else if( pSelect ){
|
||||
@@ -1211,6 +1148,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
int ipkTop = 0; /* Top of the rowid change constraint check */
|
||||
int ipkBottom = 0; /* Bottom of the rowid change constraint check */
|
||||
u8 isUpdate; /* True if this is an UPDATE operation */
|
||||
u8 bAffinityDone = 0; /* True if the OP_Affinity operation has been run */
|
||||
int regRowid = -1; /* Register holding ROWID value */
|
||||
|
||||
isUpdate = regOldData!=0;
|
||||
@@ -1265,15 +1203,17 @@ void sqlite3GenerateConstraintChecks(
|
||||
sqlite3VdbeAddOp4(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError,
|
||||
regNewData+1+i, zMsg, P4_DYNAMIC);
|
||||
sqlite3VdbeChangeP5(v, P5_ConstraintNotNull);
|
||||
VdbeCoverage(v);
|
||||
break;
|
||||
}
|
||||
case OE_Ignore: {
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regNewData+1+i, ignoreDest);
|
||||
VdbeCoverage(v);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assert( onError==OE_Replace );
|
||||
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regNewData+1+i);
|
||||
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regNewData+1+i); VdbeCoverage(v);
|
||||
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regNewData+1+i);
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
break;
|
||||
@@ -1325,6 +1265,8 @@ void sqlite3GenerateConstraintChecks(
|
||||
** it might have changed. Skip the conflict logic below if the rowid
|
||||
** is unchanged. */
|
||||
sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRowidOk, regOldData);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
|
||||
/* If the response to a rowid conflict is REPLACE but the response
|
||||
@@ -1344,6 +1286,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
/* Check to see if the new rowid already exists in the table. Skip
|
||||
** the following conflict logic if it does not. */
|
||||
sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData);
|
||||
VdbeCoverage(v);
|
||||
|
||||
/* Generate code that deals with a rowid collision */
|
||||
switch( onError ){
|
||||
@@ -1422,6 +1365,10 @@ void sqlite3GenerateConstraintChecks(
|
||||
int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */
|
||||
|
||||
if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */
|
||||
if( bAffinityDone==0 ){
|
||||
sqlite3TableAffinity(v, pTab, regNewData+1);
|
||||
bAffinityDone = 1;
|
||||
}
|
||||
iThisCur = iIdxCur+ix;
|
||||
addrUniqueOk = sqlite3VdbeMakeLabel(v);
|
||||
|
||||
@@ -1452,7 +1399,6 @@ void sqlite3GenerateConstraintChecks(
|
||||
VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName));
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]);
|
||||
sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), P4_TRANSIENT);
|
||||
VdbeComment((v, "for %s", pIdx->zName));
|
||||
sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn);
|
||||
|
||||
@@ -1480,7 +1426,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
|
||||
/* Check to see if the new index entry will be unique */
|
||||
sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
|
||||
regIdx, pIdx->nKeyCol);
|
||||
regIdx, pIdx->nKeyCol); VdbeCoverage(v);
|
||||
|
||||
/* Generate code to handle collisions */
|
||||
regR = (pIdx==pPk) ? regIdx : sqlite3GetTempRange(pParse, nPkField);
|
||||
@@ -1491,6 +1437,8 @@ void sqlite3GenerateConstraintChecks(
|
||||
** is different from old-rowid */
|
||||
if( isUpdate ){
|
||||
sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldData);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
}else{
|
||||
int x;
|
||||
@@ -1526,6 +1474,9 @@ void sqlite3GenerateConstraintChecks(
|
||||
sqlite3VdbeAddOp4(v, op,
|
||||
regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ
|
||||
);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
|
||||
VdbeCoverageIf(v, op==OP_Eq);
|
||||
VdbeCoverageIf(v, op==OP_Ne);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1597,14 +1548,17 @@ void sqlite3CompleteInsertion(
|
||||
int regData; /* Content registers (after the rowid) */
|
||||
int regRec; /* Register holding assemblied record for the table */
|
||||
int i; /* Loop counter */
|
||||
u8 bAffinityDone = 0; /* True if OP_Affinity has been run already */
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
assert( v!=0 );
|
||||
assert( pTab->pSelect==0 ); /* This table is not a VIEW */
|
||||
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||
if( aRegIdx[i]==0 ) continue;
|
||||
bAffinityDone = 1;
|
||||
if( pIdx->pPartIdxWhere ){
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i]);
|
||||
pik_flags = 0;
|
||||
@@ -1619,7 +1573,7 @@ void sqlite3CompleteInsertion(
|
||||
regData = regNewData + 1;
|
||||
regRec = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec);
|
||||
sqlite3TableAffinityStr(v, pTab);
|
||||
if( !bAffinityDone ) sqlite3TableAffinity(v, pTab, 0);
|
||||
sqlite3ExprCacheAffinityChange(pParse, regData, pTab->nCol);
|
||||
if( pParse->nested ){
|
||||
pik_flags = 0;
|
||||
@@ -1988,16 +1942,17 @@ static int xferOptimization(
|
||||
**
|
||||
** (3) onError is something other than OE_Abort and OE_Rollback.
|
||||
*/
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iDest, 0);
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iDest, 0); VdbeCoverage(v);
|
||||
emptyDestTest = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
}
|
||||
if( HasRowid(pSrc) ){
|
||||
sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead);
|
||||
emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0);
|
||||
emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
|
||||
if( pDest->iPKey>=0 ){
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
|
||||
addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid);
|
||||
VdbeCoverage(v);
|
||||
sqlite3RowidConstraint(pParse, onError, pDest);
|
||||
sqlite3VdbeJumpHere(v, addr2);
|
||||
autoIncStep(pParse, regAutoinc, regRowid);
|
||||
@@ -2011,7 +1966,7 @@ static int xferOptimization(
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
|
||||
sqlite3VdbeChangeP4(v, -1, pDest->zName, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
|
||||
}else{
|
||||
@@ -2030,10 +1985,10 @@ static int xferOptimization(
|
||||
sqlite3VdbeSetP4KeyInfo(pParse, pDestIdx);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR);
|
||||
VdbeComment((v, "%s", pDestIdx->zName));
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0);
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, regData);
|
||||
sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
|
||||
|
||||
+31
@@ -515,6 +515,13 @@ int sqlite3_config(int op, ...){
|
||||
}
|
||||
#endif
|
||||
|
||||
case SQLITE_CONFIG_WORKER_THREADS: {
|
||||
int n = va_arg(ap, int);
|
||||
if( n>SQLITE_MAX_WORKER_THREADS ) n = SQLITE_MAX_WORKER_THREADS;
|
||||
if( n>=0 ) sqlite3GlobalConfig.nWorker = n;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
rc = SQLITE_ERROR;
|
||||
break;
|
||||
@@ -800,6 +807,7 @@ static void disconnectAllVtab(sqlite3 *db){
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3VtabUnlockList(db);
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
#else
|
||||
UNUSED_PARAMETER(db);
|
||||
@@ -2496,6 +2504,7 @@ static int openDatabase(
|
||||
db->nextAutovac = -1;
|
||||
db->szMmap = sqlite3GlobalConfig.szMmap;
|
||||
db->nextPagesize = 0;
|
||||
db->nMaxSorterMmap = 0x7FFFFFFF;
|
||||
db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger | SQLITE_CacheSpill
|
||||
#if !defined(SQLITE_DEFAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX
|
||||
| SQLITE_AutoIndex
|
||||
@@ -3307,6 +3316,28 @@ int sqlite3_test_control(int op, ...){
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE, xCallback, ptr);
|
||||
**
|
||||
** Set the VDBE coverage callback function to xCallback with context
|
||||
** pointer ptr.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_VDBE_COVERAGE: {
|
||||
#ifdef SQLITE_VDBE_COVERAGE
|
||||
typedef void (*branch_callback)(void*,int,u8,u8);
|
||||
sqlite3GlobalConfig.xVdbeBranch = va_arg(ap,branch_callback);
|
||||
sqlite3GlobalConfig.pVdbeBranchArg = va_arg(ap,void*);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_SORTER_MMAP, db, nMax); */
|
||||
case SQLITE_TESTCTRL_SORTER_MMAP: {
|
||||
sqlite3 *db = va_arg(ap, sqlite3*);
|
||||
db->nMaxSorterMmap = va_arg(ap, int);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
va_end(ap);
|
||||
#endif /* SQLITE_OMIT_BUILTIN_TEST */
|
||||
|
||||
+14
-1
@@ -248,7 +248,7 @@ static void *memsys5MallocUnsafe(int nByte){
|
||||
** block. If not, then split a block of the next larger power of
|
||||
** two in order to create a new free block of size iLogsize.
|
||||
*/
|
||||
for(iBin=iLogsize; mem5.aiFreelist[iBin]<0 && iBin<=LOGMAX; iBin++){}
|
||||
for(iBin=iLogsize; iBin<=LOGMAX && mem5.aiFreelist[iBin]<0; iBin++){}
|
||||
if( iBin>LOGMAX ){
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes", nByte);
|
||||
@@ -275,6 +275,12 @@ static void *memsys5MallocUnsafe(int nByte){
|
||||
if( mem5.maxCount<mem5.currentCount ) mem5.maxCount = mem5.currentCount;
|
||||
if( mem5.maxOut<mem5.currentOut ) mem5.maxOut = mem5.currentOut;
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/* Make sure the allocated memory does not assume that it is set to zero
|
||||
** or retains a value from a previous allocation */
|
||||
memset(&mem5.zPool[i*mem5.szAtom], 0xAA, iFullSz);
|
||||
#endif
|
||||
|
||||
/* Return a pointer to the allocated memory. */
|
||||
return (void*)&mem5.zPool[i*mem5.szAtom];
|
||||
}
|
||||
@@ -332,6 +338,13 @@ static void memsys5FreeUnsafe(void *pOld){
|
||||
}
|
||||
size *= 2;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/* Overwrite freed memory with the 0x55 bit pattern to verify that it is
|
||||
** not used after being freed */
|
||||
memset(&mem5.zPool[iBlock*mem5.szAtom], 0x55, size);
|
||||
#endif
|
||||
|
||||
memsys5Link(iBlock, iLogsize);
|
||||
}
|
||||
|
||||
|
||||
+59
-23
@@ -323,6 +323,7 @@ static int posixFchown(int fd, uid_t uid, gid_t gid){
|
||||
|
||||
/* Forward reference */
|
||||
static int openDirectory(const char*, int*);
|
||||
static int unixGetpagesize(void);
|
||||
|
||||
/*
|
||||
** Many system calls are accessed through pointer-to-functions so that
|
||||
@@ -446,6 +447,9 @@ static struct unix_syscall {
|
||||
#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)
|
||||
#endif
|
||||
|
||||
{ "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 },
|
||||
#define osGetpagesize ((int(*)(void))aSyscall[24].pCurrent)
|
||||
|
||||
}; /* End of the overrideable system calls */
|
||||
|
||||
/*
|
||||
@@ -4105,6 +4109,36 @@ static int unixShmSystemLock(
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the system page size.
|
||||
**
|
||||
** This function should not be called directly by other code in this file.
|
||||
** Instead, it should be called via macro osGetpagesize().
|
||||
*/
|
||||
static int unixGetpagesize(void){
|
||||
#if defined(_BSD_SOURCE)
|
||||
return getpagesize();
|
||||
#else
|
||||
return (int)sysconf(_SC_PAGESIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the minimum number of 32KB shm regions that should be mapped at
|
||||
** a time, assuming that each mapping must be an integer multiple of the
|
||||
** current system page-size.
|
||||
**
|
||||
** Usually, this is 1. The exception seems to be systems that are configured
|
||||
** to use 64KB pages - in this case each mapping must cover at least two
|
||||
** shm regions.
|
||||
*/
|
||||
static int unixShmRegionPerMap(void){
|
||||
int shmsz = 32*1024; /* SHM region size */
|
||||
int pgsz = osGetpagesize(); /* System page size */
|
||||
assert( ((pgsz-1)&pgsz)==0 ); /* Page size must be a power of 2 */
|
||||
if( pgsz<shmsz ) return 1;
|
||||
return pgsz/shmsz;
|
||||
}
|
||||
|
||||
/*
|
||||
** Purge the unixShmNodeList list of all entries with unixShmNode.nRef==0.
|
||||
@@ -4116,10 +4150,11 @@ static void unixShmPurge(unixFile *pFd){
|
||||
unixShmNode *p = pFd->pInode->pShmNode;
|
||||
assert( unixMutexHeld() );
|
||||
if( p && p->nRef==0 ){
|
||||
int nShmPerMap = unixShmRegionPerMap();
|
||||
int i;
|
||||
assert( p->pInode==pFd->pInode );
|
||||
sqlite3_mutex_free(p->mutex);
|
||||
for(i=0; i<p->nRegion; i++){
|
||||
for(i=0; i<p->nRegion; i+=nShmPerMap){
|
||||
if( p->h>=0 ){
|
||||
osMunmap(p->apRegion[i], p->szRegion);
|
||||
}else{
|
||||
@@ -4326,6 +4361,8 @@ static int unixShmMap(
|
||||
unixShm *p;
|
||||
unixShmNode *pShmNode;
|
||||
int rc = SQLITE_OK;
|
||||
int nShmPerMap = unixShmRegionPerMap();
|
||||
int nReqRegion;
|
||||
|
||||
/* If the shared-memory file has not yet been opened, open it now. */
|
||||
if( pDbFd->pShm==0 ){
|
||||
@@ -4341,9 +4378,12 @@ static int unixShmMap(
|
||||
assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
|
||||
assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
|
||||
|
||||
if( pShmNode->nRegion<=iRegion ){
|
||||
/* Minimum number of regions required to be mapped. */
|
||||
nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap;
|
||||
|
||||
if( pShmNode->nRegion<nReqRegion ){
|
||||
char **apNew; /* New apRegion[] array */
|
||||
int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
|
||||
int nByte = nReqRegion*szRegion; /* Minimum required file size */
|
||||
struct stat sStat; /* Used by fstat() */
|
||||
|
||||
pShmNode->szRegion = szRegion;
|
||||
@@ -4392,17 +4432,19 @@ static int unixShmMap(
|
||||
|
||||
/* Map the requested memory region into this processes address space. */
|
||||
apNew = (char **)sqlite3_realloc(
|
||||
pShmNode->apRegion, (iRegion+1)*sizeof(char *)
|
||||
pShmNode->apRegion, nReqRegion*sizeof(char *)
|
||||
);
|
||||
if( !apNew ){
|
||||
rc = SQLITE_IOERR_NOMEM;
|
||||
goto shmpage_out;
|
||||
}
|
||||
pShmNode->apRegion = apNew;
|
||||
while(pShmNode->nRegion<=iRegion){
|
||||
while( pShmNode->nRegion<nReqRegion ){
|
||||
int nMap = szRegion*nShmPerMap;
|
||||
int i;
|
||||
void *pMem;
|
||||
if( pShmNode->h>=0 ){
|
||||
pMem = osMmap(0, szRegion,
|
||||
pMem = osMmap(0, nMap,
|
||||
pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE,
|
||||
MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion
|
||||
);
|
||||
@@ -4418,8 +4460,11 @@ static int unixShmMap(
|
||||
}
|
||||
memset(pMem, 0, szRegion);
|
||||
}
|
||||
pShmNode->apRegion[pShmNode->nRegion] = pMem;
|
||||
pShmNode->nRegion++;
|
||||
|
||||
for(i=0; i<nShmPerMap; i++){
|
||||
pShmNode->apRegion[pShmNode->nRegion+i] = &((char*)pMem)[szRegion*i];
|
||||
}
|
||||
pShmNode->nRegion += nShmPerMap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4633,19 +4678,6 @@ static void unixUnmapfile(unixFile *pFd){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the system page size.
|
||||
*/
|
||||
static int unixGetPagesize(void){
|
||||
#if HAVE_MREMAP
|
||||
return 512;
|
||||
#elif defined(_BSD_SOURCE)
|
||||
return getpagesize();
|
||||
#else
|
||||
return (int)sysconf(_SC_PAGESIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt to set the size of the memory mapping maintained by file
|
||||
** descriptor pFd to nNew bytes. Any existing mapping is discarded.
|
||||
@@ -4682,8 +4714,12 @@ static void unixRemapfile(
|
||||
if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
|
||||
|
||||
if( pOrig ){
|
||||
const int szSyspage = unixGetPagesize();
|
||||
#if HAVE_MREMAP
|
||||
i64 nReuse = pFd->mmapSize;
|
||||
#else
|
||||
const int szSyspage = osGetpagesize();
|
||||
i64 nReuse = (pFd->mmapSize & ~(szSyspage-1));
|
||||
#endif
|
||||
u8 *pReq = &pOrig[nReuse];
|
||||
|
||||
/* Unmap any pages of the existing mapping that cannot be reused. */
|
||||
@@ -7429,7 +7465,7 @@ int sqlite3_os_init(void){
|
||||
|
||||
/* Double-check that the aSyscall[] array has been constructed
|
||||
** correctly. See ticket [bb3a86e890c8e96ab] */
|
||||
assert( ArraySize(aSyscall)==24 );
|
||||
assert( ArraySize(aSyscall)==25 );
|
||||
|
||||
/* Register all VFSes defined in the aVfs[] array */
|
||||
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
|
||||
|
||||
+32
-5
@@ -1279,6 +1279,13 @@ void sqlite3_win32_sleep(DWORD milliseconds){
|
||||
#endif
|
||||
}
|
||||
|
||||
DWORD sqlite3Win32Wait(HANDLE hObject){
|
||||
DWORD rc;
|
||||
while( (rc = osWaitForSingleObjectEx(hObject, INFINITE,
|
||||
TRUE))==WAIT_IO_COMPLETION ){}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
|
||||
** or WinCE. Return false (zero) for Win95, Win98, or WinME.
|
||||
@@ -5135,15 +5142,29 @@ static int winFullPathname(
|
||||
** Interfaces for opening a shared library, finding entry points
|
||||
** within the shared library, and closing the shared library.
|
||||
*/
|
||||
/*
|
||||
** Interfaces for opening a shared library, finding entry points
|
||||
** within the shared library, and closing the shared library.
|
||||
*/
|
||||
static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
|
||||
HANDLE h;
|
||||
#if defined(__CYGWIN__)
|
||||
int nFull = pVfs->mxPathname+1;
|
||||
char *zFull = sqlite3MallocZero( nFull );
|
||||
void *zConverted = 0;
|
||||
if( zFull==0 ){
|
||||
OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0));
|
||||
return 0;
|
||||
}
|
||||
if( winFullPathname(pVfs, zFilename, nFull, zFull)!=SQLITE_OK ){
|
||||
sqlite3_free(zFull);
|
||||
OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0));
|
||||
return 0;
|
||||
}
|
||||
zConverted = winConvertFromUtf8Filename(zFull);
|
||||
sqlite3_free(zFull);
|
||||
#else
|
||||
void *zConverted = winConvertFromUtf8Filename(zFilename);
|
||||
UNUSED_PARAMETER(pVfs);
|
||||
#endif
|
||||
if( zConverted==0 ){
|
||||
OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0));
|
||||
return 0;
|
||||
}
|
||||
if( osIsNT() ){
|
||||
@@ -5158,6 +5179,7 @@ static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
|
||||
h = osLoadLibraryA((char*)zConverted);
|
||||
}
|
||||
#endif
|
||||
OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)h));
|
||||
sqlite3_free(zConverted);
|
||||
return (void*)h;
|
||||
}
|
||||
@@ -5166,12 +5188,17 @@ static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
|
||||
winGetLastErrorMsg(osGetLastError(), nBuf, zBufOut);
|
||||
}
|
||||
static void (*winDlSym(sqlite3_vfs *pVfs,void *pH,const char *zSym))(void){
|
||||
FARPROC proc;
|
||||
UNUSED_PARAMETER(pVfs);
|
||||
return (void(*)(void))osGetProcAddressA((HANDLE)pH, zSym);
|
||||
proc = osGetProcAddressA((HANDLE)pH, zSym);
|
||||
OSTRACE(("DLSYM handle=%p, symbol=%s, address=%p\n",
|
||||
(void*)pH, zSym, (void*)proc));
|
||||
return (void(*)(void))proc;
|
||||
}
|
||||
static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
|
||||
UNUSED_PARAMETER(pVfs);
|
||||
osFreeLibrary((HANDLE)pHandle);
|
||||
OSTRACE(("DLCLOSE handle=%p\n", (void*)pHandle));
|
||||
}
|
||||
#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
|
||||
#define winDlOpen 0
|
||||
|
||||
+10
-9
@@ -1624,12 +1624,11 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
|
||||
|
||||
if( !zMaster
|
||||
|| pPager->journalMode==PAGER_JOURNALMODE_MEMORY
|
||||
|| pPager->journalMode==PAGER_JOURNALMODE_OFF
|
||||
|| !isOpen(pPager->jfd)
|
||||
){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
pPager->setMaster = 1;
|
||||
assert( isOpen(pPager->jfd) );
|
||||
assert( pPager->journalHdr <= pPager->journalOff );
|
||||
|
||||
/* Calculate the length in bytes and the checksum of zMaster */
|
||||
@@ -4889,15 +4888,17 @@ static int hasHotJournal(Pager *pPager, int *pExists){
|
||||
if( rc==SQLITE_OK && !locked ){
|
||||
Pgno nPage; /* Number of pages in database file */
|
||||
|
||||
/* Check the size of the database file. If it consists of 0 pages,
|
||||
** then delete the journal file. See the header comment above for
|
||||
** the reasoning here. Delete the obsolete journal file under
|
||||
** a RESERVED lock to avoid race conditions and to avoid violating
|
||||
** [H33020].
|
||||
*/
|
||||
rc = pagerPagecount(pPager, &nPage);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( nPage==0 ){
|
||||
/* If the database is zero pages in size, that means that either (1) the
|
||||
** journal is a remnant from a prior database with the same name where
|
||||
** the database file but not the journal was deleted, or (2) the initial
|
||||
** transaction that populates a new database is being rolled back.
|
||||
** In either case, the journal file can be deleted. However, take care
|
||||
** not to delete the journal file if it is already open due to
|
||||
** journal_mode=PERSIST.
|
||||
*/
|
||||
if( nPage==0 && !jrnlOpen ){
|
||||
sqlite3BeginBenignMalloc();
|
||||
if( pagerLockDb(pPager, RESERVED_LOCK)==SQLITE_OK ){
|
||||
sqlite3OsDelete(pVfs, pPager->zJournal, 0);
|
||||
|
||||
+39
-4
@@ -437,14 +437,22 @@ select(A) ::= with(W) selectnowith(X). {
|
||||
selectnowith(A) ::= oneselect(X). {A = X;}
|
||||
%ifndef SQLITE_OMIT_COMPOUND_SELECT
|
||||
selectnowith(A) ::= selectnowith(X) multiselect_op(Y) oneselect(Z). {
|
||||
if( Z ){
|
||||
Z->op = (u8)Y;
|
||||
Z->pPrior = X;
|
||||
Select *pRhs = Z;
|
||||
if( pRhs && pRhs->pPrior ){
|
||||
SrcList *pFrom;
|
||||
Token x;
|
||||
x.n = 0;
|
||||
pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0,0);
|
||||
pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0,0);
|
||||
}
|
||||
if( pRhs ){
|
||||
pRhs->op = (u8)Y;
|
||||
pRhs->pPrior = X;
|
||||
if( Y!=TK_ALL ) pParse->hasCompound = 1;
|
||||
}else{
|
||||
sqlite3SelectDelete(pParse->db, X);
|
||||
}
|
||||
A = Z;
|
||||
A = pRhs;
|
||||
}
|
||||
%type multiselect_op {int}
|
||||
multiselect_op(A) ::= UNION(OP). {A = @OP;}
|
||||
@@ -1012,6 +1020,33 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
||||
*/
|
||||
A.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[N]);
|
||||
sqlite3ExprDelete(pParse->db, X.pExpr);
|
||||
}else if( Y->nExpr==1 ){
|
||||
/* Expressions of the form:
|
||||
**
|
||||
** expr1 IN (?1)
|
||||
** expr1 NOT IN (?2)
|
||||
**
|
||||
** with exactly one value on the RHS can be simplified to something
|
||||
** like this:
|
||||
**
|
||||
** expr1 == ?1
|
||||
** expr1 <> ?2
|
||||
**
|
||||
** But, the RHS of the == or <> is marked with the EP_Generic flag
|
||||
** so that it may not contribute to the computation of comparison
|
||||
** affinity or the collating sequence to use for comparison. Otherwise,
|
||||
** the semantics would be subtly different from IN or NOT IN.
|
||||
*/
|
||||
Expr *pRHS = Y->a[0].pExpr;
|
||||
Y->a[0].pExpr = 0;
|
||||
sqlite3ExprListDelete(pParse->db, Y);
|
||||
/* pRHS cannot be NULL because a malloc error would have been detected
|
||||
** before now and control would have never reached this point */
|
||||
if( ALWAYS(pRHS) ){
|
||||
pRHS->flags &= ~EP_Collate;
|
||||
pRHS->flags |= EP_Generic;
|
||||
}
|
||||
A.pExpr = sqlite3PExpr(pParse, N ? TK_NE : TK_EQ, X.pExpr, pRHS, 0);
|
||||
}else{
|
||||
A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0);
|
||||
if( A.pExpr ){
|
||||
|
||||
+31
-25
@@ -824,6 +824,7 @@ void sqlite3Pragma(
|
||||
** size of historical compatibility.
|
||||
*/
|
||||
case PragTyp_DEFAULT_CACHE_SIZE: {
|
||||
static const int iLn = VDBE_OFFSET_LINENO(2);
|
||||
static const VdbeOpList getCacheSize[] = {
|
||||
{ OP_Transaction, 0, 0, 0}, /* 0 */
|
||||
{ OP_ReadCookie, 0, 1, BTREE_DEFAULT_CACHE_SIZE}, /* 1 */
|
||||
@@ -841,7 +842,7 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cache_size", SQLITE_STATIC);
|
||||
pParse->nMem += 2;
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize,iLn);
|
||||
sqlite3VdbeChangeP1(v, addr, iDb);
|
||||
sqlite3VdbeChangeP1(v, addr+1, iDb);
|
||||
sqlite3VdbeChangeP1(v, addr+6, SQLITE_DEFAULT_CACHE_SIZE);
|
||||
@@ -1086,6 +1087,7 @@ void sqlite3Pragma(
|
||||
** file. Before writing to meta[6], check that meta[3] indicates
|
||||
** that this really is an auto-vacuum capable database.
|
||||
*/
|
||||
static const int iLn = VDBE_OFFSET_LINENO(2);
|
||||
static const VdbeOpList setMeta6[] = {
|
||||
{ OP_Transaction, 0, 1, 0}, /* 0 */
|
||||
{ OP_ReadCookie, 0, 1, BTREE_LARGEST_ROOT_PAGE},
|
||||
@@ -1095,7 +1097,7 @@ void sqlite3Pragma(
|
||||
{ OP_SetCookie, 0, BTREE_INCR_VACUUM, 1}, /* 5 */
|
||||
};
|
||||
int iAddr;
|
||||
iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6);
|
||||
iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6, iLn);
|
||||
sqlite3VdbeChangeP1(v, iAddr, iDb);
|
||||
sqlite3VdbeChangeP1(v, iAddr+1, iDb);
|
||||
sqlite3VdbeChangeP2(v, iAddr+2, iAddr+4);
|
||||
@@ -1121,10 +1123,10 @@ void sqlite3Pragma(
|
||||
}
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, iLimit, 1);
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IncrVacuum, iDb);
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IncrVacuum, iDb); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp1(v, OP_ResultRow, 1);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1);
|
||||
sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr);
|
||||
sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
break;
|
||||
}
|
||||
@@ -1695,7 +1697,7 @@ void sqlite3Pragma(
|
||||
assert( pParse->nErr>0 || pFK==0 );
|
||||
if( pFK ) break;
|
||||
if( pParse->nTab<i ) pParse->nTab = i;
|
||||
addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, 0);
|
||||
addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, 0); VdbeCoverage(v);
|
||||
for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){
|
||||
pParent = sqlite3FindTable(db, pFK->zTo, zDb);
|
||||
pIdx = 0;
|
||||
@@ -1711,26 +1713,26 @@ void sqlite3Pragma(
|
||||
if( iKey!=pTab->iPKey ){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, 0, iKey, regRow);
|
||||
sqlite3ColumnDefault(v, pTab, iKey, regRow);
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk);
|
||||
sqlite3VdbeAddOp2(v, OP_MustBeInt, regRow,
|
||||
sqlite3VdbeCurrentAddr(v)+3);
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_MustBeInt, regRow,
|
||||
sqlite3VdbeCurrentAddr(v)+3); VdbeCoverage(v);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, 0, regRow);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_NotExists, i, 0, regRow);
|
||||
sqlite3VdbeAddOp3(v, OP_NotExists, i, 0, regRow); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrOk);
|
||||
sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
|
||||
}else{
|
||||
for(j=0; j<pFK->nCol; j++){
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, 0,
|
||||
aiCols ? aiCols[j] : pFK->aCol[j].iFrom, regRow+j);
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk);
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v);
|
||||
}
|
||||
if( pParent ){
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regRow, pFK->nCol, regKey);
|
||||
sqlite3VdbeChangeP4(v, -1,
|
||||
sqlite3IndexAffinityStr(v,pIdx), P4_TRANSIENT);
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey,
|
||||
sqlite3IndexAffinityStr(v,pIdx), pFK->nCol);
|
||||
sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1);
|
||||
@@ -1741,7 +1743,7 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeResolveLabel(v, addrOk);
|
||||
sqlite3DbFree(db, aiCols);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Next, 0, addrTop+1);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, 0, addrTop+1); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, addrTop);
|
||||
}
|
||||
}
|
||||
@@ -1788,6 +1790,7 @@ void sqlite3Pragma(
|
||||
** messages have been generated, output OK. Otherwise output the
|
||||
** error message
|
||||
*/
|
||||
static const int iLn = VDBE_OFFSET_LINENO(2);
|
||||
static const VdbeOpList endCode[] = {
|
||||
{ OP_AddImm, 1, 0, 0}, /* 0 */
|
||||
{ OP_IfNeg, 1, 0, 0}, /* 1 */
|
||||
@@ -1836,6 +1839,7 @@ void sqlite3Pragma(
|
||||
|
||||
sqlite3CodeVerifySchema(pParse, i);
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Halt if out of errors */
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
|
||||
@@ -1867,11 +1871,11 @@ void sqlite3Pragma(
|
||||
/* Do the b-tree integrity checks */
|
||||
sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1);
|
||||
sqlite3VdbeChangeP5(v, (u8)i);
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2);
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
|
||||
sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName),
|
||||
P4_DYNAMIC);
|
||||
sqlite3VdbeAddOp2(v, OP_Move, 2, 4);
|
||||
sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
@@ -1889,6 +1893,7 @@ void sqlite3Pragma(
|
||||
if( pTab->pIndex==0 ) continue;
|
||||
pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Stop if out of errors */
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
sqlite3ExprCacheClear(pParse);
|
||||
@@ -1899,7 +1904,7 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */
|
||||
}
|
||||
pParse->nMem = MAX(pParse->nMem, 8+j);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v);
|
||||
loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
int jmp2, jmp3, jmp4;
|
||||
@@ -1909,7 +1914,7 @@ void sqlite3Pragma(
|
||||
pPrior = pIdx;
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1); /* increment entry count */
|
||||
jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, 0, r1,
|
||||
pIdx->nColumn);
|
||||
pIdx->nColumn); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, "row ", P4_STATIC);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
|
||||
@@ -1919,13 +1924,13 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, pIdx->zName, P4_TRANSIENT);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
|
||||
jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1);
|
||||
jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp0(v, OP_Halt);
|
||||
sqlite3VdbeJumpHere(v, jmp4);
|
||||
sqlite3VdbeJumpHere(v, jmp2);
|
||||
sqlite3VdbeResolveLabel(v, jmp3);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, loopTop-1);
|
||||
#ifndef SQLITE_OMIT_BTREECOUNT
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0,
|
||||
@@ -1933,10 +1938,11 @@ void sqlite3Pragma(
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
if( pPk==pIdx ) continue;
|
||||
addr = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr+2);
|
||||
sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr+2); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3);
|
||||
sqlite3VdbeAddOp3(v, OP_Eq, 8+j, addr+8, 3);
|
||||
sqlite3VdbeAddOp3(v, OP_Eq, 8+j, addr+8, 3); VdbeCoverage(v);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pIdx->zName, P4_TRANSIENT);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7);
|
||||
@@ -1945,7 +1951,7 @@ void sqlite3Pragma(
|
||||
#endif /* SQLITE_OMIT_BTREECOUNT */
|
||||
}
|
||||
}
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode);
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn);
|
||||
sqlite3VdbeChangeP2(v, addr, -mxErr);
|
||||
sqlite3VdbeJumpHere(v, addr+1);
|
||||
sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC);
|
||||
@@ -2083,7 +2089,7 @@ void sqlite3Pragma(
|
||||
{ OP_Integer, 0, 1, 0}, /* 1 */
|
||||
{ OP_SetCookie, 0, 0, 1}, /* 2 */
|
||||
};
|
||||
int addr = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie);
|
||||
int addr = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie, 0);
|
||||
sqlite3VdbeChangeP1(v, addr, iDb);
|
||||
sqlite3VdbeChangeP1(v, addr+1, sqlite3Atoi(zRight));
|
||||
sqlite3VdbeChangeP1(v, addr+2, iDb);
|
||||
@@ -2095,7 +2101,7 @@ void sqlite3Pragma(
|
||||
{ OP_ReadCookie, 0, 1, 0}, /* 1 */
|
||||
{ OP_ResultRow, 1, 1, 0}
|
||||
};
|
||||
int addr = sqlite3VdbeAddOpList(v, ArraySize(readCookie), readCookie);
|
||||
int addr = sqlite3VdbeAddOpList(v, ArraySize(readCookie), readCookie, 0);
|
||||
sqlite3VdbeChangeP1(v, addr, iDb);
|
||||
sqlite3VdbeChangeP1(v, addr+1, iDb);
|
||||
sqlite3VdbeChangeP3(v, addr+1, iCookie);
|
||||
|
||||
+84
-77
@@ -134,20 +134,6 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
|
||||
}
|
||||
#endif /* SQLITE_OMIT_FLOATING_POINT */
|
||||
|
||||
/*
|
||||
** Append N space characters to the given string buffer.
|
||||
*/
|
||||
void sqlite3AppendSpace(StrAccum *pAccum, int N){
|
||||
static const char zSpaces[] = " ";
|
||||
while( N>=(int)sizeof(zSpaces)-1 ){
|
||||
sqlite3StrAccumAppend(pAccum, zSpaces, sizeof(zSpaces)-1);
|
||||
N -= sizeof(zSpaces)-1;
|
||||
}
|
||||
if( N>0 ){
|
||||
sqlite3StrAccumAppend(pAccum, zSpaces, N);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the StrAccum object to an error mode.
|
||||
*/
|
||||
@@ -237,11 +223,9 @@ void sqlite3VXPrintf(
|
||||
}
|
||||
for(; (c=(*fmt))!=0; ++fmt){
|
||||
if( c!='%' ){
|
||||
int amt;
|
||||
bufpt = (char *)fmt;
|
||||
amt = 1;
|
||||
while( (c=(*++fmt))!='%' && c!=0 ) amt++;
|
||||
sqlite3StrAccumAppend(pAccum, bufpt, amt);
|
||||
while( (c=(*++fmt))!='%' && c!=0 ){};
|
||||
sqlite3StrAccumAppend(pAccum, bufpt, (int)(fmt - bufpt));
|
||||
if( c==0 ) break;
|
||||
}
|
||||
if( (c=(*++fmt))==0 ){
|
||||
@@ -422,10 +406,8 @@ void sqlite3VXPrintf(
|
||||
*(--bufpt) = zOrd[x*2];
|
||||
}
|
||||
{
|
||||
register const char *cset; /* Use registers for speed */
|
||||
register int base;
|
||||
cset = &aDigits[infop->charset];
|
||||
base = infop->base;
|
||||
const char *cset = &aDigits[infop->charset];
|
||||
u8 base = infop->base;
|
||||
do{ /* Convert to ascii */
|
||||
*(--bufpt) = cset[longvalue%base];
|
||||
longvalue = longvalue/base;
|
||||
@@ -729,29 +711,89 @@ void sqlite3VXPrintf(
|
||||
** "length" characters long. The field width is "width". Do
|
||||
** the output.
|
||||
*/
|
||||
if( !flag_leftjustify ){
|
||||
register int nspace;
|
||||
nspace = width-length;
|
||||
if( nspace>0 ){
|
||||
sqlite3AppendSpace(pAccum, nspace);
|
||||
}
|
||||
}
|
||||
if( length>0 ){
|
||||
sqlite3StrAccumAppend(pAccum, bufpt, length);
|
||||
}
|
||||
if( flag_leftjustify ){
|
||||
register int nspace;
|
||||
nspace = width-length;
|
||||
if( nspace>0 ){
|
||||
sqlite3AppendSpace(pAccum, nspace);
|
||||
}
|
||||
}
|
||||
width -= length;
|
||||
if( width>0 && !flag_leftjustify ) sqlite3AppendSpace(pAccum, width);
|
||||
sqlite3StrAccumAppend(pAccum, bufpt, length);
|
||||
if( width>0 && flag_leftjustify ) sqlite3AppendSpace(pAccum, width);
|
||||
|
||||
if( zExtra ) sqlite3_free(zExtra);
|
||||
}/* End for loop over the format string */
|
||||
} /* End of function */
|
||||
|
||||
/*
|
||||
** Append N bytes of text from z to the StrAccum object.
|
||||
** Enlarge the memory allocation on a StrAccum object so that it is
|
||||
** able to accept at least N more bytes of text.
|
||||
**
|
||||
** Return the number of bytes of text that StrAccum is able to accept
|
||||
** after the attempted enlargement. The value returned might be zero.
|
||||
*/
|
||||
static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
|
||||
char *zNew;
|
||||
assert( p->nChar+N >= p->nAlloc ); /* Only called if really needed */
|
||||
if( p->accError ){
|
||||
testcase(p->accError==STRACCUM_TOOBIG);
|
||||
testcase(p->accError==STRACCUM_NOMEM);
|
||||
return 0;
|
||||
}
|
||||
if( !p->useMalloc ){
|
||||
N = p->nAlloc - p->nChar - 1;
|
||||
setStrAccumError(p, STRACCUM_TOOBIG);
|
||||
return N;
|
||||
}else{
|
||||
char *zOld = (p->zText==p->zBase ? 0 : p->zText);
|
||||
i64 szNew = p->nChar;
|
||||
szNew += N + 1;
|
||||
if( szNew > p->mxAlloc ){
|
||||
sqlite3StrAccumReset(p);
|
||||
setStrAccumError(p, STRACCUM_TOOBIG);
|
||||
return 0;
|
||||
}else{
|
||||
p->nAlloc = (int)szNew;
|
||||
}
|
||||
if( p->useMalloc==1 ){
|
||||
zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
|
||||
}else{
|
||||
zNew = sqlite3_realloc(zOld, p->nAlloc);
|
||||
}
|
||||
if( zNew ){
|
||||
if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
|
||||
p->zText = zNew;
|
||||
}else{
|
||||
sqlite3StrAccumReset(p);
|
||||
setStrAccumError(p, STRACCUM_NOMEM);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return N;
|
||||
}
|
||||
|
||||
/*
|
||||
** Append N space characters to the given string buffer.
|
||||
*/
|
||||
void sqlite3AppendSpace(StrAccum *p, int N){
|
||||
if( p->nChar+N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ) return;
|
||||
while( (N--)>0 ) p->zText[p->nChar++] = ' ';
|
||||
}
|
||||
|
||||
/*
|
||||
** The StrAccum "p" is not large enough to accept N new bytes of z[].
|
||||
** So enlarge if first, then do the append.
|
||||
**
|
||||
** This is a helper routine to sqlite3StrAccumAppend() that does special-case
|
||||
** work (enlarging the buffer) using tail recursion, so that the
|
||||
** sqlite3StrAccumAppend() routine can use fast calling semantics.
|
||||
*/
|
||||
static void enlargeAndAppend(StrAccum *p, const char *z, int N){
|
||||
N = sqlite3StrAccumEnlarge(p, N);
|
||||
if( N>0 ){
|
||||
memcpy(&p->zText[p->nChar], z, N);
|
||||
p->nChar += N;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Append N bytes of text from z to the StrAccum object. Increase the
|
||||
** size of the memory allocation for StrAccum if necessary.
|
||||
*/
|
||||
void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
|
||||
assert( z!=0 );
|
||||
@@ -759,43 +801,8 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
|
||||
assert( N>=0 );
|
||||
assert( p->accError==0 || p->nAlloc==0 );
|
||||
if( p->nChar+N >= p->nAlloc ){
|
||||
char *zNew;
|
||||
if( p->accError ){
|
||||
testcase(p->accError==STRACCUM_TOOBIG);
|
||||
testcase(p->accError==STRACCUM_NOMEM);
|
||||
return;
|
||||
}
|
||||
if( !p->useMalloc ){
|
||||
N = p->nAlloc - p->nChar - 1;
|
||||
setStrAccumError(p, STRACCUM_TOOBIG);
|
||||
if( N<=0 ){
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
char *zOld = (p->zText==p->zBase ? 0 : p->zText);
|
||||
i64 szNew = p->nChar;
|
||||
szNew += N + 1;
|
||||
if( szNew > p->mxAlloc ){
|
||||
sqlite3StrAccumReset(p);
|
||||
setStrAccumError(p, STRACCUM_TOOBIG);
|
||||
return;
|
||||
}else{
|
||||
p->nAlloc = (int)szNew;
|
||||
}
|
||||
if( p->useMalloc==1 ){
|
||||
zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
|
||||
}else{
|
||||
zNew = sqlite3_realloc(zOld, p->nAlloc);
|
||||
}
|
||||
if( zNew ){
|
||||
if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
|
||||
p->zText = zNew;
|
||||
}else{
|
||||
sqlite3StrAccumReset(p);
|
||||
setStrAccumError(p, STRACCUM_NOMEM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
enlargeAndAppend(p,z,N);
|
||||
return;
|
||||
}
|
||||
assert( p->zText );
|
||||
memcpy(&p->zText[p->nChar], z, N);
|
||||
|
||||
+4
-2
@@ -337,6 +337,8 @@ static int lookupName(
|
||||
}else if( op!=TK_INSERT && sqlite3StrICmp("old",zTab)==0 ){
|
||||
pExpr->iTable = 0;
|
||||
pTab = pParse->pTriggerTab;
|
||||
}else{
|
||||
pTab = 0;
|
||||
}
|
||||
|
||||
if( pTab ){
|
||||
@@ -380,8 +382,8 @@ static int lookupName(
|
||||
/*
|
||||
** Perhaps the name is a reference to the ROWID
|
||||
*/
|
||||
assert( pTab!=0 || cntTab==0 );
|
||||
if( cnt==0 && cntTab==1 && sqlite3IsRowid(zCol) && HasRowid(pTab) ){
|
||||
if( cnt==0 && cntTab==1 && pMatch && sqlite3IsRowid(zCol)
|
||||
&& HasRowid(pMatch->pTab) ){
|
||||
cnt = 1;
|
||||
pExpr->iColumn = -1; /* IMP: R-44911-55124 */
|
||||
pExpr->affinity = SQLITE_AFF_INTEGER;
|
||||
|
||||
+324
-186
File diff suppressed because it is too large
Load Diff
+63
-19
@@ -45,14 +45,17 @@
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_EDITLINE
|
||||
# include <editline/editline.h>
|
||||
#endif
|
||||
#if defined(HAVE_READLINE) && HAVE_READLINE==1
|
||||
#if defined(HAVE_READLINE) && HAVE_READLINE!=0
|
||||
# include <readline/readline.h>
|
||||
# include <readline/history.h>
|
||||
#else
|
||||
# undef HAVE_READLINE
|
||||
#endif
|
||||
#if !defined(HAVE_EDITLINE) && (!defined(HAVE_READLINE) || HAVE_READLINE!=1)
|
||||
#if defined(HAVE_EDITLINE) && !defined(HAVE_READLINE)
|
||||
# define HAVE_READLINE 1
|
||||
# include <editline/readline.h>
|
||||
#endif
|
||||
#if !defined(HAVE_READLINE)
|
||||
# define add_history(X)
|
||||
# define read_history(X)
|
||||
# define write_history(X)
|
||||
@@ -62,7 +65,9 @@
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
# include <io.h>
|
||||
#define isatty(h) _isatty(h)
|
||||
#define access(f,m) _access((f),(m))
|
||||
#ifndef access
|
||||
# define access(f,m) _access((f),(m))
|
||||
#endif
|
||||
#undef popen
|
||||
#define popen _popen
|
||||
#undef pclose
|
||||
@@ -413,7 +418,7 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
|
||||
zResult = local_getline(zPrior, in);
|
||||
}else{
|
||||
zPrompt = isContinuation ? continuePrompt : mainPrompt;
|
||||
#if defined(HAVE_READLINE) && HAVE_READLINE==1
|
||||
#if defined(HAVE_READLINE)
|
||||
free(zPrior);
|
||||
zResult = readline(zPrompt);
|
||||
if( zResult && *zResult ) add_history(zResult);
|
||||
@@ -441,6 +446,7 @@ struct previous_mode_data {
|
||||
struct callback_data {
|
||||
sqlite3 *db; /* The database */
|
||||
int echoOn; /* True to echo input commands */
|
||||
int autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL statement */
|
||||
int statsOn; /* True to display memory stats before each finalize */
|
||||
int cnt; /* Number of records displayed so far */
|
||||
FILE *out; /* Write results here */
|
||||
@@ -1005,7 +1011,7 @@ static int run_table_dump_query(
|
||||
int nResult;
|
||||
int i;
|
||||
const char *z;
|
||||
rc = sqlite3_prepare(p->db, zSelect, -1, &pSelect, 0);
|
||||
rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0);
|
||||
if( rc!=SQLITE_OK || !pSelect ){
|
||||
fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
|
||||
if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
|
||||
@@ -1178,6 +1184,7 @@ static int str_in_array(const char *zStr, const char **azArray){
|
||||
** * For each "Goto", if the jump destination is earlier in the program
|
||||
** and ends on one of:
|
||||
** Yield SeekGt SeekLt RowSetRead Rewind
|
||||
** or if the P1 parameter is one instead of zero,
|
||||
** then indent all opcodes between the earlier instruction
|
||||
** and "Goto" by 2 spaces.
|
||||
*/
|
||||
@@ -1188,7 +1195,8 @@ static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
|
||||
int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */
|
||||
int iOp; /* Index of operation in p->aiIndent[] */
|
||||
|
||||
const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 0 };
|
||||
const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",
|
||||
"NextIfOpen", "PrevIfOpen", 0 };
|
||||
const char *azYield[] = { "Yield", "SeekLt", "SeekGt", "RowSetRead", "Rewind", 0 };
|
||||
const char *azGoto[] = { "Goto", 0 };
|
||||
|
||||
@@ -1225,7 +1233,9 @@ static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
|
||||
if( str_in_array(zOp, azNext) ){
|
||||
for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
|
||||
}
|
||||
if( str_in_array(zOp, azGoto) && p2op<p->nIndent && abYield[p2op] ){
|
||||
if( str_in_array(zOp, azGoto) && p2op<p->nIndent
|
||||
&& (abYield[p2op] || sqlite3_column_int(pSql, 2))
|
||||
){
|
||||
for(i=p2op+1; i<iOp; i++) p->aiIndent[i] += 2;
|
||||
}
|
||||
}
|
||||
@@ -1297,6 +1307,23 @@ static int shell_exec(
|
||||
fprintf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql);
|
||||
}
|
||||
|
||||
/* Show the EXPLAIN QUERY PLAN if .eqp is on */
|
||||
if( pArg && pArg->autoEQP ){
|
||||
sqlite3_stmt *pExplain;
|
||||
char *zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", sqlite3_sql(pStmt));
|
||||
rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
while( sqlite3_step(pExplain)==SQLITE_ROW ){
|
||||
fprintf(pArg->out,"--EQP-- %d,", sqlite3_column_int(pExplain, 0));
|
||||
fprintf(pArg->out,"%d,", sqlite3_column_int(pExplain, 1));
|
||||
fprintf(pArg->out,"%d,", sqlite3_column_int(pExplain, 2));
|
||||
fprintf(pArg->out,"%s\n", sqlite3_column_text(pExplain, 3));
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(pExplain);
|
||||
sqlite3_free(zEQP);
|
||||
}
|
||||
|
||||
/* Output TESTCTRL_EXPLAIN text of requested */
|
||||
if( pArg && pArg->mode==MODE_Explain ){
|
||||
const char *zExplain = 0;
|
||||
@@ -1453,7 +1480,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
|
||||
zTableInfo = appendText(zTableInfo, zTable, '"');
|
||||
zTableInfo = appendText(zTableInfo, ");", 0);
|
||||
|
||||
rc = sqlite3_prepare(p->db, zTableInfo, -1, &pTableInfo, 0);
|
||||
rc = sqlite3_prepare_v2(p->db, zTableInfo, -1, &pTableInfo, 0);
|
||||
free(zTableInfo);
|
||||
if( rc!=SQLITE_OK || !pTableInfo ){
|
||||
return 1;
|
||||
@@ -1890,7 +1917,7 @@ static char *csv_read_one_field(CSVReader *p){
|
||||
}
|
||||
if( c=='\n' ){
|
||||
p->nLine++;
|
||||
if( p->n>1 && p->z[p->n-1]=='\r' ) p->n--;
|
||||
if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
|
||||
}
|
||||
p->cTerm = c;
|
||||
}
|
||||
@@ -2103,10 +2130,12 @@ static void tryToClone(struct callback_data *p, const char *zNewDb){
|
||||
fprintf(stderr, "Cannot create output database: %s\n",
|
||||
sqlite3_errmsg(newDb));
|
||||
}else{
|
||||
sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0);
|
||||
sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
|
||||
tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
|
||||
tryToCloneSchema(p, newDb, "type!='table'", 0);
|
||||
sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
|
||||
sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
|
||||
}
|
||||
sqlite3_close(newDb);
|
||||
}
|
||||
@@ -2296,6 +2325,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
p->echoOn = booleanValue(azArg[1]);
|
||||
}else
|
||||
|
||||
if( c=='e' && strncmp(azArg[0], "eqp", n)==0 && nArg>1 && nArg<3 ){
|
||||
p->autoEQP = booleanValue(azArg[1]);
|
||||
}else
|
||||
|
||||
if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
|
||||
if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) exit(rc);
|
||||
rc = 2;
|
||||
@@ -2396,7 +2429,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
return 1;
|
||||
}
|
||||
nByte = strlen30(zSql);
|
||||
rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
||||
if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){
|
||||
char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
|
||||
char cSep = '(';
|
||||
@@ -2422,7 +2455,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
xCloser(sCsv.in);
|
||||
return 1;
|
||||
}
|
||||
rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
if( rc ){
|
||||
@@ -2449,7 +2482,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
}
|
||||
zSql[j++] = ')';
|
||||
zSql[j] = 0;
|
||||
rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
if( rc ){
|
||||
fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
|
||||
@@ -2868,6 +2901,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
if( c=='s' && strncmp(azArg[0], "show", n)==0 && nArg==1 ){
|
||||
int i;
|
||||
fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off");
|
||||
fprintf(p->out,"%9.9s: %s\n","eqp", p->autoEQP ? "on" : "off");
|
||||
fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" :"off");
|
||||
fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off");
|
||||
fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]);
|
||||
@@ -3500,7 +3534,8 @@ static void main_init(struct callback_data *data) {
|
||||
sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
|
||||
sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
|
||||
sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> ");
|
||||
sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
|
||||
sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
|
||||
sqlite3_config(SQLITE_CONFIG_WORKER_THREADS, 4);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3545,11 +3580,13 @@ int main(int argc, char **argv){
|
||||
int rc = 0;
|
||||
int warnInmemoryDb = 0;
|
||||
|
||||
#if USE_SYSTEM_SQLITE+0!=1
|
||||
if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){
|
||||
fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
|
||||
sqlite3_sourceid(), SQLITE_SOURCE_ID);
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
Argv0 = argv[0];
|
||||
main_init(&data);
|
||||
stdin_is_interactive = isatty(0);
|
||||
@@ -3642,6 +3679,11 @@ int main(int argc, char **argv){
|
||||
#else
|
||||
fprintf(stderr,"%s: Error: no database filename specified\n", Argv0);
|
||||
return 1;
|
||||
#endif
|
||||
#ifdef SQLITE_SHELL_DBNAME_PROC
|
||||
{ extern void SQLITE_SHELL_DBNAME_PROC(const char**);
|
||||
SQLITE_SHELL_DBNAME_PROC(&data.zDbFilename);
|
||||
warnInmemoryDb = 0; }
|
||||
#endif
|
||||
}
|
||||
data.out = stdout;
|
||||
@@ -3698,6 +3740,8 @@ int main(int argc, char **argv){
|
||||
data.showHeader = 0;
|
||||
}else if( strcmp(z,"-echo")==0 ){
|
||||
data.echoOn = 1;
|
||||
}else if( strcmp(z,"-eqp")==0 ){
|
||||
data.autoEQP = 1;
|
||||
}else if( strcmp(z,"-stats")==0 ){
|
||||
data.statsOn = 1;
|
||||
}else if( strcmp(z,"-bail")==0 ){
|
||||
@@ -3780,8 +3824,8 @@ int main(int argc, char **argv){
|
||||
);
|
||||
if( warnInmemoryDb ){
|
||||
printf("Connected to a ");
|
||||
printBold("transient in-memory database.");
|
||||
printf("\nUse \".open FILENAME\" to reopen on a "
|
||||
printBold("transient in-memory database");
|
||||
printf(".\nUse \".open FILENAME\" to reopen on a "
|
||||
"persistent database.\n");
|
||||
}
|
||||
zHome = find_home_dir();
|
||||
@@ -3791,7 +3835,7 @@ int main(int argc, char **argv){
|
||||
sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
|
||||
}
|
||||
}
|
||||
#if defined(HAVE_READLINE) && HAVE_READLINE==1
|
||||
#if defined(HAVE_READLINE)
|
||||
if( zHistory ) read_history(zHistory);
|
||||
#endif
|
||||
rc = process_input(&data, 0);
|
||||
|
||||
+14
-1
@@ -1715,6 +1715,16 @@ struct sqlite3_mem_methods {
|
||||
** SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value
|
||||
** that specifies the maximum size of the created heap.
|
||||
** </dl>
|
||||
**
|
||||
** [[SQLITE_CONFIG_WORKER_THREADS]]
|
||||
** <dt>SQLITE_CONFIG_WORKER_THREADS
|
||||
** <dd>^SQLITE_CONFIG_WORKER_THREADS takes a single argument of type int.
|
||||
** It is used to set the number of background worker threads that may be
|
||||
** launched when sorting large amounts of data. A value of 0 means launch
|
||||
** no background threads at all. The maximum number of background threads
|
||||
** allowed is configured at build-time by the SQLITE_MAX_WORKER_THREADS
|
||||
** pre-processor option.
|
||||
** </dl>
|
||||
*/
|
||||
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
|
||||
#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
|
||||
@@ -1739,6 +1749,7 @@ struct sqlite3_mem_methods {
|
||||
#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
|
||||
#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
|
||||
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
|
||||
#define SQLITE_CONFIG_WORKER_THREADS 24 /* int nWorker */
|
||||
|
||||
/*
|
||||
** CAPI3REF: Database Connection Configuration Options
|
||||
@@ -6117,7 +6128,9 @@ int sqlite3_test_control(int op, ...);
|
||||
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
|
||||
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19
|
||||
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20
|
||||
#define SQLITE_TESTCTRL_LAST 20
|
||||
#define SQLITE_TESTCTRL_VDBE_COVERAGE 21
|
||||
#define SQLITE_TESTCTRL_SORTER_MMAP 22
|
||||
#define SQLITE_TESTCTRL_LAST 22
|
||||
|
||||
/*
|
||||
** CAPI3REF: SQLite Runtime Status
|
||||
|
||||
+118
-38
@@ -12,7 +12,6 @@
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
*/
|
||||
#include "sqlite3.h"
|
||||
#ifndef _SQLITEINT_H_
|
||||
#define _SQLITEINT_H_
|
||||
|
||||
@@ -48,6 +47,44 @@
|
||||
# define _LARGEFILE_SOURCE 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** For MinGW, check to see if we can include the header file containing its
|
||||
** version information, among other things. Normally, this internal MinGW
|
||||
** header file would [only] be included automatically by other MinGW header
|
||||
** files; however, the contained version information is now required by this
|
||||
** header file to work around binary compatibility issues (see below) and
|
||||
** this is the only known way to reliably obtain it. This entire #if block
|
||||
** would be completely unnecessary if there was any other way of detecting
|
||||
** MinGW via their preprocessor (e.g. if they customized their GCC to define
|
||||
** some MinGW-specific macros). When compiling for MinGW, either the
|
||||
** _HAVE_MINGW_H or _HAVE__MINGW_H (note the extra underscore) macro must be
|
||||
** defined; otherwise, detection of conditions specific to MinGW will be
|
||||
** disabled.
|
||||
*/
|
||||
#if defined(_HAVE_MINGW_H)
|
||||
# include "mingw.h"
|
||||
#elif defined(_HAVE__MINGW_H)
|
||||
# include "_mingw.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** For MinGW version 4.x (and higher), check to see if the _USE_32BIT_TIME_T
|
||||
** define is required to maintain binary compatibility with the MSVC runtime
|
||||
** library in use (e.g. for Windows XP).
|
||||
*/
|
||||
#if !defined(_USE_32BIT_TIME_T) && !defined(_USE_64BIT_TIME_T) && \
|
||||
defined(_WIN32) && !defined(_WIN64) && \
|
||||
defined(__MINGW_MAJOR_VERSION) && __MINGW_MAJOR_VERSION >= 4 && \
|
||||
defined(__MSVCRT__)
|
||||
# define _USE_32BIT_TIME_T
|
||||
#endif
|
||||
|
||||
/* The public SQLite interface. The _FILE_OFFSET_BITS macro must appear
|
||||
** first in QNX. Also, the _USE_32BIT_TIME_T macro must appear first for
|
||||
** MinGW.
|
||||
*/
|
||||
#include "sqlite3.h"
|
||||
|
||||
/*
|
||||
** Include the configuration header output by 'configure' if we're using the
|
||||
** autoconf-based build
|
||||
@@ -385,6 +422,19 @@
|
||||
# define SQLITE_TEMP_STORE_xc 1 /* Exclude from ctime.c */
|
||||
#endif
|
||||
|
||||
/*
|
||||
** If no value has been provided for SQLITE_MAX_WORKER_THREADS, or if
|
||||
** SQLITE_TEMP_STORE is set to 3 (never use temporary files), set it
|
||||
** to zero.
|
||||
*/
|
||||
#if SQLITE_TEMP_STORE==3
|
||||
# undef SQLITE_MAX_WORKER_THREADS
|
||||
#endif
|
||||
#ifndef SQLITE_MAX_WORKER_THREADS
|
||||
# define SQLITE_MAX_WORKER_THREADS 0
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** GCC does not define the offsetof() macro so we'll have to do it
|
||||
** ourselves.
|
||||
@@ -751,6 +801,7 @@ typedef struct PrintfArguments PrintfArguments;
|
||||
typedef struct RowSet RowSet;
|
||||
typedef struct Savepoint Savepoint;
|
||||
typedef struct Select Select;
|
||||
typedef struct SQLiteThread SQLiteThread;
|
||||
typedef struct SelectDest SelectDest;
|
||||
typedef struct SrcList SrcList;
|
||||
typedef struct StrAccum StrAccum;
|
||||
@@ -930,6 +981,7 @@ struct sqlite3 {
|
||||
int nChange; /* Value returned by sqlite3_changes() */
|
||||
int nTotalChange; /* Value returned by sqlite3_total_changes() */
|
||||
int aLimit[SQLITE_N_LIMIT]; /* Limits */
|
||||
int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */
|
||||
struct sqlite3InitInfo { /* Information used during initialization */
|
||||
int newTnum; /* Rootpage of table being initialized */
|
||||
u8 iDb; /* Which db file is being initialized */
|
||||
@@ -1314,10 +1366,16 @@ struct CollSeq {
|
||||
/*
|
||||
** Additional bit values that can be ORed with an affinity without
|
||||
** changing the affinity.
|
||||
**
|
||||
** The SQLITE_NOTNULL flag is a combination of NULLEQ and JUMPIFNULL.
|
||||
** It causes an assert() to fire if either operand to a comparison
|
||||
** operator is NULL. It is added to certain comparison operators to
|
||||
** prove that the operands are always NOT NULL.
|
||||
*/
|
||||
#define SQLITE_JUMPIFNULL 0x08 /* jumps if either operand is NULL */
|
||||
#define SQLITE_STOREP2 0x10 /* Store result in reg[P2] rather than jump */
|
||||
#define SQLITE_NULLEQ 0x80 /* NULL=NULL */
|
||||
#define SQLITE_NOTNULL 0x88 /* Assert that operands are never NULL */
|
||||
|
||||
/*
|
||||
** An object of this type is created for each virtual table present in
|
||||
@@ -1576,19 +1634,20 @@ struct KeyInfo {
|
||||
**
|
||||
** This structure holds a record that has already been disassembled
|
||||
** into its constituent fields.
|
||||
**
|
||||
** The r1 and r2 member variables are only used by the optimized comparison
|
||||
** functions vdbeRecordCompareInt() and vdbeRecordCompareString().
|
||||
*/
|
||||
struct UnpackedRecord {
|
||||
KeyInfo *pKeyInfo; /* Collation and sort-order information */
|
||||
u16 nField; /* Number of entries in apMem[] */
|
||||
u8 flags; /* Boolean settings. UNPACKED_... below */
|
||||
i8 default_rc; /* Comparison result if keys are equal */
|
||||
u8 errCode; /* Error detected by xRecordCompare (CORRUPT or NOMEM) */
|
||||
Mem *aMem; /* Values */
|
||||
int r1; /* Value to return if (lhs > rhs) */
|
||||
int r2; /* Value to return if (rhs < lhs) */
|
||||
};
|
||||
|
||||
/*
|
||||
** Allowed values of UnpackedRecord.flags
|
||||
*/
|
||||
#define UNPACKED_INCRKEY 0x01 /* Make this key an epsilon larger */
|
||||
#define UNPACKED_PREFIX_MATCH 0x02 /* A prefix match is considered OK */
|
||||
|
||||
/*
|
||||
** Each SQL index is represented in memory by an
|
||||
@@ -1850,8 +1909,8 @@ struct Expr {
|
||||
#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 opeartor */
|
||||
/* unused 0x000200 */
|
||||
#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */
|
||||
#define EP_Generic 0x000200 /* Ignore COLLATE or affinity on this tree */
|
||||
#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 /* COLLATE, AS, or UNLIKELY */
|
||||
@@ -1915,7 +1974,6 @@ struct Expr {
|
||||
*/
|
||||
struct ExprList {
|
||||
int nExpr; /* Number of expressions on the list */
|
||||
int iECursor; /* VDBE Cursor associated with this ExprList */
|
||||
struct ExprList_item { /* For each expression in the list */
|
||||
Expr *pExpr; /* The list of expressions */
|
||||
char *zName; /* Token associated with this expression */
|
||||
@@ -2008,8 +2066,8 @@ typedef u64 Bitmask;
|
||||
** contains more than 63 columns and the 64-th or later column is used.
|
||||
*/
|
||||
struct SrcList {
|
||||
u8 nSrc; /* Number of tables or subqueries in the FROM clause */
|
||||
u8 nAlloc; /* Number of entries allocated in a[] below */
|
||||
int nSrc; /* Number of tables or subqueries in the FROM clause */
|
||||
u32 nAlloc; /* Number of entries allocated in a[] below */
|
||||
struct SrcList_item {
|
||||
Schema *pSchema; /* Schema to which this item is fixed */
|
||||
char *zDatabase; /* Name of database holding this table */
|
||||
@@ -2139,7 +2197,7 @@ struct Select {
|
||||
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
|
||||
u16 selFlags; /* Various SF_* values */
|
||||
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
|
||||
int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */
|
||||
int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */
|
||||
u64 nSelectRow; /* Estimated number of result rows */
|
||||
SrcList *pSrc; /* The FROM clause */
|
||||
Expr *pWhere; /* The WHERE clause */
|
||||
@@ -2163,9 +2221,9 @@ struct Select {
|
||||
#define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */
|
||||
#define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */
|
||||
#define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
|
||||
#define SF_UseSorter 0x0040 /* Sort using a sorter */
|
||||
/* 0x0040 NOT USED */
|
||||
#define SF_Values 0x0080 /* Synthesized from VALUES clause */
|
||||
#define SF_Materialize 0x0100 /* NOT USED */
|
||||
/* 0x0100 NOT USED */
|
||||
#define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
|
||||
#define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
|
||||
#define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */
|
||||
@@ -2218,13 +2276,15 @@ struct Select {
|
||||
** starting with pDest->iSdst.
|
||||
**
|
||||
** SRT_Table Store results in temporary table pDest->iSDParm.
|
||||
** This is like SRT_EphemTab except that the table
|
||||
** is assumed to already be open.
|
||||
** SRT_Fifo This is like SRT_EphemTab except that the table
|
||||
** is assumed to already be open. SRT_Fifo has
|
||||
** the additional property of being able to ignore
|
||||
** the ORDER BY clause.
|
||||
**
|
||||
** SRT_DistTable Store results in a temporary table pDest->iSDParm.
|
||||
** SRT_DistFifo Store results in a temporary table pDest->iSDParm.
|
||||
** But also use temporary table pDest->iSDParm+1 as
|
||||
** a record of all prior results and ignore any duplicate
|
||||
** rows. Name means: "Distinct Table".
|
||||
** rows. Name means: "Distinct Fifo".
|
||||
**
|
||||
** SRT_Queue Store results in priority queue pDest->iSDParm (really
|
||||
** an index). Append a sequence number so that all entries
|
||||
@@ -2238,19 +2298,20 @@ struct Select {
|
||||
#define SRT_Except 2 /* Remove result from a UNION index */
|
||||
#define SRT_Exists 3 /* Store 1 if the result is not empty */
|
||||
#define SRT_Discard 4 /* Do not save the results anywhere */
|
||||
#define SRT_Fifo 5 /* Store result as data with an automatic rowid */
|
||||
#define SRT_DistFifo 6 /* Like SRT_Fifo, but unique results only */
|
||||
#define SRT_Queue 7 /* Store result in an queue */
|
||||
#define SRT_DistQueue 8 /* Like SRT_Queue, but unique results only */
|
||||
|
||||
/* The ORDER BY clause is ignored for all of the above */
|
||||
#define IgnorableOrderby(X) ((X->eDest)<=SRT_Discard)
|
||||
#define IgnorableOrderby(X) ((X->eDest)<=SRT_DistQueue)
|
||||
|
||||
#define SRT_Output 5 /* Output each row of result */
|
||||
#define SRT_Mem 6 /* Store result in a memory cell */
|
||||
#define SRT_Set 7 /* Store results as keys in an index */
|
||||
#define SRT_EphemTab 8 /* Create transient tab and store like SRT_Table */
|
||||
#define SRT_Coroutine 9 /* Generate a single row of result */
|
||||
#define SRT_Table 10 /* Store result as data with an automatic rowid */
|
||||
#define SRT_DistTable 11 /* Like SRT_Table, but unique results only */
|
||||
#define SRT_Queue 12 /* Store result in an queue */
|
||||
#define SRT_DistQueue 13 /* Like SRT_Queue, but unique results only */
|
||||
#define SRT_Output 9 /* Output each row of result */
|
||||
#define SRT_Mem 10 /* Store result in a memory cell */
|
||||
#define SRT_Set 11 /* Store results as keys in an index */
|
||||
#define SRT_EphemTab 12 /* Create transient tab and store like SRT_Table */
|
||||
#define SRT_Coroutine 13 /* Generate a single row of result */
|
||||
#define SRT_Table 14 /* Store result as data with an automatic rowid */
|
||||
|
||||
/*
|
||||
** An instance of this object describes where to put of the results of
|
||||
@@ -2348,9 +2409,6 @@ struct Parse {
|
||||
u8 checkSchema; /* Causes schema cookie check after an error */
|
||||
u8 nested; /* Number of nested calls to the parser/code generator */
|
||||
u8 nTempReg; /* Number of temporary registers in aTempReg[] */
|
||||
u8 nTempInUse; /* Number of aTempReg[] currently checked out */
|
||||
u8 nColCache; /* Number of entries in aColCache[] */
|
||||
u8 iColCache; /* Next entry in aColCache[] to replace */
|
||||
u8 isMultiWrite; /* True if statement may modify/insert multiple rows */
|
||||
u8 mayAbort; /* True if statement may throw an ABORT exception */
|
||||
u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */
|
||||
@@ -2641,6 +2699,7 @@ struct Sqlite3Config {
|
||||
int nPage; /* Number of pages in pPage[] */
|
||||
int mxParserStack; /* maximum depth of the parser stack */
|
||||
int sharedCacheEnabled; /* true if shared-cache mode enabled */
|
||||
int nWorker; /* Number of worker threads to use */
|
||||
/* The above might be initialized to non-zero. The following need to always
|
||||
** initially be zero, however. */
|
||||
int isInit; /* True after initialization has finished */
|
||||
@@ -2657,6 +2716,13 @@ struct Sqlite3Config {
|
||||
void(*xSqllog)(void*,sqlite3*,const char*, int);
|
||||
void *pSqllogArg;
|
||||
#endif
|
||||
#ifdef SQLITE_VDBE_COVERAGE
|
||||
/* The following callback (if not NULL) is invoked on every VDBE branch
|
||||
** operation. Set the callback using SQLITE_TESTCTRL_VDBE_COVERAGE.
|
||||
*/
|
||||
void (*xVdbeBranch)(void*,int iSrcLine,u8 eThis,u8 eMx); /* Callback */
|
||||
void *pVdbeBranchArg; /* 1st argument */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -2990,7 +3056,6 @@ void sqlite3DeleteTable(sqlite3*, Table*);
|
||||
# define sqlite3AutoincrementBegin(X)
|
||||
# define sqlite3AutoincrementEnd(X)
|
||||
#endif
|
||||
int sqlite3CodeCoroutine(Parse*, Select*, SelectDest*);
|
||||
void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int);
|
||||
void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*);
|
||||
IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*);
|
||||
@@ -3038,11 +3103,12 @@ void sqlite3ExprCachePop(Parse*, int);
|
||||
void sqlite3ExprCacheRemove(Parse*, int, int);
|
||||
void sqlite3ExprCacheClear(Parse*);
|
||||
void sqlite3ExprCacheAffinityChange(Parse*, int, int);
|
||||
int sqlite3ExprCode(Parse*, Expr*, int);
|
||||
void sqlite3ExprCode(Parse*, Expr*, int);
|
||||
void sqlite3ExprCodeFactorable(Parse*, Expr*, int);
|
||||
void sqlite3ExprCodeAtInit(Parse*, Expr*, int, u8);
|
||||
int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
|
||||
int sqlite3ExprCodeTarget(Parse*, Expr*, int);
|
||||
int sqlite3ExprCodeAndCache(Parse*, Expr*, int);
|
||||
void sqlite3ExprCodeAndCache(Parse*, Expr*, int);
|
||||
int sqlite3ExprCodeExprList(Parse*, ExprList*, int, u8);
|
||||
#define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */
|
||||
#define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */
|
||||
@@ -3080,7 +3146,6 @@ int sqlite3ExprIsConstantNotJoin(Expr*);
|
||||
int sqlite3ExprIsConstantOrFunction(Expr*);
|
||||
int sqlite3ExprIsInteger(Expr*, int*);
|
||||
int sqlite3ExprCanBeNull(const Expr*);
|
||||
void sqlite3ExprCodeIsNullJump(Vdbe*, const Expr*, int, int);
|
||||
int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
|
||||
int sqlite3IsRowid(const char*);
|
||||
void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8);
|
||||
@@ -3224,7 +3289,7 @@ int sqlite3VarintLen(u64 v);
|
||||
|
||||
|
||||
const char *sqlite3IndexAffinityStr(Vdbe *, Index *);
|
||||
void sqlite3TableAffinityStr(Vdbe *, Table *);
|
||||
void sqlite3TableAffinity(Vdbe*, Table*, int);
|
||||
char sqlite3CompareAffinity(Expr *pExpr, char aff2);
|
||||
int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity);
|
||||
char sqlite3ExprAffinity(Expr *pExpr);
|
||||
@@ -3243,7 +3308,7 @@ int sqlite3ReadSchema(Parse *pParse);
|
||||
CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
|
||||
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
|
||||
CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
|
||||
Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, Token*);
|
||||
Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*);
|
||||
Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*);
|
||||
Expr *sqlite3ExprSkipCollate(Expr*);
|
||||
int sqlite3CheckCollSeq(Parse *, CollSeq *);
|
||||
@@ -3584,4 +3649,19 @@ SQLITE_EXTERN void (*sqlite3IoTrace)(const char*,...);
|
||||
#define MEMTYPE_PCACHE 0x08 /* Page cache allocations */
|
||||
#define MEMTYPE_DB 0x10 /* Uses sqlite3DbMalloc, not sqlite_malloc */
|
||||
|
||||
/*
|
||||
** Threading interface
|
||||
*/
|
||||
#if SQLITE_MAX_WORKER_THREADS>0
|
||||
int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*);
|
||||
int sqlite3ThreadJoin(SQLiteThread*, void**);
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Win32 interface
|
||||
*/
|
||||
#if SQLITE_OS_WIN
|
||||
DWORD sqlite3Win32Wait(HANDLE hObject);
|
||||
#endif
|
||||
|
||||
#endif /* _SQLITEINT_H_ */
|
||||
|
||||
@@ -3778,6 +3778,7 @@ int TCLSH_MAIN(int argc, char **argv){
|
||||
sqlite3_shutdown();
|
||||
|
||||
Tcl_FindExecutable(argv[0]);
|
||||
Tcl_SetSystemEncoding(NULL, "utf-8");
|
||||
interp = Tcl_CreateInterp();
|
||||
|
||||
#if TCLSH==2
|
||||
|
||||
+55
@@ -2703,6 +2703,46 @@ bad_args:
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: add_test_utf16bin_collate <db ptr>
|
||||
**
|
||||
** Add a utf-16 collation sequence named "utf16bin" to the database
|
||||
** handle. This collation sequence compares arguments in the same way as the
|
||||
** built-in collation "binary".
|
||||
*/
|
||||
static int test_utf16bin_collate_func(
|
||||
void *pCtx,
|
||||
int nA, const void *zA,
|
||||
int nB, const void *zB
|
||||
){
|
||||
int nCmp = (nA>nB ? nB : nA);
|
||||
int res = memcmp(zA, zB, nCmp);
|
||||
if( res==0 ) res = nA - nB;
|
||||
return res;
|
||||
}
|
||||
static int test_utf16bin_collate(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
|
||||
if( objc!=2 ) goto bad_args;
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
|
||||
rc = sqlite3_create_collation(db, "utf16bin", SQLITE_UTF16, 0,
|
||||
test_utf16bin_collate_func
|
||||
);
|
||||
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
|
||||
return TCL_OK;
|
||||
|
||||
bad_args:
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
** When the collation needed callback is invoked, record the name of
|
||||
** the requested collating function here. The recorded name is linked
|
||||
@@ -5844,6 +5884,7 @@ static int test_test_control(
|
||||
int i;
|
||||
} aVerb[] = {
|
||||
{ "SQLITE_TESTCTRL_LOCALTIME_FAULT", SQLITE_TESTCTRL_LOCALTIME_FAULT },
|
||||
{ "SQLITE_TESTCTRL_SORTER_MMAP", SQLITE_TESTCTRL_SORTER_MMAP },
|
||||
};
|
||||
int iVerb;
|
||||
int iFlag;
|
||||
@@ -5871,6 +5912,19 @@ static int test_test_control(
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, val);
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLITE_TESTCTRL_SORTER_MMAP: {
|
||||
int val;
|
||||
sqlite3 *db;
|
||||
if( objc!=4 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "DB LIMIT");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[2]), &db) ) return TCL_ERROR;
|
||||
if( Tcl_GetIntFromObj(interp, objv[3], &val) ) return TCL_ERROR;
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_SORTER_MMAP, db, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Tcl_ResetResult(interp);
|
||||
@@ -6481,6 +6535,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "add_test_collate", test_collate, 0 },
|
||||
{ "add_test_collate_needed", test_collate_needed, 0 },
|
||||
{ "add_test_function", test_function, 0 },
|
||||
{ "add_test_utf16bin_collate", test_utf16bin_collate, 0 },
|
||||
#endif
|
||||
{ "sqlite3_test_errstr", test_errstr, 0 },
|
||||
{ "tcl_variable_type", tcl_variable_type, 0 },
|
||||
|
||||
@@ -76,7 +76,6 @@ static int test_value_overhead(
|
||||
|
||||
val.flags = MEM_Str|MEM_Term|MEM_Static;
|
||||
val.z = "hello world";
|
||||
val.memType = MEM_Str;
|
||||
val.enc = SQLITE_UTF8;
|
||||
|
||||
for(i=0; i<repeat_count; i++){
|
||||
|
||||
@@ -99,6 +99,12 @@ static void set_options(Tcl_Interp *interp){
|
||||
Tcl_SetVar2(interp, "sqlite_options", "mmap", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#if SQLITE_MAX_WORKER_THREADS>0
|
||||
Tcl_SetVar2(interp, "sqlite_options", "worker_threads", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "worker_threads", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#if 1 /* def SQLITE_MEMDEBUG */
|
||||
Tcl_SetVar2(interp, "sqlite_options", "memdebug", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
|
||||
@@ -499,7 +499,6 @@ static void test_extract(
|
||||
mem.enc = ENC(db);
|
||||
pHdr += sqlite3GetVarint(pHdr, &iSerialType);
|
||||
pBody += sqlite3VdbeSerialGet(pBody, (u32)iSerialType, &mem);
|
||||
sqlite3VdbeMemStoreType(&mem);
|
||||
|
||||
if( iCurrent==iIdx ){
|
||||
sqlite3_result_value(context, &mem);
|
||||
@@ -549,7 +548,6 @@ static void test_decode(
|
||||
pHdr += sqlite3GetVarint(pHdr, &iSerialType);
|
||||
pBody += sqlite3VdbeSerialGet(pBody, (u32)iSerialType, &mem);
|
||||
|
||||
sqlite3VdbeMemStoreType(&mem);
|
||||
switch( sqlite3_value_type(&mem) ){
|
||||
case SQLITE_TEXT:
|
||||
pVal = Tcl_NewStringObj((const char*)sqlite3_value_text(&mem), -1);
|
||||
|
||||
@@ -91,6 +91,9 @@ static void statusFunc(
|
||||
/*
|
||||
** Extension load function.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int testloadext_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
@@ -109,6 +112,9 @@ int testloadext_init(
|
||||
/*
|
||||
** Another extension entry point. This one always fails.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int testbrokenext_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
|
||||
@@ -1253,6 +1253,32 @@ static int test_config_cis(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_config_worker_threads N
|
||||
*/
|
||||
static int test_config_worker_threads(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
int rc;
|
||||
int nThread;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "N");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetIntFromObj(interp, objv[1], &nThread) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
rc = sqlite3_config(SQLITE_CONFIG_WORKER_THREADS, nThread);
|
||||
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_dump_memsys3 FILENAME
|
||||
** sqlite3_dump_memsys5 FILENAME
|
||||
@@ -1506,6 +1532,7 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_config_error", test_config_error ,0 },
|
||||
{ "sqlite3_config_uri", test_config_uri ,0 },
|
||||
{ "sqlite3_config_cis", test_config_cis ,0 },
|
||||
{ "sqlite3_config_worker_threads", test_config_worker_threads ,0 },
|
||||
{ "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 },
|
||||
{ "sqlite3_dump_memsys3", test_dump_memsys3 ,3 },
|
||||
{ "sqlite3_dump_memsys5", test_dump_memsys3 ,5 },
|
||||
|
||||
+48
-1
@@ -67,6 +67,11 @@
|
||||
** test_syscall list
|
||||
** Return a list of all system calls. The list is constructed using
|
||||
** the xNextSystemCall() VFS method.
|
||||
**
|
||||
** test_syscall pagesize PGSZ
|
||||
** If PGSZ is a power of two greater than 256, install a wrapper around
|
||||
** OS function getpagesize() that reports the system page size as PGSZ.
|
||||
** Or, if PGSZ is less than zero, remove any wrapper already installed.
|
||||
*/
|
||||
|
||||
#include "sqliteInt.h"
|
||||
@@ -89,7 +94,9 @@ static struct TestSyscallGlobal {
|
||||
int bPersist; /* 1 for persistent errors, 0 for transient */
|
||||
int nCount; /* Fail after this many more calls */
|
||||
int nFail; /* Number of failures that have occurred */
|
||||
} gSyscall = { 0, 0 };
|
||||
int pgsz;
|
||||
sqlite3_syscall_ptr orig_getpagesize;
|
||||
} gSyscall = { 0, 0, 0, 0, 0 };
|
||||
|
||||
static int ts_open(const char *, int, int);
|
||||
static int ts_close(int fd);
|
||||
@@ -650,6 +657,45 @@ static int test_syscall_defaultvfs(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static int ts_getpagesize(void){
|
||||
return gSyscall.pgsz;
|
||||
}
|
||||
|
||||
static int test_syscall_pagesize(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
|
||||
int pgsz;
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "PGSZ");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetIntFromObj(interp, objv[2], &pgsz) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( pgsz<0 ){
|
||||
if( gSyscall.orig_getpagesize ){
|
||||
pVfs->xSetSystemCall(pVfs, "getpagesize", gSyscall.orig_getpagesize);
|
||||
}
|
||||
}else{
|
||||
if( pgsz<512 || (pgsz & (pgsz-1)) ){
|
||||
Tcl_AppendResult(interp, "pgsz out of range", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
gSyscall.orig_getpagesize = pVfs->xGetSystemCall(pVfs, "getpagesize");
|
||||
gSyscall.pgsz = pgsz;
|
||||
pVfs->xSetSystemCall(
|
||||
pVfs, "getpagesize", (sqlite3_syscall_ptr)ts_getpagesize
|
||||
);
|
||||
}
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static int test_syscall(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
@@ -668,6 +714,7 @@ static int test_syscall(
|
||||
{ "exists", test_syscall_exists },
|
||||
{ "list", test_syscall_list },
|
||||
{ "defaultvfs", test_syscall_defaultvfs },
|
||||
{ "pagesize", test_syscall_pagesize },
|
||||
{ 0, 0 }
|
||||
};
|
||||
int iCmd;
|
||||
|
||||
+220
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
** 2012 July 21
|
||||
**
|
||||
** 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 presents a simple cross-platform threading interface for
|
||||
** use internally by SQLite.
|
||||
**
|
||||
** A "thread" can be created using sqlite3ThreadCreate(). This thread
|
||||
** runs independently of its creator until it is joined using
|
||||
** sqlite3ThreadJoin(), at which point it terminates.
|
||||
**
|
||||
** Threads do not have to be real. It could be that the work of the
|
||||
** "thread" is done by the main thread at either the sqlite3ThreadCreate()
|
||||
** or sqlite3ThreadJoin() call. This is, in fact, what happens in
|
||||
** single threaded systems. Nothing in SQLite requires multiple threads.
|
||||
** This interface exists so that applications that want to take advantage
|
||||
** of multiple cores can do so, while also allowing applications to stay
|
||||
** single-threaded if desired.
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
#if SQLITE_MAX_WORKER_THREADS>0
|
||||
|
||||
/********************************* Unix Pthreads ****************************/
|
||||
#if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0
|
||||
|
||||
#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */
|
||||
#include <pthread.h>
|
||||
|
||||
/* A running thread */
|
||||
struct SQLiteThread {
|
||||
pthread_t tid;
|
||||
int done;
|
||||
void *pOut;
|
||||
};
|
||||
|
||||
/* Create a new thread */
|
||||
int sqlite3ThreadCreate(
|
||||
SQLiteThread **ppThread, /* OUT: Write the thread object here */
|
||||
void *(*xTask)(void*), /* Routine to run in a separate thread */
|
||||
void *pIn /* Argument passed into xTask() */
|
||||
){
|
||||
SQLiteThread *p;
|
||||
|
||||
assert( ppThread!=0 );
|
||||
assert( xTask!=0 );
|
||||
*ppThread = 0;
|
||||
p = sqlite3Malloc(sizeof(*p));
|
||||
if( p==0 ) return SQLITE_NOMEM;
|
||||
memset(p, 0, sizeof(*p));
|
||||
if( sqlite3GlobalConfig.bCoreMutex==0
|
||||
|| pthread_create(&p->tid, 0, xTask, pIn)!=0
|
||||
){
|
||||
p->done = 1;
|
||||
p->pOut = xTask(pIn);
|
||||
}
|
||||
*ppThread = p;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Get the results of the thread */
|
||||
int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
|
||||
int rc;
|
||||
|
||||
assert( ppOut!=0 );
|
||||
if( p==0 ) return SQLITE_NOMEM;
|
||||
if( p->done ){
|
||||
*ppOut = p->pOut;
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
rc = pthread_join(p->tid, ppOut);
|
||||
}
|
||||
sqlite3_free(p);
|
||||
return rc ? SQLITE_ERROR : SQLITE_OK;
|
||||
}
|
||||
|
||||
#endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */
|
||||
/******************************** End Unix Pthreads *************************/
|
||||
|
||||
|
||||
/********************************* Win32 Threads ****************************/
|
||||
#if SQLITE_OS_WIN && !SQLITE_OS_WINRT && SQLITE_THREADSAFE>0
|
||||
|
||||
#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */
|
||||
#include <process.h>
|
||||
|
||||
/* A running thread */
|
||||
struct SQLiteThread {
|
||||
uintptr_t tid; /* The thread handle */
|
||||
void *(*xTask)(void*); /* The routine to run as a thread */
|
||||
void *pIn; /* Argument to xTask */
|
||||
void *pResult; /* Result of xTask */
|
||||
};
|
||||
|
||||
/* Thread procedure Win32 compatibility shim */
|
||||
static void sqlite3ThreadProc(
|
||||
void *pArg /* IN: Pointer to the SQLiteThread structure */
|
||||
){
|
||||
SQLiteThread *p = (SQLiteThread *)pArg;
|
||||
|
||||
assert( p!=0 );
|
||||
assert( p->xTask!=0 );
|
||||
p->pResult = p->xTask(p->pIn);
|
||||
_endthread();
|
||||
}
|
||||
|
||||
/* Create a new thread */
|
||||
int sqlite3ThreadCreate(
|
||||
SQLiteThread **ppThread, /* OUT: Write the thread object here */
|
||||
void *(*xTask)(void*), /* Routine to run in a separate thread */
|
||||
void *pIn /* Argument passed into xTask() */
|
||||
){
|
||||
SQLiteThread *p;
|
||||
|
||||
assert( ppThread!=0 );
|
||||
assert( xTask!=0 );
|
||||
*ppThread = 0;
|
||||
p = sqlite3Malloc(sizeof(*p));
|
||||
if( p==0 ) return SQLITE_NOMEM;
|
||||
if( sqlite3GlobalConfig.bCoreMutex==0 ){
|
||||
memset(p, 0, sizeof(*p));
|
||||
}else{
|
||||
p->xTask = xTask;
|
||||
p->pIn = pIn;
|
||||
p->tid = _beginthread(sqlite3ThreadProc, 0, p);
|
||||
if( p->tid==(uintptr_t)-1 ){
|
||||
memset(p, 0, sizeof(*p));
|
||||
}
|
||||
}
|
||||
if( p->xTask==0 ){
|
||||
p->pResult = xTask(pIn);
|
||||
}
|
||||
*ppThread = p;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Get the results of the thread */
|
||||
int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
|
||||
DWORD rc;
|
||||
|
||||
assert( ppOut!=0 );
|
||||
if( p==0 ) return SQLITE_NOMEM;
|
||||
if( p->xTask==0 ){
|
||||
rc = WAIT_OBJECT_0;
|
||||
}else{
|
||||
rc = sqlite3Win32Wait((HANDLE)p->tid);
|
||||
assert( rc!=WAIT_IO_COMPLETION );
|
||||
}
|
||||
if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult;
|
||||
sqlite3_free(p);
|
||||
return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR;
|
||||
}
|
||||
|
||||
#endif /* SQLITE_OS_WIN && !SQLITE_OS_WINRT */
|
||||
/******************************** End Win32 Threads *************************/
|
||||
|
||||
|
||||
/********************************* Single-Threaded **************************/
|
||||
#ifndef SQLITE_THREADS_IMPLEMENTED
|
||||
/*
|
||||
** This implementation does not actually create a new thread. It does the
|
||||
** work of the thread in the main thread, when either the thread is created
|
||||
** or when it is joined
|
||||
*/
|
||||
|
||||
/* A running thread */
|
||||
struct SQLiteThread {
|
||||
void *(*xTask)(void*); /* The routine to run as a thread */
|
||||
void *pIn; /* Argument to xTask */
|
||||
void *pResult; /* Result of xTask */
|
||||
};
|
||||
|
||||
/* Create a new thread */
|
||||
int sqlite3ThreadCreate(
|
||||
SQLiteThread **ppThread, /* OUT: Write the thread object here */
|
||||
void *(*xTask)(void*), /* Routine to run in a separate thread */
|
||||
void *pIn /* Argument passed into xTask() */
|
||||
){
|
||||
SQLiteThread *p;
|
||||
|
||||
assert( ppThread!=0 );
|
||||
assert( xTask!=0 );
|
||||
*ppThread = 0;
|
||||
p = sqlite3Malloc(sizeof(*p));
|
||||
if( p==0 ) return SQLITE_NOMEM;
|
||||
if( (SQLITE_PTR_TO_INT(p)/17)&1 ){
|
||||
p->xTask = xTask;
|
||||
p->pIn = pIn;
|
||||
}else{
|
||||
p->xTask = 0;
|
||||
p->pResult = xTask(pIn);
|
||||
}
|
||||
*ppThread = p;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Get the results of the thread */
|
||||
int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
|
||||
assert( ppOut!=0 );
|
||||
if( p==0 ) return SQLITE_NOMEM;
|
||||
if( p->xTask ){
|
||||
*ppOut = p->xTask(p->pIn);
|
||||
}else{
|
||||
*ppOut = p->pResult;
|
||||
}
|
||||
sqlite3_free(p);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
#endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */
|
||||
/****************************** End Single-Threaded *************************/
|
||||
#endif /* SQLITE_MAX_WORKER_THREADS>0 */
|
||||
+2
-1
@@ -566,6 +566,7 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
|
||||
assert( pTable!=0 );
|
||||
if( (v = sqlite3GetVdbe(pParse))!=0 ){
|
||||
int base;
|
||||
static const int iLn = VDBE_OFFSET_LINENO(2);
|
||||
static const VdbeOpList dropTrigger[] = {
|
||||
{ OP_Rewind, 0, ADDR(9), 0},
|
||||
{ OP_String8, 0, 1, 0}, /* 1 */
|
||||
@@ -580,7 +581,7 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
|
||||
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3OpenMasterTable(pParse, iDb);
|
||||
base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger);
|
||||
base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger, iLn);
|
||||
sqlite3VdbeChangeP4(v, base+1, pTrigger->zName, P4_TRANSIENT);
|
||||
sqlite3VdbeChangeP4(v, base+4, "trigger", P4_STATIC);
|
||||
sqlite3ChangeCookie(pParse, iDb);
|
||||
|
||||
+15
-8
@@ -390,7 +390,7 @@ void sqlite3Update(
|
||||
regKey = iPk;
|
||||
}else{
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey,
|
||||
sqlite3IndexAffinityStr(v, pPk), P4_TRANSIENT);
|
||||
sqlite3IndexAffinityStr(v, pPk), nPk);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iEph, regKey);
|
||||
}
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
@@ -434,18 +434,23 @@ void sqlite3Update(
|
||||
if( aToOpen[iDataCur-iBaseCur] ){
|
||||
assert( pPk!=0 );
|
||||
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey, nKey);
|
||||
VdbeCoverageNeverTaken(v);
|
||||
}
|
||||
labelContinue = labelBreak;
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak);
|
||||
VdbeCoverage(v);
|
||||
}else if( pPk ){
|
||||
labelContinue = sqlite3VdbeMakeLabel(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v);
|
||||
addrTop = sqlite3VdbeAddOp2(v, OP_RowKey, iEph, regKey);
|
||||
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey, 0);
|
||||
VdbeCoverage(v);
|
||||
}else{
|
||||
labelContinue = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet, labelBreak,
|
||||
regOldRowid);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
|
||||
/* If the record number will change, set register regNewRowid to
|
||||
@@ -455,7 +460,7 @@ void sqlite3Update(
|
||||
assert( chngKey || pTrigger || hasFK || regOldRowid==regNewRowid );
|
||||
if( chngRowid ){
|
||||
sqlite3ExprCode(pParse, pRowidExpr, regNewRowid);
|
||||
sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid);
|
||||
sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid); VdbeCoverage(v);
|
||||
}
|
||||
|
||||
/* Compute the old pre-UPDATE content of the row being changed, if that
|
||||
@@ -524,8 +529,7 @@ void sqlite3Update(
|
||||
** verified. One could argue that this is wrong.
|
||||
*/
|
||||
if( tmask&TRIGGER_BEFORE ){
|
||||
sqlite3VdbeAddOp2(v, OP_Affinity, regNew, pTab->nCol);
|
||||
sqlite3TableAffinityStr(v, pTab);
|
||||
sqlite3TableAffinity(v, pTab, regNew);
|
||||
sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
|
||||
TRIGGER_BEFORE, pTab, regOldRowid, onError, labelContinue);
|
||||
|
||||
@@ -537,8 +541,10 @@ void sqlite3Update(
|
||||
*/
|
||||
if( pPk ){
|
||||
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue,regKey,nKey);
|
||||
VdbeCoverage(v);
|
||||
}else{
|
||||
sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
|
||||
/* If it did not delete it, the row-trigger may still have modified
|
||||
@@ -574,6 +580,7 @@ void sqlite3Update(
|
||||
}else{
|
||||
j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, 0, regOldRowid);
|
||||
}
|
||||
VdbeCoverageNeverTaken(v);
|
||||
}
|
||||
sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, aRegIdx);
|
||||
|
||||
@@ -617,7 +624,7 @@ void sqlite3Update(
|
||||
/* Nothing to do at end-of-loop for a single-pass */
|
||||
}else if( pPk ){
|
||||
sqlite3VdbeResolveLabel(v, labelContinue);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop); VdbeCoverage(v);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, labelContinue);
|
||||
}
|
||||
@@ -746,7 +753,7 @@ static void updateVirtualTable(
|
||||
/* Generate code to scan the ephemeral table and call VUpdate. */
|
||||
iReg = ++pParse->nMem;
|
||||
pParse->nMem += pTab->nCol+1;
|
||||
addr = sqlite3VdbeAddOp2(v, OP_Rewind, ephemTab, 0);
|
||||
addr = sqlite3VdbeAddOp2(v, OP_Rewind, ephemTab, 0); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, ephemTab, 0, iReg);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, ephemTab, (pRowid?1:0), iReg+1);
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
@@ -756,7 +763,7 @@ static void updateVirtualTable(
|
||||
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2, iReg, pVTab, P4_VTAB);
|
||||
sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError);
|
||||
sqlite3MayAbort(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);
|
||||
|
||||
|
||||
@@ -317,7 +317,7 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem);
|
||||
pMem->enc = desiredEnc;
|
||||
pMem->flags |= (MEM_Term|MEM_Dyn);
|
||||
pMem->flags |= (MEM_Term);
|
||||
pMem->z = (char*)zOut;
|
||||
pMem->zMalloc = pMem->z;
|
||||
|
||||
@@ -445,7 +445,6 @@ char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte, u8 enc){
|
||||
}
|
||||
assert( (m.flags & MEM_Term)!=0 || db->mallocFailed );
|
||||
assert( (m.flags & MEM_Str)!=0 || db->mallocFailed );
|
||||
assert( (m.flags & MEM_Dyn)!=0 || db->mallocFailed );
|
||||
assert( m.z || db->mallocFailed );
|
||||
return m.z;
|
||||
}
|
||||
|
||||
+320
-167
File diff suppressed because it is too large
Load Diff
+46
-3
@@ -65,9 +65,12 @@ struct VdbeOp {
|
||||
char *zComment; /* Comment to improve readability */
|
||||
#endif
|
||||
#ifdef VDBE_PROFILE
|
||||
int cnt; /* Number of times this instruction was executed */
|
||||
u32 cnt; /* Number of times this instruction was executed */
|
||||
u64 cycles; /* Total time spent executing this instruction */
|
||||
#endif
|
||||
#ifdef SQLITE_VDBE_COVERAGE
|
||||
int iSrcLine; /* Source-code line that generated this opcode */
|
||||
#endif
|
||||
};
|
||||
typedef struct VdbeOp VdbeOp;
|
||||
|
||||
@@ -167,7 +170,7 @@ int sqlite3VdbeAddOp2(Vdbe*,int,int,int);
|
||||
int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
|
||||
int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
|
||||
int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int);
|
||||
int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
|
||||
int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno);
|
||||
void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
|
||||
void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1);
|
||||
void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2);
|
||||
@@ -208,9 +211,12 @@ void sqlite3VdbeSetVarmask(Vdbe*, int);
|
||||
#endif
|
||||
|
||||
void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*);
|
||||
int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*);
|
||||
int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*,int);
|
||||
UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **);
|
||||
|
||||
typedef int (*RecordCompare)(int,const void*,UnpackedRecord*,int);
|
||||
RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*);
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *);
|
||||
#endif
|
||||
@@ -238,4 +244,41 @@ void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *);
|
||||
# define VdbeModuleComment(X)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The VdbeCoverage macros are used to set a coverage testing point
|
||||
** for VDBE branch instructions. The coverage testing points are line
|
||||
** numbers in the sqlite3.c source file. VDBE branch coverage testing
|
||||
** only works with an amalagmation build. That's ok since a VDBE branch
|
||||
** coverage build designed for testing the test suite only. No application
|
||||
** should ever ship with VDBE branch coverage measuring turned on.
|
||||
**
|
||||
** VdbeCoverage(v) // Mark the previously coded instruction
|
||||
** // as a branch
|
||||
**
|
||||
** VdbeCoverageIf(v, conditional) // Mark previous if conditional true
|
||||
**
|
||||
** VdbeCoverageAlwaysTaken(v) // Previous branch is always taken
|
||||
**
|
||||
** VdbeCoverageNeverTaken(v) // Previous branch is never taken
|
||||
**
|
||||
** Every VDBE branch operation must be tagged with one of the macros above.
|
||||
** If not, then when "make test" is run with -DSQLITE_VDBE_COVERAGE and
|
||||
** -DSQLITE_DEBUG then an ALWAYS() will fail in the vdbeTakeBranch()
|
||||
** routine in vdbe.c, alerting the developer to the missed tag.
|
||||
*/
|
||||
#ifdef SQLITE_VDBE_COVERAGE
|
||||
void sqlite3VdbeSetLineNumber(Vdbe*,int);
|
||||
# define VdbeCoverage(v) sqlite3VdbeSetLineNumber(v,__LINE__)
|
||||
# define VdbeCoverageIf(v,x) if(x)sqlite3VdbeSetLineNumber(v,__LINE__)
|
||||
# define VdbeCoverageAlwaysTaken(v) sqlite3VdbeSetLineNumber(v,2);
|
||||
# define VdbeCoverageNeverTaken(v) sqlite3VdbeSetLineNumber(v,1);
|
||||
# define VDBE_OFFSET_LINENO(x) (__LINE__+x)
|
||||
#else
|
||||
# define VdbeCoverage(v)
|
||||
# define VdbeCoverageIf(v,x)
|
||||
# define VdbeCoverageAlwaysTaken(v)
|
||||
# define VdbeCoverageNeverTaken(v)
|
||||
# define VDBE_OFFSET_LINENO(x) 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
+6
-5
@@ -72,6 +72,7 @@ struct VdbeCursor {
|
||||
u8 nullRow; /* True if pointing to a row with no data */
|
||||
u8 rowidIsValid; /* True if lastRowid is valid */
|
||||
u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
|
||||
Bool isEphemeral:1; /* True for an ephemeral table */
|
||||
Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
|
||||
Bool isTable:1; /* True if a table requiring integer keys */
|
||||
Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */
|
||||
@@ -168,7 +169,6 @@ struct Mem {
|
||||
} u;
|
||||
int n; /* Number of characters in string value, excluding '\0' */
|
||||
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
|
||||
u8 memType; /* Lower 5 bits of flags */
|
||||
u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
|
||||
#ifdef SQLITE_DEBUG
|
||||
Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */
|
||||
@@ -195,6 +195,7 @@ struct Mem {
|
||||
#define MEM_Int 0x0004 /* Value is an integer */
|
||||
#define MEM_Real 0x0008 /* Value is a real number */
|
||||
#define MEM_Blob 0x0010 /* Value is a BLOB */
|
||||
#define MEM_AffMask 0x001f /* Mask of affinity bits */
|
||||
#define MEM_RowSet 0x0020 /* Value is a RowSet object */
|
||||
#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */
|
||||
#define MEM_Undefined 0x0080 /* Value is undefined */
|
||||
@@ -208,7 +209,7 @@ struct Mem {
|
||||
** string is \000 or \u0000 terminated
|
||||
*/
|
||||
#define MEM_Term 0x0200 /* String rep is nul terminated */
|
||||
#define MEM_Dyn 0x0400 /* Need to call sqliteFree() on Mem.z */
|
||||
#define MEM_Dyn 0x0400 /* Need to call Mem.xDel() on Mem.z */
|
||||
#define MEM_Static 0x0800 /* Mem.z points to a static string */
|
||||
#define MEM_Ephem 0x1000 /* Mem.z points to an ephemeral string */
|
||||
#define MEM_Agg 0x2000 /* Mem.z points to an agg function context */
|
||||
@@ -434,11 +435,10 @@ int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
|
||||
int sqlite3VdbeCloseStatement(Vdbe *, int);
|
||||
void sqlite3VdbeFrameDelete(VdbeFrame*);
|
||||
int sqlite3VdbeFrameRestore(VdbeFrame *);
|
||||
#define sqlite3VdbeMemStoreType(X) (X)->memType = (u8)((X)->flags&0x1f)
|
||||
/* void sqlite3VdbeMemStoreType(Mem *pMem); */
|
||||
int sqlite3VdbeTransferError(Vdbe *p);
|
||||
|
||||
int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *);
|
||||
int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *);
|
||||
void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *);
|
||||
void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *);
|
||||
int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *);
|
||||
int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *);
|
||||
@@ -456,6 +456,7 @@ int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *);
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
void sqlite3VdbeMemAboutToChange(Vdbe*,Mem*);
|
||||
int sqlite3VdbeCheckMemInvariants(Mem*);
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
||||
|
||||
+26
-24
@@ -135,7 +135,6 @@ const void *sqlite3_value_blob(sqlite3_value *pVal){
|
||||
Mem *p = (Mem*)pVal;
|
||||
if( p->flags & (MEM_Blob|MEM_Str) ){
|
||||
sqlite3VdbeMemExpandBlob(p);
|
||||
p->flags &= ~MEM_Str;
|
||||
p->flags |= MEM_Blob;
|
||||
return p->n ? p->z : 0;
|
||||
}else{
|
||||
@@ -206,7 +205,7 @@ int sqlite3_value_type(sqlite3_value* pVal){
|
||||
SQLITE_INTEGER, /* 0x1e */
|
||||
SQLITE_NULL, /* 0x1f */
|
||||
};
|
||||
return aType[pVal->memType&0x1f];
|
||||
return aType[pVal->flags&MEM_AffMask];
|
||||
}
|
||||
|
||||
/**************************** sqlite3_result_ *******************************
|
||||
@@ -727,6 +726,30 @@ int sqlite3_data_count(sqlite3_stmt *pStmt){
|
||||
return pVm->nResColumn;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to static memory containing an SQL NULL value.
|
||||
*/
|
||||
static const Mem *columnNullValue(void){
|
||||
/* Even though the Mem structure contains an element
|
||||
** of type i64, on certain architectures (x86) with certain compiler
|
||||
** switches (-Os), gcc may align this Mem object on a 4-byte boundary
|
||||
** instead of an 8-byte one. This all works fine, except that when
|
||||
** running with SQLITE_DEBUG defined the SQLite code sometimes assert()s
|
||||
** that a Mem structure is located on an 8-byte boundary. To prevent
|
||||
** these assert()s from failing, when building with SQLITE_DEBUG defined
|
||||
** using gcc, we force nullMem to be 8-byte aligned using the magical
|
||||
** __attribute__((aligned(8))) macro. */
|
||||
static const Mem nullMem
|
||||
#if defined(SQLITE_DEBUG) && defined(__GNUC__)
|
||||
__attribute__((aligned(8)))
|
||||
#endif
|
||||
= {0, "", (double)0, {0}, 0, MEM_Null, 0,
|
||||
#ifdef SQLITE_DEBUG
|
||||
0, 0, /* pScopyFrom, pFiller */
|
||||
#endif
|
||||
0, 0 };
|
||||
return &nullMem;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check to see if column iCol of the given statement is valid. If
|
||||
@@ -743,32 +766,11 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
|
||||
sqlite3_mutex_enter(pVm->db->mutex);
|
||||
pOut = &pVm->pResultSet[i];
|
||||
}else{
|
||||
/* If the value passed as the second argument is out of range, return
|
||||
** a pointer to the following static Mem object which contains the
|
||||
** value SQL NULL. Even though the Mem structure contains an element
|
||||
** of type i64, on certain architectures (x86) with certain compiler
|
||||
** switches (-Os), gcc may align this Mem object on a 4-byte boundary
|
||||
** instead of an 8-byte one. This all works fine, except that when
|
||||
** running with SQLITE_DEBUG defined the SQLite code sometimes assert()s
|
||||
** that a Mem structure is located on an 8-byte boundary. To prevent
|
||||
** these assert()s from failing, when building with SQLITE_DEBUG defined
|
||||
** using gcc, we force nullMem to be 8-byte aligned using the magical
|
||||
** __attribute__((aligned(8))) macro. */
|
||||
static const Mem nullMem
|
||||
#if defined(SQLITE_DEBUG) && defined(__GNUC__)
|
||||
__attribute__((aligned(8)))
|
||||
#endif
|
||||
= {0, "", (double)0, {0}, 0, MEM_Null, SQLITE_NULL, 0,
|
||||
#ifdef SQLITE_DEBUG
|
||||
0, 0, /* pScopyFrom, pFiller */
|
||||
#endif
|
||||
0, 0 };
|
||||
|
||||
if( pVm && ALWAYS(pVm->db) ){
|
||||
sqlite3_mutex_enter(pVm->db->mutex);
|
||||
sqlite3Error(pVm->db, SQLITE_RANGE, 0);
|
||||
}
|
||||
pOut = (Mem*)&nullMem;
|
||||
pOut = (Mem*)columnNullValue();
|
||||
}
|
||||
return pOut;
|
||||
}
|
||||
|
||||
+668
-69
@@ -173,6 +173,9 @@ int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
|
||||
#ifdef VDBE_PROFILE
|
||||
pOp->cycles = 0;
|
||||
pOp->cnt = 0;
|
||||
#endif
|
||||
#ifdef SQLITE_VDBE_COVERAGE
|
||||
pOp->iSrcLine = 0;
|
||||
#endif
|
||||
return i;
|
||||
}
|
||||
@@ -535,7 +538,7 @@ VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg){
|
||||
** Add a whole list of operations to the operation stack. Return the
|
||||
** address of the first operation added.
|
||||
*/
|
||||
int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){
|
||||
int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp, int iLineno){
|
||||
int addr;
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p) ){
|
||||
@@ -563,6 +566,11 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){
|
||||
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||
pOut->zComment = 0;
|
||||
#endif
|
||||
#ifdef SQLITE_VDBE_COVERAGE
|
||||
pOut->iSrcLine = iLineno+i;
|
||||
#else
|
||||
(void)iLineno;
|
||||
#endif
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( p->db->flags & SQLITE_VdbeAddopTrace ){
|
||||
sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]);
|
||||
@@ -775,7 +783,9 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
|
||||
addr = p->nOp - 1;
|
||||
}
|
||||
pOp = &p->aOp[addr];
|
||||
assert( pOp->p4type==P4_NOTUSED || pOp->p4type==P4_INT32 );
|
||||
assert( pOp->p4type==P4_NOTUSED
|
||||
|| pOp->p4type==P4_INT32
|
||||
|| pOp->p4type==P4_KEYINFO );
|
||||
freeP4(db, pOp->p4type, pOp->p4.p);
|
||||
pOp->p4.p = 0;
|
||||
if( n==P4_INT32 ){
|
||||
@@ -851,6 +861,15 @@ void sqlite3VdbeNoopComment(Vdbe *p, const char *zFormat, ...){
|
||||
}
|
||||
#endif /* NDEBUG */
|
||||
|
||||
#ifdef SQLITE_VDBE_COVERAGE
|
||||
/*
|
||||
** Set the value if the iSrcLine field for the previously coded instruction.
|
||||
*/
|
||||
void sqlite3VdbeSetLineNumber(Vdbe *v, int iLine){
|
||||
sqlite3VdbeGetOp(v,-1)->iSrcLine = iLine;
|
||||
}
|
||||
#endif /* SQLITE_VDBE_COVERAGE */
|
||||
|
||||
/*
|
||||
** Return the opcode for a given address. If the address is -1, then
|
||||
** return the most recently inserted opcode.
|
||||
@@ -1174,7 +1193,7 @@ void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){
|
||||
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||
displayComment(pOp, zP4, zCom, sizeof(zCom));
|
||||
#else
|
||||
zCom[0] = 0
|
||||
zCom[0] = 0;
|
||||
#endif
|
||||
/* NB: The sqlite3OpcodeName() function is implemented by code created
|
||||
** by the mkopcodeh.awk and mkopcodec.awk scripts which extract the
|
||||
@@ -1203,6 +1222,7 @@ static void releaseMemArray(Mem *p, int N){
|
||||
}
|
||||
for(pEnd=&p[N]; p<pEnd; p++){
|
||||
assert( (&p[1])==pEnd || p[0].db==p[1].db );
|
||||
assert( sqlite3VdbeCheckMemInvariants(p) );
|
||||
|
||||
/* This block is really an inlined version of sqlite3VdbeMemRelease()
|
||||
** that takes advantage of the fact that the memory cell value is
|
||||
@@ -1216,6 +1236,10 @@ static void releaseMemArray(Mem *p, int N){
|
||||
** with no indexes using a single prepared INSERT statement, bind()
|
||||
** and reset(). Inserts are grouped into a transaction.
|
||||
*/
|
||||
testcase( p->flags & MEM_Agg );
|
||||
testcase( p->flags & MEM_Dyn );
|
||||
testcase( p->flags & MEM_Frame );
|
||||
testcase( p->flags & MEM_RowSet );
|
||||
if( p->flags&(MEM_Agg|MEM_Dyn|MEM_Frame|MEM_RowSet) ){
|
||||
sqlite3VdbeMemRelease(p);
|
||||
}else if( p->zMalloc ){
|
||||
@@ -1345,7 +1369,6 @@ int sqlite3VdbeList(
|
||||
}
|
||||
if( p->explain==1 ){
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->memType = MEM_Int;
|
||||
pMem->u.i = i; /* Program counter */
|
||||
pMem++;
|
||||
|
||||
@@ -1353,7 +1376,6 @@ int sqlite3VdbeList(
|
||||
pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */
|
||||
assert( pMem->z!=0 );
|
||||
pMem->n = sqlite3Strlen30(pMem->z);
|
||||
pMem->memType = MEM_Str;
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
pMem++;
|
||||
|
||||
@@ -1379,24 +1401,21 @@ int sqlite3VdbeList(
|
||||
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->u.i = pOp->p1; /* P1 */
|
||||
pMem->memType = MEM_Int;
|
||||
pMem++;
|
||||
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->u.i = pOp->p2; /* P2 */
|
||||
pMem->memType = MEM_Int;
|
||||
pMem++;
|
||||
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->u.i = pOp->p3; /* P3 */
|
||||
pMem->memType = MEM_Int;
|
||||
pMem++;
|
||||
|
||||
if( sqlite3VdbeMemGrow(pMem, 32, 0) ){ /* P4 */
|
||||
assert( p->db->mallocFailed );
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
pMem->flags = MEM_Dyn|MEM_Str|MEM_Term;
|
||||
pMem->flags = MEM_Str|MEM_Term;
|
||||
zP4 = displayP4(pOp, pMem->z, 32);
|
||||
if( zP4!=pMem->z ){
|
||||
sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0);
|
||||
@@ -1405,7 +1424,6 @@ int sqlite3VdbeList(
|
||||
pMem->n = sqlite3Strlen30(pMem->z);
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
}
|
||||
pMem->memType = MEM_Str;
|
||||
pMem++;
|
||||
|
||||
if( p->explain==1 ){
|
||||
@@ -1413,10 +1431,9 @@ int sqlite3VdbeList(
|
||||
assert( p->db->mallocFailed );
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
pMem->flags = MEM_Dyn|MEM_Str|MEM_Term;
|
||||
pMem->flags = MEM_Str|MEM_Term;
|
||||
pMem->n = 2;
|
||||
sqlite3_snprintf(3, pMem->z, "%.2x", pOp->p5); /* P5 */
|
||||
pMem->memType = MEM_Str;
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
pMem++;
|
||||
|
||||
@@ -1425,13 +1442,11 @@ int sqlite3VdbeList(
|
||||
assert( p->db->mallocFailed );
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
pMem->flags = MEM_Dyn|MEM_Str|MEM_Term;
|
||||
pMem->flags = MEM_Str|MEM_Term;
|
||||
pMem->n = displayComment(pOp, zP4, pMem->z, 500);
|
||||
pMem->memType = MEM_Str;
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
#else
|
||||
pMem->flags = MEM_Null; /* Comment */
|
||||
pMem->memType = MEM_Null;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2552,12 +2567,24 @@ int sqlite3VdbeReset(Vdbe *p){
|
||||
fprintf(out, "%02x", p->aOp[i].opcode);
|
||||
}
|
||||
fprintf(out, "\n");
|
||||
if( p->zSql ){
|
||||
char c, pc = 0;
|
||||
fprintf(out, "-- ");
|
||||
for(i=0; (c = p->zSql[i])!=0; i++){
|
||||
if( pc=='\n' ) fprintf(out, "-- ");
|
||||
putc(c, out);
|
||||
pc = c;
|
||||
}
|
||||
if( pc!='\n' ) fprintf(out, "\n");
|
||||
}
|
||||
for(i=0; i<p->nOp; i++){
|
||||
fprintf(out, "%6d %10lld %8lld ",
|
||||
char zHdr[100];
|
||||
sqlite3_snprintf(sizeof(zHdr), zHdr, "%6u %12llu %8llu ",
|
||||
p->aOp[i].cnt,
|
||||
p->aOp[i].cycles,
|
||||
p->aOp[i].cnt>0 ? p->aOp[i].cycles/p->aOp[i].cnt : 0
|
||||
);
|
||||
fprintf(out, "%s", zHdr);
|
||||
sqlite3VdbePrintOp(out, i, &p->aOp[i]);
|
||||
}
|
||||
fclose(out);
|
||||
@@ -2708,7 +2735,7 @@ int sqlite3VdbeCursorMoveto(VdbeCursor *p){
|
||||
if( rc ) return rc;
|
||||
if( hasMoved ){
|
||||
p->cacheStatus = CACHE_STALE;
|
||||
p->nullRow = 1;
|
||||
if( hasMoved==2 ) p->nullRow = 1;
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
@@ -2912,6 +2939,14 @@ u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Input "x" is a sequence of unsigned characters that represent a
|
||||
** big-endian integer. Return the equivalent native integer
|
||||
*/
|
||||
#define ONE_BYTE_INT(x) ((i8)(x)[0])
|
||||
#define TWO_BYTE_INT(x) (256*(i8)((x)[0])|(x)[1])
|
||||
#define THREE_BYTE_INT(x) (65536*(i8)((x)[0])|((x)[1]<<8)|(x)[2])
|
||||
#define FOUR_BYTE_UINT(x) (((u32)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3])
|
||||
|
||||
/*
|
||||
** Deserialize the data blob pointed to by buf as serial type serial_type
|
||||
** and store the result in pMem. Return the number of bytes read.
|
||||
@@ -2923,7 +2958,6 @@ u32 sqlite3VdbeSerialGet(
|
||||
){
|
||||
u64 x;
|
||||
u32 y;
|
||||
int i;
|
||||
switch( serial_type ){
|
||||
case 10: /* Reserved for future use */
|
||||
case 11: /* Reserved for future use */
|
||||
@@ -2932,34 +2966,34 @@ u32 sqlite3VdbeSerialGet(
|
||||
break;
|
||||
}
|
||||
case 1: { /* 1-byte signed integer */
|
||||
pMem->u.i = (signed char)buf[0];
|
||||
pMem->u.i = ONE_BYTE_INT(buf);
|
||||
pMem->flags = MEM_Int;
|
||||
testcase( pMem->u.i<0 );
|
||||
return 1;
|
||||
}
|
||||
case 2: { /* 2-byte signed integer */
|
||||
i = 256*(signed char)buf[0] | buf[1];
|
||||
pMem->u.i = (i64)i;
|
||||
pMem->u.i = TWO_BYTE_INT(buf);
|
||||
pMem->flags = MEM_Int;
|
||||
testcase( pMem->u.i<0 );
|
||||
return 2;
|
||||
}
|
||||
case 3: { /* 3-byte signed integer */
|
||||
i = 65536*(signed char)buf[0] | (buf[1]<<8) | buf[2];
|
||||
pMem->u.i = (i64)i;
|
||||
pMem->u.i = THREE_BYTE_INT(buf);
|
||||
pMem->flags = MEM_Int;
|
||||
testcase( pMem->u.i<0 );
|
||||
return 3;
|
||||
}
|
||||
case 4: { /* 4-byte signed integer */
|
||||
y = ((unsigned)buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
|
||||
y = FOUR_BYTE_UINT(buf);
|
||||
pMem->u.i = (i64)*(int*)&y;
|
||||
pMem->flags = MEM_Int;
|
||||
testcase( pMem->u.i<0 );
|
||||
return 4;
|
||||
}
|
||||
case 5: { /* 6-byte signed integer */
|
||||
x = 256*(signed char)buf[0] + buf[1];
|
||||
y = ((unsigned)buf[2]<<24) | (buf[3]<<16) | (buf[4]<<8) | buf[5];
|
||||
x = (x<<32) | y;
|
||||
pMem->u.i = *(i64*)&x;
|
||||
pMem->u.i = FOUR_BYTE_UINT(buf+2) + (((i64)1)<<32)*TWO_BYTE_INT(buf);
|
||||
pMem->flags = MEM_Int;
|
||||
testcase( pMem->u.i<0 );
|
||||
return 6;
|
||||
}
|
||||
case 6: /* 8-byte signed integer */
|
||||
@@ -2976,12 +3010,13 @@ u32 sqlite3VdbeSerialGet(
|
||||
swapMixedEndianFloat(t2);
|
||||
assert( sizeof(r1)==sizeof(t2) && memcmp(&r1, &t2, sizeof(r1))==0 );
|
||||
#endif
|
||||
x = ((unsigned)buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
|
||||
y = ((unsigned)buf[4]<<24) | (buf[5]<<16) | (buf[6]<<8) | buf[7];
|
||||
x = FOUR_BYTE_UINT(buf);
|
||||
y = FOUR_BYTE_UINT(buf+4);
|
||||
x = (x<<32) | y;
|
||||
if( serial_type==6 ){
|
||||
pMem->u.i = *(i64*)&x;
|
||||
pMem->flags = MEM_Int;
|
||||
testcase( pMem->u.i<0 );
|
||||
}else{
|
||||
assert( sizeof(x)==8 && sizeof(pMem->r)==8 );
|
||||
swapMixedEndianFloat(x);
|
||||
@@ -3073,7 +3108,7 @@ void sqlite3VdbeRecordUnpack(
|
||||
u32 szHdr;
|
||||
Mem *pMem = p->aMem;
|
||||
|
||||
p->flags = 0;
|
||||
p->default_rc = 0;
|
||||
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
|
||||
idx = getVarint32(aKey, szHdr);
|
||||
d = szHdr;
|
||||
@@ -3094,26 +3129,18 @@ void sqlite3VdbeRecordUnpack(
|
||||
p->nField = u;
|
||||
}
|
||||
|
||||
#if SQLITE_DEBUG
|
||||
/*
|
||||
** This function compares the two table rows or index records
|
||||
** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero
|
||||
** or positive integer if key1 is less than, equal to or
|
||||
** greater than key2. The {nKey1, pKey1} key must be a blob
|
||||
** created by th OP_MakeRecord opcode of the VDBE. The pPKey2
|
||||
** key must be a parsed key such as obtained from
|
||||
** sqlite3VdbeParseRecord.
|
||||
**
|
||||
** Key1 and Key2 do not have to contain the same number of fields.
|
||||
** The key with fewer fields is usually compares less than the
|
||||
** longer key. However if the UNPACKED_INCRKEY flags in pPKey2 is set
|
||||
** and the common prefixes are equal, then key1 is less than key2.
|
||||
** Or if the UNPACKED_MATCH_PREFIX flag is set and the prefixes are
|
||||
** equal, then the keys are considered to be equal and
|
||||
** the parts beyond the common prefix are ignored.
|
||||
** This function compares two index or table record keys in the same way
|
||||
** as the sqlite3VdbeRecordCompare() routine. Unlike VdbeRecordCompare(),
|
||||
** this function deserializes and compares values using the
|
||||
** sqlite3VdbeSerialGet() and sqlite3MemCompare() functions. It is used
|
||||
** in assert() statements to ensure that the optimized code in
|
||||
** sqlite3VdbeRecordCompare() returns results with these two primitives.
|
||||
*/
|
||||
int sqlite3VdbeRecordCompare(
|
||||
static int vdbeRecordCompareDebug(
|
||||
int nKey1, const void *pKey1, /* Left key */
|
||||
UnpackedRecord *pPKey2 /* Right key */
|
||||
const UnpackedRecord *pPKey2 /* Right key */
|
||||
){
|
||||
u32 d1; /* Offset into aKey[] of next data element */
|
||||
u32 idx1; /* Offset into aKey[] of next header element */
|
||||
@@ -3187,24 +3214,598 @@ int sqlite3VdbeRecordCompare(
|
||||
assert( mem1.zMalloc==0 );
|
||||
|
||||
/* rc==0 here means that one of the keys ran out of fields and
|
||||
** all the fields up to that point were equal. If the UNPACKED_INCRKEY
|
||||
** flag is set, then break the tie by treating key2 as larger.
|
||||
** If the UPACKED_PREFIX_MATCH flag is set, then keys with common prefixes
|
||||
** are considered to be equal. Otherwise, the longer key is the
|
||||
** larger. As it happens, the pPKey2 will always be the longer
|
||||
** if there is a difference.
|
||||
** all the fields up to that point were equal. Return the the default_rc
|
||||
** value. */
|
||||
return pPKey2->default_rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Both *pMem1 and *pMem2 contain string values. Compare the two values
|
||||
** using the collation sequence pColl. As usual, return a negative , zero
|
||||
** or positive value if *pMem1 is less than, equal to or greater than
|
||||
** *pMem2, respectively. Similar in spirit to "rc = (*pMem1) - (*pMem2);".
|
||||
*/
|
||||
static int vdbeCompareMemString(
|
||||
const Mem *pMem1,
|
||||
const Mem *pMem2,
|
||||
const CollSeq *pColl,
|
||||
u8 *prcErr /* If an OOM occurs, set to SQLITE_NOMEM */
|
||||
){
|
||||
if( pMem1->enc==pColl->enc ){
|
||||
/* The strings are already in the correct encoding. Call the
|
||||
** comparison function directly */
|
||||
return pColl->xCmp(pColl->pUser,pMem1->n,pMem1->z,pMem2->n,pMem2->z);
|
||||
}else{
|
||||
int rc;
|
||||
const void *v1, *v2;
|
||||
int n1, n2;
|
||||
Mem c1;
|
||||
Mem c2;
|
||||
memset(&c1, 0, sizeof(c1));
|
||||
memset(&c2, 0, sizeof(c2));
|
||||
sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem);
|
||||
sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem);
|
||||
v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc);
|
||||
n1 = v1==0 ? 0 : c1.n;
|
||||
v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc);
|
||||
n2 = v2==0 ? 0 : c2.n;
|
||||
rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2);
|
||||
sqlite3VdbeMemRelease(&c1);
|
||||
sqlite3VdbeMemRelease(&c2);
|
||||
if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Compare the values contained by the two memory cells, returning
|
||||
** negative, zero or positive if pMem1 is less than, equal to, or greater
|
||||
** than pMem2. Sorting order is NULL's first, followed by numbers (integers
|
||||
** and reals) sorted numerically, followed by text ordered by the collating
|
||||
** sequence pColl and finally blob's ordered by memcmp().
|
||||
**
|
||||
** Two NULL values are considered equal by this function.
|
||||
*/
|
||||
int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
|
||||
int rc;
|
||||
int f1, f2;
|
||||
int combined_flags;
|
||||
|
||||
f1 = pMem1->flags;
|
||||
f2 = pMem2->flags;
|
||||
combined_flags = f1|f2;
|
||||
assert( (combined_flags & MEM_RowSet)==0 );
|
||||
|
||||
/* If one value is NULL, it is less than the other. If both values
|
||||
** are NULL, return 0.
|
||||
*/
|
||||
assert( rc==0 );
|
||||
if( pPKey2->flags & UNPACKED_INCRKEY ){
|
||||
rc = -1;
|
||||
}else if( pPKey2->flags & UNPACKED_PREFIX_MATCH ){
|
||||
/* Leave rc==0 */
|
||||
}else if( idx1<szHdr1 ){
|
||||
rc = 1;
|
||||
if( combined_flags&MEM_Null ){
|
||||
return (f2&MEM_Null) - (f1&MEM_Null);
|
||||
}
|
||||
|
||||
/* If one value is a number and the other is not, the number is less.
|
||||
** If both are numbers, compare as reals if one is a real, or as integers
|
||||
** if both values are integers.
|
||||
*/
|
||||
if( combined_flags&(MEM_Int|MEM_Real) ){
|
||||
double r1, r2;
|
||||
if( (f1 & f2 & MEM_Int)!=0 ){
|
||||
if( pMem1->u.i < pMem2->u.i ) return -1;
|
||||
if( pMem1->u.i > pMem2->u.i ) return 1;
|
||||
return 0;
|
||||
}
|
||||
if( (f1&MEM_Real)!=0 ){
|
||||
r1 = pMem1->r;
|
||||
}else if( (f1&MEM_Int)!=0 ){
|
||||
r1 = (double)pMem1->u.i;
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
if( (f2&MEM_Real)!=0 ){
|
||||
r2 = pMem2->r;
|
||||
}else if( (f2&MEM_Int)!=0 ){
|
||||
r2 = (double)pMem2->u.i;
|
||||
}else{
|
||||
return -1;
|
||||
}
|
||||
if( r1<r2 ) return -1;
|
||||
if( r1>r2 ) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If one value is a string and the other is a blob, the string is less.
|
||||
** If both are strings, compare using the collating functions.
|
||||
*/
|
||||
if( combined_flags&MEM_Str ){
|
||||
if( (f1 & MEM_Str)==0 ){
|
||||
return 1;
|
||||
}
|
||||
if( (f2 & MEM_Str)==0 ){
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert( pMem1->enc==pMem2->enc );
|
||||
assert( pMem1->enc==SQLITE_UTF8 ||
|
||||
pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE );
|
||||
|
||||
/* The collation sequence must be defined at this point, even if
|
||||
** the user deletes the collation sequence after the vdbe program is
|
||||
** compiled (this was not always the case).
|
||||
*/
|
||||
assert( !pColl || pColl->xCmp );
|
||||
|
||||
if( pColl ){
|
||||
return vdbeCompareMemString(pMem1, pMem2, pColl, 0);
|
||||
}
|
||||
/* If a NULL pointer was passed as the collate function, fall through
|
||||
** to the blob case and use memcmp(). */
|
||||
}
|
||||
|
||||
/* Both values must be blobs. Compare using memcmp(). */
|
||||
rc = memcmp(pMem1->z, pMem2->z, (pMem1->n>pMem2->n)?pMem2->n:pMem1->n);
|
||||
if( rc==0 ){
|
||||
rc = pMem1->n - pMem2->n;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** The first argument passed to this function is a serial-type that
|
||||
** corresponds to an integer - all values between 1 and 9 inclusive
|
||||
** except 7. The second points to a buffer containing an integer value
|
||||
** serialized according to serial_type. This function deserializes
|
||||
** and returns the value.
|
||||
*/
|
||||
static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){
|
||||
u32 y;
|
||||
assert( CORRUPT_DB || (serial_type>=1 && serial_type<=9 && serial_type!=7) );
|
||||
switch( serial_type ){
|
||||
case 0:
|
||||
case 1:
|
||||
testcase( aKey[0]&0x80 );
|
||||
return ONE_BYTE_INT(aKey);
|
||||
case 2:
|
||||
testcase( aKey[0]&0x80 );
|
||||
return TWO_BYTE_INT(aKey);
|
||||
case 3:
|
||||
testcase( aKey[0]&0x80 );
|
||||
return THREE_BYTE_INT(aKey);
|
||||
case 4: {
|
||||
testcase( aKey[0]&0x80 );
|
||||
y = FOUR_BYTE_UINT(aKey);
|
||||
return (i64)*(int*)&y;
|
||||
}
|
||||
case 5: {
|
||||
testcase( aKey[0]&0x80 );
|
||||
return FOUR_BYTE_UINT(aKey+2) + (((i64)1)<<32)*TWO_BYTE_INT(aKey);
|
||||
}
|
||||
case 6: {
|
||||
u64 x = FOUR_BYTE_UINT(aKey);
|
||||
testcase( aKey[0]&0x80 );
|
||||
x = (x<<32) | FOUR_BYTE_UINT(aKey+4);
|
||||
return (i64)*(i64*)&x;
|
||||
}
|
||||
}
|
||||
|
||||
return (serial_type - 8);
|
||||
}
|
||||
|
||||
/*
|
||||
** This function compares the two table rows or index records
|
||||
** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero
|
||||
** or positive integer if key1 is less than, equal to or
|
||||
** greater than key2. The {nKey1, pKey1} key must be a blob
|
||||
** created by th OP_MakeRecord opcode of the VDBE. The pPKey2
|
||||
** key must be a parsed key such as obtained from
|
||||
** sqlite3VdbeParseRecord.
|
||||
**
|
||||
** If argument bSkip is non-zero, it is assumed that the caller has already
|
||||
** determined that the first fields of the keys are equal.
|
||||
**
|
||||
** Key1 and Key2 do not have to contain the same number of fields. If all
|
||||
** fields that appear in both keys are equal, then pPKey2->default_rc is
|
||||
** returned.
|
||||
**
|
||||
** If database corruption is discovered, set pPKey2->errCode to
|
||||
** SQLITE_CORRUPT and return 0. If an OOM error is encountered,
|
||||
** pPKey2->errCode is set to SQLITE_NOMEM and, if it is not NULL, the
|
||||
** malloc-failed flag set on database handle (pPKey2->pKeyInfo->db).
|
||||
*/
|
||||
int sqlite3VdbeRecordCompare(
|
||||
int nKey1, const void *pKey1, /* Left key */
|
||||
UnpackedRecord *pPKey2, /* Right key */
|
||||
int bSkip /* If true, skip the first field */
|
||||
){
|
||||
u32 d1; /* Offset into aKey[] of next data element */
|
||||
int i; /* Index of next field to compare */
|
||||
u32 szHdr1; /* Size of record header in bytes */
|
||||
u32 idx1; /* Offset of first type in header */
|
||||
int rc = 0; /* Return value */
|
||||
Mem *pRhs = pPKey2->aMem; /* Next field of pPKey2 to compare */
|
||||
KeyInfo *pKeyInfo = pPKey2->pKeyInfo;
|
||||
const unsigned char *aKey1 = (const unsigned char *)pKey1;
|
||||
Mem mem1;
|
||||
|
||||
/* If bSkip is true, then the caller has already determined that the first
|
||||
** two elements in the keys are equal. Fix the various stack variables so
|
||||
** that this routine begins comparing at the second field. */
|
||||
if( bSkip ){
|
||||
u32 s1;
|
||||
idx1 = 1 + getVarint32(&aKey1[1], s1);
|
||||
szHdr1 = aKey1[0];
|
||||
d1 = szHdr1 + sqlite3VdbeSerialTypeLen(s1);
|
||||
i = 1;
|
||||
pRhs++;
|
||||
}else{
|
||||
idx1 = getVarint32(aKey1, szHdr1);
|
||||
d1 = szHdr1;
|
||||
if( d1>(unsigned)nKey1 ){
|
||||
pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
|
||||
return 0; /* Corruption */
|
||||
}
|
||||
i = 0;
|
||||
}
|
||||
|
||||
VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */
|
||||
assert( pPKey2->pKeyInfo->nField+pPKey2->pKeyInfo->nXField>=pPKey2->nField
|
||||
|| CORRUPT_DB );
|
||||
assert( pPKey2->pKeyInfo->aSortOrder!=0 );
|
||||
assert( pPKey2->pKeyInfo->nField>0 );
|
||||
assert( idx1<=szHdr1 || CORRUPT_DB );
|
||||
do{
|
||||
u32 serial_type;
|
||||
|
||||
/* RHS is an integer */
|
||||
if( pRhs->flags & MEM_Int ){
|
||||
serial_type = aKey1[idx1];
|
||||
testcase( serial_type==12 );
|
||||
if( serial_type>=12 ){
|
||||
rc = +1;
|
||||
}else if( serial_type==0 ){
|
||||
rc = -1;
|
||||
}else if( serial_type==7 ){
|
||||
double rhs = (double)pRhs->u.i;
|
||||
sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
|
||||
if( mem1.r<rhs ){
|
||||
rc = -1;
|
||||
}else if( mem1.r>rhs ){
|
||||
rc = +1;
|
||||
}
|
||||
}else{
|
||||
i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]);
|
||||
i64 rhs = pRhs->u.i;
|
||||
if( lhs<rhs ){
|
||||
rc = -1;
|
||||
}else if( lhs>rhs ){
|
||||
rc = +1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* RHS is real */
|
||||
else if( pRhs->flags & MEM_Real ){
|
||||
serial_type = aKey1[idx1];
|
||||
if( serial_type>=12 ){
|
||||
rc = +1;
|
||||
}else if( serial_type==0 ){
|
||||
rc = -1;
|
||||
}else{
|
||||
double rhs = pRhs->r;
|
||||
double lhs;
|
||||
sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
|
||||
if( serial_type==7 ){
|
||||
lhs = mem1.r;
|
||||
}else{
|
||||
lhs = (double)mem1.u.i;
|
||||
}
|
||||
if( lhs<rhs ){
|
||||
rc = -1;
|
||||
}else if( lhs>rhs ){
|
||||
rc = +1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* RHS is a string */
|
||||
else if( pRhs->flags & MEM_Str ){
|
||||
getVarint32(&aKey1[idx1], serial_type);
|
||||
testcase( serial_type==12 );
|
||||
if( serial_type<12 ){
|
||||
rc = -1;
|
||||
}else if( !(serial_type & 0x01) ){
|
||||
rc = +1;
|
||||
}else{
|
||||
mem1.n = (serial_type - 12) / 2;
|
||||
testcase( (d1+mem1.n)==(unsigned)nKey1 );
|
||||
testcase( (d1+mem1.n+1)==(unsigned)nKey1 );
|
||||
if( (d1+mem1.n) > (unsigned)nKey1 ){
|
||||
pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
|
||||
return 0; /* Corruption */
|
||||
}else if( pKeyInfo->aColl[i] ){
|
||||
mem1.enc = pKeyInfo->enc;
|
||||
mem1.db = pKeyInfo->db;
|
||||
mem1.flags = MEM_Str;
|
||||
mem1.z = (char*)&aKey1[d1];
|
||||
rc = vdbeCompareMemString(
|
||||
&mem1, pRhs, pKeyInfo->aColl[i], &pPKey2->errCode
|
||||
);
|
||||
}else{
|
||||
int nCmp = MIN(mem1.n, pRhs->n);
|
||||
rc = memcmp(&aKey1[d1], pRhs->z, nCmp);
|
||||
if( rc==0 ) rc = mem1.n - pRhs->n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* RHS is a blob */
|
||||
else if( pRhs->flags & MEM_Blob ){
|
||||
getVarint32(&aKey1[idx1], serial_type);
|
||||
testcase( serial_type==12 );
|
||||
if( serial_type<12 || (serial_type & 0x01) ){
|
||||
rc = -1;
|
||||
}else{
|
||||
int nStr = (serial_type - 12) / 2;
|
||||
testcase( (d1+nStr)==(unsigned)nKey1 );
|
||||
testcase( (d1+nStr+1)==(unsigned)nKey1 );
|
||||
if( (d1+nStr) > (unsigned)nKey1 ){
|
||||
pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
|
||||
return 0; /* Corruption */
|
||||
}else{
|
||||
int nCmp = MIN(nStr, pRhs->n);
|
||||
rc = memcmp(&aKey1[d1], pRhs->z, nCmp);
|
||||
if( rc==0 ) rc = nStr - pRhs->n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* RHS is null */
|
||||
else{
|
||||
serial_type = aKey1[idx1];
|
||||
rc = (serial_type!=0);
|
||||
}
|
||||
|
||||
if( rc!=0 ){
|
||||
if( pKeyInfo->aSortOrder[i] ){
|
||||
rc = -rc;
|
||||
}
|
||||
assert( CORRUPT_DB || pKeyInfo->db==0
|
||||
|| (rc<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0)
|
||||
|| (rc>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0)
|
||||
|| pKeyInfo->db->mallocFailed
|
||||
);
|
||||
assert( mem1.zMalloc==0 ); /* See comment below */
|
||||
return rc;
|
||||
}
|
||||
|
||||
i++;
|
||||
pRhs++;
|
||||
d1 += sqlite3VdbeSerialTypeLen(serial_type);
|
||||
idx1 += sqlite3VarintLen(serial_type);
|
||||
}while( idx1<(unsigned)szHdr1 && i<pPKey2->nField && d1<=(unsigned)nKey1 );
|
||||
|
||||
/* No memory allocation is ever used on mem1. Prove this using
|
||||
** the following assert(). If the assert() fails, it indicates a
|
||||
** memory leak and a need to call sqlite3VdbeMemRelease(&mem1). */
|
||||
assert( mem1.zMalloc==0 );
|
||||
|
||||
/* rc==0 here means that one or both of the keys ran out of fields and
|
||||
** all the fields up to that point were equal. Return the the default_rc
|
||||
** value. */
|
||||
assert( CORRUPT_DB
|
||||
|| pPKey2->default_rc==vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)
|
||||
);
|
||||
return pPKey2->default_rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is an optimized version of sqlite3VdbeRecordCompare()
|
||||
** that (a) the first field of pPKey2 is an integer, and (b) the
|
||||
** size-of-header varint at the start of (pKey1/nKey1) fits in a single
|
||||
** byte (i.e. is less than 128).
|
||||
**
|
||||
** To avoid concerns about buffer overreads, this routine is only used
|
||||
** on schemas where the maximum valid header size is 63 bytes or less.
|
||||
*/
|
||||
static int vdbeRecordCompareInt(
|
||||
int nKey1, const void *pKey1, /* Left key */
|
||||
UnpackedRecord *pPKey2, /* Right key */
|
||||
int bSkip /* Ignored */
|
||||
){
|
||||
const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1 & 0x3F];
|
||||
int serial_type = ((const u8*)pKey1)[1];
|
||||
int res;
|
||||
u32 y;
|
||||
u64 x;
|
||||
i64 v = pPKey2->aMem[0].u.i;
|
||||
i64 lhs;
|
||||
UNUSED_PARAMETER(bSkip);
|
||||
|
||||
assert( bSkip==0 );
|
||||
assert( (*(u8*)pKey1)<=0x3F || CORRUPT_DB );
|
||||
switch( serial_type ){
|
||||
case 1: { /* 1-byte signed integer */
|
||||
lhs = ONE_BYTE_INT(aKey);
|
||||
testcase( lhs<0 );
|
||||
break;
|
||||
}
|
||||
case 2: { /* 2-byte signed integer */
|
||||
lhs = TWO_BYTE_INT(aKey);
|
||||
testcase( lhs<0 );
|
||||
break;
|
||||
}
|
||||
case 3: { /* 3-byte signed integer */
|
||||
lhs = THREE_BYTE_INT(aKey);
|
||||
testcase( lhs<0 );
|
||||
break;
|
||||
}
|
||||
case 4: { /* 4-byte signed integer */
|
||||
y = FOUR_BYTE_UINT(aKey);
|
||||
lhs = (i64)*(int*)&y;
|
||||
testcase( lhs<0 );
|
||||
break;
|
||||
}
|
||||
case 5: { /* 6-byte signed integer */
|
||||
lhs = FOUR_BYTE_UINT(aKey+2) + (((i64)1)<<32)*TWO_BYTE_INT(aKey);
|
||||
testcase( lhs<0 );
|
||||
break;
|
||||
}
|
||||
case 6: { /* 8-byte signed integer */
|
||||
x = FOUR_BYTE_UINT(aKey);
|
||||
x = (x<<32) | FOUR_BYTE_UINT(aKey+4);
|
||||
lhs = *(i64*)&x;
|
||||
testcase( lhs<0 );
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
lhs = 0;
|
||||
break;
|
||||
case 9:
|
||||
lhs = 1;
|
||||
break;
|
||||
|
||||
/* This case could be removed without changing the results of running
|
||||
** this code. Including it causes gcc to generate a faster switch
|
||||
** statement (since the range of switch targets now starts at zero and
|
||||
** is contiguous) but does not cause any duplicate code to be generated
|
||||
** (as gcc is clever enough to combine the two like cases). Other
|
||||
** compilers might be similar. */
|
||||
case 0: case 7:
|
||||
return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 0);
|
||||
|
||||
default:
|
||||
return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 0);
|
||||
}
|
||||
|
||||
if( v>lhs ){
|
||||
res = pPKey2->r1;
|
||||
}else if( v<lhs ){
|
||||
res = pPKey2->r2;
|
||||
}else if( pPKey2->nField>1 ){
|
||||
/* The first fields of the two keys are equal. Compare the trailing
|
||||
** fields. */
|
||||
res = sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 1);
|
||||
}else{
|
||||
/* The first fields of the two keys are equal and there are no trailing
|
||||
** fields. Return pPKey2->default_rc in this case. */
|
||||
res = pPKey2->default_rc;
|
||||
}
|
||||
|
||||
assert( (res==0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)==0)
|
||||
|| (res<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0)
|
||||
|| (res>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0)
|
||||
|| CORRUPT_DB
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is an optimized version of sqlite3VdbeRecordCompare()
|
||||
** that (a) the first field of pPKey2 is a string, that (b) the first field
|
||||
** uses the collation sequence BINARY and (c) that the size-of-header varint
|
||||
** at the start of (pKey1/nKey1) fits in a single byte.
|
||||
*/
|
||||
static int vdbeRecordCompareString(
|
||||
int nKey1, const void *pKey1, /* Left key */
|
||||
UnpackedRecord *pPKey2, /* Right key */
|
||||
int bSkip
|
||||
){
|
||||
const u8 *aKey1 = (const u8*)pKey1;
|
||||
int serial_type;
|
||||
int res;
|
||||
UNUSED_PARAMETER(bSkip);
|
||||
|
||||
assert( bSkip==0 );
|
||||
getVarint32(&aKey1[1], serial_type);
|
||||
|
||||
if( serial_type<12 ){
|
||||
res = pPKey2->r1; /* (pKey1/nKey1) is a number or a null */
|
||||
}else if( !(serial_type & 0x01) ){
|
||||
res = pPKey2->r2; /* (pKey1/nKey1) is a blob */
|
||||
}else{
|
||||
int nCmp;
|
||||
int nStr;
|
||||
int szHdr = aKey1[0];
|
||||
|
||||
nStr = (serial_type-12) / 2;
|
||||
if( (szHdr + nStr) > nKey1 ){
|
||||
pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
|
||||
return 0; /* Corruption */
|
||||
}
|
||||
nCmp = MIN( pPKey2->aMem[0].n, nStr );
|
||||
res = memcmp(&aKey1[szHdr], pPKey2->aMem[0].z, nCmp);
|
||||
|
||||
if( res==0 ){
|
||||
res = nStr - pPKey2->aMem[0].n;
|
||||
if( res==0 ){
|
||||
if( pPKey2->nField>1 ){
|
||||
res = sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 1);
|
||||
}else{
|
||||
res = pPKey2->default_rc;
|
||||
}
|
||||
}else if( res>0 ){
|
||||
res = pPKey2->r2;
|
||||
}else{
|
||||
res = pPKey2->r1;
|
||||
}
|
||||
}else if( res>0 ){
|
||||
res = pPKey2->r2;
|
||||
}else{
|
||||
res = pPKey2->r1;
|
||||
}
|
||||
}
|
||||
|
||||
assert( (res==0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)==0)
|
||||
|| (res<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0)
|
||||
|| (res>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0)
|
||||
|| CORRUPT_DB
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to an sqlite3VdbeRecordCompare() compatible function
|
||||
** suitable for comparing serialized records to the unpacked record passed
|
||||
** as the only argument.
|
||||
*/
|
||||
RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){
|
||||
/* varintRecordCompareInt() and varintRecordCompareString() both assume
|
||||
** that the size-of-header varint that occurs at the start of each record
|
||||
** fits in a single byte (i.e. is 127 or less). varintRecordCompareInt()
|
||||
** also assumes that it is safe to overread a buffer by at least the
|
||||
** maximum possible legal header size plus 8 bytes. Because there is
|
||||
** guaranteed to be at least 74 (but not 136) bytes of padding following each
|
||||
** buffer passed to varintRecordCompareInt() this makes it convenient to
|
||||
** limit the size of the header to 64 bytes in cases where the first field
|
||||
** is an integer.
|
||||
**
|
||||
** The easiest way to enforce this limit is to consider only records with
|
||||
** 13 fields or less. If the first field is an integer, the maximum legal
|
||||
** header size is (12*5 + 1 + 1) bytes. */
|
||||
if( (p->pKeyInfo->nField + p->pKeyInfo->nXField)<=13 ){
|
||||
int flags = p->aMem[0].flags;
|
||||
if( p->pKeyInfo->aSortOrder[0] ){
|
||||
p->r1 = 1;
|
||||
p->r2 = -1;
|
||||
}else{
|
||||
p->r1 = -1;
|
||||
p->r2 = 1;
|
||||
}
|
||||
if( (flags & MEM_Int) ){
|
||||
return vdbeRecordCompareInt;
|
||||
}
|
||||
testcase( flags & MEM_Real );
|
||||
testcase( flags & MEM_Null );
|
||||
testcase( flags & MEM_Blob );
|
||||
if( (flags & (MEM_Real|MEM_Null|MEM_Blob))==0 && p->pKeyInfo->aColl[0]==0 ){
|
||||
assert( flags & MEM_Str );
|
||||
return vdbeRecordCompareString;
|
||||
}
|
||||
}
|
||||
|
||||
return sqlite3VdbeRecordCompare;
|
||||
}
|
||||
|
||||
/*
|
||||
** pCur points at an index entry created using the OP_MakeRecord opcode.
|
||||
@@ -3295,9 +3896,9 @@ idx_rowid_corruption:
|
||||
** of the keys prior to the final rowid, not the entire key.
|
||||
*/
|
||||
int sqlite3VdbeIdxKeyCompare(
|
||||
VdbeCursor *pC, /* The cursor to compare against */
|
||||
UnpackedRecord *pUnpacked, /* Unpacked version of key to compare against */
|
||||
int *res /* Write the comparison result here */
|
||||
VdbeCursor *pC, /* The cursor to compare against */
|
||||
UnpackedRecord *pUnpacked, /* Unpacked version of key */
|
||||
int *res /* Write the comparison result here */
|
||||
){
|
||||
i64 nCellKey = 0;
|
||||
int rc;
|
||||
@@ -3307,7 +3908,7 @@ int sqlite3VdbeIdxKeyCompare(
|
||||
assert( sqlite3BtreeCursorIsValid(pCur) );
|
||||
VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey);
|
||||
assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */
|
||||
/* nCellKey will always be between 0 and 0xffffffff because of the say
|
||||
/* nCellKey will always be between 0 and 0xffffffff because of the way
|
||||
** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */
|
||||
if( nCellKey<=0 || nCellKey>0x7fffffff ){
|
||||
*res = 0;
|
||||
@@ -3318,8 +3919,7 @@ int sqlite3VdbeIdxKeyCompare(
|
||||
if( rc ){
|
||||
return rc;
|
||||
}
|
||||
assert( pUnpacked->flags & UNPACKED_PREFIX_MATCH );
|
||||
*res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked);
|
||||
*res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked, 0);
|
||||
sqlite3VdbeMemRelease(&m);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -3383,7 +3983,6 @@ sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff){
|
||||
if( pRet ){
|
||||
sqlite3VdbeMemCopy((Mem *)pRet, pMem);
|
||||
sqlite3ValueApplyAffinity(pRet, aff, SQLITE_UTF8);
|
||||
sqlite3VdbeMemStoreType((Mem *)pRet);
|
||||
}
|
||||
return pRet;
|
||||
}
|
||||
|
||||
+2
-3
@@ -133,14 +133,13 @@ int sqlite3_blob_open(
|
||||
** which closes the b-tree cursor and (possibly) commits the
|
||||
** transaction.
|
||||
*/
|
||||
static const int iLn = VDBE_OFFSET_LINENO(4);
|
||||
static const VdbeOpList openBlob[] = {
|
||||
/* {OP_Transaction, 0, 0, 0}, // 0: Inserted separately */
|
||||
{OP_TableLock, 0, 0, 0}, /* 1: Acquire a read or write lock */
|
||||
|
||||
/* One of the following two instructions is replaced by an OP_Noop. */
|
||||
{OP_OpenRead, 0, 0, 0}, /* 2: Open cursor 0 for reading */
|
||||
{OP_OpenWrite, 0, 0, 0}, /* 3: Open cursor 0 for read/write */
|
||||
|
||||
{OP_Variable, 1, 1, 1}, /* 4: Push the rowid to the stack */
|
||||
{OP_NotExists, 0, 10, 1}, /* 5: Seek the cursor */
|
||||
{OP_Column, 0, 0, 1}, /* 6 */
|
||||
@@ -265,7 +264,7 @@ int sqlite3_blob_open(
|
||||
pTab->pSchema->schema_cookie,
|
||||
pTab->pSchema->iGeneration);
|
||||
sqlite3VdbeChangeP5(v, 1);
|
||||
sqlite3VdbeAddOpList(v, sizeof(openBlob)/sizeof(VdbeOpList), openBlob);
|
||||
sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn);
|
||||
|
||||
/* Make sure a mutex is held on the table to be accessed */
|
||||
sqlite3VdbeUsesBtree(v, iDb);
|
||||
|
||||
+56
-148
@@ -18,6 +18,42 @@
|
||||
#include "sqliteInt.h"
|
||||
#include "vdbeInt.h"
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
** Check invariants on a Mem object.
|
||||
**
|
||||
** This routine is intended for use inside of assert() statements, like
|
||||
** this: assert( sqlite3VdbeCheckMemInvariants(pMem) );
|
||||
*/
|
||||
int sqlite3VdbeCheckMemInvariants(Mem *p){
|
||||
/* The MEM_Dyn bit is set if and only if Mem.xDel is a non-NULL destructor
|
||||
** function for Mem.z
|
||||
*/
|
||||
assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 );
|
||||
assert( (p->flags & MEM_Dyn)!=0 || p->xDel==0 );
|
||||
|
||||
/* If p holds a string or blob, the Mem.z must point to exactly
|
||||
** one of the following:
|
||||
**
|
||||
** (1) Memory in Mem.zMalloc and managed by the Mem object
|
||||
** (2) Memory to be freed using Mem.xDel
|
||||
** (3) An ephermal string or blob
|
||||
** (4) A static string or blob
|
||||
*/
|
||||
if( (p->flags & (MEM_Str|MEM_Blob)) && p->z!=0 ){
|
||||
assert(
|
||||
((p->z==p->zMalloc)? 1 : 0) +
|
||||
((p->flags&MEM_Dyn)!=0 ? 1 : 0) +
|
||||
((p->flags&MEM_Ephem)!=0 ? 1 : 0) +
|
||||
((p->flags&MEM_Static)!=0 ? 1 : 0) == 1
|
||||
);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** If pMem is an object with a valid string representation, this routine
|
||||
** ensures the internal encoding for the string representation is
|
||||
@@ -67,12 +103,7 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
|
||||
** in pMem->z is discarded.
|
||||
*/
|
||||
int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
|
||||
assert( 1 >=
|
||||
((pMem->zMalloc && pMem->zMalloc==pMem->z) ? 1 : 0) +
|
||||
(((pMem->flags&MEM_Dyn)&&pMem->xDel) ? 1 : 0) +
|
||||
((pMem->flags&MEM_Ephem) ? 1 : 0) +
|
||||
((pMem->flags&MEM_Static) ? 1 : 0)
|
||||
);
|
||||
assert( sqlite3VdbeCheckMemInvariants(pMem) );
|
||||
assert( (pMem->flags&MEM_RowSet)==0 );
|
||||
|
||||
/* If the bPreserve flag is set to true, then the memory cell must already
|
||||
@@ -90,7 +121,8 @@ int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
|
||||
pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n);
|
||||
}
|
||||
if( pMem->zMalloc==0 ){
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
VdbeMemRelease(pMem);
|
||||
pMem->z = 0;
|
||||
pMem->flags = MEM_Null;
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@@ -99,13 +131,13 @@ int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
|
||||
if( pMem->z && bPreserve && pMem->z!=pMem->zMalloc ){
|
||||
memcpy(pMem->zMalloc, pMem->z, pMem->n);
|
||||
}
|
||||
if( (pMem->flags&MEM_Dyn)!=0 && pMem->xDel ){
|
||||
assert( pMem->xDel!=SQLITE_DYNAMIC );
|
||||
if( (pMem->flags&MEM_Dyn)!=0 ){
|
||||
assert( pMem->xDel!=0 && pMem->xDel!=SQLITE_DYNAMIC );
|
||||
pMem->xDel((void *)(pMem->z));
|
||||
}
|
||||
|
||||
pMem->z = pMem->zMalloc;
|
||||
pMem->flags &= ~(MEM_Ephem|MEM_Static);
|
||||
pMem->flags &= ~(MEM_Dyn|MEM_Ephem|MEM_Static);
|
||||
pMem->xDel = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -274,9 +306,9 @@ void sqlite3VdbeMemReleaseExternal(Mem *p){
|
||||
sqlite3VdbeMemFinalize(p, p->u.pDef);
|
||||
assert( (p->flags & MEM_Agg)==0 );
|
||||
sqlite3VdbeMemRelease(p);
|
||||
}else if( p->flags&MEM_Dyn && p->xDel ){
|
||||
}else if( p->flags&MEM_Dyn ){
|
||||
assert( (p->flags&MEM_RowSet)==0 );
|
||||
assert( p->xDel!=SQLITE_DYNAMIC );
|
||||
assert( p->xDel!=SQLITE_DYNAMIC && p->xDel!=0 );
|
||||
p->xDel((void *)p->z);
|
||||
p->xDel = 0;
|
||||
}else if( p->flags&MEM_RowSet ){
|
||||
@@ -289,9 +321,10 @@ void sqlite3VdbeMemReleaseExternal(Mem *p){
|
||||
/*
|
||||
** Release any memory held by the Mem. This may leave the Mem in an
|
||||
** inconsistent state, for example with (Mem.z==0) and
|
||||
** (Mem.memType==MEM_Str).
|
||||
** (Mem.flags==MEM_Str).
|
||||
*/
|
||||
void sqlite3VdbeMemRelease(Mem *p){
|
||||
assert( sqlite3VdbeCheckMemInvariants(p) );
|
||||
VdbeMemRelease(p);
|
||||
if( p->zMalloc ){
|
||||
sqlite3DbFree(p->db, p->zMalloc);
|
||||
@@ -480,7 +513,6 @@ void sqlite3VdbeMemSetNull(Mem *pMem){
|
||||
sqlite3RowSetClear(pMem->u.pRowSet);
|
||||
}
|
||||
MemSetTypeFlag(pMem, MEM_Null);
|
||||
pMem->memType = MEM_Null;
|
||||
}
|
||||
void sqlite3ValueSetNull(sqlite3_value *p){
|
||||
sqlite3VdbeMemSetNull((Mem*)p);
|
||||
@@ -493,7 +525,6 @@ void sqlite3ValueSetNull(sqlite3_value *p){
|
||||
void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->flags = MEM_Blob|MEM_Zero;
|
||||
pMem->memType = MEM_Blob;
|
||||
pMem->n = 0;
|
||||
if( n<0 ) n = 0;
|
||||
pMem->u.nZero = n;
|
||||
@@ -516,7 +547,6 @@ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->u.i = val;
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->memType = MEM_Int;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
@@ -531,7 +561,6 @@ void sqlite3VdbeMemSetDouble(Mem *pMem, double val){
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->r = val;
|
||||
pMem->flags = MEM_Real;
|
||||
pMem->memType = MEM_Real;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -629,6 +658,7 @@ int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
|
||||
VdbeMemRelease(pTo);
|
||||
memcpy(pTo, pFrom, MEMCELLSIZE);
|
||||
pTo->flags &= ~MEM_Dyn;
|
||||
pTo->xDel = 0;
|
||||
|
||||
if( pTo->flags&(MEM_Str|MEM_Blob) ){
|
||||
if( 0==(pFrom->flags&MEM_Static) ){
|
||||
@@ -739,7 +769,6 @@ int sqlite3VdbeMemSetStr(
|
||||
pMem->n = nByte;
|
||||
pMem->flags = flags;
|
||||
pMem->enc = (enc==0 ? SQLITE_UTF8 : enc);
|
||||
pMem->memType = flags&0x1f;
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
if( pMem->enc!=SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){
|
||||
@@ -754,119 +783,6 @@ int sqlite3VdbeMemSetStr(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Compare the values contained by the two memory cells, returning
|
||||
** negative, zero or positive if pMem1 is less than, equal to, or greater
|
||||
** than pMem2. Sorting order is NULL's first, followed by numbers (integers
|
||||
** and reals) sorted numerically, followed by text ordered by the collating
|
||||
** sequence pColl and finally blob's ordered by memcmp().
|
||||
**
|
||||
** Two NULL values are considered equal by this function.
|
||||
*/
|
||||
int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
|
||||
int rc;
|
||||
int f1, f2;
|
||||
int combined_flags;
|
||||
|
||||
f1 = pMem1->flags;
|
||||
f2 = pMem2->flags;
|
||||
combined_flags = f1|f2;
|
||||
assert( (combined_flags & MEM_RowSet)==0 );
|
||||
|
||||
/* If one value is NULL, it is less than the other. If both values
|
||||
** are NULL, return 0.
|
||||
*/
|
||||
if( combined_flags&MEM_Null ){
|
||||
return (f2&MEM_Null) - (f1&MEM_Null);
|
||||
}
|
||||
|
||||
/* If one value is a number and the other is not, the number is less.
|
||||
** If both are numbers, compare as reals if one is a real, or as integers
|
||||
** if both values are integers.
|
||||
*/
|
||||
if( combined_flags&(MEM_Int|MEM_Real) ){
|
||||
double r1, r2;
|
||||
if( (f1 & f2 & MEM_Int)!=0 ){
|
||||
if( pMem1->u.i < pMem2->u.i ) return -1;
|
||||
if( pMem1->u.i > pMem2->u.i ) return 1;
|
||||
return 0;
|
||||
}
|
||||
if( (f1&MEM_Real)!=0 ){
|
||||
r1 = pMem1->r;
|
||||
}else if( (f1&MEM_Int)!=0 ){
|
||||
r1 = (double)pMem1->u.i;
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
if( (f2&MEM_Real)!=0 ){
|
||||
r2 = pMem2->r;
|
||||
}else if( (f2&MEM_Int)!=0 ){
|
||||
r2 = (double)pMem2->u.i;
|
||||
}else{
|
||||
return -1;
|
||||
}
|
||||
if( r1<r2 ) return -1;
|
||||
if( r1>r2 ) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If one value is a string and the other is a blob, the string is less.
|
||||
** If both are strings, compare using the collating functions.
|
||||
*/
|
||||
if( combined_flags&MEM_Str ){
|
||||
if( (f1 & MEM_Str)==0 ){
|
||||
return 1;
|
||||
}
|
||||
if( (f2 & MEM_Str)==0 ){
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert( pMem1->enc==pMem2->enc );
|
||||
assert( pMem1->enc==SQLITE_UTF8 ||
|
||||
pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE );
|
||||
|
||||
/* The collation sequence must be defined at this point, even if
|
||||
** the user deletes the collation sequence after the vdbe program is
|
||||
** compiled (this was not always the case).
|
||||
*/
|
||||
assert( !pColl || pColl->xCmp );
|
||||
|
||||
if( pColl ){
|
||||
if( pMem1->enc==pColl->enc ){
|
||||
/* The strings are already in the correct encoding. Call the
|
||||
** comparison function directly */
|
||||
return pColl->xCmp(pColl->pUser,pMem1->n,pMem1->z,pMem2->n,pMem2->z);
|
||||
}else{
|
||||
const void *v1, *v2;
|
||||
int n1, n2;
|
||||
Mem c1;
|
||||
Mem c2;
|
||||
memset(&c1, 0, sizeof(c1));
|
||||
memset(&c2, 0, sizeof(c2));
|
||||
sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem);
|
||||
sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem);
|
||||
v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc);
|
||||
n1 = v1==0 ? 0 : c1.n;
|
||||
v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc);
|
||||
n2 = v2==0 ? 0 : c2.n;
|
||||
rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2);
|
||||
sqlite3VdbeMemRelease(&c1);
|
||||
sqlite3VdbeMemRelease(&c2);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
/* If a NULL pointer was passed as the collate function, fall through
|
||||
** to the blob case and use memcmp(). */
|
||||
}
|
||||
|
||||
/* Both values must be blobs. Compare using memcmp(). */
|
||||
rc = memcmp(pMem1->z, pMem2->z, (pMem1->n>pMem2->n)?pMem2->n:pMem1->n);
|
||||
if( rc==0 ){
|
||||
rc = pMem1->n - pMem2->n;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Move data out of a btree key or data field and into a Mem structure.
|
||||
** The data or key is taken from the entry that pCur is currently pointing
|
||||
@@ -907,22 +823,22 @@ int sqlite3VdbeMemFromBtree(
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->z = &zData[offset];
|
||||
pMem->flags = MEM_Blob|MEM_Ephem;
|
||||
pMem->n = (int)amt;
|
||||
}else if( SQLITE_OK==(rc = sqlite3VdbeMemGrow(pMem, amt+2, 0)) ){
|
||||
pMem->flags = MEM_Blob|MEM_Dyn|MEM_Term;
|
||||
pMem->enc = 0;
|
||||
pMem->memType = MEM_Blob;
|
||||
if( key ){
|
||||
rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z);
|
||||
}else{
|
||||
rc = sqlite3BtreeData(pCur, offset, amt, pMem->z);
|
||||
}
|
||||
pMem->z[amt] = 0;
|
||||
pMem->z[amt+1] = 0;
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( rc==SQLITE_OK ){
|
||||
pMem->z[amt] = 0;
|
||||
pMem->z[amt+1] = 0;
|
||||
pMem->flags = MEM_Blob|MEM_Term;
|
||||
pMem->n = (int)amt;
|
||||
}else{
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
}
|
||||
}
|
||||
pMem->n = (int)amt;
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -980,7 +896,6 @@ sqlite3_value *sqlite3ValueNew(sqlite3 *db){
|
||||
Mem *p = sqlite3DbMallocZero(db, sizeof(*p));
|
||||
if( p ){
|
||||
p->flags = MEM_Null;
|
||||
p->memType = MEM_Null;
|
||||
p->db = db;
|
||||
}
|
||||
return p;
|
||||
@@ -1026,11 +941,9 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
|
||||
if( pRec->pKeyInfo ){
|
||||
assert( pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField==nCol );
|
||||
assert( pRec->pKeyInfo->enc==ENC(db) );
|
||||
pRec->flags = UNPACKED_PREFIX_MATCH;
|
||||
pRec->aMem = (Mem *)((u8*)pRec + ROUND8(sizeof(UnpackedRecord)));
|
||||
for(i=0; i<nCol; i++){
|
||||
pRec->aMem[i].flags = MEM_Null;
|
||||
pRec->aMem[i].memType = MEM_Null;
|
||||
pRec->aMem[i].db = db;
|
||||
}
|
||||
}else{
|
||||
@@ -1103,7 +1016,6 @@ static int valueFromExpr(
|
||||
zVal = sqlite3MPrintf(db, "%s%s", zNeg, pExpr->u.zToken);
|
||||
if( zVal==0 ) goto no_mem;
|
||||
sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC);
|
||||
if( op==TK_FLOAT ) pVal->memType = MEM_Real;
|
||||
}
|
||||
if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_NONE ){
|
||||
sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8);
|
||||
@@ -1121,9 +1033,9 @@ static int valueFromExpr(
|
||||
){
|
||||
sqlite3VdbeMemNumerify(pVal);
|
||||
if( pVal->u.i==SMALLEST_INT64 ){
|
||||
pVal->flags &= MEM_Int;
|
||||
pVal->flags &= ~MEM_Int;
|
||||
pVal->flags |= MEM_Real;
|
||||
pVal->r = (double)LARGEST_INT64;
|
||||
pVal->r = (double)SMALLEST_INT64;
|
||||
}else{
|
||||
pVal->u.i = -pVal->u.i;
|
||||
}
|
||||
@@ -1149,9 +1061,6 @@ static int valueFromExpr(
|
||||
}
|
||||
#endif
|
||||
|
||||
if( pVal ){
|
||||
sqlite3VdbeMemStoreType(pVal);
|
||||
}
|
||||
*ppVal = pVal;
|
||||
return rc;
|
||||
|
||||
@@ -1315,7 +1224,6 @@ int sqlite3Stat4ProbeSetValue(
|
||||
sqlite3ValueApplyAffinity(pVal, affinity, ENC(db));
|
||||
}
|
||||
pVal->db = pParse->db;
|
||||
sqlite3VdbeMemStoreType((Mem*)pVal);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
|
||||
+1198
-451
File diff suppressed because it is too large
Load Diff
@@ -1306,7 +1306,7 @@ int sqlite3WalOpen(
|
||||
sqlite3OsClose(pRet->pWalFd);
|
||||
sqlite3_free(pRet);
|
||||
}else{
|
||||
int iDC = sqlite3OsDeviceCharacteristics(pRet->pWalFd);
|
||||
int iDC = sqlite3OsDeviceCharacteristics(pDbFd);
|
||||
if( iDC & SQLITE_IOCAP_SEQUENTIAL ){ pRet->syncHeader = 0; }
|
||||
if( iDC & SQLITE_IOCAP_POWERSAFE_OVERWRITE ){
|
||||
pRet->padToSectorBoundary = 0;
|
||||
@@ -2677,7 +2677,7 @@ static int walWriteToLog(
|
||||
iAmt -= iFirstAmt;
|
||||
pContent = (void*)(iFirstAmt + (char*)pContent);
|
||||
assert( p->syncFlags & (SQLITE_SYNC_NORMAL|SQLITE_SYNC_FULL) );
|
||||
rc = sqlite3OsSync(p->pFd, p->syncFlags);
|
||||
rc = sqlite3OsSync(p->pFd, p->syncFlags & SQLITE_SYNC_MASK);
|
||||
if( iAmt==0 || rc ) return rc;
|
||||
}
|
||||
rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset);
|
||||
|
||||
+390
-235
File diff suppressed because it is too large
Load Diff
+3
-4
@@ -121,7 +121,7 @@ struct WhereLoop {
|
||||
struct { /* Information for virtual tables */
|
||||
int idxNum; /* Index number */
|
||||
u8 needFree; /* True if sqlite3_free(idxStr) is needed */
|
||||
u8 isOrdered; /* True if satisfies ORDER BY */
|
||||
i8 isOrdered; /* True if satisfies ORDER BY */
|
||||
u16 omitMask; /* Terms that may be omitted */
|
||||
char *idxStr; /* Index identifier string */
|
||||
} vtab;
|
||||
@@ -183,8 +183,7 @@ struct WherePath {
|
||||
Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */
|
||||
LogEst nRow; /* Estimated number of rows generated by this path */
|
||||
LogEst rCost; /* Total cost of this path */
|
||||
u8 isOrdered; /* True if this path satisfies ORDER BY */
|
||||
u8 isOrderedValid; /* True if the isOrdered field is valid */
|
||||
i8 isOrdered; /* No. of ORDER BY terms satisfied. -1 for unknown */
|
||||
WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */
|
||||
};
|
||||
|
||||
@@ -398,7 +397,7 @@ struct WhereInfo {
|
||||
Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
|
||||
LogEst nRowOut; /* Estimated number of output rows */
|
||||
u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
|
||||
u8 bOBSat; /* ORDER BY satisfied by indices */
|
||||
i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */
|
||||
u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */
|
||||
u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
|
||||
u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */
|
||||
|
||||
@@ -334,4 +334,25 @@ do_test alter4-8.2 {
|
||||
}
|
||||
} [list $::sql]
|
||||
|
||||
|
||||
# Test that a default value equal to -1 multipied by the smallest possible
|
||||
# 64-bit integer is correctly converted to a real.
|
||||
do_execsql_test alter4-9.1 {
|
||||
CREATE TABLE t5(
|
||||
a INTEGER DEFAULT -9223372036854775808,
|
||||
b INTEGER DEFAULT (-(-9223372036854775808))
|
||||
);
|
||||
INSERT INTO t5 DEFAULT VALUES;
|
||||
}
|
||||
|
||||
do_execsql_test alter4-9.2 { SELECT typeof(a), a, typeof(b), b FROM t5; } {
|
||||
integer -9223372036854775808
|
||||
real 9.22337203685478e+18
|
||||
}
|
||||
|
||||
do_execsql_test alter4-9.3 {
|
||||
ALTER TABLE t5 ADD COLUMN c INTEGER DEFAULT (-(-9223372036854775808));
|
||||
SELECT typeof(c), c FROM t5;
|
||||
} {real 9.22337203685478e+18}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -326,6 +326,7 @@ do_execsql_test 6.2 {
|
||||
reset_db
|
||||
sqlite3_db_config_lookaside db 0 0 0
|
||||
|
||||
database_may_be_corrupt
|
||||
do_execsql_test 7.1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE INDEX i1 ON t1(a, b);
|
||||
@@ -366,6 +367,8 @@ do_execsql_test 7.5 {
|
||||
SELECT * FROM t1 WHERE a = 5;
|
||||
} {5 5}
|
||||
|
||||
database_never_corrupt
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix capi3
|
||||
|
||||
# Do not use a codec for tests in this file, as the database file is
|
||||
# manipulated directly using tcl scripts (using the [hexio_write] command).
|
||||
@@ -1221,6 +1222,23 @@ do_test capi3-19.1 {
|
||||
sqlite3_prepare_tkt3134 db
|
||||
} {}
|
||||
|
||||
# Test that calling sqlite3_column_blob() on a TEXT value does not change
|
||||
# the return type of subsequent calls to sqlite3_column_type().
|
||||
#
|
||||
do_execsql_test 20.1 {
|
||||
CREATE TABLE t4(x);
|
||||
INSERT INTO t4 VALUES('abcdefghij');
|
||||
}
|
||||
do_test 20.2 {
|
||||
set stmt [sqlite3_prepare db "SELECT * FROM t4" -1 dummy]
|
||||
sqlite3_step $stmt
|
||||
} {SQLITE_ROW}
|
||||
do_test 20.3 { sqlite3_column_type $stmt 0 } {TEXT}
|
||||
do_test 20.4 { sqlite3_column_blob $stmt 0 } {abcdefghij}
|
||||
do_test 20.5 { sqlite3_column_type $stmt 0 } {TEXT}
|
||||
do_test 20.6 { sqlite3_finalize $stmt } SQLITE_OK
|
||||
|
||||
|
||||
# Tests of the interface when no VFS is registered.
|
||||
#
|
||||
if {![info exists tester_do_binarylog]} {
|
||||
|
||||
+5
-1
@@ -20,7 +20,11 @@ source $testdir/tester.tcl
|
||||
# Make sure the system encoding is utf-8. Otherwise, if the system encoding
|
||||
# is other than utf-8, [file isfile $x] may not refer to the same file
|
||||
# as [sqlite3 db $x].
|
||||
encoding system utf-8
|
||||
#
|
||||
# This is no longer needed here because it should be done within the test
|
||||
# fixture executable itself, via Tcl_SetSystemEncoding.
|
||||
#
|
||||
# encoding system utf-8
|
||||
|
||||
# Do not use a codec for tests in this file, as the database file is
|
||||
# manipulated directly using tcl scripts (using the [hexio_write] command).
|
||||
|
||||
+3
-8
@@ -47,12 +47,12 @@ do_test 1.2 {
|
||||
catchsql {
|
||||
SELECT c FROM t1 WHERE a>'abc';
|
||||
}
|
||||
} {0 {}}
|
||||
} {1 {database disk image is malformed}}
|
||||
do_test 1.3 {
|
||||
catchsql {
|
||||
PRAGMA integrity_check
|
||||
}
|
||||
} {0 ok}
|
||||
} {1 {database disk image is malformed}}
|
||||
do_test 1.4 {
|
||||
catchsql {
|
||||
SELECT c FROM t1 ORDER BY a;
|
||||
@@ -71,11 +71,6 @@ do_test 2.1 {
|
||||
catchsql {
|
||||
SELECT rowid FROM t1 WHERE a='abc' and b='xyz123456789XYZ';
|
||||
}
|
||||
# The following test result is brittle. The point above is to try to
|
||||
# force a buffer overread by a corrupt database file. If we get an
|
||||
# incorrect answer from a corrupt database file, that is OK. If the
|
||||
# result below changes, that just means that "undefined behavior" has
|
||||
# changed.
|
||||
} {0 52}
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
finish_test
|
||||
|
||||
+13
-11
@@ -20,6 +20,18 @@ set testprefix corruptH
|
||||
do_not_use_codec
|
||||
database_may_be_corrupt
|
||||
|
||||
# The corruption migrations tested by the code in this file are not detected
|
||||
# mmap mode.
|
||||
#
|
||||
# The reason is that in mmap mode, the different queries may use different
|
||||
# PgHdr objects for the same page (same data, but different PgHdr container
|
||||
# objects). And so the corruption is not detected.
|
||||
#
|
||||
if {[permutation]=="mmap"} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# Initialize the database.
|
||||
#
|
||||
do_execsql_test 1.1 {
|
||||
@@ -52,6 +64,7 @@ do_test 1.2 {
|
||||
} {}
|
||||
|
||||
do_test 1.3 {
|
||||
breakpoint
|
||||
db eval { PRAGMA secure_delete=1 }
|
||||
list [catch {
|
||||
db eval { SELECT * FROM t1 WHERE a IN (1, 2) } {
|
||||
@@ -97,9 +110,6 @@ do_test 2.2 {
|
||||
} {}
|
||||
|
||||
|
||||
# The corruption migration caused by the test case below does not
|
||||
# cause corruption to be detected in mmap mode.
|
||||
#
|
||||
# The trick here is that the root page of the tree scanned by the outer
|
||||
# query is also currently on the free-list. So while the first seek on
|
||||
# the table (for a==1) works, by the time the second is attempted The
|
||||
@@ -109,15 +119,7 @@ do_test 2.2 {
|
||||
# the cursor (as it is now marked with PgHdr.intKey==0) and returns
|
||||
# SQLITE_CORRUPT.
|
||||
#
|
||||
# However, in mmap mode, the outer query and the inner queries use
|
||||
# different PgHdr objects (same data, but different PgHdr container
|
||||
# objects). And so the corruption is not detected. Instead, the second
|
||||
# seek fails to find anything and only a single row is returned.
|
||||
#
|
||||
set res23 {1 {database disk image is malformed}}
|
||||
if {[permutation]=="mmap"} {
|
||||
set res23 {0 one}
|
||||
}
|
||||
do_test 2.3 {
|
||||
list [catch {
|
||||
set res [list]
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
# 2014-01-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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix corruptI
|
||||
|
||||
if {[permutation]=="mmap"} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# Do not use a codec for tests in this file, as the database file is
|
||||
# manipulated directly using tcl scripts (using the [hexio_write] command).
|
||||
#
|
||||
do_not_use_codec
|
||||
database_may_be_corrupt
|
||||
|
||||
# Initialize the database.
|
||||
#
|
||||
do_execsql_test 1.1 {
|
||||
PRAGMA page_size=1024;
|
||||
PRAGMA auto_vacuum=0;
|
||||
CREATE TABLE t1(a);
|
||||
CREATE INDEX i1 ON t1(a);
|
||||
INSERT INTO t1 VALUES('abcdefghijklmnop');
|
||||
} {}
|
||||
db close
|
||||
|
||||
do_test 1.2 {
|
||||
set offset [hexio_get_int [hexio_read test.db [expr 2*1024 + 8] 2]]
|
||||
set off [expr 2*1024 + $offset + 1]
|
||||
hexio_write test.db $off 7f06
|
||||
sqlite3 db test.db
|
||||
catchsql { SELECT * FROM t1 WHERE a = 10 }
|
||||
} {0 {}}
|
||||
|
||||
do_test 1.3 {
|
||||
db close
|
||||
set offset [hexio_get_int [hexio_read test.db [expr 2*1024 + 8] 2]]
|
||||
set off [expr 2*1024 + $offset + 1]
|
||||
hexio_write test.db $off FFFF7f02
|
||||
sqlite3 db test.db
|
||||
catchsql { SELECT * FROM t1 WHERE a = 10 }
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
do_test 2.0 {
|
||||
execsql {
|
||||
CREATE TABLE r(x);
|
||||
INSERT INTO r VALUES('ABCDEFGHIJK');
|
||||
CREATE INDEX r1 ON r(x);
|
||||
}
|
||||
set pg [db one {SELECT rootpage FROM sqlite_master WHERE name = 'r1'}]
|
||||
} {5}
|
||||
|
||||
do_test 2.1 {
|
||||
db close
|
||||
set offset [hexio_get_int [hexio_read test.db [expr (5-1)*1024 + 8] 2]]
|
||||
set off [expr (5-1)*1024 + $offset + 1]
|
||||
hexio_write test.db $off FFFF0004
|
||||
sqlite3 db test.db
|
||||
catchsql { SELECT * FROM r WHERE x >= 10.0 }
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
do_test 2.2 {
|
||||
catchsql { SELECT * FROM r WHERE x >= 10 }
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
|
||||
finish_test
|
||||
+1
-1
@@ -162,7 +162,7 @@ do_execsql_test 2.0 {
|
||||
foreach {tn sql temptables res} {
|
||||
1 "a, b FROM t1" {} {A B a b}
|
||||
2 "b, a FROM t1" {} {B A b a}
|
||||
3 "a, b, c FROM t1" {hash} {a b c A B C}
|
||||
3 "a, b, c FROM t1" {hash} {A B C a b c}
|
||||
4 "a, b, c FROM t1 ORDER BY a, b, c" {btree} {A B C a b c}
|
||||
5 "b FROM t1 WHERE a = 'a'" {} {b}
|
||||
6 "b FROM t1 ORDER BY +b COLLATE binary" {btree hash} {B b}
|
||||
|
||||
@@ -219,4 +219,32 @@ do_execsql_test 5.2 {
|
||||
SELECT count(*) FROM sqlite_master WHERE name LIKE 't8%';
|
||||
} {0 6}
|
||||
|
||||
# At one point this was causing a memory leak.
|
||||
#
|
||||
foreach {tn sql} {
|
||||
1 {}
|
||||
2 { INSERT INTO ft(ft) VALUES('merge=2,2'); }
|
||||
} {
|
||||
reset_db
|
||||
do_execsql_test 6.$tn.1 "
|
||||
CREATE TABLE t1(x);
|
||||
CREATE VIRTUAL TABLE ft USING fts3;
|
||||
INSERT INTO ft VALUES('hello world');
|
||||
$sql
|
||||
"
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 6.$tn.2 { SELECT * FROM t1 } {}
|
||||
|
||||
do_test 6.$tn.3 {
|
||||
sqlite3 db2 test.db
|
||||
db2 eval { DROP TABLE t1 }
|
||||
db2 close
|
||||
set stmt [sqlite3_prepare db { SELECT * FROM ft } -1 dummy]
|
||||
sqlite3_finalize $stmt
|
||||
} {SQLITE_OK}
|
||||
db close
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -354,6 +354,17 @@ do_test fts3d-6.5 {
|
||||
SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1;
|
||||
}
|
||||
} {xyz_content xyz_segdir xyz_segments}
|
||||
|
||||
# ALTER TABLE RENAME on an FTS3 table following an incr-merge op.
|
||||
#
|
||||
do_test fts3d-6.6 {
|
||||
execsql { INSERT INTO xyz(xyz) VALUES('merge=2,2') }
|
||||
sqlite3 db test.db
|
||||
execsql {
|
||||
ALTER TABLE xyz RENAME TO ott;
|
||||
SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1;
|
||||
}
|
||||
} {ott_content ott_segdir ott_segments ott_stat}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -1361,4 +1361,9 @@ for {set i 65536} {$i<=0x10ffff} {incr i 139} {
|
||||
do_execsql_test func-30.5.$i {SELECT unicode(char($i))} $i
|
||||
}
|
||||
|
||||
# Test char().
|
||||
#
|
||||
do_execsql_test func-31.1 {
|
||||
SELECT char(), length(char()), typeof(char())
|
||||
} {{} 0 text}
|
||||
finish_test
|
||||
|
||||
+177
@@ -159,4 +159,181 @@ do_test in4-3.12 {
|
||||
execsql { SELECT * FROM t3 WHERE x IN (1, 2) AND y IN ()}
|
||||
} {}
|
||||
|
||||
# Tests for "... IN (?)" and "... NOT IN (?)". In other words, tests
|
||||
# for when the RHS of IN is a single expression. This should work the
|
||||
# same as the == and <> operators.
|
||||
#
|
||||
do_execsql_test in4-3.21 {
|
||||
SELECT * FROM t3 WHERE x=10 AND y IN (10);
|
||||
} {10 10 10}
|
||||
do_execsql_test in4-3.22 {
|
||||
SELECT * FROM t3 WHERE x IN (10) AND y=10;
|
||||
} {10 10 10}
|
||||
do_execsql_test in4-3.23 {
|
||||
SELECT * FROM t3 WHERE x IN (10) AND y IN (10);
|
||||
} {10 10 10}
|
||||
do_execsql_test in4-3.24 {
|
||||
SELECT * FROM t3 WHERE x=1 AND y NOT IN (10);
|
||||
} {1 1 1}
|
||||
do_execsql_test in4-3.25 {
|
||||
SELECT * FROM t3 WHERE x NOT IN (10) AND y=1;
|
||||
} {1 1 1}
|
||||
do_execsql_test in4-3.26 {
|
||||
SELECT * FROM t3 WHERE x NOT IN (10) AND y NOT IN (10);
|
||||
} {1 1 1}
|
||||
|
||||
# The query planner recognizes that "x IN (?)" only generates a
|
||||
# single match and can use this information to optimize-out ORDER BY
|
||||
# clauses.
|
||||
#
|
||||
do_execsql_test in4-3.31 {
|
||||
DROP INDEX t3i1;
|
||||
CREATE UNIQUE INDEX t3xy ON t3(x,y);
|
||||
|
||||
SELECT *, '|' FROM t3 A, t3 B
|
||||
WHERE A.x=10 AND A.y IN (10)
|
||||
AND B.x=1 AND B.y IN (1);
|
||||
} {10 10 10 1 1 1 |}
|
||||
do_execsql_test in4-3.32 {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT *, '|' FROM t3 A, t3 B
|
||||
WHERE A.x=10 AND A.y IN (10)
|
||||
AND B.x=1 AND B.y IN (1);
|
||||
} {~/B-TREE/} ;# No separate sorting pass
|
||||
do_execsql_test in4-3.33 {
|
||||
SELECT *, '|' FROM t3 A, t3 B
|
||||
WHERE A.x IN (10) AND A.y=10
|
||||
AND B.x IN (1) AND B.y=1;
|
||||
} {10 10 10 1 1 1 |}
|
||||
do_execsql_test in4-3.34 {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT *, '|' FROM t3 A, t3 B
|
||||
WHERE A.x IN (10) AND A.y=10
|
||||
AND B.x IN (1) AND B.y=1;
|
||||
} {~/B-TREE/} ;# No separate sorting pass
|
||||
|
||||
# An expression of the form "x IN (?,?)" creates an ephemeral table to
|
||||
# hold the list of values on the RHS. But "x IN (?)" does not create
|
||||
# an ephemeral table.
|
||||
#
|
||||
do_execsql_test in4-3.41 {
|
||||
SELECT * FROM t3 WHERE x IN (10,11);
|
||||
} {10 10 10}
|
||||
do_execsql_test in4-3.42 {
|
||||
EXPLAIN
|
||||
SELECT * FROM t3 WHERE x IN (10,11);
|
||||
} {/OpenEphemeral/}
|
||||
do_execsql_test in4-3.43 {
|
||||
SELECT * FROM t3 WHERE x IN (10);
|
||||
} {10 10 10}
|
||||
do_execsql_test in4-3.44 {
|
||||
EXPLAIN
|
||||
SELECT * FROM t3 WHERE x IN (10);
|
||||
} {~/OpenEphemeral/}
|
||||
do_execsql_test in4-3.45 {
|
||||
SELECT * FROM t3 WHERE x NOT IN (10,11);
|
||||
} {1 1 1}
|
||||
do_execsql_test in4-3.46 {
|
||||
EXPLAIN
|
||||
SELECT * FROM t3 WHERE x NOT IN (10,11);
|
||||
} {/OpenEphemeral/}
|
||||
do_execsql_test in4-3.47 {
|
||||
SELECT * FROM t3 WHERE x NOT IN (10);
|
||||
} {1 1 1}
|
||||
do_execsql_test in4-3.48 {
|
||||
EXPLAIN
|
||||
SELECT * FROM t3 WHERE x NOT IN (10);
|
||||
} {~/OpenEphemeral/}
|
||||
|
||||
# Make sure that when "x IN (?)" is converted into "x==?" that collating
|
||||
# sequence and affinity computations do not get messed up.
|
||||
#
|
||||
do_execsql_test in4-4.1 {
|
||||
CREATE TABLE t4a(a TEXT, b TEXT COLLATE nocase, c);
|
||||
INSERT INTO t4a VALUES('ABC','abc',1);
|
||||
INSERT INTO t4a VALUES('def','xyz',2);
|
||||
INSERT INTO t4a VALUES('ghi','ghi',3);
|
||||
SELECT c FROM t4a WHERE a=b ORDER BY c;
|
||||
} {3}
|
||||
do_execsql_test in4-4.2 {
|
||||
SELECT c FROM t4a WHERE b=a ORDER BY c;
|
||||
} {1 3}
|
||||
do_execsql_test in4-4.3 {
|
||||
SELECT c FROM t4a WHERE (a||'')=b ORDER BY c;
|
||||
} {1 3}
|
||||
do_execsql_test in4-4.4 {
|
||||
SELECT c FROM t4a WHERE (a||'')=(b||'') ORDER BY c;
|
||||
} {3}
|
||||
do_execsql_test in4-4.5 {
|
||||
SELECT c FROM t4a WHERE a IN (b) ORDER BY c;
|
||||
} {3}
|
||||
do_execsql_test in4-4.6 {
|
||||
SELECT c FROM t4a WHERE (a||'') IN (b) ORDER BY c;
|
||||
} {3}
|
||||
|
||||
|
||||
do_execsql_test in4-4.11 {
|
||||
CREATE TABLE t4b(a TEXT, b NUMERIC, c);
|
||||
INSERT INTO t4b VALUES('1.0',1,4);
|
||||
SELECT c FROM t4b WHERE a=b;
|
||||
} {4}
|
||||
do_execsql_test in4-4.12 {
|
||||
SELECT c FROM t4b WHERE b=a;
|
||||
} {4}
|
||||
do_execsql_test in4-4.13 {
|
||||
SELECT c FROM t4b WHERE +a=b;
|
||||
} {4}
|
||||
do_execsql_test in4-4.14 {
|
||||
SELECT c FROM t4b WHERE a=+b;
|
||||
} {}
|
||||
do_execsql_test in4-4.15 {
|
||||
SELECT c FROM t4b WHERE +b=a;
|
||||
} {}
|
||||
do_execsql_test in4-4.16 {
|
||||
SELECT c FROM t4b WHERE b=+a;
|
||||
} {4}
|
||||
do_execsql_test in4-4.17 {
|
||||
SELECT c FROM t4b WHERE a IN (b);
|
||||
} {}
|
||||
do_execsql_test in4-4.18 {
|
||||
SELECT c FROM t4b WHERE b IN (a);
|
||||
} {4}
|
||||
do_execsql_test in4-4.19 {
|
||||
SELECT c FROM t4b WHERE +b IN (a);
|
||||
} {}
|
||||
|
||||
do_execsql_test in4-5.1 {
|
||||
CREATE TABLE t5(c INTEGER PRIMARY KEY, d TEXT COLLATE nocase);
|
||||
INSERT INTO t5 VALUES(17, 'fuzz');
|
||||
SELECT 1 FROM t5 WHERE 'fuzz' IN (d); -- match
|
||||
SELECT 2 FROM t5 WHERE 'FUZZ' IN (d); -- no match
|
||||
SELECT 3 FROM t5 WHERE d IN ('fuzz'); -- match
|
||||
SELECT 4 FROM t5 WHERE d IN ('FUZZ'); -- match
|
||||
} {1 3 4}
|
||||
|
||||
# An expression of the form "x IN (y)" can be used as "x=y" by the
|
||||
# query planner when computing transitive constraints or to run the
|
||||
# query using an index on y.
|
||||
#
|
||||
do_execsql_test in4-6.1 {
|
||||
CREATE TABLE t6a(a INTEGER PRIMARY KEY, b);
|
||||
INSERT INTO t6a VALUES(1,2),(3,4),(5,6);
|
||||
CREATE TABLE t6b(c INTEGER PRIMARY KEY, d);
|
||||
INSERT INTO t6b VALUES(4,44),(5,55),(6,66);
|
||||
|
||||
SELECT * FROM t6a, t6b WHERE a=3 AND b IN (c);
|
||||
} {3 4 4 44}
|
||||
do_execsql_test in4-6.1-eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t6a, t6b WHERE a=3 AND b IN (c);
|
||||
} {~/SCAN/}
|
||||
do_execsql_test in4-6.2 {
|
||||
SELECT * FROM t6a, t6b WHERE a=3 AND c IN (b);
|
||||
} {3 4 4 44}
|
||||
do_execsql_test in4-6.2-eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t6a, t6b WHERE a=3 AND c IN (b);
|
||||
} {~/SCAN/}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+11
-1
@@ -398,11 +398,21 @@ ifcapable compound {
|
||||
} {1 2 3 4 5 6 7 8 9}
|
||||
do_test insert-10.2 {
|
||||
catchsql {
|
||||
INSERT INTO t10 VALUES(11,12,13), (14,15);
|
||||
INSERT INTO t10 VALUES(11,12,13), (14,15), (16,17,28);
|
||||
}
|
||||
} {1 {all VALUES must have the same number of terms}}
|
||||
}
|
||||
|
||||
# Need for the OP_SoftNull opcode
|
||||
#
|
||||
do_execsql_test insert-11.1 {
|
||||
CREATE TABLE t11a AS SELECT '123456789' AS x;
|
||||
CREATE TABLE t11b (a INTEGER PRIMARY KEY, b, c);
|
||||
INSERT INTO t11b SELECT x, x, x FROM t11a;
|
||||
SELECT quote(a), quote(b), quote(c) FROM t11b;
|
||||
} {123456789 '123456789' '123456789'}
|
||||
|
||||
|
||||
integrity_check insert-99.0
|
||||
|
||||
finish_test
|
||||
|
||||
+1
-1
@@ -253,7 +253,7 @@ ifcapable vacuum {
|
||||
#
|
||||
do_test insert4-5.1 {
|
||||
# Table does not exist.
|
||||
catchsql { INSERT INTO t2 SELECT * FROM nosuchtable }
|
||||
catchsql { INSERT INTO t2 SELECT a, b FROM nosuchtable }
|
||||
} {1 {no such table: nosuchtable}}
|
||||
do_test insert4-5.2 {
|
||||
# Number of columns does not match.
|
||||
|
||||
@@ -641,4 +641,39 @@ do_test join-11.10 {
|
||||
execsql { SELECT * FROM t2 NATURAL JOIN t1 }
|
||||
} {1 one 2 two}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that at most 64 tables are allowed in a join.
|
||||
#
|
||||
do_execsql_test join-12.1 {
|
||||
CREATE TABLE t14(x);
|
||||
INSERT INTO t14 VALUES('abcdefghij');
|
||||
}
|
||||
|
||||
proc jointest {tn nTbl res} {
|
||||
set sql "SELECT 1 FROM [string repeat t14, [expr $nTbl-1]] t14;"
|
||||
uplevel [list do_catchsql_test $tn $sql $res]
|
||||
}
|
||||
|
||||
jointest join-12.2 30 {0 1}
|
||||
jointest join-12.3 63 {0 1}
|
||||
jointest join-12.4 64 {0 1}
|
||||
jointest join-12.5 65 {1 {at most 64 tables in a join}}
|
||||
jointest join-12.6 66 {1 {at most 64 tables in a join}}
|
||||
jointest join-12.7 127 {1 {at most 64 tables in a join}}
|
||||
jointest join-12.8 128 {1 {at most 64 tables in a join}}
|
||||
jointest join-12.9 1000 {1 {at most 64 tables in a join}}
|
||||
|
||||
# If SQLite is built with SQLITE_MEMDEBUG, then the huge number of realloc()
|
||||
# calls made by the following test cases are too time consuming to run.
|
||||
# Without SQLITE_MEMDEBUG, realloc() is fast enough that these are not
|
||||
# a problem.
|
||||
ifcapable pragma&&compileoption_diags {
|
||||
if {[lsearch [db eval {PRAGMA compile_options}] MEMDEBUG]<0} {
|
||||
jointest join-12.10 65534 {1 {at most 64 tables in a join}}
|
||||
jointest join-12.11 65535 {1 {too many references to "t14": max 65535}}
|
||||
jointest join-12.12 65536 {1 {too many references to "t14": max 65535}}
|
||||
jointest join-12.13 65537 {1 {too many references to "t14": max 65535}}
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -616,4 +616,24 @@ do_test limit-13.81 {
|
||||
db eval {SELECT z FROM v13c LIMIT 1 OFFSET 8}
|
||||
} {}
|
||||
|
||||
do_execsql_test limit-14.1 {
|
||||
SELECT 123 LIMIT 1 OFFSET 0
|
||||
} {123}
|
||||
do_execsql_test limit-14.2 {
|
||||
SELECT 123 LIMIT 1 OFFSET 1
|
||||
} {}
|
||||
do_execsql_test limit-14.3 {
|
||||
SELECT 123 LIMIT 0 OFFSET 0
|
||||
} {}
|
||||
do_execsql_test limit-14.4 {
|
||||
SELECT 123 LIMIT 0 OFFSET 1
|
||||
} {}
|
||||
do_execsql_test limit-14.6 {
|
||||
SELECT 123 LIMIT -1 OFFSET 0
|
||||
} {123}
|
||||
do_execsql_test limit-14.7 {
|
||||
SELECT 123 LIMIT -1 OFFSET 1
|
||||
} {}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+17
-4
@@ -66,6 +66,12 @@ if {$::tcl_platform(os) eq "Darwin"} {
|
||||
set dlerror_nosymbol {dlsym(XXX, %2$s): symbol not found}
|
||||
}
|
||||
|
||||
if {$::tcl_platform(platform) eq "windows"} {
|
||||
set dlerror_nosuchfile {The specified module could not be found.*}
|
||||
set dlerror_notadll {%%1 is not a valid Win32 application.*}
|
||||
set dlerror_nosymbol {The specified procedure could not be found.*}
|
||||
}
|
||||
|
||||
# Make sure the test extension actually exists. If it does not
|
||||
# exist, try to create it. If unable to create it, then skip this
|
||||
# test file.
|
||||
@@ -167,7 +173,7 @@ do_test loadext-2.3 {
|
||||
regsub {0x[1234567890abcdefABCDEF]*} $msg XXX msg
|
||||
}
|
||||
list $rc $msg
|
||||
} [list 1 [format $dlerror_nosymbol $testextension icecream]]
|
||||
} /[list 1 [format $dlerror_nosymbol $testextension icecream]]/
|
||||
|
||||
# Try to load an extension for which the entry point fails (returns non-zero)
|
||||
#
|
||||
@@ -267,10 +273,17 @@ do_malloc_test loadext-5 -tclprep {
|
||||
} -tclbody {
|
||||
if {[autoinstall_test_functions]==7} {error "out of memory"}
|
||||
}
|
||||
do_malloc_test loadext-6 -tclbody {
|
||||
db enable_load_extension 1
|
||||
sqlite3_load_extension db $::testextension testloadext_init
|
||||
|
||||
# On Windows, this malloc test must be skipped because the winDlOpen
|
||||
# function itself can fail due to "out of memory" conditions.
|
||||
#
|
||||
if {$::tcl_platform(platform) ne "windows"} {
|
||||
do_malloc_test loadext-6 -tclbody {
|
||||
db enable_load_extension 1
|
||||
sqlite3_load_extension db $::testextension testloadext_init
|
||||
}
|
||||
}
|
||||
|
||||
autoinstall_test_functions
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -880,6 +880,28 @@ do_malloc_test 39 -tclprep {
|
||||
db close
|
||||
}
|
||||
|
||||
reset_db
|
||||
add_test_utf16bin_collate db
|
||||
do_execsql_test 40.1 {
|
||||
CREATE TABLE t1(a);
|
||||
INSERT INTO t1 VALUES('fghij');
|
||||
INSERT INTO t1 VALUES('pqrst');
|
||||
INSERT INTO t1 VALUES('abcde');
|
||||
INSERT INTO t1 VALUES('uvwxy');
|
||||
INSERT INTO t1 VALUES('klmno');
|
||||
}
|
||||
do_execsql_test 40.2 {
|
||||
SELECT * FROM t1 ORDER BY 1 COLLATE utf16bin;
|
||||
} {abcde fghij klmno pqrst uvwxy}
|
||||
do_faultsim_test 40.3 -faults oom-trans* -body {
|
||||
execsql {
|
||||
SELECT * FROM t1 ORDER BY 1 COLLATE utf16bin;
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {abcde fghij klmno pqrst uvwxy}}
|
||||
faultsim_integrity_check
|
||||
}
|
||||
|
||||
# Ensure that no file descriptors were leaked.
|
||||
do_test malloc-99.X {
|
||||
catch {db close}
|
||||
|
||||
+22
-1
@@ -25,7 +25,6 @@ if {!$MEMDEBUG} {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
# Construct a test database
|
||||
#
|
||||
forcedelete test.db.bu
|
||||
@@ -116,6 +115,28 @@ ifcapable stat3 {
|
||||
}
|
||||
}
|
||||
|
||||
do_execsql_test 7.0 {
|
||||
PRAGMA cache_size = 5;
|
||||
}
|
||||
do_faultsim_test 7 -faults oom-trans* -prep {
|
||||
if {$iFail < 500} { set iFail 2000 }
|
||||
if {$iFail > 1215} { set iFail 2000 }
|
||||
} -body {
|
||||
execsql {
|
||||
WITH r(x,y) AS (
|
||||
SELECT 1, randomblob(100)
|
||||
UNION ALL
|
||||
SELECT x+1, randomblob(100) FROM r
|
||||
LIMIT 1000
|
||||
)
|
||||
SELECT count(x), length(y) FROM r GROUP BY (x%5)
|
||||
}
|
||||
} -test {
|
||||
set res [list 200 100 200 100 200 100 200 100 200 100]
|
||||
faultsim_test_result [list 0 $res]
|
||||
}
|
||||
|
||||
|
||||
# Ensure that no file descriptors were leaked.
|
||||
do_test malloc-99.X {
|
||||
catch {db close}
|
||||
|
||||
+20
-2
@@ -64,10 +64,28 @@ do_execsql_test 1.7 {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT DISTINCT c, b, a FROM t1 WHERE +a=0;
|
||||
} {/B-TREE/}
|
||||
do_execsql_test 2.1 {
|
||||
|
||||
# In some cases, it is faster to do repeated index lookups than it is to
|
||||
# sort. But in other cases, it is faster to sort than to do repeated index
|
||||
# lookups.
|
||||
#
|
||||
do_execsql_test 2.1a {
|
||||
CREATE TABLE t2(a,b,c);
|
||||
CREATE INDEX t2bc ON t2(b,c);
|
||||
ANALYZE;
|
||||
INSERT INTO sqlite_stat1 VALUES('t1','t1bc','1000000 10 9');
|
||||
INSERT INTO sqlite_stat1 VALUES('t2','t2bc','100 10 5');
|
||||
ANALYZE sqlite_master;
|
||||
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t2 WHERE a=0 ORDER BY a, b, c;
|
||||
} {~/B-TREE/}
|
||||
do_execsql_test 2.1b {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t1 WHERE a=0 ORDER BY a, b, c;
|
||||
} {~/B-TREE/}
|
||||
} {/B-TREE/}
|
||||
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t1 WHERE +a=0 ORDER BY a, b, c;
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
# 2014-03-21
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing that the block-sort optimization.
|
||||
#
|
||||
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix orderby6
|
||||
|
||||
# Run all tests twice. Once with a normal table and a second time
|
||||
# with a WITHOUT ROWID table
|
||||
#
|
||||
foreach {tn rowidclause} {1 {} 2 {WITHOUT ROWID}} {
|
||||
|
||||
# Construct a table with 1000 rows and a split primary key
|
||||
#
|
||||
reset_db
|
||||
do_test $tn.1 {
|
||||
db eval "CREATE TABLE t1(a,b,c,PRIMARY KEY(b,c)) $rowidclause;"
|
||||
db eval {
|
||||
WITH RECURSIVE
|
||||
cnt(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM cnt WHERE x<1000)
|
||||
INSERT INTO t1 SELECT x, x%40, x/40 FROM cnt;
|
||||
}
|
||||
} {}
|
||||
|
||||
# Run various ORDER BY queries that can benefit from block-sort.
|
||||
# Compare the output to the same output using a full-sort enforced
|
||||
# by adding + to each term of the ORDER BY clause.
|
||||
#
|
||||
do_execsql_test $tn.2 {
|
||||
SELECT b,a,c FROM t1 ORDER BY b,a,c;
|
||||
} [db eval {SELECT b,a,c FROM t1 ORDER BY +b,+a,+c}]
|
||||
do_execsql_test $tn.3 {
|
||||
SELECT b,a,c FROM t1 ORDER BY b,c DESC,a;
|
||||
} [db eval {SELECT b,a,c FROM t1 ORDER BY +b,+c DESC,+a}]
|
||||
do_execsql_test $tn.4 {
|
||||
SELECT b,a,c FROM t1 ORDER BY b DESC,c,a;
|
||||
} [db eval {SELECT b,a,c FROM t1 ORDER BY +b DESC,+c,+a}]
|
||||
do_execsql_test $tn.5 {
|
||||
SELECT b,a,c FROM t1 ORDER BY b DESC,a,c;
|
||||
} [db eval {SELECT b,a,c FROM t1 ORDER BY +b DESC,+a,+c}]
|
||||
|
||||
# LIMIT and OFFSET clauses on block-sort queries.
|
||||
#
|
||||
do_execsql_test $tn.11 {
|
||||
SELECT a FROM t1 ORDER BY b, a LIMIT 10 OFFSET 20;
|
||||
} {840 880 920 960 1000 1 41 81 121 161}
|
||||
do_execsql_test $tn.11x {
|
||||
SELECT a FROM t1 ORDER BY +b, a LIMIT 10 OFFSET 20;
|
||||
} {840 880 920 960 1000 1 41 81 121 161}
|
||||
|
||||
do_execsql_test $tn.12 {
|
||||
SELECT a FROM t1 ORDER BY b DESC, a LIMIT 10 OFFSET 20;
|
||||
} {839 879 919 959 999 38 78 118 158 198}
|
||||
do_execsql_test $tn.12 {
|
||||
SELECT a FROM t1 ORDER BY +b DESC, a LIMIT 10 OFFSET 20;
|
||||
} {839 879 919 959 999 38 78 118 158 198}
|
||||
|
||||
do_execsql_test $tn.13 {
|
||||
SELECT a FROM t1 ORDER BY b, a DESC LIMIT 10 OFFSET 45;
|
||||
} {161 121 81 41 1 962 922 882 842 802}
|
||||
do_execsql_test $tn.13x {
|
||||
SELECT a FROM t1 ORDER BY +b, a DESC LIMIT 10 OFFSET 45;
|
||||
} {161 121 81 41 1 962 922 882 842 802}
|
||||
|
||||
do_execsql_test $tn.14 {
|
||||
SELECT a FROM t1 ORDER BY b DESC, a LIMIT 10 OFFSET 45;
|
||||
} {838 878 918 958 998 37 77 117 157 197}
|
||||
do_execsql_test $tn.14x {
|
||||
SELECT a FROM t1 ORDER BY +b DESC, a LIMIT 10 OFFSET 45;
|
||||
} {838 878 918 958 998 37 77 117 157 197}
|
||||
|
||||
# Many test cases where the LIMIT+OFFSET window is in various
|
||||
# alignments with block-sort boundaries.
|
||||
#
|
||||
foreach {tx limit offset orderby} {
|
||||
1 10 24 {+b,+a}
|
||||
2 10 25 {+b,+a}
|
||||
3 10 26 {+b,+a}
|
||||
4 10 39 {+b,+a}
|
||||
5 10 40 {+b,+a}
|
||||
6 10 41 {+b,+a}
|
||||
7 27 24 {+b,+a}
|
||||
8 27 49 {+b,+a}
|
||||
11 10 24 {+b DESC,+a}
|
||||
12 10 25 {+b DESC,+a}
|
||||
13 10 26 {+b DESC,+a}
|
||||
14 10 39 {+b DESC,+a}
|
||||
15 10 40 {+b DESC,+a}
|
||||
16 10 41 {+b DESC,+a}
|
||||
17 27 24 {+b DESC,+a}
|
||||
18 27 49 {+b DESC,+a}
|
||||
21 10 24 {+b,+a DESC}
|
||||
22 10 25 {+b,+a DESC}
|
||||
23 10 26 {+b,+a DESC}
|
||||
24 10 39 {+b,+a DESC}
|
||||
25 10 40 {+b,+a DESC}
|
||||
26 10 41 {+b,+a DESC}
|
||||
27 27 24 {+b,+a DESC}
|
||||
28 27 49 {+b,+a DESC}
|
||||
31 10 24 {+b DESC,+a DESC}
|
||||
32 10 25 {+b DESC,+a DESC}
|
||||
33 10 26 {+b DESC,+a DESC}
|
||||
34 10 39 {+b DESC,+a DESC}
|
||||
35 10 40 {+b DESC,+a DESC}
|
||||
36 10 41 {+b DESC,+a DESC}
|
||||
37 27 24 {+b DESC,+a DESC}
|
||||
38 27 49 {+b DESC,+a DESC}
|
||||
} {
|
||||
set sql1 "SELECT a FROM t1 ORDER BY $orderby LIMIT $limit OFFSET $offset;"
|
||||
set sql2 [string map {+ {}} $sql1]
|
||||
# puts $sql2\n$sql1\n[db eval $sql2]
|
||||
do_test $tn.21.$tx {db eval $::sql2} [db eval $sql1]
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# A second test table, t2, has many columns open to sorting.
|
||||
do_test $tn.31 {
|
||||
db eval "CREATE TABLE t2(a,b,c,d,e,f,PRIMARY KEY(b,c,d,e,f)) $rowidclause;"
|
||||
db eval {
|
||||
WITH RECURSIVE
|
||||
cnt(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM cnt WHERE x<242)
|
||||
INSERT INTO t2 SELECT x, x%3, (x/3)%3, (x/9)%3, (x/27)%3, (x/81)%3
|
||||
FROM cnt;
|
||||
}
|
||||
} {}
|
||||
|
||||
do_execsql_test $tn.32 {
|
||||
SELECT a FROM t2 ORDER BY b,c,d,e,f;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}]
|
||||
do_execsql_test $tn.33 {
|
||||
SELECT a FROM t2 ORDER BY b,c,d,e,+f;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}]
|
||||
do_execsql_test $tn.34 {
|
||||
SELECT a FROM t2 ORDER BY b,c,d,+e,+f;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}]
|
||||
do_execsql_test $tn.35 {
|
||||
SELECT a FROM t2 ORDER BY b,c,+d,+e,+f;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}]
|
||||
do_execsql_test $tn.36 {
|
||||
SELECT a FROM t2 ORDER BY b,+c,+d,+e,+f;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}]
|
||||
|
||||
do_execsql_test $tn.37 {
|
||||
SELECT a FROM t2 ORDER BY b,c,d,e,f DESC;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f DESC;}]
|
||||
do_execsql_test $tn.38 {
|
||||
SELECT a FROM t2 ORDER BY b,c,d,e DESC,f;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e DESC,+f;}]
|
||||
do_execsql_test $tn.39 {
|
||||
SELECT a FROM t2 ORDER BY b,c,d DESC,e,f;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d DESC,+e,+f;}]
|
||||
do_execsql_test $tn.40 {
|
||||
SELECT a FROM t2 ORDER BY b,c DESC,d,e,f;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b,+c DESC,+d,+e,+f;}]
|
||||
do_execsql_test $tn.41 {
|
||||
SELECT a FROM t2 ORDER BY b DESC,c,d,e,f;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b DESC,+c,+d,+e,+f;}]
|
||||
|
||||
do_execsql_test $tn.42 {
|
||||
SELECT a FROM t2 ORDER BY b DESC,c DESC,d,e,f LIMIT 31;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b DESC,+c DESC,+d,+e,+f LIMIT 31}]
|
||||
do_execsql_test $tn.43 {
|
||||
SELECT a FROM t2 ORDER BY b,c,d,e,f DESC LIMIT 8 OFFSET 7;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f DESC LIMIT 8 OFFSET 7}]
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -112,6 +112,7 @@ set allquicktests [test_set $alltests -exclude {
|
||||
incrvacuum_ioerr.test autovacuum_crash.test btree8.test shared_err.test
|
||||
vtab_err.test walslow.test walcrash.test walcrash3.test
|
||||
walthread.test rtree3.test indexfault.test securedel2.test
|
||||
sort3.test
|
||||
}]
|
||||
if {[info exists ::env(QUICKTEST_INCLUDE)]} {
|
||||
set allquicktests [concat $allquicktests $::env(QUICKTEST_INCLUDE)]
|
||||
|
||||
+13
-5
@@ -1575,6 +1575,8 @@ do_test pragma-20.8 {
|
||||
forcedelete data_dir
|
||||
} ;# endif windows
|
||||
|
||||
database_may_be_corrupt
|
||||
|
||||
do_test 21.1 {
|
||||
# Create a corrupt database in testerr.db. And a non-corrupt at test.db.
|
||||
#
|
||||
@@ -1600,11 +1602,16 @@ Multiple uses for byte 672 of page 15}
|
||||
set auxerr {*** in database aux ***
|
||||
Multiple uses for byte 672 of page 15}
|
||||
|
||||
set mainerr {/{\*\*\* in database main \*\*\*
|
||||
Multiple uses for byte 672 of page 15}.*/}
|
||||
set auxerr {/{\*\*\* in database aux \*\*\*
|
||||
Multiple uses for byte 672 of page 15}.*/}
|
||||
|
||||
do_test 22.2 {
|
||||
catch { db close }
|
||||
sqlite3 db testerr.db
|
||||
execsql { PRAGMA integrity_check }
|
||||
} [list $mainerr]
|
||||
} $mainerr
|
||||
|
||||
do_test 22.3.1 {
|
||||
catch { db close }
|
||||
@@ -1613,13 +1620,13 @@ do_test 22.3.1 {
|
||||
ATTACH 'testerr.db' AS 'aux';
|
||||
PRAGMA integrity_check;
|
||||
}
|
||||
} [list $auxerr]
|
||||
} $auxerr
|
||||
do_test 22.3.2 {
|
||||
execsql { PRAGMA main.integrity_check; }
|
||||
} {ok}
|
||||
do_test 22.3.3 {
|
||||
execsql { PRAGMA aux.integrity_check; }
|
||||
} [list $auxerr]
|
||||
} $auxerr
|
||||
|
||||
do_test 22.4.1 {
|
||||
catch { db close }
|
||||
@@ -1628,10 +1635,10 @@ do_test 22.4.1 {
|
||||
ATTACH 'test.db' AS 'aux';
|
||||
PRAGMA integrity_check;
|
||||
}
|
||||
} [list $mainerr]
|
||||
} $mainerr
|
||||
do_test 22.4.2 {
|
||||
execsql { PRAGMA main.integrity_check; }
|
||||
} [list $mainerr]
|
||||
} $mainerr
|
||||
do_test 22.4.3 {
|
||||
execsql { PRAGMA aux.integrity_check; }
|
||||
} {ok}
|
||||
@@ -1680,4 +1687,5 @@ do_test 23.5 {
|
||||
}
|
||||
} {0 0 t1 y {} {NO ACTION} {NO ACTION} NONE}
|
||||
|
||||
database_never_corrupt
|
||||
finish_test
|
||||
|
||||
@@ -824,4 +824,40 @@ do_test select4-13.1 {
|
||||
}
|
||||
} {1 2}
|
||||
|
||||
# 2014-02-18: Make sure compound SELECTs work with VALUES clauses
|
||||
#
|
||||
do_execsql_test select4-14.1 {
|
||||
CREATE TABLE t14(a,b,c);
|
||||
INSERT INTO t14 VALUES(1,2,3),(4,5,6);
|
||||
SELECT * FROM t14 INTERSECT VALUES(3,2,1),(2,3,1),(1,2,3),(2,1,3);
|
||||
} {1 2 3}
|
||||
do_execsql_test select4-14.2 {
|
||||
SELECT * FROM t14 INTERSECT VALUES(1,2,3);
|
||||
} {1 2 3}
|
||||
do_execsql_test select4-14.3 {
|
||||
SELECT * FROM t14
|
||||
UNION VALUES(3,2,1),(2,3,1),(1,2,3),(7,8,9),(4,5,6)
|
||||
UNION SELECT * FROM t14 ORDER BY 1, 2, 3
|
||||
} {1 2 3 2 3 1 3 2 1 4 5 6 7 8 9}
|
||||
do_execsql_test select4-14.4 {
|
||||
SELECT * FROM t14
|
||||
UNION VALUES(3,2,1)
|
||||
UNION SELECT * FROM t14 ORDER BY 1, 2, 3
|
||||
} {1 2 3 3 2 1 4 5 6}
|
||||
do_execsql_test select4-14.5 {
|
||||
SELECT * FROM t14 EXCEPT VALUES(3,2,1),(2,3,1),(1,2,3),(2,1,3);
|
||||
} {4 5 6}
|
||||
do_execsql_test select4-14.6 {
|
||||
SELECT * FROM t14 EXCEPT VALUES(1,2,3)
|
||||
} {4 5 6}
|
||||
do_execsql_test select4-14.7 {
|
||||
SELECT * FROM t14 EXCEPT VALUES(1,2,3) EXCEPT VALUES(4,5,6)
|
||||
} {}
|
||||
do_execsql_test select4-14.8 {
|
||||
SELECT * FROM t14 EXCEPT VALUES('a','b','c') EXCEPT VALUES(4,5,6)
|
||||
} {1 2 3}
|
||||
do_execsql_test select4-14.9 {
|
||||
SELECT * FROM t14 UNION ALL VALUES(3,2,1),(2,3,1),(1,2,3),(2,1,3);
|
||||
} {1 2 3 4 5 6 3 2 1 2 3 1 1 2 3 2 1 3}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -1292,5 +1292,22 @@ do_test selectA-3.97 {
|
||||
ORDER BY y COLLATE NOCASE DESC,x,z)))
|
||||
}
|
||||
} {MAD}
|
||||
do_execsql_test selectA-3.98 {
|
||||
WITH RECURSIVE
|
||||
xyz(n) AS (
|
||||
SELECT upper((SELECT x FROM (
|
||||
SELECT x,y,z FROM t2
|
||||
INTERSECT SELECT a,b,c FROM t3
|
||||
EXCEPT SELECT c,b,a FROM t1
|
||||
UNION SELECT a,b,c FROM t3
|
||||
INTERSECT SELECT a,b,c FROM t3
|
||||
EXCEPT SELECT c,b,a FROM t1
|
||||
UNION SELECT a,b,c FROM t3
|
||||
ORDER BY y COLLATE NOCASE DESC,x,z)))
|
||||
UNION ALL
|
||||
SELECT n || '+' FROM xyz WHERE length(n)<5
|
||||
)
|
||||
SELECT n FROM xyz ORDER BY +n;
|
||||
} {MAD MAD+ MAD++}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# 2014-03-03
|
||||
#
|
||||
# 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 verifies that an OP_Copy operation is used instead of OP_SCopy
|
||||
# in a compound select in a case where the source register might be changed
|
||||
# before the copy is used.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix selectF
|
||||
|
||||
do_execsql_test 1 {
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE t1(a, b, c);
|
||||
INSERT INTO "t1" VALUES(1,'one','I');
|
||||
CREATE TABLE t2(d, e, f);
|
||||
INSERT INTO "t2" VALUES(5,'ten','XX');
|
||||
INSERT INTO "t2" VALUES(6,NULL,NULL);
|
||||
|
||||
CREATE INDEX i1 ON t1(b, a);
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
#explain_i {
|
||||
# SELECT * FROM t2
|
||||
# UNION ALL
|
||||
# SELECT * FROM t1 WHERE a<5
|
||||
# ORDER BY 2, 1
|
||||
#}
|
||||
|
||||
do_execsql_test 2 {
|
||||
SELECT * FROM t2
|
||||
UNION ALL
|
||||
SELECT * FROM t1 WHERE a<5
|
||||
ORDER BY 2, 1
|
||||
} {6 {} {} 1 one I 5 ten XX}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
+1
-1
@@ -105,7 +105,7 @@ do_test shell1-1.7.1 {
|
||||
set rc [lindex $res 0]
|
||||
list $rc \
|
||||
[regexp {SQLite version} $res] \
|
||||
[regexp {Enter SQL statements} $res]
|
||||
[regexp {Enter ".help" for usage hints} $res]
|
||||
} {0 1 1}
|
||||
|
||||
# -batch force batch I/O
|
||||
|
||||
@@ -285,6 +285,25 @@ do_test shell5-1.10 {
|
||||
db eval {SELECT hex(c) FROM t1 ORDER BY rowid}
|
||||
} {636F6C756D6E33 783320220D0A64617461222033 783320220A64617461222033}
|
||||
|
||||
# Blank last column with \r\n line endings.
|
||||
do_test shell5-1.11 {
|
||||
set out [open shell5.csv w]
|
||||
fconfigure $out -translation binary
|
||||
puts $out "column1,column2,column3\r"
|
||||
puts $out "a,b, \r"
|
||||
puts $out "x,y,\r"
|
||||
puts $out "p,q,r\r"
|
||||
close $out
|
||||
catch {db close}
|
||||
forcedelete test.db
|
||||
catchcmd test.db {.mode csv
|
||||
.import shell5.csv t1
|
||||
}
|
||||
sqlite3 db test.db
|
||||
db eval {SELECT *, '|' FROM t1}
|
||||
} {a b { } | x y {} | p q r |}
|
||||
|
||||
|
||||
db close
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -209,4 +209,42 @@ do_execsql_test skipscan1-4.1 {
|
||||
SELECT i FROM t4 WHERE h=8;
|
||||
} {9 9 9 9 9 9 9 9}
|
||||
|
||||
# Make sure skip-scan cost computation in the query planner takes into
|
||||
# account the fact that the seek must occur multiple times.
|
||||
#
|
||||
# Prior to 2014-03-10, the costs were computed incorrectly which would
|
||||
# cause index t5i2 to be used instead of t5i1 on the skipscan1-5.3.
|
||||
#
|
||||
do_execsql_test skipscan1-5.1 {
|
||||
CREATE TABLE t5(
|
||||
id INTEGER PRIMARY KEY,
|
||||
loc TEXT,
|
||||
lang INTEGER,
|
||||
utype INTEGER,
|
||||
xa INTEGER,
|
||||
xd INTEGER,
|
||||
xh INTEGER
|
||||
);
|
||||
CREATE INDEX t5i1 on t5(loc, xh, xa, utype, lang);
|
||||
CREATE INDEX t5i2 ON t5(xd,loc,utype,lang);
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT xh, loc FROM t5 WHERE loc >= 'M' AND loc < 'N';
|
||||
} {/.*COVERING INDEX t5i1 .*/}
|
||||
do_execsql_test skipscan1-5.2 {
|
||||
ANALYZE;
|
||||
DELETE FROM sqlite_stat1;
|
||||
DROP TABLE IF EXISTS sqlite_stat4;
|
||||
DROP TABLE IF EXISTS sqlite_stat3;
|
||||
INSERT INTO sqlite_stat1 VALUES('t5','t5i1','2702931 3 2 2 2 2');
|
||||
INSERT INTO sqlite_stat1 VALUES('t5','t5i2','2702931 686 2 2 2');
|
||||
ANALYZE sqlite_master;
|
||||
} {}
|
||||
db cache flush
|
||||
do_execsql_test skipscan1-5.3 {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT xh, loc FROM t5 WHERE loc >= 'M' AND loc < 'N';
|
||||
} {/.*COVERING INDEX t5i1 .*/}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -464,4 +464,26 @@ do_test sort-12.1 {
|
||||
}
|
||||
} {1 2 xxx 1 3 yyy 1 1 zzz}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check that the sorter in vdbesort.c sorts in a stable fashion.
|
||||
#
|
||||
do_execsql_test sort-13.0 {
|
||||
CREATE TABLE t10(a, b);
|
||||
}
|
||||
do_test sort-13.1 {
|
||||
db transaction {
|
||||
for {set i 0} {$i < 100000} {incr i} {
|
||||
execsql { INSERT INTO t10 VALUES( $i/10, $i%10 ) }
|
||||
}
|
||||
}
|
||||
} {}
|
||||
do_execsql_test sort-13.2 {
|
||||
SELECT a, b FROM t10 ORDER BY a;
|
||||
} [db eval {SELECT a, b FROM t10 ORDER BY a, b}]
|
||||
do_execsql_test sort-13.3 {
|
||||
PRAGMA cache_size = 5;
|
||||
SELECT a, b FROM t10 ORDER BY a;
|
||||
} [db eval {SELECT a, b FROM t10 ORDER BY a, b}]
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user