Compare commits
169 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6193d49cdf | |||
| 54e2efcd2f | |||
| 50da9382f9 | |||
| 6948ed5977 | |||
| dbd6a7dc06 | |||
| ac48b751e2 | |||
| f4dd26c5a0 | |||
| 43606175e2 | |||
| 32d0eba4c2 | |||
| 75f9558808 | |||
| 628dfe163f | |||
| cfb3235752 | |||
| 761f691d0e | |||
| 1cc3a36d90 | |||
| caab5f42db | |||
| 8e633b3ba9 | |||
| 662c50e067 | |||
| 96a7e28df6 | |||
| b808d77771 | |||
| b6017a44c5 | |||
| 75e96b3100 | |||
| 53b2459a36 | |||
| 52105783fd | |||
| ecc0f84d08 | |||
| b3d3bea31d | |||
| 9ca431aef8 | |||
| 4eb8d7fa89 | |||
| 9f549d548d | |||
| bf96228754 | |||
| 0d8d9c9eff | |||
| b9cd86a091 | |||
| 34ad36bf81 | |||
| 3e7d012eb1 | |||
| 2fb79e9b04 | |||
| ba7cce317b | |||
| 18333efd51 | |||
| ab087d4e67 | |||
| f9e91972c9 | |||
| 29c9969871 | |||
| adc117d40e | |||
| 37f03dfb1f | |||
| db528529bf | |||
| 8fe3e9d882 | |||
| a77edc69ee | |||
| 1fe162fd0c | |||
| 0002d246a9 | |||
| bb7aa2d85e | |||
| f07b249f92 | |||
| 633647af75 | |||
| 701ff6ad2d | |||
| 918938f9c2 | |||
| 49297c86d2 | |||
| 119fc11eb0 | |||
| a14b7e02e9 | |||
| 174f855306 | |||
| 16f0582c1b | |||
| 74869e5e52 | |||
| 6b904f5e01 | |||
| 920c83f18f | |||
| 5f42995a0a | |||
| 5b3a3b359a | |||
| 7adbcffcb9 | |||
| 154cc74601 | |||
| 978896e0eb | |||
| d3d52ef147 | |||
| a80e160634 | |||
| 46acfc2b47 | |||
| 544cab7651 | |||
| 1cb0266dcb | |||
| f53524b4f7 | |||
| 59d705ab80 | |||
| 1f9144ed41 | |||
| a3b2da9889 | |||
| af3332989f | |||
| fc8f4b658c | |||
| f5da7dbb07 | |||
| b30574bcae | |||
| 85c2dc0ae6 | |||
| 970ea372c4 | |||
| 116b56a2cc | |||
| 6f25936c9c | |||
| 6295ff1d3e | |||
| a5d75ba9ea | |||
| 7553c82894 | |||
| 9c4527e57d | |||
| 943d825b54 | |||
| 29df8d1fc2 | |||
| 4b34eb3bf5 | |||
| d3bc75fb94 | |||
| 473af4fe03 | |||
| 688633cb9e | |||
| d3bb79bd0f | |||
| 510b7ff536 | |||
| c3becddb75 | |||
| bbc0177460 | |||
| ba28b5ab0a | |||
| 1ed1e616f7 | |||
| 202230ef5c | |||
| 708b22b1e3 | |||
| 891d6b4e9e | |||
| 1ba30db8bd | |||
| a6bf20b587 | |||
| 1e45c7db56 | |||
| e43d6aee45 | |||
| a2df53bd61 | |||
| f157d10f9f | |||
| fb546afb4d | |||
| f8563c00b2 | |||
| e6e1d124db | |||
| f80d4ff59f | |||
| 3ee83efec1 | |||
| 1554bc8a2e | |||
| 4146b4e34a | |||
| acc83d2e4f | |||
| f42d318002 | |||
| e611f14471 | |||
| 5cc95ebf37 | |||
| 9b38d6660f | |||
| 567bd44917 | |||
| a92b81f487 | |||
| 3cf48e3e89 | |||
| 59dbe3a5ef | |||
| e1f1c0802c | |||
| cc98b1fc89 | |||
| 063d57039e | |||
| 2996796dcf | |||
| f3f883fcd7 | |||
| 35a0925a23 | |||
| 30741eb0d3 | |||
| 0e9b43ff85 | |||
| 9715f7f033 | |||
| 1d62a66230 | |||
| cb1b0a693a | |||
| 1cfaf8eafb | |||
| 8d990b34db | |||
| 76adb23980 | |||
| 2147221c36 | |||
| 6e5688d375 | |||
| 81415257ec | |||
| 8a89d834d6 | |||
| 9c58b63c18 | |||
| 2efd3488ba | |||
| 70cdf38232 | |||
| 5328181db1 | |||
| 3b2ede1f03 | |||
| e6d065a81e | |||
| bda4cb876c | |||
| 555227bec0 | |||
| bce0414844 | |||
| 2ead47cb49 | |||
| 114ce7a4b1 | |||
| 24d772cc27 | |||
| bd1d270ec9 | |||
| 6bd166b81e | |||
| 66accfc56b | |||
| 8b174f2916 | |||
| 8a284dcefe | |||
| 1325adf5e9 | |||
| f0e808c60b | |||
| e324782254 | |||
| ad67e66dca | |||
| 99d5b4cde6 | |||
| 4a54bb5794 | |||
| dfe11bae99 | |||
| 182e84c116 | |||
| 5e98e838da | |||
| 72052a73a3 | |||
| a3928dd7be | |||
| 33bec3f5e8 |
+7
-6
@@ -566,6 +566,7 @@ SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||
SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
||||
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
|
||||
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ
|
||||
FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000
|
||||
FUZZCHECK_SRC = $(TOP)/test/fuzzcheck.c $(TOP)/test/ossfuzz.c
|
||||
DBFUZZ_OPT =
|
||||
|
||||
@@ -620,7 +621,8 @@ fuzzcheck$(TEXE): $(FUZZCHECK_SRC) sqlite3.c sqlite3.h
|
||||
$(LTLINK) -o $@ $(FUZZCHECK_OPT) $(FUZZCHECK_SRC) sqlite3.c $(TLIBS)
|
||||
|
||||
ossshell$(TEXE): $(TOP)/test/ossfuzz.c $(TOP)/test/ossshell.c sqlite3.c sqlite3.h
|
||||
$(LTLINK) -o $@ $(FUZZCHECK_OPT) $(TOP)/test/ossshell.c sqlite3.c sqlite3.h $(TLIBS)
|
||||
$(LTLINK) -o $@ $(FUZZCHECK_OPT) $(TOP)/test/ossshell.c \
|
||||
$(TOP)/test/ossfuzz.c sqlite3.c $(TLIBS)
|
||||
|
||||
dbfuzz$(TEXE): $(TOP)/test/dbfuzz.c sqlite3.c sqlite3.h
|
||||
$(LTLINK) -o $@ $(DBFUZZ_OPT) $(TOP)/test/dbfuzz.c sqlite3.c $(TLIBS)
|
||||
@@ -1153,6 +1155,10 @@ sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl
|
||||
sqlite3_analyzer$(TEXE): sqlite3_analyzer.c
|
||||
$(LTLINK) sqlite3_analyzer.c -o $@ $(LIBTCL) $(TLIBS)
|
||||
|
||||
dbdump$(TEXE): $(TOP)/ext/misc/dbdump.c sqlite3.lo
|
||||
$(LTLINK) -DDBDUMP_STANDALONE -o $@ \
|
||||
$(TOP)/ext/misc/dbdump.c sqlite3.lo $(TLIBS)
|
||||
|
||||
showdb$(TEXE): $(TOP)/tool/showdb.c sqlite3.lo
|
||||
$(LTLINK) -o $@ $(TOP)/tool/showdb.c sqlite3.lo $(TLIBS)
|
||||
|
||||
@@ -1185,11 +1191,6 @@ KV_OPT += -DSQLITE_DIRECT_OVERFLOW_READ
|
||||
kvtest$(TEXE): $(TOP)/test/kvtest.c sqlite3.c
|
||||
$(LTLINK) $(KV_OPT) -o $@ $(TOP)/test/kvtest.c sqlite3.c $(TLIBS)
|
||||
|
||||
DBSELFTEST_OPT += -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_FTS4
|
||||
|
||||
dbselftest$(TEXE): $(TOP)/test/dbselftest.c sqlite3.c
|
||||
$(LTLINK) $(DBSELFTEST_OPT) -o $@ $(TOP)/test/dbselftest.c sqlite3.c $(TLIBS)
|
||||
|
||||
rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.lo
|
||||
$(LTLINK) -I. -o $@ $(TOP)/ext/rbu/rbu.c sqlite3.lo $(TLIBS)
|
||||
|
||||
|
||||
+10
-3
@@ -745,8 +745,11 @@ RCC = $(RCC) -DSQLITE_ENABLE_API_ARMOR=1
|
||||
|
||||
!IF $(DEBUG)>2
|
||||
TCC = $(TCC) -DSQLITE_DEBUG=1
|
||||
TCC = $(TCC) -DSQLITE_ENABLE_WHERETRACE -DSQLITE_ENABLE_SELECTTRACE
|
||||
RCC = $(RCC) -DSQLITE_DEBUG=1
|
||||
!IF $(DYNAMIC_SHELL)==0
|
||||
TCC = $(TCC) -DSQLITE_ENABLE_WHERETRACE -DSQLITE_ENABLE_SELECTTRACE
|
||||
RCC = $(RCC) -DSQLITE_ENABLE_WHERETRACE -DSQLITE_ENABLE_SELECTTRACE
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
!IF $(DEBUG)>4 || $(OSTRACE)!=0
|
||||
@@ -1510,7 +1513,7 @@ SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_SHELL_JSON1 -DSQLITE_ENABLE_
|
||||
#
|
||||
MPTESTER_COMPILE_OPTS = -DSQLITE_SHELL_JSON1 -DSQLITE_ENABLE_FTS5
|
||||
FUZZERSHELL_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1
|
||||
FUZZCHECK_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ
|
||||
FUZZCHECK_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ -DSQLITE_MAX_MEMORY=50000000
|
||||
FUZZCHECK_SRC = $(TOP)\test\fuzzcheck.c $(TOP)\test\ossfuzz.c
|
||||
OSSSHELL_SRC = $(TOP)\test\ossshell.c $(TOP)\test\ossfuzz.c
|
||||
DBFUZZ_COMPILE_OPTS = -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION
|
||||
@@ -2178,6 +2181,10 @@ sqlite3_analyzer.exe: sqlite3_analyzer.c $(LIBRESOBJS)
|
||||
$(LTLINK) $(NO_WARN) -DBUILD_sqlite -I$(TCLINCDIR) sqlite3_analyzer.c \
|
||||
/link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS) $(TLIBS)
|
||||
|
||||
dbdump.exe: $(TOP)\ext\misc\dbdump.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) -DDBDUMP_STANDALONE $(TOP)\ext\misc\dbdump.c $(SQLITE3C) \
|
||||
/link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS)
|
||||
|
||||
testloadext.lo: $(TOP)\src\test_loadext.c
|
||||
$(LTCOMPILE) $(NO_WARN) -c $(TOP)\src\test_loadext.c
|
||||
|
||||
@@ -2256,7 +2263,7 @@ clean:
|
||||
del /Q tclsqlite3.exe $(SQLITETCLH) $(SQLITETCLDECLSH) 2>NUL
|
||||
del /Q testloadext.dll 2>NUL
|
||||
del /Q testfixture.exe test.db 2>NUL
|
||||
del /Q LogEst.exe fts3view.exe rollback-test.exe showdb.exe 2>NUL
|
||||
del /Q LogEst.exe fts3view.exe rollback-test.exe showdb.exe dbdump.exe 2>NUL
|
||||
del /Q changeset.exe 2>NUL
|
||||
del /Q showjournal.exe showstat4.exe showwal.exe speedtest1.exe 2>NUL
|
||||
del /Q mptester.exe wordcount.exe rbu.exe srcck1.exe 2>NUL
|
||||
|
||||
@@ -8,6 +8,48 @@ If you are reading this on a Git mirror someplace, you are doing it wrong.
|
||||
The [official repository](https://www.sqlite.org/src/) is better. Go there
|
||||
now.
|
||||
|
||||
## Obtaining The Code
|
||||
|
||||
SQLite sources are managed using the
|
||||
[Fossil](https://www.fossil-scm.org/), a distributed version control system
|
||||
that was specifically designed to support SQLite development.
|
||||
If you do not want to use Fossil, you can download tarballs or ZIP
|
||||
archives as follows:
|
||||
|
||||
* Lastest trunk check-in:
|
||||
<https://www.sqlite.org/src/tarball/sqlite.tar.gz> or
|
||||
<https://www.sqlite.org/src/zip/sqlite.zip>.
|
||||
|
||||
* Latest release:
|
||||
<https://www.sqlite.org/src/tarball/sqlite.tar.gz?r=release> or
|
||||
<https://www.sqlite.org/src/zip/sqlite.zip?r=release>.
|
||||
|
||||
* For other check-ins, substitute an appropriate branch name or
|
||||
tag or hash prefix for "release" in the URLs of the previous
|
||||
bullet. Or browse the [timeline](https://www.sqlite.org/src/timeline)
|
||||
to locate the check-in desired, click on its information page link,
|
||||
then click on the "Tarball" or "ZIP Archive" links on the information
|
||||
page.
|
||||
|
||||
If you do want to use Fossil to check out the source tree,
|
||||
first install Fossil version 2.0 or later.
|
||||
(Source tarballs and precompiled binaries available
|
||||
[here](https://www.fossil-scm.org/fossil/uv/download.html).)
|
||||
Then run commands like this:
|
||||
|
||||
mkdir ~/sqlite
|
||||
cd ~/sqlite
|
||||
fossil clone https://www.sqlite.org/src sqlite.fossil
|
||||
fossil open sqlite.fossil
|
||||
|
||||
After setting up a repository using the steps above, you can always
|
||||
update to the lastest version using:
|
||||
|
||||
fossil update trunk ;# latest trunk check-in
|
||||
fossil update release ;# latest official release
|
||||
|
||||
Or type "fossil ui" to get a web-based user interface.
|
||||
|
||||
## Compiling
|
||||
|
||||
First create a directory in which to place
|
||||
@@ -18,13 +60,13 @@ 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)
|
||||
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.
|
||||
|
||||
@@ -43,13 +85,13 @@ 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
|
||||
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
|
||||
|
||||
@@ -645,6 +645,10 @@ RCC = $(RCC) -DSQLITE_ENABLE_API_ARMOR=1
|
||||
!IF $(DEBUG)>2
|
||||
TCC = $(TCC) -DSQLITE_DEBUG=1
|
||||
RCC = $(RCC) -DSQLITE_DEBUG=1
|
||||
!IF $(DYNAMIC_SHELL)==0
|
||||
TCC = $(TCC) -DSQLITE_ENABLE_WHERETRACE -DSQLITE_ENABLE_SELECTTRACE
|
||||
RCC = $(RCC) -DSQLITE_ENABLE_WHERETRACE -DSQLITE_ENABLE_SELECTTRACE
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
!IF $(DEBUG)>4 || $(OSTRACE)!=0
|
||||
|
||||
@@ -55,9 +55,9 @@ AS_IF([ test x"$enable_editline" != xno ],[
|
||||
LIBS=""
|
||||
AC_SEARCH_LIBS([readline],[edit],[
|
||||
AC_DEFINE([HAVE_EDITLINE],1,Define to use BSD editline)
|
||||
READLINE_LIBS=$LIBS
|
||||
READLINE_LIBS="$LIBS -ltinfo"
|
||||
enable_readline=no
|
||||
])
|
||||
],[],[-ltinfo])
|
||||
AS_UNSET(ac_cv_search_readline)
|
||||
LIBS=$sLIBS
|
||||
])
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.69 for sqlite 3.18.0.
|
||||
# Generated by GNU Autoconf 2.69 for sqlite 3.19.0.
|
||||
#
|
||||
#
|
||||
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
|
||||
@@ -726,8 +726,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='sqlite'
|
||||
PACKAGE_TARNAME='sqlite'
|
||||
PACKAGE_VERSION='3.18.0'
|
||||
PACKAGE_STRING='sqlite 3.18.0'
|
||||
PACKAGE_VERSION='3.19.0'
|
||||
PACKAGE_STRING='sqlite 3.19.0'
|
||||
PACKAGE_BUGREPORT=''
|
||||
PACKAGE_URL=''
|
||||
|
||||
@@ -1463,7 +1463,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.18.0 to adapt to many kinds of systems.
|
||||
\`configure' configures sqlite 3.19.0 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1528,7 +1528,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlite 3.18.0:";;
|
||||
short | recursive ) echo "Configuration of sqlite 3.19.0:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1652,7 +1652,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlite configure 3.18.0
|
||||
sqlite configure 3.19.0
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
@@ -2071,7 +2071,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.18.0, which was
|
||||
It was created by sqlite $as_me 3.19.0, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -11252,7 +11252,7 @@ else
|
||||
fi
|
||||
|
||||
if test "${use_debug}" = "yes" ; then
|
||||
TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE"
|
||||
TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0"
|
||||
else
|
||||
TARGET_DEBUG="-DNDEBUG"
|
||||
fi
|
||||
@@ -11356,7 +11356,7 @@ fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support MEMSYS5" >&5
|
||||
$as_echo_n "checking whether to support MEMSYS5... " >&6; }
|
||||
if test "${enable_memsys5}" = "yes"; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_MEMSYS5"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MEMSYS5"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
else
|
||||
@@ -11373,7 +11373,7 @@ fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support MEMSYS3" >&5
|
||||
$as_echo_n "checking whether to support MEMSYS3... " >&6; }
|
||||
if test "${enable_memsys3}" = "yes" -a "${enable_memsys5}" = "no"; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_MEMSYS3"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MEMSYS3"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
else
|
||||
@@ -11391,7 +11391,7 @@ else
|
||||
fi
|
||||
|
||||
if test "${enable_fts3}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS3"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3"
|
||||
fi
|
||||
# Check whether --enable-fts4 was given.
|
||||
if test "${enable_fts4+set}" = set; then :
|
||||
@@ -11401,7 +11401,7 @@ else
|
||||
fi
|
||||
|
||||
if test "${enable_fts4}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS4"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS4"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5
|
||||
$as_echo_n "checking for library containing log... " >&6; }
|
||||
if ${ac_cv_search_log+:} false; then :
|
||||
@@ -11467,7 +11467,7 @@ else
|
||||
fi
|
||||
|
||||
if test "${enable_fts5}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS5"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS5"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5
|
||||
$as_echo_n "checking for library containing log... " >&6; }
|
||||
if ${ac_cv_search_log+:} false; then :
|
||||
@@ -11536,7 +11536,7 @@ else
|
||||
fi
|
||||
|
||||
if test "${enable_json1}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_JSON1"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_JSON1"
|
||||
fi
|
||||
|
||||
#########
|
||||
@@ -11549,7 +11549,7 @@ else
|
||||
fi
|
||||
|
||||
if test "${enable_rtree}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_RTREE"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE"
|
||||
fi
|
||||
|
||||
#########
|
||||
@@ -11562,8 +11562,8 @@ else
|
||||
fi
|
||||
|
||||
if test "${enable_session}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_SESSION"
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_PREUPDATE_HOOK"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SESSION"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK"
|
||||
fi
|
||||
|
||||
#########
|
||||
@@ -12151,7 +12151,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=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.18.0, which was
|
||||
This file was extended by sqlite $as_me 3.19.0, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -12217,7 +12217,7 @@ _ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||
ac_cs_version="\\
|
||||
sqlite config.status 3.18.0
|
||||
sqlite config.status 3.19.0
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
+10
-10
@@ -560,7 +560,7 @@ AC_SEARCH_LIBS(fdatasync, [rt])
|
||||
AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],[enable debugging & verbose explain]),
|
||||
[use_debug=$enableval],[use_debug=no])
|
||||
if test "${use_debug}" = "yes" ; then
|
||||
TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE"
|
||||
TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0"
|
||||
else
|
||||
TARGET_DEBUG="-DNDEBUG"
|
||||
fi
|
||||
@@ -596,7 +596,7 @@ AC_ARG_ENABLE(memsys5,
|
||||
[enable_memsys5=yes],[enable_memsys5=no])
|
||||
AC_MSG_CHECKING([whether to support MEMSYS5])
|
||||
if test "${enable_memsys5}" = "yes"; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_MEMSYS5"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MEMSYS5"
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
@@ -606,7 +606,7 @@ AC_ARG_ENABLE(memsys3,
|
||||
[enable_memsys3=yes],[enable_memsys3=no])
|
||||
AC_MSG_CHECKING([whether to support MEMSYS3])
|
||||
if test "${enable_memsys3}" = "yes" -a "${enable_memsys5}" = "no"; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_MEMSYS3"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MEMSYS3"
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
@@ -618,20 +618,20 @@ AC_ARG_ENABLE(fts3, AC_HELP_STRING([--enable-fts3],
|
||||
[Enable the FTS3 extension]),
|
||||
[enable_fts3=yes],[enable_fts3=no])
|
||||
if test "${enable_fts3}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS3"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3"
|
||||
fi
|
||||
AC_ARG_ENABLE(fts4, AC_HELP_STRING([--enable-fts4],
|
||||
[Enable the FTS4 extension]),
|
||||
[enable_fts4=yes],[enable_fts4=no])
|
||||
if test "${enable_fts4}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS4"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS4"
|
||||
AC_SEARCH_LIBS([log],[m])
|
||||
fi
|
||||
AC_ARG_ENABLE(fts5, AC_HELP_STRING([--enable-fts5],
|
||||
[Enable the FTS5 extension]),
|
||||
[enable_fts5=yes],[enable_fts5=no])
|
||||
if test "${enable_fts5}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS5"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS5"
|
||||
AC_SEARCH_LIBS([log],[m])
|
||||
fi
|
||||
|
||||
@@ -641,7 +641,7 @@ AC_ARG_ENABLE(json1, AC_HELP_STRING([--enable-json1],
|
||||
[Enable the JSON1 extension]),
|
||||
[enable_json1=yes],[enable_json1=no])
|
||||
if test "${enable_json1}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_JSON1"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_JSON1"
|
||||
fi
|
||||
|
||||
#########
|
||||
@@ -650,7 +650,7 @@ AC_ARG_ENABLE(rtree, AC_HELP_STRING([--enable-rtree],
|
||||
[Enable the RTREE extension]),
|
||||
[enable_rtree=yes],[enable_rtree=no])
|
||||
if test "${enable_rtree}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_RTREE"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE"
|
||||
fi
|
||||
|
||||
#########
|
||||
@@ -659,8 +659,8 @@ AC_ARG_ENABLE(session, AC_HELP_STRING([--enable-session],
|
||||
[Enable the SESSION extension]),
|
||||
[enable_session=yes],[enable_session=no])
|
||||
if test "${enable_session}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_SESSION"
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_PREUPDATE_HOOK"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SESSION"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK"
|
||||
fi
|
||||
|
||||
#########
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
## Loadable Extensions
|
||||
|
||||
Various [loadable extensions](https://www.sqlite.org/loadext.html) for
|
||||
SQLite are found in subfolders.
|
||||
|
||||
Most subfolders are dedicated to a single loadable extension (for
|
||||
example FTS5, or RTREE). But the misc/ subfolder contains a collection
|
||||
of smaller single-file extensions.
|
||||
@@ -1,2 +0,0 @@
|
||||
Version loadable extensions to SQLite are found in subfolders
|
||||
of this folder.
|
||||
+10
-4
@@ -349,8 +349,9 @@ int sqlite3Fts3PutVarint(char *p, sqlite_int64 v){
|
||||
** Return the number of bytes read, or 0 on error.
|
||||
** The value is stored in *v.
|
||||
*/
|
||||
int sqlite3Fts3GetVarint(const char *p, sqlite_int64 *v){
|
||||
const char *pStart = p;
|
||||
int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
|
||||
const unsigned char *p = (const unsigned char*)pBuf;
|
||||
const unsigned char *pStart = p;
|
||||
u32 a;
|
||||
u64 b;
|
||||
int shift;
|
||||
@@ -1397,7 +1398,9 @@ static int fts3InitVtab(
|
||||
char *z;
|
||||
int n = 0;
|
||||
z = (char *)sqlite3Fts3NextToken(aCol[iCol], &n);
|
||||
memcpy(zCsr, z, n);
|
||||
if( n>0 ){
|
||||
memcpy(zCsr, z, n);
|
||||
}
|
||||
zCsr[n] = '\0';
|
||||
sqlite3Fts3Dequote(zCsr);
|
||||
p->azColumn[iCol] = zCsr;
|
||||
@@ -3408,8 +3411,10 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){
|
||||
const u32 nMinMerge = 64; /* Minimum amount of incr-merge work to do */
|
||||
|
||||
Fts3Table *p = (Fts3Table*)pVtab;
|
||||
int rc = sqlite3Fts3PendingTermsFlush(p);
|
||||
int rc;
|
||||
i64 iLastRowid = sqlite3_last_insert_rowid(p->db);
|
||||
|
||||
rc = sqlite3Fts3PendingTermsFlush(p);
|
||||
if( rc==SQLITE_OK
|
||||
&& p->nLeafAdd>(nMinMerge/16)
|
||||
&& p->nAutoincrmerge && p->nAutoincrmerge!=0xff
|
||||
@@ -3424,6 +3429,7 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){
|
||||
if( A>(int)nMinMerge ) rc = sqlite3Fts3Incrmerge(p, A, p->nAutoincrmerge);
|
||||
}
|
||||
sqlite3Fts3SegmentsClose(p);
|
||||
sqlite3_set_last_insert_rowid(p->db, iLastRowid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
+13
-13
@@ -136,16 +136,16 @@ static int unicodeAddExceptions(
|
||||
){
|
||||
const unsigned char *z = (const unsigned char *)zIn;
|
||||
const unsigned char *zTerm = &z[nIn];
|
||||
int iCode;
|
||||
unsigned int iCode;
|
||||
int nEntry = 0;
|
||||
|
||||
assert( bAlnum==0 || bAlnum==1 );
|
||||
|
||||
while( z<zTerm ){
|
||||
READ_UTF8(z, zTerm, iCode);
|
||||
assert( (sqlite3FtsUnicodeIsalnum(iCode) & 0xFFFFFFFE)==0 );
|
||||
if( sqlite3FtsUnicodeIsalnum(iCode)!=bAlnum
|
||||
&& sqlite3FtsUnicodeIsdiacritic(iCode)==0
|
||||
assert( (sqlite3FtsUnicodeIsalnum((int)iCode) & 0xFFFFFFFE)==0 );
|
||||
if( sqlite3FtsUnicodeIsalnum((int)iCode)!=bAlnum
|
||||
&& sqlite3FtsUnicodeIsdiacritic((int)iCode)==0
|
||||
){
|
||||
nEntry++;
|
||||
}
|
||||
@@ -162,13 +162,13 @@ static int unicodeAddExceptions(
|
||||
z = (const unsigned char *)zIn;
|
||||
while( z<zTerm ){
|
||||
READ_UTF8(z, zTerm, iCode);
|
||||
if( sqlite3FtsUnicodeIsalnum(iCode)!=bAlnum
|
||||
&& sqlite3FtsUnicodeIsdiacritic(iCode)==0
|
||||
if( sqlite3FtsUnicodeIsalnum((int)iCode)!=bAlnum
|
||||
&& sqlite3FtsUnicodeIsdiacritic((int)iCode)==0
|
||||
){
|
||||
int i, j;
|
||||
for(i=0; i<nNew && aNew[i]<iCode; i++);
|
||||
for(i=0; i<nNew && aNew[i]<(int)iCode; i++);
|
||||
for(j=nNew; j>i; j--) aNew[j] = aNew[j-1];
|
||||
aNew[i] = iCode;
|
||||
aNew[i] = (int)iCode;
|
||||
nNew++;
|
||||
}
|
||||
}
|
||||
@@ -318,7 +318,7 @@ static int unicodeNext(
|
||||
){
|
||||
unicode_cursor *pCsr = (unicode_cursor *)pC;
|
||||
unicode_tokenizer *p = ((unicode_tokenizer *)pCsr->base.pTokenizer);
|
||||
int iCode = 0;
|
||||
unsigned int iCode = 0;
|
||||
char *zOut;
|
||||
const unsigned char *z = &pCsr->aInput[pCsr->iOff];
|
||||
const unsigned char *zStart = z;
|
||||
@@ -330,7 +330,7 @@ static int unicodeNext(
|
||||
** the input. */
|
||||
while( z<zTerm ){
|
||||
READ_UTF8(z, zTerm, iCode);
|
||||
if( unicodeIsAlnum(p, iCode) ) break;
|
||||
if( unicodeIsAlnum(p, (int)iCode) ) break;
|
||||
zStart = z;
|
||||
}
|
||||
if( zStart>=zTerm ) return SQLITE_DONE;
|
||||
@@ -350,7 +350,7 @@ static int unicodeNext(
|
||||
|
||||
/* Write the folded case of the last character read to the output */
|
||||
zEnd = z;
|
||||
iOut = sqlite3FtsUnicodeFold(iCode, p->bRemoveDiacritic);
|
||||
iOut = sqlite3FtsUnicodeFold((int)iCode, p->bRemoveDiacritic);
|
||||
if( iOut ){
|
||||
WRITE_UTF8(zOut, iOut);
|
||||
}
|
||||
@@ -358,8 +358,8 @@ static int unicodeNext(
|
||||
/* If the cursor is not at EOF, read the next character */
|
||||
if( z>=zTerm ) break;
|
||||
READ_UTF8(z, zTerm, iCode);
|
||||
}while( unicodeIsAlnum(p, iCode)
|
||||
|| sqlite3FtsUnicodeIsdiacritic(iCode)
|
||||
}while( unicodeIsAlnum(p, (int)iCode)
|
||||
|| sqlite3FtsUnicodeIsdiacritic((int)iCode)
|
||||
);
|
||||
|
||||
/* Set the output variables and return. */
|
||||
|
||||
+10
-11
@@ -127,9 +127,9 @@ int sqlite3FtsUnicodeIsalnum(int c){
|
||||
0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001,
|
||||
};
|
||||
|
||||
if( c<128 ){
|
||||
return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
|
||||
}else if( c<(1<<22) ){
|
||||
if( (unsigned int)c<128 ){
|
||||
return ( (aAscii[c >> 5] & ((unsigned int)1 << (c & 0x001F)))==0 );
|
||||
}else if( (unsigned int)c<(1<<22) ){
|
||||
unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
|
||||
int iRes = 0;
|
||||
int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
|
||||
@@ -322,16 +322,17 @@ int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
|
||||
|
||||
int ret = c;
|
||||
|
||||
assert( c>=0 );
|
||||
assert( sizeof(unsigned short)==2 && sizeof(unsigned char)==1 );
|
||||
|
||||
if( c<128 ){
|
||||
if( c>='A' && c<='Z' ) ret = c + ('a' - 'A');
|
||||
}else if( c<65536 ){
|
||||
const struct TableEntry *p;
|
||||
int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
|
||||
int iLo = 0;
|
||||
int iRes = -1;
|
||||
|
||||
assert( c>aEntry[0].iCode );
|
||||
while( iHi>=iLo ){
|
||||
int iTest = (iHi + iLo) / 2;
|
||||
int cmp = (c - aEntry[iTest].iCode);
|
||||
@@ -342,14 +343,12 @@ int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
|
||||
iHi = iTest-1;
|
||||
}
|
||||
}
|
||||
assert( iRes<0 || c>=aEntry[iRes].iCode );
|
||||
|
||||
if( iRes>=0 ){
|
||||
const struct TableEntry *p = &aEntry[iRes];
|
||||
if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){
|
||||
ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF;
|
||||
assert( ret>0 );
|
||||
}
|
||||
assert( iRes>=0 && c>=aEntry[iRes].iCode );
|
||||
p = &aEntry[iRes];
|
||||
if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){
|
||||
ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF;
|
||||
assert( ret>0 );
|
||||
}
|
||||
|
||||
if( bRemoveDiacritic ) ret = remove_diacritic(ret);
|
||||
|
||||
@@ -4956,11 +4956,14 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
|
||||
** Convert the text beginning at *pz into an integer and return
|
||||
** its value. Advance *pz to point to the first character past
|
||||
** the integer.
|
||||
**
|
||||
** This function used for parameters to merge= and incrmerge=
|
||||
** commands.
|
||||
*/
|
||||
static int fts3Getint(const char **pz){
|
||||
const char *z = *pz;
|
||||
int i = 0;
|
||||
while( (*z)>='0' && (*z)<='9' ) i = 10*i + *(z++) - '0';
|
||||
while( (*z)>='0' && (*z)<='9' && i<214748363 ) i = 10*i + *(z++) - '0';
|
||||
*pz = z;
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
srcdir=`dirname $(dirname $(dirname $(dirname $0)))`
|
||||
./testfixture $srcdir/test/fts3.test --output=fts3cov-out.txt
|
||||
|
||||
echo ""
|
||||
|
||||
for f in `ls $srcdir/ext/fts3/*.c`
|
||||
do
|
||||
f=`basename $f`
|
||||
echo -ne "$f: "
|
||||
gcov -b $f | grep Taken | sed 's/Taken at least once://'
|
||||
done
|
||||
|
||||
@@ -227,7 +227,7 @@ proc print_isalnum {zFunc lRange} {
|
||||
an_print_ascii_bitmap $lRange
|
||||
puts {
|
||||
if( (unsigned int)c<128 ){
|
||||
return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
|
||||
return ( (aAscii[c >> 5] & ((unsigned int)1 << (c & 0x001F)))==0 );
|
||||
}else if( (unsigned int)c<(1<<22) ){
|
||||
unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
|
||||
int iRes = 0;
|
||||
|
||||
+13
-2
@@ -1110,7 +1110,10 @@ static int fts5ExprNodeNext_OR(
|
||||
|| (bFromValid && fts5RowidCmp(pExpr, p1->iRowid, iFrom)<0)
|
||||
){
|
||||
int rc = fts5ExprNodeNext(pExpr, p1, bFromValid, iFrom);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
if( rc!=SQLITE_OK ){
|
||||
pNode->bNomatch = 0;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1141,7 +1144,10 @@ static int fts5ExprNodeTest_AND(
|
||||
if( cmp>0 ){
|
||||
/* Advance pChild until it points to iLast or laster */
|
||||
rc = fts5ExprNodeNext(pExpr, pChild, 1, iLast);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
if( rc!=SQLITE_OK ){
|
||||
pAnd->bNomatch = 0;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the child node is now at EOF, so is the parent AND node. Otherwise,
|
||||
@@ -1180,6 +1186,8 @@ static int fts5ExprNodeNext_AND(
|
||||
int rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = fts5ExprNodeTest_AND(pExpr, pNode);
|
||||
}else{
|
||||
pNode->bNomatch = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -1222,6 +1230,9 @@ static int fts5ExprNodeNext_NOT(
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = fts5ExprNodeTest_NOT(pExpr, pNode);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
pNode->bNomatch = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
+10
-15
@@ -545,11 +545,6 @@ int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the averages record */
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = fts5StorageSaveTotals(p);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -753,11 +748,6 @@ int sqlite3Fts5StorageIndexInsert(
|
||||
}
|
||||
sqlite3_free(buf.p);
|
||||
|
||||
/* Write the averages record */
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = fts5StorageSaveTotals(p);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1092,12 +1082,17 @@ int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow){
|
||||
** Flush any data currently held in-memory to disk.
|
||||
*/
|
||||
int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit){
|
||||
if( bCommit && p->bTotalsValid ){
|
||||
int rc = fts5StorageSaveTotals(p);
|
||||
p->bTotalsValid = 0;
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
int rc = SQLITE_OK;
|
||||
i64 iLastRowid = sqlite3_last_insert_rowid(p->pConfig->db);
|
||||
if( p->bTotalsValid ){
|
||||
rc = fts5StorageSaveTotals(p);
|
||||
if( bCommit ) p->bTotalsValid = 0;
|
||||
}
|
||||
return sqlite3Fts5IndexSync(p->pIndex, bCommit);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5IndexSync(p->pIndex, bCommit);
|
||||
}
|
||||
sqlite3_set_last_insert_rowid(p->pConfig->db, iLastRowid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int sqlite3Fts5StorageRollback(Fts5Storage *p){
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
# 2016 February 2
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
#
|
||||
# This file is focused on OOM errors.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
source $testdir/malloc_common.tcl
|
||||
set testprefix fts5faultA
|
||||
|
||||
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
foreach_detail_mode $testprefix {
|
||||
if {"%DETAIL%"=="none"} continue
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE o1 USING fts5(a, b, c, detail=%DETAIL%);
|
||||
INSERT INTO o1(o1, rank) VALUES('pgsz', 32);
|
||||
|
||||
WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<60 )
|
||||
INSERT INTO o1 SELECT 'A', 'B', 'C' FROM s;
|
||||
|
||||
WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<60 )
|
||||
INSERT INTO o1 SELECT 'C', 'A', 'B' FROM s;
|
||||
|
||||
WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<60 )
|
||||
INSERT INTO o1 SELECT 'B', 'C', 'A' FROM s;
|
||||
}
|
||||
|
||||
do_faultsim_test 1 -faults int* -prep {
|
||||
sqlite3 db test.db
|
||||
} -body {
|
||||
execsql { SELECT count(*) FROM o1('a') }
|
||||
} -test {
|
||||
faultsim_test_result {0 180} {1 {vtable constructor failed: o1}}
|
||||
}
|
||||
|
||||
do_faultsim_test 2 -faults int* -prep {
|
||||
sqlite3 db test.db
|
||||
} -body {
|
||||
execsql { SELECT * FROM o1('a:a AND {b c}:b') ORDER BY rank }
|
||||
expr 1
|
||||
} -test {
|
||||
faultsim_test_result {0 1} {1 {vtable constructor failed: o1}}
|
||||
}
|
||||
|
||||
do_faultsim_test 3 -faults int* -prep {
|
||||
sqlite3 db test.db
|
||||
} -body {
|
||||
execsql { SELECT * FROM o1('{b c}:b NOT a:a') ORDER BY rank }
|
||||
expr 1
|
||||
} -test {
|
||||
faultsim_test_result {0 1} {1 {vtable constructor failed: o1}}
|
||||
}
|
||||
|
||||
do_faultsim_test 4 -faults int* -prep {
|
||||
sqlite3 db test.db
|
||||
} -body {
|
||||
execsql { SELECT * FROM o1('b:b OR a:a') }
|
||||
expr 1
|
||||
} -test {
|
||||
faultsim_test_result {0 1} {1 {vtable constructor failed: o1}}
|
||||
}
|
||||
|
||||
do_faultsim_test 5 -faults int* -prep {
|
||||
sqlite3 db test.db
|
||||
} -body {
|
||||
execsql { SELECT count(*) FROM o1('c:b') }
|
||||
expr 1
|
||||
} -test {
|
||||
faultsim_test_result {0 1} {1 {vtable constructor failed: o1}}
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,73 @@
|
||||
# 2017 Feb 27
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Tests of the last_insert_rowid functionality with fts5.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5lastrowid
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(str);
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
INSERT INTO t1 VALUES('one string');
|
||||
INSERT INTO t1 VALUES('two string');
|
||||
INSERT INTO t1 VALUES('three string');
|
||||
SELECT last_insert_rowid();
|
||||
} {3}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES('one string');
|
||||
INSERT INTO t1 VALUES('two string');
|
||||
INSERT INTO t1 VALUES('three string');
|
||||
COMMIT;
|
||||
SELECT last_insert_rowid();
|
||||
} {6}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
INSERT INTO t1(rowid, str) VALUES(-22, 'some more text');
|
||||
SELECT last_insert_rowid();
|
||||
} {-22}
|
||||
|
||||
do_execsql_test 1.4 {
|
||||
BEGIN;
|
||||
INSERT INTO t1(rowid, str) VALUES(45, 'some more text');
|
||||
INSERT INTO t1(rowid, str) VALUES(46, 'some more text');
|
||||
INSERT INTO t1(rowid, str) VALUES(222, 'some more text');
|
||||
SELECT last_insert_rowid();
|
||||
COMMIT;
|
||||
SELECT last_insert_rowid();
|
||||
} {222 222}
|
||||
|
||||
do_execsql_test 1.5 {
|
||||
CREATE TABLE x1(x);
|
||||
INSERT INTO x1 VALUES('john'), ('paul'), ('george'), ('ringo');
|
||||
INSERT INTO t1 SELECT x FROM x1;
|
||||
SELECT last_insert_rowid();
|
||||
} {226}
|
||||
|
||||
do_execsql_test 1.6 {
|
||||
INSERT INTO t1(rowid, str) SELECT rowid+10, x FROM x1;
|
||||
SELECT last_insert_rowid();
|
||||
} {14}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
## Miscellaneous Extensions
|
||||
|
||||
This folder contains a collection of smaller loadable extensions.
|
||||
See <https://www.sqlite.org/loadext.html> for instructions on how
|
||||
to compile and use loadable extensions.
|
||||
Each extension in this folder is implemented in a single file of C code.
|
||||
|
||||
Each source file contains a description in its header comment. See the
|
||||
header comments for details about each extension. Additional notes are
|
||||
as follows:
|
||||
|
||||
* **carray.c** — This module implements the
|
||||
[carray](https://www.sqlite.org/carray.html) table-valued function.
|
||||
It is a good example of how to go about implementing a custom
|
||||
[table-valued function](https://www.sqlite.org/vtab.html#tabfunc2).
|
||||
|
||||
* **dbdump.c** — This is not actually a loadable extension, but
|
||||
rather a library that implements an approximate equivalent to the
|
||||
".dump" command of the
|
||||
[command-line shell](https://www.sqlite.org/cli.html).
|
||||
|
||||
* **memvfs.c** — This file implements a custom
|
||||
[VFS](https://www.sqlite.org/vfs.html) that stores an entire database
|
||||
file in a single block of RAM. It serves as a good example of how
|
||||
to implement a simple custom VFS.
|
||||
|
||||
* **rot13.c** — This file implements the very simple rot13()
|
||||
substitution function. This file makes a good template for implementing
|
||||
new custom SQL functions for SQLite.
|
||||
|
||||
* **series.c** — This is an implementation of the
|
||||
"generate_series" [virtual table](https://www.sqlite.org/vtab.html).
|
||||
It can make a good template for new custom virtual table implementations.
|
||||
|
||||
* **shathree.c** — An implementation of the sha3() and
|
||||
sha3_query() SQL functions. The file is named "shathree.c" instead
|
||||
of "sha3.c" because the default entry point names in SQLite are based
|
||||
on the source filename with digits removed, so if we used the name
|
||||
"sha3.c" then the entry point would conflict with the prior "sha1.c"
|
||||
extension.
|
||||
@@ -0,0 +1,717 @@
|
||||
/*
|
||||
** 2016-03-13
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This file implements a C-language subroutine that converts the content
|
||||
** of an SQLite database into UTF-8 text SQL statements that can be used
|
||||
** to exactly recreate the original database. ROWID values are preserved.
|
||||
**
|
||||
** A prototype of the implemented subroutine is this:
|
||||
**
|
||||
** int sqlite3_db_dump(
|
||||
** sqlite3 *db,
|
||||
** const char *zSchema,
|
||||
** const char *zTable,
|
||||
** void (*xCallback)(void*, const char*),
|
||||
** void *pArg
|
||||
** );
|
||||
**
|
||||
** The db parameter is the database connection. zSchema is the schema within
|
||||
** that database which is to be dumped. Usually the zSchema is "main" but
|
||||
** can also be "temp" or any ATTACH-ed database. If zTable is not NULL, then
|
||||
** only the content of that one table is dumped. If zTable is NULL, then all
|
||||
** tables are dumped.
|
||||
**
|
||||
** The generate text is passed to xCallback() in multiple calls. The second
|
||||
** argument to xCallback() is a copy of the pArg parameter. The first
|
||||
** argument is some of the output text that this routine generates. The
|
||||
** signature to xCallback() is designed to make it compatible with fputs().
|
||||
**
|
||||
** The sqlite3_db_dump() subroutine returns SQLITE_OK on success or some error
|
||||
** code if it encounters a problem.
|
||||
**
|
||||
** If this file is compiled with -DDBDUMP_STANDALONE then a "main()" routine
|
||||
** is included so that this routine becomes a command-line utility. The
|
||||
** command-line utility takes two or three arguments which are the name
|
||||
** of the database file, the schema, and optionally the table, forming the
|
||||
** first three arguments of a single call to the library routine.
|
||||
*/
|
||||
#include "sqlite3.h"
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
** The state of the dump process.
|
||||
*/
|
||||
typedef struct DState DState;
|
||||
struct DState {
|
||||
sqlite3 *db; /* The database connection */
|
||||
int nErr; /* Number of errors seen so far */
|
||||
int rc; /* Error code */
|
||||
int writableSchema; /* True if in writable_schema mode */
|
||||
int (*xCallback)(const char*,void*); /* Send output here */
|
||||
void *pArg; /* Argument to xCallback() */
|
||||
};
|
||||
|
||||
/*
|
||||
** A variable length string to which one can append text.
|
||||
*/
|
||||
typedef struct DText DText;
|
||||
struct DText {
|
||||
char *z; /* The text */
|
||||
int n; /* Number of bytes of content in z[] */
|
||||
int nAlloc; /* Number of bytes allocated to z[] */
|
||||
};
|
||||
|
||||
/*
|
||||
** Initialize and destroy a DText object
|
||||
*/
|
||||
static void initText(DText *p){
|
||||
memset(p, 0, sizeof(*p));
|
||||
}
|
||||
static void freeText(DText *p){
|
||||
sqlite3_free(p->z);
|
||||
initText(p);
|
||||
}
|
||||
|
||||
/* zIn is either a pointer to a NULL-terminated string in memory obtained
|
||||
** from malloc(), or a NULL pointer. The string pointed to by zAppend is
|
||||
** added to zIn, and the result returned in memory obtained from malloc().
|
||||
** zIn, if it was not NULL, is freed.
|
||||
**
|
||||
** If the third argument, quote, is not '\0', then it is used as a
|
||||
** quote character for zAppend.
|
||||
*/
|
||||
static void appendText(DText *p, char const *zAppend, char quote){
|
||||
int len;
|
||||
int i;
|
||||
int nAppend = (int)(strlen(zAppend) & 0x3fffffff);
|
||||
|
||||
len = nAppend+p->n+1;
|
||||
if( quote ){
|
||||
len += 2;
|
||||
for(i=0; i<nAppend; i++){
|
||||
if( zAppend[i]==quote ) len++;
|
||||
}
|
||||
}
|
||||
|
||||
if( p->n+len>=p->nAlloc ){
|
||||
char *zNew;
|
||||
p->nAlloc = p->nAlloc*2 + len + 20;
|
||||
zNew = sqlite3_realloc(p->z, p->nAlloc);
|
||||
if( zNew==0 ){
|
||||
freeText(p);
|
||||
return;
|
||||
}
|
||||
p->z = zNew;
|
||||
}
|
||||
|
||||
if( quote ){
|
||||
char *zCsr = p->z+p->n;
|
||||
*zCsr++ = quote;
|
||||
for(i=0; i<nAppend; i++){
|
||||
*zCsr++ = zAppend[i];
|
||||
if( zAppend[i]==quote ) *zCsr++ = quote;
|
||||
}
|
||||
*zCsr++ = quote;
|
||||
p->n = (int)(zCsr - p->z);
|
||||
*zCsr = '\0';
|
||||
}else{
|
||||
memcpy(p->z+p->n, zAppend, nAppend);
|
||||
p->n += nAppend;
|
||||
p->z[p->n] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt to determine if identifier zName needs to be quoted, either
|
||||
** because it contains non-alphanumeric characters, or because it is an
|
||||
** SQLite keyword. Be conservative in this estimate: When in doubt assume
|
||||
** that quoting is required.
|
||||
**
|
||||
** Return '"' if quoting is required. Return 0 if no quoting is required.
|
||||
*/
|
||||
static char quoteChar(const char *zName){
|
||||
/* All SQLite keywords, in alphabetical order */
|
||||
static const char *azKeywords[] = {
|
||||
"ABORT", "ACTION", "ADD", "AFTER", "ALL", "ALTER", "ANALYZE", "AND", "AS",
|
||||
"ASC", "ATTACH", "AUTOINCREMENT", "BEFORE", "BEGIN", "BETWEEN", "BY",
|
||||
"CASCADE", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN", "COMMIT",
|
||||
"CONFLICT", "CONSTRAINT", "CREATE", "CROSS", "CURRENT_DATE",
|
||||
"CURRENT_TIME", "CURRENT_TIMESTAMP", "DATABASE", "DEFAULT", "DEFERRABLE",
|
||||
"DEFERRED", "DELETE", "DESC", "DETACH", "DISTINCT", "DROP", "EACH",
|
||||
"ELSE", "END", "ESCAPE", "EXCEPT", "EXCLUSIVE", "EXISTS", "EXPLAIN",
|
||||
"FAIL", "FOR", "FOREIGN", "FROM", "FULL", "GLOB", "GROUP", "HAVING", "IF",
|
||||
"IGNORE", "IMMEDIATE", "IN", "INDEX", "INDEXED", "INITIALLY", "INNER",
|
||||
"INSERT", "INSTEAD", "INTERSECT", "INTO", "IS", "ISNULL", "JOIN", "KEY",
|
||||
"LEFT", "LIKE", "LIMIT", "MATCH", "NATURAL", "NO", "NOT", "NOTNULL",
|
||||
"NULL", "OF", "OFFSET", "ON", "OR", "ORDER", "OUTER", "PLAN", "PRAGMA",
|
||||
"PRIMARY", "QUERY", "RAISE", "RECURSIVE", "REFERENCES", "REGEXP",
|
||||
"REINDEX", "RELEASE", "RENAME", "REPLACE", "RESTRICT", "RIGHT",
|
||||
"ROLLBACK", "ROW", "SAVEPOINT", "SELECT", "SET", "TABLE", "TEMP",
|
||||
"TEMPORARY", "THEN", "TO", "TRANSACTION", "TRIGGER", "UNION", "UNIQUE",
|
||||
"UPDATE", "USING", "VACUUM", "VALUES", "VIEW", "VIRTUAL", "WHEN", "WHERE",
|
||||
"WITH", "WITHOUT",
|
||||
};
|
||||
int i, lwr, upr, mid, c;
|
||||
if( !isalpha((unsigned char)zName[0]) && zName[0]!='_' ) return '"';
|
||||
for(i=0; zName[i]; i++){
|
||||
if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ) return '"';
|
||||
}
|
||||
lwr = 0;
|
||||
upr = sizeof(azKeywords)/sizeof(azKeywords[0]) - 1;
|
||||
while( lwr<=upr ){
|
||||
mid = (lwr+upr)/2;
|
||||
c = sqlite3_stricmp(azKeywords[mid], zName);
|
||||
if( c==0 ) return '"';
|
||||
if( c<0 ){
|
||||
lwr = mid+1;
|
||||
}else{
|
||||
upr = mid-1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Release memory previously allocated by tableColumnList().
|
||||
*/
|
||||
static void freeColumnList(char **azCol){
|
||||
int i;
|
||||
for(i=1; azCol[i]; i++){
|
||||
sqlite3_free(azCol[i]);
|
||||
}
|
||||
/* azCol[0] is a static string */
|
||||
sqlite3_free(azCol);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a list of pointers to strings which are the names of all
|
||||
** columns in table zTab. The memory to hold the names is dynamically
|
||||
** allocated and must be released by the caller using a subsequent call
|
||||
** to freeColumnList().
|
||||
**
|
||||
** The azCol[0] entry is usually NULL. However, if zTab contains a rowid
|
||||
** value that needs to be preserved, then azCol[0] is filled in with the
|
||||
** name of the rowid column.
|
||||
**
|
||||
** The first regular column in the table is azCol[1]. The list is terminated
|
||||
** by an entry with azCol[i]==0.
|
||||
*/
|
||||
static char **tableColumnList(DState *p, const char *zTab){
|
||||
char **azCol = 0;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
char *zSql;
|
||||
int nCol = 0;
|
||||
int nAlloc = 0;
|
||||
int nPK = 0; /* Number of PRIMARY KEY columns seen */
|
||||
int isIPK = 0; /* True if one PRIMARY KEY column of type INTEGER */
|
||||
int preserveRowid = 1;
|
||||
int rc;
|
||||
|
||||
zSql = sqlite3_mprintf("PRAGMA table_info=%Q", zTab);
|
||||
if( zSql==0 ) return 0;
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
if( rc ) return 0;
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
if( nCol>=nAlloc-2 ){
|
||||
char **azNew;
|
||||
nAlloc = nAlloc*2 + nCol + 10;
|
||||
azNew = sqlite3_realloc(azCol, nAlloc*sizeof(azCol[0]));
|
||||
if( azNew==0 ) goto col_oom;
|
||||
azCol = azNew;
|
||||
azCol[0] = 0;
|
||||
}
|
||||
azCol[++nCol] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1));
|
||||
if( azCol[nCol]==0 ) goto col_oom;
|
||||
if( sqlite3_column_int(pStmt, 5) ){
|
||||
nPK++;
|
||||
if( nPK==1
|
||||
&& sqlite3_stricmp((const char*)sqlite3_column_text(pStmt,2),
|
||||
"INTEGER")==0
|
||||
){
|
||||
isIPK = 1;
|
||||
}else{
|
||||
isIPK = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
pStmt = 0;
|
||||
azCol[nCol+1] = 0;
|
||||
|
||||
/* The decision of whether or not a rowid really needs to be preserved
|
||||
** is tricky. We never need to preserve a rowid for a WITHOUT ROWID table
|
||||
** or a table with an INTEGER PRIMARY KEY. We are unable to preserve
|
||||
** rowids on tables where the rowid is inaccessible because there are other
|
||||
** columns in the table named "rowid", "_rowid_", and "oid".
|
||||
*/
|
||||
if( isIPK ){
|
||||
/* If a single PRIMARY KEY column with type INTEGER was seen, then it
|
||||
** might be an alise for the ROWID. But it might also be a WITHOUT ROWID
|
||||
** table or a INTEGER PRIMARY KEY DESC column, neither of which are
|
||||
** ROWID aliases. To distinguish these cases, check to see if
|
||||
** there is a "pk" entry in "PRAGMA index_list". There will be
|
||||
** no "pk" index if the PRIMARY KEY really is an alias for the ROWID.
|
||||
*/
|
||||
zSql = sqlite3_mprintf("SELECT 1 FROM pragma_index_list(%Q)"
|
||||
" WHERE origin='pk'", zTab);
|
||||
if( zSql==0 ) goto col_oom;
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
if( rc ){
|
||||
freeColumnList(azCol);
|
||||
return 0;
|
||||
}
|
||||
rc = sqlite3_step(pStmt);
|
||||
sqlite3_finalize(pStmt);
|
||||
pStmt = 0;
|
||||
preserveRowid = rc==SQLITE_ROW;
|
||||
}
|
||||
if( preserveRowid ){
|
||||
/* Only preserve the rowid if we can find a name to use for the
|
||||
** rowid */
|
||||
static char *azRowid[] = { "rowid", "_rowid_", "oid" };
|
||||
int i, j;
|
||||
for(j=0; j<3; j++){
|
||||
for(i=1; i<=nCol; i++){
|
||||
if( sqlite3_stricmp(azRowid[j],azCol[i])==0 ) break;
|
||||
}
|
||||
if( i>nCol ){
|
||||
/* At this point, we know that azRowid[j] is not the name of any
|
||||
** ordinary column in the table. Verify that azRowid[j] is a valid
|
||||
** name for the rowid before adding it to azCol[0]. WITHOUT ROWID
|
||||
** tables will fail this last check */
|
||||
int rc;
|
||||
rc = sqlite3_table_column_metadata(p->db,0,zTab,azRowid[j],0,0,0,0,0);
|
||||
if( rc==SQLITE_OK ) azCol[0] = azRowid[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return azCol;
|
||||
|
||||
col_oom:
|
||||
sqlite3_finalize(pStmt);
|
||||
freeColumnList(azCol);
|
||||
p->nErr++;
|
||||
p->rc = SQLITE_NOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Send mprintf-formatted content to the output callback.
|
||||
*/
|
||||
static void output_formatted(DState *p, const char *zFormat, ...){
|
||||
va_list ap;
|
||||
char *z;
|
||||
va_start(ap, zFormat);
|
||||
z = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
p->xCallback(z, p->pArg);
|
||||
sqlite3_free(z);
|
||||
}
|
||||
|
||||
/*
|
||||
** Output the given string as a quoted string using SQL quoting conventions.
|
||||
**
|
||||
** The "\n" and "\r" characters are converted to char(10) and char(13)
|
||||
** to prevent them from being transformed by end-of-line translators.
|
||||
*/
|
||||
static void output_quoted_string(DState *p, const unsigned char *z){
|
||||
int i;
|
||||
char c;
|
||||
int inQuote = 0;
|
||||
int bStarted = 0;
|
||||
|
||||
for(i=0; (c = z[i])!=0 && c!='\'' && c!='\n' && c!='\r'; i++){}
|
||||
if( c==0 ){
|
||||
output_formatted(p, "'%s'", z);
|
||||
return;
|
||||
}
|
||||
while( *z ){
|
||||
for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){}
|
||||
if( c=='\'' ) i++;
|
||||
if( i ){
|
||||
if( !inQuote ){
|
||||
if( bStarted ) p->xCallback("||", p->pArg);
|
||||
p->xCallback("'", p->pArg);
|
||||
inQuote = 1;
|
||||
}
|
||||
output_formatted(p, "%.*s", i, z);
|
||||
z += i;
|
||||
bStarted = 1;
|
||||
}
|
||||
if( c=='\'' ){
|
||||
p->xCallback("'", p->pArg);
|
||||
continue;
|
||||
}
|
||||
if( inQuote ){
|
||||
p->xCallback("'", p->pArg);
|
||||
inQuote = 0;
|
||||
}
|
||||
if( c==0 ){
|
||||
break;
|
||||
}
|
||||
for(i=0; (c = z[i])=='\r' || c=='\n'; i++){
|
||||
if( bStarted ) p->xCallback("||", p->pArg);
|
||||
output_formatted(p, "char(%d)", c);
|
||||
bStarted = 1;
|
||||
}
|
||||
z += i;
|
||||
}
|
||||
if( inQuote ) p->xCallback("'", p->pArg);
|
||||
}
|
||||
|
||||
/*
|
||||
** This is an sqlite3_exec callback routine used for dumping the database.
|
||||
** Each row received by this callback consists of a table name,
|
||||
** the table type ("index" or "table") and SQL to create the table.
|
||||
** This routine should print text sufficient to recreate the table.
|
||||
*/
|
||||
static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
|
||||
int rc;
|
||||
const char *zTable;
|
||||
const char *zType;
|
||||
const char *zSql;
|
||||
DState *p = (DState*)pArg;
|
||||
sqlite3_stmt *pStmt;
|
||||
|
||||
(void)azCol;
|
||||
if( nArg!=3 ) return 1;
|
||||
zTable = azArg[0];
|
||||
zType = azArg[1];
|
||||
zSql = azArg[2];
|
||||
|
||||
if( strcmp(zTable, "sqlite_sequence")==0 ){
|
||||
p->xCallback("DELETE FROM sqlite_sequence;\n", p->pArg);
|
||||
}else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){
|
||||
p->xCallback("ANALYZE sqlite_master;\n", p->pArg);
|
||||
}else if( strncmp(zTable, "sqlite_", 7)==0 ){
|
||||
return 0;
|
||||
}else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
|
||||
if( !p->writableSchema ){
|
||||
p->xCallback("PRAGMA writable_schema=ON;\n", p->pArg);
|
||||
p->writableSchema = 1;
|
||||
}
|
||||
output_formatted(p,
|
||||
"INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
|
||||
"VALUES('table','%q','%q',0,'%q');",
|
||||
zTable, zTable, zSql);
|
||||
return 0;
|
||||
}else{
|
||||
if( sqlite3_strglob("CREATE TABLE ['\"]*", zSql)==0 ){
|
||||
p->xCallback("CREATE TABLE IF NOT EXISTS ", p->pArg);
|
||||
p->xCallback(zSql+13, p->pArg);
|
||||
}else{
|
||||
p->xCallback(zSql, p->pArg);
|
||||
}
|
||||
p->xCallback(";\n", p->pArg);
|
||||
}
|
||||
|
||||
if( strcmp(zType, "table")==0 ){
|
||||
DText sSelect;
|
||||
DText sTable;
|
||||
char **azCol;
|
||||
int i;
|
||||
int nCol;
|
||||
|
||||
azCol = tableColumnList(p, zTable);
|
||||
if( azCol==0 ) return 0;
|
||||
|
||||
initText(&sTable);
|
||||
appendText(&sTable, "INSERT INTO ", 0);
|
||||
|
||||
/* Always quote the table name, even if it appears to be pure ascii,
|
||||
** in case it is a keyword. Ex: INSERT INTO "table" ... */
|
||||
appendText(&sTable, zTable, quoteChar(zTable));
|
||||
|
||||
/* If preserving the rowid, add a column list after the table name.
|
||||
** In other words: "INSERT INTO tab(rowid,a,b,c,...) VALUES(...)"
|
||||
** instead of the usual "INSERT INTO tab VALUES(...)".
|
||||
*/
|
||||
if( azCol[0] ){
|
||||
appendText(&sTable, "(", 0);
|
||||
appendText(&sTable, azCol[0], 0);
|
||||
for(i=1; azCol[i]; i++){
|
||||
appendText(&sTable, ",", 0);
|
||||
appendText(&sTable, azCol[i], quoteChar(azCol[i]));
|
||||
}
|
||||
appendText(&sTable, ")", 0);
|
||||
}
|
||||
appendText(&sTable, " VALUES(", 0);
|
||||
|
||||
/* Build an appropriate SELECT statement */
|
||||
initText(&sSelect);
|
||||
appendText(&sSelect, "SELECT ", 0);
|
||||
if( azCol[0] ){
|
||||
appendText(&sSelect, azCol[0], 0);
|
||||
appendText(&sSelect, ",", 0);
|
||||
}
|
||||
for(i=1; azCol[i]; i++){
|
||||
appendText(&sSelect, azCol[i], quoteChar(azCol[i]));
|
||||
if( azCol[i+1] ){
|
||||
appendText(&sSelect, ",", 0);
|
||||
}
|
||||
}
|
||||
nCol = i;
|
||||
if( azCol[0]==0 ) nCol--;
|
||||
freeColumnList(azCol);
|
||||
appendText(&sSelect, " FROM ", 0);
|
||||
appendText(&sSelect, zTable, quoteChar(zTable));
|
||||
|
||||
rc = sqlite3_prepare_v2(p->db, sSelect.z, -1, &pStmt, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
p->nErr++;
|
||||
if( p->rc==SQLITE_OK ) p->rc = rc;
|
||||
}else{
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
p->xCallback(sTable.z, p->pArg);
|
||||
for(i=0; i<nCol; i++){
|
||||
if( i ) p->xCallback(",", p->pArg);
|
||||
switch( sqlite3_column_type(pStmt,i) ){
|
||||
case SQLITE_INTEGER: {
|
||||
output_formatted(p, "%lld", sqlite3_column_int64(pStmt,i));
|
||||
break;
|
||||
}
|
||||
case SQLITE_FLOAT: {
|
||||
double r = sqlite3_column_double(pStmt,i);
|
||||
output_formatted(p, "%!.20g", r);
|
||||
break;
|
||||
}
|
||||
case SQLITE_NULL: {
|
||||
p->xCallback("NULL", p->pArg);
|
||||
break;
|
||||
}
|
||||
case SQLITE_TEXT: {
|
||||
output_quoted_string(p, sqlite3_column_text(pStmt,i));
|
||||
break;
|
||||
}
|
||||
case SQLITE_BLOB: {
|
||||
int nByte = sqlite3_column_bytes(pStmt,i);
|
||||
unsigned char *a = (unsigned char*)sqlite3_column_blob(pStmt,i);
|
||||
int j;
|
||||
p->xCallback("x'", p->pArg);
|
||||
for(j=0; j<nByte; j++){
|
||||
char zWord[3];
|
||||
zWord[0] = "0123456789abcdef"[(a[j]>>4)&15];
|
||||
zWord[1] = "0123456789abcdef"[a[j]&15];
|
||||
zWord[2] = 0;
|
||||
p->xCallback(zWord, p->pArg);
|
||||
}
|
||||
p->xCallback("'", p->pArg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
p->xCallback(");\n", p->pArg);
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
freeText(&sTable);
|
||||
freeText(&sSelect);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Execute a query statement that will generate SQL output. Print
|
||||
** the result columns, comma-separated, on a line and then add a
|
||||
** semicolon terminator to the end of that line.
|
||||
**
|
||||
** If the number of columns is 1 and that column contains text "--"
|
||||
** then write the semicolon on a separate line. That way, if a
|
||||
** "--" comment occurs at the end of the statement, the comment
|
||||
** won't consume the semicolon terminator.
|
||||
*/
|
||||
static void output_sql_from_query(
|
||||
DState *p, /* Query context */
|
||||
const char *zSelect, /* SELECT statement to extract content */
|
||||
...
|
||||
){
|
||||
sqlite3_stmt *pSelect;
|
||||
int rc;
|
||||
int nResult;
|
||||
int i;
|
||||
const char *z;
|
||||
char *zSql;
|
||||
va_list ap;
|
||||
va_start(ap, zSelect);
|
||||
zSql = sqlite3_vmprintf(zSelect, ap);
|
||||
va_end(ap);
|
||||
if( zSql==0 ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
p->nErr++;
|
||||
return;
|
||||
}
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pSelect, 0);
|
||||
sqlite3_free(zSql);
|
||||
if( rc!=SQLITE_OK || !pSelect ){
|
||||
output_formatted(p, "/**** ERROR: (%d) %s *****/\n", rc,
|
||||
sqlite3_errmsg(p->db));
|
||||
p->nErr++;
|
||||
return;
|
||||
}
|
||||
rc = sqlite3_step(pSelect);
|
||||
nResult = sqlite3_column_count(pSelect);
|
||||
while( rc==SQLITE_ROW ){
|
||||
z = (const char*)sqlite3_column_text(pSelect, 0);
|
||||
p->xCallback(z, p->pArg);
|
||||
for(i=1; i<nResult; i++){
|
||||
p->xCallback(",", p->pArg);
|
||||
p->xCallback((const char*)sqlite3_column_text(pSelect,i), p->pArg);
|
||||
}
|
||||
if( z==0 ) z = "";
|
||||
while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;
|
||||
if( z[0] ){
|
||||
p->xCallback("\n;\n", p->pArg);
|
||||
}else{
|
||||
p->xCallback(";\n", p->pArg);
|
||||
}
|
||||
rc = sqlite3_step(pSelect);
|
||||
}
|
||||
rc = sqlite3_finalize(pSelect);
|
||||
if( rc!=SQLITE_OK ){
|
||||
output_formatted(p, "/**** ERROR: (%d) %s *****/\n", rc,
|
||||
sqlite3_errmsg(p->db));
|
||||
if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Run zQuery. Use dump_callback() as the callback routine so that
|
||||
** the contents of the query are output as SQL statements.
|
||||
**
|
||||
** If we get a SQLITE_CORRUPT error, rerun the query after appending
|
||||
** "ORDER BY rowid DESC" to the end.
|
||||
*/
|
||||
static void run_schema_dump_query(
|
||||
DState *p,
|
||||
const char *zQuery,
|
||||
...
|
||||
){
|
||||
char *zErr = 0;
|
||||
char *z;
|
||||
va_list ap;
|
||||
va_start(ap, zQuery);
|
||||
z = sqlite3_vmprintf(zQuery, ap);
|
||||
va_end(ap);
|
||||
sqlite3_exec(p->db, z, dump_callback, p, &zErr);
|
||||
sqlite3_free(z);
|
||||
if( zErr ){
|
||||
output_formatted(p, "/****** %s ******/\n", zErr);
|
||||
sqlite3_free(zErr);
|
||||
p->nErr++;
|
||||
zErr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert an SQLite database into SQL statements that will recreate that
|
||||
** database.
|
||||
*/
|
||||
int sqlite3_db_dump(
|
||||
sqlite3 *db, /* The database connection */
|
||||
const char *zSchema, /* Which schema to dump. Usually "main". */
|
||||
const char *zTable, /* Which table to dump. NULL means everything. */
|
||||
int (*xCallback)(const char*,void*), /* Output sent to this callback */
|
||||
void *pArg /* Second argument of the callback */
|
||||
){
|
||||
DState x;
|
||||
memset(&x, 0, sizeof(x));
|
||||
x.rc = sqlite3_exec(db, "BEGIN", 0, 0, 0);
|
||||
if( x.rc ) return x.rc;
|
||||
x.db = db;
|
||||
x.xCallback = xCallback;
|
||||
x.pArg = pArg;
|
||||
xCallback("PRAGMA foreign_keys=OFF;\nBEGIN TRANSACTION;\n", pArg);
|
||||
if( zTable==0 ){
|
||||
run_schema_dump_query(&x,
|
||||
"SELECT name, type, sql FROM \"%w\".sqlite_master "
|
||||
"WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'",
|
||||
zSchema
|
||||
);
|
||||
run_schema_dump_query(&x,
|
||||
"SELECT name, type, sql FROM \"%w\".sqlite_master "
|
||||
"WHERE name=='sqlite_sequence'", zSchema
|
||||
);
|
||||
output_sql_from_query(&x,
|
||||
"SELECT sql FROM sqlite_master "
|
||||
"WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0
|
||||
);
|
||||
}else{
|
||||
run_schema_dump_query(&x,
|
||||
"SELECT name, type, sql FROM \"%w\".sqlite_master "
|
||||
"WHERE tbl_name=%Q COLLATE nocase AND type=='table'"
|
||||
" AND sql NOT NULL",
|
||||
zSchema, zTable
|
||||
);
|
||||
output_sql_from_query(&x,
|
||||
"SELECT sql FROM \"%w\".sqlite_master "
|
||||
"WHERE sql NOT NULL"
|
||||
" AND type IN ('index','trigger','view')"
|
||||
" AND tbl_name=%Q COLLATE nocase",
|
||||
zSchema, zTable
|
||||
);
|
||||
}
|
||||
if( x.writableSchema ){
|
||||
xCallback("PRAGMA writable_schema=OFF;\n", pArg);
|
||||
}
|
||||
xCallback(x.nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n", pArg);
|
||||
sqlite3_exec(db, "COMMIT", 0, 0, 0);
|
||||
return x.rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* The generic subroutine is above. The code the follows implements
|
||||
** the command-line interface.
|
||||
*/
|
||||
#ifdef DBDUMP_STANDALONE
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
** Command-line interface
|
||||
*/
|
||||
int main(int argc, char **argv){
|
||||
sqlite3 *db;
|
||||
const char *zDb;
|
||||
const char *zSchema;
|
||||
const char *zTable = 0;
|
||||
int rc;
|
||||
|
||||
if( argc<2 || argc>4 ){
|
||||
fprintf(stderr, "Usage: %s DATABASE ?SCHEMA? ?TABLE?\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
zDb = argv[1];
|
||||
zSchema = argc>=3 ? argv[2] : "main";
|
||||
zTable = argc==4 ? argv[3] : 0;
|
||||
|
||||
rc = sqlite3_open(zDb, &db);
|
||||
if( rc ){
|
||||
fprintf(stderr, "Cannot open \"%s\": %s\n", zDb, sqlite3_errmsg(db));
|
||||
sqlite3_close(db);
|
||||
return 1;
|
||||
}
|
||||
rc = sqlite3_db_dump(db, zSchema, zTable,
|
||||
(int(*)(const char*,void*))fputs, (void*)stdout);
|
||||
if( rc ){
|
||||
fprintf(stderr, "Error: sqlite3_db_dump() returns %d\n", rc);
|
||||
}
|
||||
sqlite3_close(db);
|
||||
return rc!=SQLITE_OK;
|
||||
}
|
||||
#endif /* DBDUMP_STANDALONE */
|
||||
+138
-20
@@ -138,9 +138,10 @@ static const char * const jsonType[] = {
|
||||
#define JNODE_RAW 0x01 /* Content is raw, not JSON encoded */
|
||||
#define JNODE_ESCAPE 0x02 /* Content is text with \ escapes */
|
||||
#define JNODE_REMOVE 0x04 /* Do not output */
|
||||
#define JNODE_REPLACE 0x08 /* Replace with JsonNode.iVal */
|
||||
#define JNODE_APPEND 0x10 /* More ARRAY/OBJECT entries at u.iAppend */
|
||||
#define JNODE_LABEL 0x20 /* Is a label of an object */
|
||||
#define JNODE_REPLACE 0x08 /* Replace with JsonNode.u.iReplace */
|
||||
#define JNODE_PATCH 0x10 /* Patch with JsonNode.u.pPatch */
|
||||
#define JNODE_APPEND 0x20 /* More ARRAY/OBJECT entries at u.iAppend */
|
||||
#define JNODE_LABEL 0x40 /* Is a label of an object */
|
||||
|
||||
|
||||
/* A single node of parsed JSON
|
||||
@@ -148,12 +149,13 @@ static const char * const jsonType[] = {
|
||||
struct JsonNode {
|
||||
u8 eType; /* One of the JSON_ type values */
|
||||
u8 jnFlags; /* JNODE flags */
|
||||
u8 iVal; /* Replacement value when JNODE_REPLACE */
|
||||
u32 n; /* Bytes of content, or number of sub-nodes */
|
||||
union {
|
||||
const char *zJContent; /* Content for INT, REAL, and STRING */
|
||||
u32 iAppend; /* More terms for ARRAY and OBJECT */
|
||||
u32 iKey; /* Key for ARRAY objects in json_tree() */
|
||||
u32 iReplace; /* Replacement content for JNODE_REPLACE */
|
||||
JsonNode *pPatch; /* Node chain of patch for JNODE_PATCH */
|
||||
} u;
|
||||
};
|
||||
|
||||
@@ -410,6 +412,13 @@ static void jsonRenderNode(
|
||||
JsonString *pOut, /* Write JSON here */
|
||||
sqlite3_value **aReplace /* Replacement values */
|
||||
){
|
||||
if( pNode->jnFlags & (JNODE_REPLACE|JNODE_PATCH) ){
|
||||
if( pNode->jnFlags & JNODE_REPLACE ){
|
||||
jsonAppendValue(pOut, aReplace[pNode->u.iReplace]);
|
||||
return;
|
||||
}
|
||||
pNode = pNode->u.pPatch;
|
||||
}
|
||||
switch( pNode->eType ){
|
||||
default: {
|
||||
assert( pNode->eType==JSON_NULL );
|
||||
@@ -441,12 +450,7 @@ static void jsonRenderNode(
|
||||
jsonAppendChar(pOut, '[');
|
||||
for(;;){
|
||||
while( j<=pNode->n ){
|
||||
if( pNode[j].jnFlags & (JNODE_REMOVE|JNODE_REPLACE) ){
|
||||
if( pNode[j].jnFlags & JNODE_REPLACE ){
|
||||
jsonAppendSeparator(pOut);
|
||||
jsonAppendValue(pOut, aReplace[pNode[j].iVal]);
|
||||
}
|
||||
}else{
|
||||
if( (pNode[j].jnFlags & JNODE_REMOVE)==0 ){
|
||||
jsonAppendSeparator(pOut);
|
||||
jsonRenderNode(&pNode[j], pOut, aReplace);
|
||||
}
|
||||
@@ -468,11 +472,7 @@ static void jsonRenderNode(
|
||||
jsonAppendSeparator(pOut);
|
||||
jsonRenderNode(&pNode[j], pOut, aReplace);
|
||||
jsonAppendChar(pOut, ':');
|
||||
if( pNode[j+1].jnFlags & JNODE_REPLACE ){
|
||||
jsonAppendValue(pOut, aReplace[pNode[j+1].iVal]);
|
||||
}else{
|
||||
jsonRenderNode(&pNode[j+1], pOut, aReplace);
|
||||
}
|
||||
jsonRenderNode(&pNode[j+1], pOut, aReplace);
|
||||
}
|
||||
j += 1 + jsonNodeSize(&pNode[j+1]);
|
||||
}
|
||||
@@ -699,7 +699,6 @@ static int jsonParseAddNode(
|
||||
p = &pParse->aNode[pParse->nNode];
|
||||
p->eType = (u8)eType;
|
||||
p->jnFlags = 0;
|
||||
p->iVal = 0;
|
||||
p->n = n;
|
||||
p->u.zJContent = zContent;
|
||||
return pParse->nNode++;
|
||||
@@ -1165,6 +1164,25 @@ static void jsonWrongNumArgs(
|
||||
sqlite3_free(zMsg);
|
||||
}
|
||||
|
||||
/*
|
||||
** Mark all NULL entries in the Object passed in as JNODE_REMOVE.
|
||||
*/
|
||||
static void jsonRemoveAllNulls(JsonNode *pNode){
|
||||
int i, n;
|
||||
assert( pNode->eType==JSON_OBJECT );
|
||||
n = pNode->n;
|
||||
for(i=2; i<=n; i += jsonNodeSize(&pNode[i])+1){
|
||||
switch( pNode[i].eType ){
|
||||
case JSON_NULL:
|
||||
pNode[i].jnFlags |= JNODE_REMOVE;
|
||||
break;
|
||||
case JSON_OBJECT:
|
||||
jsonRemoveAllNulls(&pNode[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
** SQL functions used for testing and debugging
|
||||
@@ -1357,6 +1375,105 @@ static void jsonExtractFunc(
|
||||
jsonParseReset(&x);
|
||||
}
|
||||
|
||||
/* This is the RFC 7396 MergePatch algorithm.
|
||||
*/
|
||||
static JsonNode *jsonMergePatch(
|
||||
JsonParse *pParse, /* The JSON parser that contains the TARGET */
|
||||
int iTarget, /* Node of the TARGET in pParse */
|
||||
JsonNode *pPatch /* The PATCH */
|
||||
){
|
||||
u32 i, j;
|
||||
u32 iRoot;
|
||||
JsonNode *pTarget;
|
||||
if( pPatch->eType!=JSON_OBJECT ){
|
||||
return pPatch;
|
||||
}
|
||||
assert( iTarget>=0 && iTarget<pParse->nNode );
|
||||
pTarget = &pParse->aNode[iTarget];
|
||||
assert( (pPatch->jnFlags & JNODE_APPEND)==0 );
|
||||
if( pTarget->eType!=JSON_OBJECT ){
|
||||
jsonRemoveAllNulls(pPatch);
|
||||
return pPatch;
|
||||
}
|
||||
iRoot = iTarget;
|
||||
for(i=1; i<pPatch->n; i += jsonNodeSize(&pPatch[i+1])+1){
|
||||
u32 nKey;
|
||||
const char *zKey;
|
||||
assert( pPatch[i].eType==JSON_STRING );
|
||||
assert( pPatch[i].jnFlags & JNODE_LABEL );
|
||||
nKey = pPatch[i].n;
|
||||
zKey = pPatch[i].u.zJContent;
|
||||
assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
|
||||
for(j=1; j<pTarget->n; j += jsonNodeSize(&pTarget[j+1])+1 ){
|
||||
assert( pTarget[j].eType==JSON_STRING );
|
||||
assert( pTarget[j].jnFlags & JNODE_LABEL );
|
||||
assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
|
||||
if( pTarget[j].n==nKey && strncmp(pTarget[j].u.zJContent,zKey,nKey)==0 ){
|
||||
if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_PATCH) ) break;
|
||||
if( pPatch[i+1].eType==JSON_NULL ){
|
||||
pTarget[j+1].jnFlags |= JNODE_REMOVE;
|
||||
}else{
|
||||
JsonNode *pNew = jsonMergePatch(pParse, iTarget+j+1, &pPatch[i+1]);
|
||||
if( pNew==0 ) return 0;
|
||||
pTarget = &pParse->aNode[iTarget];
|
||||
if( pNew!=&pTarget[j+1] ){
|
||||
pTarget[j+1].u.pPatch = pNew;
|
||||
pTarget[j+1].jnFlags |= JNODE_PATCH;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( j>=pTarget->n && pPatch[i+1].eType!=JSON_NULL ){
|
||||
int iStart, iPatch;
|
||||
iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
|
||||
jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
|
||||
iPatch = jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
|
||||
if( pParse->oom ) return 0;
|
||||
jsonRemoveAllNulls(pPatch);
|
||||
pTarget = &pParse->aNode[iTarget];
|
||||
pParse->aNode[iRoot].jnFlags |= JNODE_APPEND;
|
||||
pParse->aNode[iRoot].u.iAppend = iStart - iRoot;
|
||||
iRoot = iStart;
|
||||
pParse->aNode[iPatch].jnFlags |= JNODE_PATCH;
|
||||
pParse->aNode[iPatch].u.pPatch = &pPatch[i+1];
|
||||
}
|
||||
}
|
||||
return pTarget;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the json_mergepatch(JSON1,JSON2) function. Return a JSON
|
||||
** object that is the result of running the RFC 7396 MergePatch() algorithm
|
||||
** on the two arguments.
|
||||
*/
|
||||
static void jsonPatchFunc(
|
||||
sqlite3_context *ctx,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
JsonParse x; /* The JSON that is being patched */
|
||||
JsonParse y; /* The patch */
|
||||
JsonNode *pResult; /* The result of the merge */
|
||||
|
||||
UNUSED_PARAM(argc);
|
||||
if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
|
||||
if( jsonParse(&y, ctx, (const char*)sqlite3_value_text(argv[1])) ){
|
||||
jsonParseReset(&x);
|
||||
return;
|
||||
}
|
||||
pResult = jsonMergePatch(&x, 0, y.aNode);
|
||||
assert( pResult!=0 || x.oom );
|
||||
if( pResult ){
|
||||
jsonReturnJson(pResult, ctx, 0);
|
||||
}else{
|
||||
sqlite3_result_error_nomem(ctx);
|
||||
}
|
||||
jsonParseReset(&x);
|
||||
jsonParseReset(&y);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Implementation of the json_object(NAME,VALUE,...) function. Return a JSON
|
||||
** object that contains all name/value given in arguments. Or if any name
|
||||
@@ -1460,11 +1577,11 @@ static void jsonReplaceFunc(
|
||||
if( x.nErr ) goto replace_err;
|
||||
if( pNode ){
|
||||
pNode->jnFlags |= (u8)JNODE_REPLACE;
|
||||
pNode->iVal = (u8)(i+1);
|
||||
pNode->u.iReplace = i + 1;
|
||||
}
|
||||
}
|
||||
if( x.aNode[0].jnFlags & JNODE_REPLACE ){
|
||||
sqlite3_result_value(ctx, argv[x.aNode[0].iVal]);
|
||||
sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
|
||||
}else{
|
||||
jsonReturnJson(x.aNode, ctx, argv);
|
||||
}
|
||||
@@ -1514,11 +1631,11 @@ static void jsonSetFunc(
|
||||
goto jsonSetDone;
|
||||
}else if( pNode && (bApnd || bIsSet) ){
|
||||
pNode->jnFlags |= (u8)JNODE_REPLACE;
|
||||
pNode->iVal = (u8)(i+1);
|
||||
pNode->u.iReplace = i + 1;
|
||||
}
|
||||
}
|
||||
if( x.aNode[0].jnFlags & JNODE_REPLACE ){
|
||||
sqlite3_result_value(ctx, argv[x.aNode[0].iVal]);
|
||||
sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
|
||||
}else{
|
||||
jsonReturnJson(x.aNode, ctx, argv);
|
||||
}
|
||||
@@ -2161,6 +2278,7 @@ int sqlite3Json1Init(sqlite3 *db){
|
||||
{ "json_extract", -1, 0, jsonExtractFunc },
|
||||
{ "json_insert", -1, 0, jsonSetFunc },
|
||||
{ "json_object", -1, 0, jsonObjectFunc },
|
||||
{ "json_patch", 2, 0, jsonPatchFunc },
|
||||
{ "json_quote", 1, 0, jsonQuoteFunc },
|
||||
{ "json_remove", -1, 0, jsonRemoveFunc },
|
||||
{ "json_replace", -1, 0, jsonReplaceFunc },
|
||||
|
||||
@@ -0,0 +1,714 @@
|
||||
/*
|
||||
** 2017-03-08
|
||||
**
|
||||
** 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 SQLite extension implements a functions that compute SHA1 hashes.
|
||||
** Two SQL functions are implemented:
|
||||
**
|
||||
** sha3(X,SIZE)
|
||||
** sha3_query(Y,SIZE)
|
||||
**
|
||||
** The sha3(X) function computes the SHA3 hash of the input X, or NULL if
|
||||
** X is NULL.
|
||||
**
|
||||
** The sha3_query(Y) function evalutes all queries in the SQL statements of Y
|
||||
** and returns a hash of their results.
|
||||
**
|
||||
** The SIZE argument is optional. If omitted, the SHA3-256 hash algorithm
|
||||
** is used. If SIZE is included it must be one of the integers 224, 256,
|
||||
** 384, or 512, to determine SHA3 hash variant that is computed.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
typedef sqlite3_uint64 u64;
|
||||
|
||||
/******************************************************************************
|
||||
** The Hash Engine
|
||||
*/
|
||||
/*
|
||||
** Macros to determine whether the machine is big or little endian,
|
||||
** and whether or not that determination is run-time or compile-time.
|
||||
**
|
||||
** For best performance, an attempt is made to guess at the byte-order
|
||||
** using C-preprocessor macros. If that is unsuccessful, or if
|
||||
** -DSHA3_BYTEORDER=0 is set, then byte-order is determined
|
||||
** at run-time.
|
||||
*/
|
||||
#ifndef SHA3_BYTEORDER
|
||||
# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \
|
||||
defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
|
||||
defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
|
||||
defined(__arm__)
|
||||
# define SHA3_BYTEORDER 1234
|
||||
# elif defined(sparc) || defined(__ppc__)
|
||||
# define SHA3_BYTEORDER 4321
|
||||
# else
|
||||
# define SHA3_BYTEORDER 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** State structure for a SHA3 hash in progress
|
||||
*/
|
||||
typedef struct SHA3Context SHA3Context;
|
||||
struct SHA3Context {
|
||||
union {
|
||||
u64 s[25]; /* Keccak state. 5x5 lines of 64 bits each */
|
||||
unsigned char x[1600]; /* ... or 1600 bytes */
|
||||
} u;
|
||||
unsigned nRate; /* Bytes of input accepted per Keccak iteration */
|
||||
unsigned nLoaded; /* Input bytes loaded into u.x[] so far this cycle */
|
||||
unsigned ixMask; /* Insert next input into u.x[nLoaded^ixMask]. */
|
||||
};
|
||||
|
||||
/*
|
||||
** A single step of the Keccak mixing function for a 1600-bit state
|
||||
*/
|
||||
static void KeccakF1600Step(SHA3Context *p){
|
||||
int i;
|
||||
u64 B0, B1, B2, B3, B4;
|
||||
u64 C0, C1, C2, C3, C4;
|
||||
u64 D0, D1, D2, D3, D4;
|
||||
static const u64 RC[] = {
|
||||
0x0000000000000001ULL, 0x0000000000008082ULL,
|
||||
0x800000000000808aULL, 0x8000000080008000ULL,
|
||||
0x000000000000808bULL, 0x0000000080000001ULL,
|
||||
0x8000000080008081ULL, 0x8000000000008009ULL,
|
||||
0x000000000000008aULL, 0x0000000000000088ULL,
|
||||
0x0000000080008009ULL, 0x000000008000000aULL,
|
||||
0x000000008000808bULL, 0x800000000000008bULL,
|
||||
0x8000000000008089ULL, 0x8000000000008003ULL,
|
||||
0x8000000000008002ULL, 0x8000000000000080ULL,
|
||||
0x000000000000800aULL, 0x800000008000000aULL,
|
||||
0x8000000080008081ULL, 0x8000000000008080ULL,
|
||||
0x0000000080000001ULL, 0x8000000080008008ULL
|
||||
};
|
||||
# define A00 (p->u.s[0])
|
||||
# define A01 (p->u.s[1])
|
||||
# define A02 (p->u.s[2])
|
||||
# define A03 (p->u.s[3])
|
||||
# define A04 (p->u.s[4])
|
||||
# define A10 (p->u.s[5])
|
||||
# define A11 (p->u.s[6])
|
||||
# define A12 (p->u.s[7])
|
||||
# define A13 (p->u.s[8])
|
||||
# define A14 (p->u.s[9])
|
||||
# define A20 (p->u.s[10])
|
||||
# define A21 (p->u.s[11])
|
||||
# define A22 (p->u.s[12])
|
||||
# define A23 (p->u.s[13])
|
||||
# define A24 (p->u.s[14])
|
||||
# define A30 (p->u.s[15])
|
||||
# define A31 (p->u.s[16])
|
||||
# define A32 (p->u.s[17])
|
||||
# define A33 (p->u.s[18])
|
||||
# define A34 (p->u.s[19])
|
||||
# define A40 (p->u.s[20])
|
||||
# define A41 (p->u.s[21])
|
||||
# define A42 (p->u.s[22])
|
||||
# define A43 (p->u.s[23])
|
||||
# define A44 (p->u.s[24])
|
||||
# define ROL64(a,x) ((a<<x)|(a>>(64-x)))
|
||||
|
||||
for(i=0; i<24; i+=4){
|
||||
C0 = A00^A10^A20^A30^A40;
|
||||
C1 = A01^A11^A21^A31^A41;
|
||||
C2 = A02^A12^A22^A32^A42;
|
||||
C3 = A03^A13^A23^A33^A43;
|
||||
C4 = A04^A14^A24^A34^A44;
|
||||
D0 = C4^ROL64(C1, 1);
|
||||
D1 = C0^ROL64(C2, 1);
|
||||
D2 = C1^ROL64(C3, 1);
|
||||
D3 = C2^ROL64(C4, 1);
|
||||
D4 = C3^ROL64(C0, 1);
|
||||
|
||||
B0 = (A00^D0);
|
||||
B1 = ROL64((A11^D1), 44);
|
||||
B2 = ROL64((A22^D2), 43);
|
||||
B3 = ROL64((A33^D3), 21);
|
||||
B4 = ROL64((A44^D4), 14);
|
||||
A00 = B0 ^((~B1)& B2 );
|
||||
A00 ^= RC[i];
|
||||
A11 = B1 ^((~B2)& B3 );
|
||||
A22 = B2 ^((~B3)& B4 );
|
||||
A33 = B3 ^((~B4)& B0 );
|
||||
A44 = B4 ^((~B0)& B1 );
|
||||
|
||||
B2 = ROL64((A20^D0), 3);
|
||||
B3 = ROL64((A31^D1), 45);
|
||||
B4 = ROL64((A42^D2), 61);
|
||||
B0 = ROL64((A03^D3), 28);
|
||||
B1 = ROL64((A14^D4), 20);
|
||||
A20 = B0 ^((~B1)& B2 );
|
||||
A31 = B1 ^((~B2)& B3 );
|
||||
A42 = B2 ^((~B3)& B4 );
|
||||
A03 = B3 ^((~B4)& B0 );
|
||||
A14 = B4 ^((~B0)& B1 );
|
||||
|
||||
B4 = ROL64((A40^D0), 18);
|
||||
B0 = ROL64((A01^D1), 1);
|
||||
B1 = ROL64((A12^D2), 6);
|
||||
B2 = ROL64((A23^D3), 25);
|
||||
B3 = ROL64((A34^D4), 8);
|
||||
A40 = B0 ^((~B1)& B2 );
|
||||
A01 = B1 ^((~B2)& B3 );
|
||||
A12 = B2 ^((~B3)& B4 );
|
||||
A23 = B3 ^((~B4)& B0 );
|
||||
A34 = B4 ^((~B0)& B1 );
|
||||
|
||||
B1 = ROL64((A10^D0), 36);
|
||||
B2 = ROL64((A21^D1), 10);
|
||||
B3 = ROL64((A32^D2), 15);
|
||||
B4 = ROL64((A43^D3), 56);
|
||||
B0 = ROL64((A04^D4), 27);
|
||||
A10 = B0 ^((~B1)& B2 );
|
||||
A21 = B1 ^((~B2)& B3 );
|
||||
A32 = B2 ^((~B3)& B4 );
|
||||
A43 = B3 ^((~B4)& B0 );
|
||||
A04 = B4 ^((~B0)& B1 );
|
||||
|
||||
B3 = ROL64((A30^D0), 41);
|
||||
B4 = ROL64((A41^D1), 2);
|
||||
B0 = ROL64((A02^D2), 62);
|
||||
B1 = ROL64((A13^D3), 55);
|
||||
B2 = ROL64((A24^D4), 39);
|
||||
A30 = B0 ^((~B1)& B2 );
|
||||
A41 = B1 ^((~B2)& B3 );
|
||||
A02 = B2 ^((~B3)& B4 );
|
||||
A13 = B3 ^((~B4)& B0 );
|
||||
A24 = B4 ^((~B0)& B1 );
|
||||
|
||||
C0 = A00^A20^A40^A10^A30;
|
||||
C1 = A11^A31^A01^A21^A41;
|
||||
C2 = A22^A42^A12^A32^A02;
|
||||
C3 = A33^A03^A23^A43^A13;
|
||||
C4 = A44^A14^A34^A04^A24;
|
||||
D0 = C4^ROL64(C1, 1);
|
||||
D1 = C0^ROL64(C2, 1);
|
||||
D2 = C1^ROL64(C3, 1);
|
||||
D3 = C2^ROL64(C4, 1);
|
||||
D4 = C3^ROL64(C0, 1);
|
||||
|
||||
B0 = (A00^D0);
|
||||
B1 = ROL64((A31^D1), 44);
|
||||
B2 = ROL64((A12^D2), 43);
|
||||
B3 = ROL64((A43^D3), 21);
|
||||
B4 = ROL64((A24^D4), 14);
|
||||
A00 = B0 ^((~B1)& B2 );
|
||||
A00 ^= RC[i+1];
|
||||
A31 = B1 ^((~B2)& B3 );
|
||||
A12 = B2 ^((~B3)& B4 );
|
||||
A43 = B3 ^((~B4)& B0 );
|
||||
A24 = B4 ^((~B0)& B1 );
|
||||
|
||||
B2 = ROL64((A40^D0), 3);
|
||||
B3 = ROL64((A21^D1), 45);
|
||||
B4 = ROL64((A02^D2), 61);
|
||||
B0 = ROL64((A33^D3), 28);
|
||||
B1 = ROL64((A14^D4), 20);
|
||||
A40 = B0 ^((~B1)& B2 );
|
||||
A21 = B1 ^((~B2)& B3 );
|
||||
A02 = B2 ^((~B3)& B4 );
|
||||
A33 = B3 ^((~B4)& B0 );
|
||||
A14 = B4 ^((~B0)& B1 );
|
||||
|
||||
B4 = ROL64((A30^D0), 18);
|
||||
B0 = ROL64((A11^D1), 1);
|
||||
B1 = ROL64((A42^D2), 6);
|
||||
B2 = ROL64((A23^D3), 25);
|
||||
B3 = ROL64((A04^D4), 8);
|
||||
A30 = B0 ^((~B1)& B2 );
|
||||
A11 = B1 ^((~B2)& B3 );
|
||||
A42 = B2 ^((~B3)& B4 );
|
||||
A23 = B3 ^((~B4)& B0 );
|
||||
A04 = B4 ^((~B0)& B1 );
|
||||
|
||||
B1 = ROL64((A20^D0), 36);
|
||||
B2 = ROL64((A01^D1), 10);
|
||||
B3 = ROL64((A32^D2), 15);
|
||||
B4 = ROL64((A13^D3), 56);
|
||||
B0 = ROL64((A44^D4), 27);
|
||||
A20 = B0 ^((~B1)& B2 );
|
||||
A01 = B1 ^((~B2)& B3 );
|
||||
A32 = B2 ^((~B3)& B4 );
|
||||
A13 = B3 ^((~B4)& B0 );
|
||||
A44 = B4 ^((~B0)& B1 );
|
||||
|
||||
B3 = ROL64((A10^D0), 41);
|
||||
B4 = ROL64((A41^D1), 2);
|
||||
B0 = ROL64((A22^D2), 62);
|
||||
B1 = ROL64((A03^D3), 55);
|
||||
B2 = ROL64((A34^D4), 39);
|
||||
A10 = B0 ^((~B1)& B2 );
|
||||
A41 = B1 ^((~B2)& B3 );
|
||||
A22 = B2 ^((~B3)& B4 );
|
||||
A03 = B3 ^((~B4)& B0 );
|
||||
A34 = B4 ^((~B0)& B1 );
|
||||
|
||||
C0 = A00^A40^A30^A20^A10;
|
||||
C1 = A31^A21^A11^A01^A41;
|
||||
C2 = A12^A02^A42^A32^A22;
|
||||
C3 = A43^A33^A23^A13^A03;
|
||||
C4 = A24^A14^A04^A44^A34;
|
||||
D0 = C4^ROL64(C1, 1);
|
||||
D1 = C0^ROL64(C2, 1);
|
||||
D2 = C1^ROL64(C3, 1);
|
||||
D3 = C2^ROL64(C4, 1);
|
||||
D4 = C3^ROL64(C0, 1);
|
||||
|
||||
B0 = (A00^D0);
|
||||
B1 = ROL64((A21^D1), 44);
|
||||
B2 = ROL64((A42^D2), 43);
|
||||
B3 = ROL64((A13^D3), 21);
|
||||
B4 = ROL64((A34^D4), 14);
|
||||
A00 = B0 ^((~B1)& B2 );
|
||||
A00 ^= RC[i+2];
|
||||
A21 = B1 ^((~B2)& B3 );
|
||||
A42 = B2 ^((~B3)& B4 );
|
||||
A13 = B3 ^((~B4)& B0 );
|
||||
A34 = B4 ^((~B0)& B1 );
|
||||
|
||||
B2 = ROL64((A30^D0), 3);
|
||||
B3 = ROL64((A01^D1), 45);
|
||||
B4 = ROL64((A22^D2), 61);
|
||||
B0 = ROL64((A43^D3), 28);
|
||||
B1 = ROL64((A14^D4), 20);
|
||||
A30 = B0 ^((~B1)& B2 );
|
||||
A01 = B1 ^((~B2)& B3 );
|
||||
A22 = B2 ^((~B3)& B4 );
|
||||
A43 = B3 ^((~B4)& B0 );
|
||||
A14 = B4 ^((~B0)& B1 );
|
||||
|
||||
B4 = ROL64((A10^D0), 18);
|
||||
B0 = ROL64((A31^D1), 1);
|
||||
B1 = ROL64((A02^D2), 6);
|
||||
B2 = ROL64((A23^D3), 25);
|
||||
B3 = ROL64((A44^D4), 8);
|
||||
A10 = B0 ^((~B1)& B2 );
|
||||
A31 = B1 ^((~B2)& B3 );
|
||||
A02 = B2 ^((~B3)& B4 );
|
||||
A23 = B3 ^((~B4)& B0 );
|
||||
A44 = B4 ^((~B0)& B1 );
|
||||
|
||||
B1 = ROL64((A40^D0), 36);
|
||||
B2 = ROL64((A11^D1), 10);
|
||||
B3 = ROL64((A32^D2), 15);
|
||||
B4 = ROL64((A03^D3), 56);
|
||||
B0 = ROL64((A24^D4), 27);
|
||||
A40 = B0 ^((~B1)& B2 );
|
||||
A11 = B1 ^((~B2)& B3 );
|
||||
A32 = B2 ^((~B3)& B4 );
|
||||
A03 = B3 ^((~B4)& B0 );
|
||||
A24 = B4 ^((~B0)& B1 );
|
||||
|
||||
B3 = ROL64((A20^D0), 41);
|
||||
B4 = ROL64((A41^D1), 2);
|
||||
B0 = ROL64((A12^D2), 62);
|
||||
B1 = ROL64((A33^D3), 55);
|
||||
B2 = ROL64((A04^D4), 39);
|
||||
A20 = B0 ^((~B1)& B2 );
|
||||
A41 = B1 ^((~B2)& B3 );
|
||||
A12 = B2 ^((~B3)& B4 );
|
||||
A33 = B3 ^((~B4)& B0 );
|
||||
A04 = B4 ^((~B0)& B1 );
|
||||
|
||||
C0 = A00^A30^A10^A40^A20;
|
||||
C1 = A21^A01^A31^A11^A41;
|
||||
C2 = A42^A22^A02^A32^A12;
|
||||
C3 = A13^A43^A23^A03^A33;
|
||||
C4 = A34^A14^A44^A24^A04;
|
||||
D0 = C4^ROL64(C1, 1);
|
||||
D1 = C0^ROL64(C2, 1);
|
||||
D2 = C1^ROL64(C3, 1);
|
||||
D3 = C2^ROL64(C4, 1);
|
||||
D4 = C3^ROL64(C0, 1);
|
||||
|
||||
B0 = (A00^D0);
|
||||
B1 = ROL64((A01^D1), 44);
|
||||
B2 = ROL64((A02^D2), 43);
|
||||
B3 = ROL64((A03^D3), 21);
|
||||
B4 = ROL64((A04^D4), 14);
|
||||
A00 = B0 ^((~B1)& B2 );
|
||||
A00 ^= RC[i+3];
|
||||
A01 = B1 ^((~B2)& B3 );
|
||||
A02 = B2 ^((~B3)& B4 );
|
||||
A03 = B3 ^((~B4)& B0 );
|
||||
A04 = B4 ^((~B0)& B1 );
|
||||
|
||||
B2 = ROL64((A10^D0), 3);
|
||||
B3 = ROL64((A11^D1), 45);
|
||||
B4 = ROL64((A12^D2), 61);
|
||||
B0 = ROL64((A13^D3), 28);
|
||||
B1 = ROL64((A14^D4), 20);
|
||||
A10 = B0 ^((~B1)& B2 );
|
||||
A11 = B1 ^((~B2)& B3 );
|
||||
A12 = B2 ^((~B3)& B4 );
|
||||
A13 = B3 ^((~B4)& B0 );
|
||||
A14 = B4 ^((~B0)& B1 );
|
||||
|
||||
B4 = ROL64((A20^D0), 18);
|
||||
B0 = ROL64((A21^D1), 1);
|
||||
B1 = ROL64((A22^D2), 6);
|
||||
B2 = ROL64((A23^D3), 25);
|
||||
B3 = ROL64((A24^D4), 8);
|
||||
A20 = B0 ^((~B1)& B2 );
|
||||
A21 = B1 ^((~B2)& B3 );
|
||||
A22 = B2 ^((~B3)& B4 );
|
||||
A23 = B3 ^((~B4)& B0 );
|
||||
A24 = B4 ^((~B0)& B1 );
|
||||
|
||||
B1 = ROL64((A30^D0), 36);
|
||||
B2 = ROL64((A31^D1), 10);
|
||||
B3 = ROL64((A32^D2), 15);
|
||||
B4 = ROL64((A33^D3), 56);
|
||||
B0 = ROL64((A34^D4), 27);
|
||||
A30 = B0 ^((~B1)& B2 );
|
||||
A31 = B1 ^((~B2)& B3 );
|
||||
A32 = B2 ^((~B3)& B4 );
|
||||
A33 = B3 ^((~B4)& B0 );
|
||||
A34 = B4 ^((~B0)& B1 );
|
||||
|
||||
B3 = ROL64((A40^D0), 41);
|
||||
B4 = ROL64((A41^D1), 2);
|
||||
B0 = ROL64((A42^D2), 62);
|
||||
B1 = ROL64((A43^D3), 55);
|
||||
B2 = ROL64((A44^D4), 39);
|
||||
A40 = B0 ^((~B1)& B2 );
|
||||
A41 = B1 ^((~B2)& B3 );
|
||||
A42 = B2 ^((~B3)& B4 );
|
||||
A43 = B3 ^((~B4)& B0 );
|
||||
A44 = B4 ^((~B0)& B1 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize a new hash. iSize determines the size of the hash
|
||||
** in bits and should be one of 224, 256, 384, or 512. Or iSize
|
||||
** can be zero to use the default hash size of 256 bits.
|
||||
*/
|
||||
static void SHA3Init(SHA3Context *p, int iSize){
|
||||
memset(p, 0, sizeof(*p));
|
||||
if( iSize>=128 && iSize<=512 ){
|
||||
p->nRate = (1600 - ((iSize + 31)&~31)*2)/8;
|
||||
}else{
|
||||
p->nRate = (1600 - 2*256)/8;
|
||||
}
|
||||
#if SHA3_BYTEORDER==1234
|
||||
/* Known to be little-endian at compile-time. No-op */
|
||||
#elif SHA3_BYTEORDER==4321
|
||||
p->ixMask = 7; /* Big-endian */
|
||||
#else
|
||||
{
|
||||
static unsigned int one = 1;
|
||||
if( 1==*(unsigned char*)&one ){
|
||||
/* Little endian. No byte swapping. */
|
||||
p->ixMask = 0;
|
||||
}else{
|
||||
/* Big endian. Byte swap. */
|
||||
p->ixMask = 7;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Make consecutive calls to the SHA3Update function to add new content
|
||||
** to the hash
|
||||
*/
|
||||
static void SHA3Update(
|
||||
SHA3Context *p,
|
||||
const unsigned char *aData,
|
||||
unsigned int nData
|
||||
){
|
||||
unsigned int i = 0;
|
||||
#if SHA3_BYTEORDER==1234
|
||||
if( (p->nLoaded % 8)==0 && ((aData - (const unsigned char*)0)&7)==0 ){
|
||||
for(; i+7<nData; i+=8){
|
||||
p->u.s[p->nLoaded/8] ^= *(u64*)&aData[i];
|
||||
p->nLoaded += 8;
|
||||
if( p->nLoaded>=p->nRate ){
|
||||
KeccakF1600Step(p);
|
||||
p->nLoaded = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
for(; i<nData; i++){
|
||||
#if SHA3_BYTEORDER==1234
|
||||
p->u.x[p->nLoaded] ^= aData[i];
|
||||
#elif SHA3_BYTEORDER==4321
|
||||
p->u.x[p->nLoaded^0x07] ^= aData[i];
|
||||
#else
|
||||
p->u.x[p->nLoaded^p->ixMask] ^= aData[i];
|
||||
#endif
|
||||
p->nLoaded++;
|
||||
if( p->nLoaded==p->nRate ){
|
||||
KeccakF1600Step(p);
|
||||
p->nLoaded = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** After all content has been added, invoke SHA3Final() to compute
|
||||
** the final hash. The function returns a pointer to the binary
|
||||
** hash value.
|
||||
*/
|
||||
static unsigned char *SHA3Final(SHA3Context *p){
|
||||
unsigned int i;
|
||||
if( p->nLoaded==p->nRate-1 ){
|
||||
const unsigned char c1 = 0x86;
|
||||
SHA3Update(p, &c1, 1);
|
||||
}else{
|
||||
const unsigned char c2 = 0x06;
|
||||
const unsigned char c3 = 0x80;
|
||||
SHA3Update(p, &c2, 1);
|
||||
p->nLoaded = p->nRate - 1;
|
||||
SHA3Update(p, &c3, 1);
|
||||
}
|
||||
for(i=0; i<p->nRate; i++){
|
||||
p->u.x[i+p->nRate] = p->u.x[i^p->ixMask];
|
||||
}
|
||||
return &p->u.x[p->nRate];
|
||||
}
|
||||
/* End of the hashing logic
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
** Implementation of the sha3(X,SIZE) function.
|
||||
**
|
||||
** Return a BLOB which is the SIZE-bit SHA3 hash of X. The default
|
||||
** size is 256. If X is a BLOB, it is hashed as is.
|
||||
** For all other non-NULL types of input, X is converted into a UTF-8 string
|
||||
** and the string is hashed without the trailing 0x00 terminator. The hash
|
||||
** of a NULL value is NULL.
|
||||
*/
|
||||
static void sha3Func(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
SHA3Context cx;
|
||||
int eType = sqlite3_value_type(argv[0]);
|
||||
int nByte = sqlite3_value_bytes(argv[0]);
|
||||
int iSize;
|
||||
if( argc==1 ){
|
||||
iSize = 256;
|
||||
}else{
|
||||
iSize = sqlite3_value_int(argv[1]);
|
||||
if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){
|
||||
sqlite3_result_error(context, "SHA3 size should be one of: 224 256 "
|
||||
"384 512", -1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if( eType==SQLITE_NULL ) return;
|
||||
SHA3Init(&cx, iSize);
|
||||
if( eType==SQLITE_BLOB ){
|
||||
SHA3Update(&cx, sqlite3_value_blob(argv[0]), nByte);
|
||||
}else{
|
||||
SHA3Update(&cx, sqlite3_value_text(argv[0]), nByte);
|
||||
}
|
||||
sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/* Compute a string using sqlite3_vsnprintf() with a maximum length
|
||||
** of 50 bytes and add it to the hash.
|
||||
*/
|
||||
static void hash_step_vformat(
|
||||
SHA3Context *p, /* Add content to this context */
|
||||
const char *zFormat,
|
||||
...
|
||||
){
|
||||
va_list ap;
|
||||
int n;
|
||||
char zBuf[50];
|
||||
va_start(ap, zFormat);
|
||||
sqlite3_vsnprintf(sizeof(zBuf),zBuf,zFormat,ap);
|
||||
va_end(ap);
|
||||
n = (int)strlen(zBuf);
|
||||
SHA3Update(p, (unsigned char*)zBuf, n);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the sha3_query(SQL,SIZE) function.
|
||||
**
|
||||
** This function compiles and runs the SQL statement(s) given in the
|
||||
** argument. The results are hashed using a SIZE-bit SHA3. The default
|
||||
** size is 256.
|
||||
**
|
||||
** The format of the byte stream that is hashed is summarized as follows:
|
||||
**
|
||||
** S<n>:<sql>
|
||||
** R
|
||||
** N
|
||||
** I<int>
|
||||
** F<ieee-float>
|
||||
** B<size>:<bytes>
|
||||
** T<size>:<text>
|
||||
**
|
||||
** <sql> is the original SQL text for each statement run and <n> is
|
||||
** the size of that text. The SQL text is UTF-8. A single R character
|
||||
** occurs before the start of each row. N means a NULL value.
|
||||
** I mean an 8-byte little-endian integer <int>. F is a floating point
|
||||
** number with an 8-byte little-endian IEEE floating point value <ieee-float>.
|
||||
** B means blobs of <size> bytes. T means text rendered as <size>
|
||||
** bytes of UTF-8. The <n> and <size> values are expressed as an ASCII
|
||||
** text integers.
|
||||
**
|
||||
** For each SQL statement in the X input, there is one S segment. Each
|
||||
** S segment is followed by zero or more R segments, one for each row in the
|
||||
** result set. After each R, there are one or more N, I, F, B, or T segments,
|
||||
** one for each column in the result set. Segments are concatentated directly
|
||||
** with no delimiters of any kind.
|
||||
*/
|
||||
static void sha3QueryFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
const char *zSql = (const char*)sqlite3_value_text(argv[0]);
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
int nCol; /* Number of columns in the result set */
|
||||
int i; /* Loop counter */
|
||||
int rc;
|
||||
int n;
|
||||
const char *z;
|
||||
SHA3Context cx;
|
||||
int iSize;
|
||||
|
||||
if( argc==1 ){
|
||||
iSize = 256;
|
||||
}else{
|
||||
iSize = sqlite3_value_int(argv[1]);
|
||||
if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){
|
||||
sqlite3_result_error(context, "SHA3 size should be one of: 224 256 "
|
||||
"384 512", -1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if( zSql==0 ) return;
|
||||
SHA3Init(&cx, iSize);
|
||||
while( zSql[0] ){
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql);
|
||||
if( rc ){
|
||||
char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s",
|
||||
zSql, sqlite3_errmsg(db));
|
||||
sqlite3_finalize(pStmt);
|
||||
sqlite3_result_error(context, zMsg, -1);
|
||||
sqlite3_free(zMsg);
|
||||
return;
|
||||
}
|
||||
if( !sqlite3_stmt_readonly(pStmt) ){
|
||||
char *zMsg = sqlite3_mprintf("non-query: [%s]", sqlite3_sql(pStmt));
|
||||
sqlite3_finalize(pStmt);
|
||||
sqlite3_result_error(context, zMsg, -1);
|
||||
sqlite3_free(zMsg);
|
||||
return;
|
||||
}
|
||||
nCol = sqlite3_column_count(pStmt);
|
||||
z = sqlite3_sql(pStmt);
|
||||
n = (int)strlen(z);
|
||||
hash_step_vformat(&cx,"S%d:",n);
|
||||
SHA3Update(&cx,(unsigned char*)z,n);
|
||||
|
||||
/* Compute a hash over the result of the query */
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
SHA3Update(&cx,(const unsigned char*)"R",1);
|
||||
for(i=0; i<nCol; i++){
|
||||
switch( sqlite3_column_type(pStmt,i) ){
|
||||
case SQLITE_NULL: {
|
||||
SHA3Update(&cx, (const unsigned char*)"N",1);
|
||||
break;
|
||||
}
|
||||
case SQLITE_INTEGER: {
|
||||
sqlite3_uint64 u;
|
||||
int j;
|
||||
unsigned char x[9];
|
||||
sqlite3_int64 v = sqlite3_column_int64(pStmt,i);
|
||||
memcpy(&u, &v, 8);
|
||||
for(j=8; j>=1; j--){
|
||||
x[j] = u & 0xff;
|
||||
u >>= 8;
|
||||
}
|
||||
x[0] = 'I';
|
||||
SHA3Update(&cx, x, 9);
|
||||
break;
|
||||
}
|
||||
case SQLITE_FLOAT: {
|
||||
sqlite3_uint64 u;
|
||||
int j;
|
||||
unsigned char x[9];
|
||||
double r = sqlite3_column_double(pStmt,i);
|
||||
memcpy(&u, &r, 8);
|
||||
for(j=8; j>=1; j--){
|
||||
x[j] = u & 0xff;
|
||||
u >>= 8;
|
||||
}
|
||||
x[0] = 'F';
|
||||
SHA3Update(&cx,x,9);
|
||||
break;
|
||||
}
|
||||
case SQLITE_TEXT: {
|
||||
int n2 = sqlite3_column_bytes(pStmt, i);
|
||||
const unsigned char *z2 = sqlite3_column_text(pStmt, i);
|
||||
hash_step_vformat(&cx,"T%d:",n2);
|
||||
SHA3Update(&cx, z2, n2);
|
||||
break;
|
||||
}
|
||||
case SQLITE_BLOB: {
|
||||
int n2 = sqlite3_column_bytes(pStmt, i);
|
||||
const unsigned char *z2 = sqlite3_column_blob(pStmt, i);
|
||||
hash_step_vformat(&cx,"B%d:",n2);
|
||||
SHA3Update(&cx, z2, n2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
}
|
||||
sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_shathree_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "sha3", 1, SQLITE_UTF8, 0,
|
||||
sha3Func, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "sha3", 2, SQLITE_UTF8, 0,
|
||||
sha3Func, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "sha3_query", 1, SQLITE_UTF8, 0,
|
||||
sha3QueryFunc, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "sha3_query", 2, SQLITE_UTF8, 0,
|
||||
sha3QueryFunc, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
# 2017 March 02
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
if {![info exists testdir]} {
|
||||
set testdir [file join [file dirname [info script]] .. .. test]
|
||||
}
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix rbucrash2
|
||||
|
||||
db close
|
||||
forcedelete test.db-oal rbu.db
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_uri 1
|
||||
reset_db
|
||||
|
||||
# Set up a target database and an rbu update database. The target
|
||||
# db is the usual "test.db", the rbu db is "test.db2".
|
||||
#
|
||||
forcedelete test.db2
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a, b, c, PRIMARY KEY(a), UNIQUE(b));
|
||||
INSERT INTO t1 VALUES(1, 2, 3);
|
||||
INSERT INTO t1 VALUES(4, 5, 6);
|
||||
INSERT INTO t1 VALUES(7, 8, 9);
|
||||
|
||||
ATTACH 'test.db2' AS rbu;
|
||||
CREATE TABLE rbu.data_t1(a, b, c, rbu_control);
|
||||
INSERT INTO data_t1 VALUES('one', randomblob(3500), NULL, 0);
|
||||
INSERT INTO data_t1 VALUES('two', randomblob(3500), NULL, 0);
|
||||
INSERT INTO data_t1 VALUES('three', randomblob(3500), NULL, 0);
|
||||
INSERT INTO data_t1 VALUES('four', randomblob(3500), NULL, 0);
|
||||
INSERT INTO data_t1 VALUES('five', randomblob(3500), NULL, 0);
|
||||
INSERT INTO data_t1 VALUES('six', randomblob(3500), NULL, 0);
|
||||
}
|
||||
db_save_and_close
|
||||
|
||||
proc do_rbu_crash_test2 {tn script} {
|
||||
|
||||
foreach {f blksz} {
|
||||
test.db 512
|
||||
test.db2 512
|
||||
test.db 4096
|
||||
test.db2 4096
|
||||
} {
|
||||
set bDone 0
|
||||
for {set iDelay 1} {$bDone==0} {incr iDelay} {
|
||||
forcedelete test.db2 test.db2-journal test.db test.db-oal test.db-wal
|
||||
db_restore
|
||||
|
||||
set res [
|
||||
crashsql -file $f -delay $iDelay -tclbody $script -dflt 1 -opendb {} \
|
||||
-blocksize $blksz {}
|
||||
]
|
||||
|
||||
set bDone 1
|
||||
if {$res == "1 {child process exited abnormally}"} {
|
||||
set bDone 0
|
||||
} elseif {$res != "0 {}"} {
|
||||
error "unexected catchsql result: $res"
|
||||
}
|
||||
|
||||
sqlite3rbu rbu test.db test.db2
|
||||
while {[rbu step]=="SQLITE_OK"} {}
|
||||
rbu close
|
||||
|
||||
sqlite3 db test.db
|
||||
do_execsql_test $tn.delay=$iDelay.f=$f.blksz=$blksz {
|
||||
PRAGMA integrity_check;
|
||||
} {ok}
|
||||
db close
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for {set x 1} {$x < 10} {incr x} {
|
||||
do_rbu_crash_test2 1.$x {
|
||||
sqlite3rbu rbu test.db test.db2
|
||||
while {[rbu step]=="SQLITE_OK"} {
|
||||
rbu savestate
|
||||
}
|
||||
rbu close
|
||||
}
|
||||
}
|
||||
|
||||
for {set x 1} {$x < 2} {incr x} {
|
||||
do_rbu_crash_test2 2.$x {
|
||||
sqlite3rbu rbu test.db test.db2
|
||||
while {[rbu step]=="SQLITE_OK"} {
|
||||
rbu close
|
||||
sqlite3rbu rbu test.db test.db2
|
||||
}
|
||||
rbu close
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -40,6 +40,7 @@ proc create_rbu1 {filename} {
|
||||
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
PRAGMA page_size = 4096;
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
|
||||
}
|
||||
|
||||
@@ -266,6 +267,7 @@ foreach bReopen {0 1} {
|
||||
do_test 3.$bReopen.1.0 {
|
||||
reset_db
|
||||
execsql {
|
||||
PRAGMA page_size = 4096;
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
|
||||
CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
|
||||
CREATE TABLE t3(a INTEGER PRIMARY KEY, b);
|
||||
|
||||
+50
-3
@@ -356,6 +356,7 @@ struct sqlite3rbu {
|
||||
RbuObjIter objiter; /* Iterator for skipping through tbl/idx */
|
||||
const char *zVfsName; /* Name of automatically created rbu vfs */
|
||||
rbu_file *pTargetFd; /* File handle open on target db */
|
||||
int nPagePerSector; /* Pages per sector for pTargetFd */
|
||||
i64 iOalSz;
|
||||
i64 nPhaseOneStep;
|
||||
|
||||
@@ -2620,6 +2621,23 @@ static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){
|
||||
if( p->nFrame==0 || (pState && pState->iWalCksum!=p->iWalCksum) ){
|
||||
p->rc = SQLITE_DONE;
|
||||
p->eStage = RBU_STAGE_DONE;
|
||||
}else{
|
||||
int nSectorSize;
|
||||
sqlite3_file *pDb = p->pTargetFd->pReal;
|
||||
sqlite3_file *pWal = p->pTargetFd->pWalFd->pReal;
|
||||
assert( p->nPagePerSector==0 );
|
||||
nSectorSize = pDb->pMethods->xSectorSize(pDb);
|
||||
if( nSectorSize>p->pgsz ){
|
||||
p->nPagePerSector = nSectorSize / p->pgsz;
|
||||
}else{
|
||||
p->nPagePerSector = 1;
|
||||
}
|
||||
|
||||
/* Call xSync() on the wal file. This causes SQLite to sync the
|
||||
** directory in which the target database and the wal file reside, in
|
||||
** case it has not been synced since the rename() call in
|
||||
** rbuMoveOalFile(). */
|
||||
p->rc = pWal->pMethods->xSync(pWal, SQLITE_SYNC_NORMAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3275,9 +3293,26 @@ int sqlite3rbu_step(sqlite3rbu *p){
|
||||
p->rc = SQLITE_DONE;
|
||||
}
|
||||
}else{
|
||||
RbuFrame *pFrame = &p->aFrame[p->nStep];
|
||||
rbuCheckpointFrame(p, pFrame);
|
||||
p->nStep++;
|
||||
/* At one point the following block copied a single frame from the
|
||||
** wal file to the database file. So that one call to sqlite3rbu_step()
|
||||
** checkpointed a single frame.
|
||||
**
|
||||
** However, if the sector-size is larger than the page-size, and the
|
||||
** application calls sqlite3rbu_savestate() or close() immediately
|
||||
** after this step, then rbu_step() again, then a power failure occurs,
|
||||
** then the database page written here may be damaged. Work around
|
||||
** this by checkpointing frames until the next page in the aFrame[]
|
||||
** lies on a different disk sector to the current one. */
|
||||
u32 iSector;
|
||||
do{
|
||||
RbuFrame *pFrame = &p->aFrame[p->nStep];
|
||||
iSector = (pFrame->iDbPage-1) / p->nPagePerSector;
|
||||
rbuCheckpointFrame(p, pFrame);
|
||||
p->nStep++;
|
||||
}while( p->nStep<p->nFrame
|
||||
&& iSector==((p->aFrame[p->nStep].iDbPage-1) / p->nPagePerSector)
|
||||
&& p->rc==SQLITE_OK
|
||||
);
|
||||
}
|
||||
p->nProgress++;
|
||||
}
|
||||
@@ -3718,6 +3753,12 @@ int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
|
||||
p->rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, &p->zErrmsg);
|
||||
}
|
||||
|
||||
/* Sync the db file if currently doing an incremental checkpoint */
|
||||
if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_CKPT ){
|
||||
sqlite3_file *pDb = p->pTargetFd->pReal;
|
||||
p->rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
|
||||
}
|
||||
|
||||
rbuSaveState(p, p->eStage);
|
||||
|
||||
if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_OAL ){
|
||||
@@ -3842,6 +3883,12 @@ int sqlite3rbu_savestate(sqlite3rbu *p){
|
||||
if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, 0);
|
||||
}
|
||||
|
||||
/* Sync the db file */
|
||||
if( rc==SQLITE_OK && p->eStage==RBU_STAGE_CKPT ){
|
||||
sqlite3_file *pDb = p->pTargetFd->pReal;
|
||||
rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
|
||||
}
|
||||
|
||||
p->rc = rc;
|
||||
rbuSaveState(p, p->eStage);
|
||||
rc = p->rc;
|
||||
|
||||
+9
-9
@@ -458,15 +458,15 @@ static i64 readInt64(u8 *p){
|
||||
memcpy(&x, p, 8);
|
||||
return x;
|
||||
#else
|
||||
return (
|
||||
(((i64)p[0]) << 56) +
|
||||
(((i64)p[1]) << 48) +
|
||||
(((i64)p[2]) << 40) +
|
||||
(((i64)p[3]) << 32) +
|
||||
(((i64)p[4]) << 24) +
|
||||
(((i64)p[5]) << 16) +
|
||||
(((i64)p[6]) << 8) +
|
||||
(((i64)p[7]) << 0)
|
||||
return (i64)(
|
||||
(((u64)p[0]) << 56) +
|
||||
(((u64)p[1]) << 48) +
|
||||
(((u64)p[2]) << 40) +
|
||||
(((u64)p[3]) << 32) +
|
||||
(((u64)p[4]) << 24) +
|
||||
(((u64)p[5]) << 16) +
|
||||
(((u64)p[6]) << 8) +
|
||||
(((u64)p[7]) << 0)
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
*/
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
** If a database contains the SQLITE_USER table, then the
|
||||
** sqlite3_user_authenticate() interface must be invoked with an
|
||||
@@ -85,4 +89,8 @@ int sqlite3_user_delete(
|
||||
const char *zUsername /* Username to remove */
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of the 'extern "C"' block */
|
||||
#endif
|
||||
|
||||
#endif /* SQLITE_USER_AUTHENTICATION */
|
||||
|
||||
@@ -477,10 +477,9 @@ SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||
SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
||||
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
|
||||
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5
|
||||
FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000
|
||||
DBFUZZ_OPT =
|
||||
KV_OPT = -DSQLITE_THREADSAFE=0 -DSQLITE_DIRECT_OVERFLOW_READ
|
||||
DBSELFTEST_OPT = -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION
|
||||
DBSELFTEST_OPT += -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5
|
||||
ST_OPT = -DSQLITE_THREADSAFE=0
|
||||
|
||||
# This is the default Makefile target. The objects listed here
|
||||
@@ -762,6 +761,10 @@ sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl
|
||||
sqlite3_analyzer$(EXE): sqlite3_analyzer.c
|
||||
$(TCCX) $(TCL_FLAGS) sqlite3_analyzer.c -o $@ $(LIBTCL) $(THREADLIB)
|
||||
|
||||
dbdump$(EXE): $(TOP)/ext/misc/dbdump.c sqlite3.o
|
||||
$(TCCX) -DDBDUMP_STANDALONE -o dbdump$(EXE) \
|
||||
$(TOP)/ext/misc/dbdump.c sqlite3.o $(THREADLIB)
|
||||
|
||||
# Rules to build the 'testfixture' application.
|
||||
#
|
||||
TESTFIXTURE_FLAGS = -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
|
||||
@@ -902,9 +905,6 @@ speedtest1$(EXE): $(TOP)/test/speedtest1.c sqlite3.c
|
||||
kvtest$(EXE): $(TOP)/test/kvtest.c sqlite3.c
|
||||
$(TCCX) -I. $(KV_OPT) -o kvtest$(EXE) $(TOP)/test/kvtest.c sqlite3.c $(THREADLIB)
|
||||
|
||||
dbselftest$(EXE): $(TOP)/test/dbselftest.c sqlite3.c
|
||||
$(TCCX) -I. $(DBSELFTEST_OPT) -o dbselftest$(EXE) $(TOP)/test/dbselftest.c sqlite3.c $(THREADLIB)
|
||||
|
||||
rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.o
|
||||
$(TCC) -I. -o rbu$(EXE) $(TOP)/ext/rbu/rbu.c sqlite3.o \
|
||||
$(THREADLIB)
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
C Proof\sof\sconcept\sfor\sa\s"PRAGMA\svdbe_cycle_limit=N"\scommand.\s\sWhen\sN>0,\ninvoke\ssqlite3_interrupt()\swhenever\sany\sbyte\scode\sprogram\suses\smore\sthan\nN\svirtual\smachine\scycles.
|
||||
D 2017-02-21T13:29:18.463
|
||||
F Makefile.in edb6bcdd37748d2b1c3422ff727c748df7ffe918
|
||||
C Use\sreplace()\sinstead\sof\schar()\sto\squote\snewline\sand\sreturn\scharacters\sin\nstrings\sin\sthe\soutput\sof\s.dump,\sto\savoid\sexcess\sexpression\scomplexity.
|
||||
D 2017-04-07T11:45:58.111
|
||||
F Makefile.in 1cc758ce3374a32425e4d130c2fe7b026b20de5b8843243de75f087c0a2661fb
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc a89ea37ab5928026001569f056973b9059492fe2
|
||||
F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7
|
||||
F VERSION 3605fa447e4623f5ff4a6adc97b1fde9a257b8f2
|
||||
F Makefile.msc a4c0613a18663bda56d8cf76079ab6590a7c3602e54befb4bbdef76bcaa38b6a
|
||||
F README.md 2b15fae33852f2f53996774c21fb41e1d94181c4401a0e43ac93e11f2cc901b9
|
||||
F VERSION 0a0e02e16b44ea735b40118fc844311b2ab0d35b25fbeda5120aee62f973f663
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
|
||||
F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
|
||||
F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
|
||||
F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903
|
||||
F autoconf/Makefile.am 1a47d071e3d5435f8f7ebff7eb6703848bbd65d4
|
||||
F autoconf/Makefile.msc 3de603bcec5c07462801a20fd7dc1b871400af99
|
||||
F autoconf/Makefile.msc 1fba0d762d115509d4fce7e333305cee172d521aaacec8bbf7aad5503605d3fb
|
||||
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
|
||||
F autoconf/README.txt 4f04b0819303aabaa35fff5f7b257fb0c1ef95f1
|
||||
F autoconf/configure.ac cacf2616abf6e4a569bde2ef365c143caeec40bc
|
||||
F autoconf/configure.ac 2893b823ecc86cea13739f6c8109a41392254d1db08235c5615e0af5722c8578
|
||||
F autoconf/tea/Makefile.in b438a7020446c8a8156e8d97c8914a04833da6fd
|
||||
F autoconf/tea/README 3e9a3c060f29a44344ab50aec506f4db903fb873
|
||||
F autoconf/tea/aclocal.m4 52c47aac44ce0ddb1f918b6993e8beb8eee88f43
|
||||
@@ -30,13 +30,13 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63
|
||||
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
|
||||
F config.h.in 6376abec766e9a0785178b1823b5a587e9f1ccbc
|
||||
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
|
||||
F configure b15d030a8ae2e672d76c97b6667dacb98934a467 x
|
||||
F configure.ac 605173e829ab64514ed89f9b53d0da1739d7b0a0
|
||||
F configure bddf7d1d945894b724e2b16a1266359a40abec2c798c95b4409a7ebf771c38ef x
|
||||
F configure.ac 901e8db2c211e8b655e51ee24f2b8faa33407acde87effc47f70380f3b04e452
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/lemon.html b5a3c07d33ecb8e019ce8f7660fe2dbbad9d7977
|
||||
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
|
||||
F doc/vfs-shm.txt e101f27ea02a8387ce46a05be2b1a902a021d37a
|
||||
F ext/README.txt 913a7bd3f4837ab14d7e063304181787658b14e1
|
||||
F ext/README.md fd5f78013b0a2bc6f0067afb19e6ad040e89a10179b4f6f03eee58fac5f169bd
|
||||
F ext/async/README.txt e12275968f6fde133a80e04387d0e839b0c51f91
|
||||
F ext/async/sqlite3async.c 0f3070cc3f5ede78f2b9361fb3b629ce200d7d74
|
||||
F ext/async/sqlite3async.h f489b080af7e72aec0e1ee6f1d98ab6cf2e4dcef
|
||||
@@ -70,7 +70,7 @@ 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 c4d7eecb12de9749851bcab6e5ca616a5803047a
|
||||
F ext/fts3/fts3.c f0d5de1bc2155ba7cd7c0c1a751779a3a8857fa34d5c12f3b233a23fa2e79ea2
|
||||
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
||||
F ext/fts3/fts3Int.h eb2502000148e80913b965db3e59f29251266d0a
|
||||
F ext/fts3/fts3_aux.c 9edc3655fcb287f0467d0a4b886a01c6185fe9f1
|
||||
@@ -86,15 +86,16 @@ F ext/fts3/fts3_tokenize_vtab.c a27593ab19657166f6fa5ec073b678cc29a75860
|
||||
F ext/fts3/fts3_tokenizer.c a22bf311a71f3efa9d7012d8cc48fc9b0f3dace7
|
||||
F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3
|
||||
F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004
|
||||
F ext/fts3/fts3_unicode.c a93f5edc0aff44ef8b06d7cb55b52026541ca145
|
||||
F ext/fts3/fts3_unicode2.c c3d01968d497bd7001e7dc774ba75b372738c057
|
||||
F ext/fts3/fts3_write.c c3863f23b6b4623c8b9d5cf31c12ce4469f78ca9
|
||||
F ext/fts3/fts3_unicode.c 525a3bd9a7564603c5c061b7de55403a565307758a94600e8a2f6b00d1c40d9d
|
||||
F ext/fts3/fts3_unicode2.c cc04fc672bfd42b1e650398cb0bf71f64f9aae032cfe75bbcfe75b9cf966029c
|
||||
F ext/fts3/fts3_write.c a51d48d646974ee2fb4b17fcd5da0416a5759a32dcacc2cce2ba00d5a767848e
|
||||
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
|
||||
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
|
||||
F ext/fts3/tool/fts3cov.sh c331d006359456cf6f8f953e37f2b9c7d568f3863f00bb5f7eb87fea4ac01b73
|
||||
F ext/fts3/tool/fts3view.c 202801a2056995b763864d60c2dee744d46f1677
|
||||
F ext/fts3/unicode/CaseFolding.txt 8c678ca52ecc95e16bc7afc2dbf6fc9ffa05db8c
|
||||
F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7
|
||||
F ext/fts3/unicode/mkunicode.tcl 2debed3f582d77b3fdd0b8830880250021571fd8
|
||||
F ext/fts3/unicode/mkunicode.tcl ab0543a3b2399092ea2dd75df1bef333405b0d7f6b8c4951a0fbb60e780cb69f
|
||||
F ext/fts3/unicode/parseunicode.tcl da577d1384810fb4e2b209bf3313074353193e95
|
||||
F ext/fts5/extract_api_docs.tcl a36e54ec777172ddd3f9a88daf593b00848368e0
|
||||
F ext/fts5/fts5.h 62f3e33ceeb9a428db139f9c012186b371da1cc7
|
||||
@@ -102,11 +103,11 @@ F ext/fts5/fts5Int.h c629b24d2b92b99596f3b8e82289fddca06df6e1
|
||||
F ext/fts5/fts5_aux.c 67acf8d51723cf28ffc3828210ba662df4b8d267
|
||||
F ext/fts5/fts5_buffer.c 4c1502d4c956cd092c89ce4480867f9d8bf325cd
|
||||
F ext/fts5/fts5_config.c 5af9c360e99669d29f06492c370892394aba0857
|
||||
F ext/fts5/fts5_expr.c 33f0e8063ac7360bcd71c0ff0dcbacdc05fffe50
|
||||
F ext/fts5/fts5_expr.c c6ecc2280162a3714d15dce2a8f2299f748b627c
|
||||
F ext/fts5/fts5_hash.c 880998e596b60f078348d48732ca4ad9a90caad2
|
||||
F ext/fts5/fts5_index.c f67032a9a529ba52a545e6e3ab970764199c05d4
|
||||
F ext/fts5/fts5_main.c f85281445dcf8be32d18841c93a6f90fe27dbfe2
|
||||
F ext/fts5/fts5_storage.c de0ed8a06738bde433afe11e92295ceaffbc4e58
|
||||
F ext/fts5/fts5_storage.c 8f0e65cb33bde8f449e1c9b4be4600d18b4da6e9
|
||||
F ext/fts5/fts5_tcl.c 4a901f00c8553740dba63511603f5527d741c26a
|
||||
F ext/fts5/fts5_test_mi.c 783b86697ebf773c18fc109992426c0173a055bc
|
||||
F ext/fts5/fts5_test_tok.c db08af63673c3a7d39f053b36fd6e065017706be
|
||||
@@ -160,10 +161,12 @@ F ext/fts5/test/fts5fault8.test 6785af34bd1760de74e2824ea9c161965af78f85
|
||||
F ext/fts5/test/fts5fault9.test e10e395428a9ea0596ebe752ff7123d16ab78e08
|
||||
F ext/fts5/test/fts5faultA.test fa5d59c0ff62b7125cd14eee38ded1c46e15a7ea
|
||||
F ext/fts5/test/fts5faultB.test 7f3bba790fa172073ac314f9b8ed197390b61eca
|
||||
F ext/fts5/test/fts5faultD.test cc5d1225556e356615e719c612e845d41bff7d5a
|
||||
F ext/fts5/test/fts5full.test 6f6143af0c6700501d9fd597189dfab1555bb741
|
||||
F ext/fts5/test/fts5fuzz1.test bece4695fc169b61ab236ada7931c6e4942cbef9
|
||||
F ext/fts5/test/fts5hash.test 06f9309ccb4d5050a131594e9e47d0b21456837d
|
||||
F ext/fts5/test/fts5integrity.test f5e4f8d284385875068ad0f3e894ce43e9de835d
|
||||
F ext/fts5/test/fts5lastrowid.test 4fac1aba696dd6c956e03b0cf91f6f1f3aaec494
|
||||
F ext/fts5/test/fts5matchinfo.test f7dde99697bcb310ea8faa8eb2714d9f4dfc0e1b
|
||||
F ext/fts5/test/fts5merge.test 9f65f090d214ff865c56bef4f864aaa1182af6e3
|
||||
F ext/fts5/test/fts5merge2.test a6da3c16d694235938d1939f503cfa53f0943d75
|
||||
@@ -204,16 +207,18 @@ F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
|
||||
F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43
|
||||
F ext/icu/icu.c 84900472a088a3a172c6c079f58a1d3a1952c332
|
||||
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
||||
F ext/misc/README.md 8e008c8d2b02e09096b31dfba033253ac27c6c06a18aa5826e299fa7601d90b2
|
||||
F ext/misc/amatch.c 211108e201105e4bb0c076527b8cfd34330fc234
|
||||
F ext/misc/carray.c 40c27641010a4dc67e3690bdb7c9d36ca58b3c2d
|
||||
F ext/misc/closure.c 0d2a038df8fbae7f19de42e7c7d71f2e4dc88704
|
||||
F ext/misc/compress.c 122faa92d25033d6c3f07c39231de074ab3d2e83
|
||||
F ext/misc/csv.c 531a46cbad789fca0aa9db69a0e6c8ac9e68767d
|
||||
F ext/misc/dbdump.c 34174d537318027b159e3341105866c05a4149376ede59988c82280bed144e6d
|
||||
F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2
|
||||
F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f
|
||||
F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25
|
||||
F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c
|
||||
F ext/misc/json1.c 552a7d730863419e05dc947265b28bd411680e2e
|
||||
F ext/misc/json1.c 92b9e404bd79cc76d3ef2b3a9e37bf775700f7d645466fd41d2e8742e3fa16fb
|
||||
F ext/misc/memvfs.c e5225bc22e79dde6b28380f3a068ddf600683a33
|
||||
F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
|
||||
F ext/misc/percentile.c 92699c8cd7d517ff610e6037e56506f8904dae2e
|
||||
@@ -223,6 +228,7 @@ F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a
|
||||
F ext/misc/scrub.c 1c5bfb8b0cd18b602fcb55755e84abf0023ac2fb
|
||||
F ext/misc/series.c e11e534ada797d5b816d7e7a93c022306563ca35
|
||||
F ext/misc/sha1.c 0b9e9b855354910d3ca467bf39099d570e73db56
|
||||
F ext/misc/shathree.c fa185d7aee0ad0aca5e091b4a2db7baff11796170e5793b5de99e511a13af448
|
||||
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
|
||||
F ext/misc/spellfix.c a4723b6aff748a417b5091b68a46443265c40f0d
|
||||
F ext/misc/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512
|
||||
@@ -248,6 +254,7 @@ F ext/rbu/rbuB.test c25bc325b8072a766e56bb76c001866b405925c2
|
||||
F ext/rbu/rbuC.test efe47db508a0269b683cb2a1913a425ffd39a831
|
||||
F ext/rbu/rbu_common.tcl a38e8e2d4a50fd6aaf151633714c1b1d2fae3ead
|
||||
F ext/rbu/rbucrash.test 8d2ed5d4b05fef6c00c2a6b5f7ead71fa172a695
|
||||
F ext/rbu/rbucrash2.test b2ecbdd7bb72c88bd217c65bd00dafa07f7f2d4d
|
||||
F ext/rbu/rbudiff.test 3e605cf624d00d04d0fb1316a3acec4fbe3b3ac5
|
||||
F ext/rbu/rbudor.test 99b05cc0df613e962c2c8085cfb05686a09cf315
|
||||
F ext/rbu/rbufault.test cc0be8d5d392d98b0c2d6a51be377ea989250a89
|
||||
@@ -255,16 +262,16 @@ F ext/rbu/rbufault2.test 9a7f19edd6ea35c4c9f807d8a3db0a03a5670c06
|
||||
F ext/rbu/rbufault3.test 54a399888ac4af44c68f9f58afbed23149428bca
|
||||
F ext/rbu/rbufault4.test 34e70701cbec51571ffbd9fbf9d4e0f2ec495ca7
|
||||
F ext/rbu/rbufts.test 828cd689da825f0a7b7c53ffc1f6f7fdb6fa5bda
|
||||
F ext/rbu/rbuprogress.test e3e25fb7622641b8f2df7c6b7a7eb6fddfc46a4b
|
||||
F ext/rbu/rbuprogress.test 1849d4e0e50616edf5ce75ce7db86622e656b5cf
|
||||
F ext/rbu/rburesume.test 8acb77f4a422ff55acfcfc9cc15a5cb210b1de83
|
||||
F ext/rbu/rbusave.test 0f43b6686084f426ddd040b878426452fd2c2f48
|
||||
F ext/rbu/rbuvacuum.test 4a977447c15c2581ab668781d9ef4294382530e0
|
||||
F ext/rbu/rbuvacuum2.test 2074ab14fe66e1c7e7210c62562650dcd215bbaa
|
||||
F ext/rbu/sqlite3rbu.c bb0de6cdbdb14a7d55a097238a434b7e99caf318
|
||||
F ext/rbu/sqlite3rbu.c 2a89efba9eeba8e6c89a498dc195e8efbdde2694
|
||||
F ext/rbu/sqlite3rbu.h 6fb6294c34a9ca93b5894a33bca530c6f08decba
|
||||
F ext/rbu/test_rbu.c 5aa22616afac6f71ebd3d9bc9bf1006cfabcca88
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/rtree.c 3f3a595dba485e340246fa2c8ba330a6b9768b00
|
||||
F ext/rtree/rtree.c 0acd285bfacc347579a5df9fe947212fb99e2775a40c43f027c3a16936c58e7e
|
||||
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
||||
F ext/rtree/rtree1.test 42dadfc7b44a436cd74a1bebc0b9b689e4eaf7ec
|
||||
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
|
||||
@@ -312,13 +319,13 @@ F ext/session/sessionwor.test 2f3744236dc8b170a695b7d8ddc8c743c7e79fdc
|
||||
F ext/session/sqlite3session.c 13642d9c754cc18f17e141f82860d269e2adf920
|
||||
F ext/session/sqlite3session.h d4db650adfcc7a4360e9f12a09c2d117b1db6b53
|
||||
F ext/session/test_session.c eb0bd6c1ea791c1d66ee4ef94c16500dad936386
|
||||
F ext/userauth/sqlite3userauth.h 19cb6f0e31316d0ee4afdfb7a85ef9da3333a220
|
||||
F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
|
||||
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
|
||||
F ext/userauth/userauth.c 3410be31283abba70255d71fd24734e017a4497f
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk 08e0b151abb46353c677ac4974b50c6077f85eee
|
||||
F main.mk 9abb506e717887d57f754bae139b85c1a06d6f2ac25b589f3e792e310567f278
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@@ -331,38 +338,38 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 3b23977620ce9662ac54443f65b87ba996e36121
|
||||
F src/analyze.c ac7a5d7e3cee07d074697904e00e4a8ab7b2b4f5
|
||||
F src/analyze.c 0d0ccf7520a201d8747ea2f02c92c26e26f801bc161f714f27b9f7630dde0421
|
||||
F src/attach.c 8c476f8bd5d2afe11d925f890d30e527e5b0ce43
|
||||
F src/auth.c 930b376a9c56998557367e6f7f8aaeac82a2a792
|
||||
F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
|
||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||
F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca
|
||||
F src/btree.c 3ae66974881e74df9909093818b4c3428f8d7982
|
||||
F src/btree.h e6d352808956ec163a17f832193a3e198b3fb0ac
|
||||
F src/btreeInt.h cd55d39d9916270837a88c12e701047cba0729b0
|
||||
F src/build.c 9e799f1edd910dfa8a0bc29bd390d35d310596af
|
||||
F src/btree.c 24ae5472bd0b53b4130ecdda389deb621af721d1fcb50890b878102b00bd10fa
|
||||
F src/btree.h bf64dfeeddeebdb775a5eba0098bbc00d073290d
|
||||
F src/btreeInt.h a392d353104b4add58b4a59cb185f5d5693dde832c565b77d8d4c343ed98f610
|
||||
F src/build.c 4026a9c554b233e50c5e9ad46963e676cf54dd2306d952aa1eaa07a1bc9ce14f
|
||||
F src/callback.c 2e76147783386374bf01b227f752c81ec872d730
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c a9984df73898c042a5cfc8f9d8e7723d02bc35c9
|
||||
F src/date.c dc3f1391d9297f8c748132813aaffcb117090d6e
|
||||
F src/ctime.c 47d91a25ad8f199a71a5b1b7b169d6dd0d6e98c5719eca801568798743d1161c
|
||||
F src/date.c ee676e7694dfadbdd2fde1a258a71be8360ba5ae
|
||||
F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d
|
||||
F src/delete.c 0d9d5549d42e79ce4d82ff1db1e6c81e36d2f67c
|
||||
F src/expr.c 8a29e9b72d4b642189999c41782cd6c5bc43512f
|
||||
F src/expr.c 6bce2cbdd822963cf28e782938a96274cc37f18ac28dec7a4e35ccac09f66ce8
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 2e9aabe1aee76273aff8a84ee92c464e095400ae
|
||||
F src/func.c c67273e1ec08abbdcc14c189892a3ff6eeece86b
|
||||
F src/func.c 9d52522cc8ae7f5cdadfe14594262f1618bc1f86083c4cd6da861b4cf5af6174
|
||||
F src/global.c 4a34512d82fc5aa13c802db06bcfff5e1d3de955
|
||||
F src/hash.c 63d0ee752a3b92d4695b2b1f5259c4621b2cfebd
|
||||
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
|
||||
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c 3ed64afc49c0a2221e397b9f65d231ffbef506fe
|
||||
F src/insert.c d4bb3a135948553d18cf992f76f7ed7b18aa0327f250607b5a6671e55d9947d5
|
||||
F src/legacy.c e88ed13c2d531decde75d42c2e35623fb9ce3cb0
|
||||
F src/loadext.c a68d8d1d14cf7488bb29dc5311cb1ce9a4404258
|
||||
F src/main.c e207b81542d13b9f13d61e78ca441f9781f055b0
|
||||
F src/malloc.c d0a1474236486165bcb349af82e2a6560178bf7b
|
||||
F src/loadext.c a72909474dadce771d3669bf84bf689424f6f87d471fee898589c3ef9b2acfd9
|
||||
F src/main.c 158326243c5ddc8b98a1e983fa488650cf76d760
|
||||
F src/malloc.c e20bb2b48abec52d3faf01cce12e8b4f95973755fafec98d45162dfdab111978
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c fd7cd6fe21d46fe0a4186367dd8dc26d87b787eb
|
||||
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
||||
F src/mem2.c f1940d9e91948dd6a908fbb9ce3835c36b5d83c3
|
||||
F src/mem3.c 8768ac94694f31ffaf8b4d0ea5dc08af7010a35a
|
||||
F src/mem5.c 9bf955937b07f8c32541c8a9991f33ce3173d944
|
||||
@@ -383,24 +390,24 @@ F src/os_win.c 2a6c73eef01c51a048cc4ddccd57f981afbec18a
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c ff1232b3088a39806035ecfac4fffeb22717d80b
|
||||
F src/pager.h f2a99646c5533ffe11afa43e9e0bea74054e4efa
|
||||
F src/parse.y af8830094f4aecb91cb69721f3601ad10c36abc4
|
||||
F src/parse.y 48b03113704ee8bd78ee6996d81de7fbee22e105
|
||||
F src/pcache.c 62835bed959e2914edd26afadfecce29ece0e870
|
||||
F src/pcache.h 2cedcd8407eb23017d92790b112186886e179490
|
||||
F src/pcache1.c e3967219b2a92b9edcb9324a4ba75009090d3953
|
||||
F src/pragma.c 9180cce9a16e0835c6f7d0aa42d8938ce59c2011
|
||||
F src/pragma.h 1ec44ee89a43e65bf70c9ef4ef066df217b9ab3f
|
||||
F src/pcache1.c 1195a21fe28e223e024f900b2011e80df53793f0356a24caace4188b098540dc
|
||||
F src/pragma.c 220474f113cade6a6b5bacd3e3a65eca339acbee804128bc5db13a9cad55fba5
|
||||
F src/pragma.h 37a1311d0388db480388d7ec09054f7103045eff20d4971f8a433b77f40b9921
|
||||
F src/prepare.c b1140c3d0cf59bc85ace00ce363153041b424b7a
|
||||
F src/printf.c 67427bbee66d891fc6f6f5aada857e9cdb368c1c
|
||||
F src/printf.c 8757834f1b54dae512fb25eb1acc8e94a0d15dd2290b58f2563f65973265adb2
|
||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c f9bc0de45a30a450da47b3766de00be89bf9be79
|
||||
F src/resolve.c 3e518b962d932a997fae373366880fc028c75706
|
||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||
F src/select.c d12f3539f80db38b09015561b569e0eb1c4b6c5f
|
||||
F src/shell.c bf976d5301be9d8a4c52852c97909cc9a41ee20d
|
||||
F src/sqlite.h.in 751ff125eb159c8f92c182b8df980a5e4f50e966
|
||||
F src/select.c afcf31d8ed7c890328a31d3f350467ccd273af345b24562382b398d6d9cd0664
|
||||
F src/shell.c 3680725485ce5022dc683d593e8a4b95f973597d843ddb8be788d7dc24d16de9
|
||||
F src/sqlite.h.in ab77e511620eebbd4ed7e4f52fae697b6870dda66c945acd2d3066f99c98e17e
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 8648034aa702469afb553231677306cc6492a1ae
|
||||
F src/sqliteInt.h 46fe8e5aee3825d77fa771216ef263dc947030e7
|
||||
F src/sqliteLimit.h c0373387c287c8d0932510b5547ecde31b5da247
|
||||
F src/sqlite3ext.h 58fd0676d3111d02e62e5a35992a7d3da5d3f88753acc174f2d37b774fbbdd28
|
||||
F src/sqliteInt.h 6cf244eb06119b44e155717708e54f0638c35e9bd8ef59ea570eb1f093f0da44
|
||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||
F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1
|
||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||
F src/tclsqlite.c 6c2151b6d8d98e183a04466d40df8889c0574d79
|
||||
@@ -409,7 +416,7 @@ F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
|
||||
F src/test3.c d03f5b5da9a2410b7a91c64b0d3306ed28ab6fee
|
||||
F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
|
||||
F src/test5.c 328aae2c010c57a9829d255dc099d6899311672d
|
||||
F src/test6.c 121060d2e79a4f5047eb12b5135b23a6a7a5af01
|
||||
F src/test6.c 004ad42f121f693b8cbe060d1a330678abc61620
|
||||
F src/test7.c 5612e9aecf934d6df7bba6ce861fdf5ba5456010
|
||||
F src/test8.c 4f4904721167b32f7a4fa8c7b32a07a673d6cc86
|
||||
F src/test9.c 12e5ba554d2d1cbe0158f6ab3f7ffcd7a86ee4e5
|
||||
@@ -419,7 +426,7 @@ F src/test_backup.c bf5da90c9926df0a4b941f2d92825a01bbe090a0
|
||||
F src/test_bestindex.c d23f80d334c59662af69191854c76b8d3d0c8c96
|
||||
F src/test_blob.c f65ac717da2618691cf9dad094e6da0219dcd208
|
||||
F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274
|
||||
F src/test_config.c 83179ea845479b5be9a651d014649e3f2722a1fe
|
||||
F src/test_config.c edcba290248dc18736dd814c9b95863c6762e0b35753048d8cbe5bf65f7abfbb
|
||||
F src/test_delete.c af7eab5702f853fb1c62a5f7665e2234cf1ae17b
|
||||
F src/test_demovfs.c a0c3bdd45ed044115c2c9f7779e56eafff18741e
|
||||
F src/test_devsym.c 4e58dec2602d8e139ca08659f62a62450587cb58
|
||||
@@ -429,7 +436,7 @@ F src/test_hexio.c 1d4469ca61ab202a1fcec6543f584d2407205e8d
|
||||
F src/test_init.c 4413c211a94b62157ca4c145b3f27c497f03c664
|
||||
F src/test_intarray.c 988fc61cb0ff539f4172c0d95f15287c92516f64
|
||||
F src/test_intarray.h f3b7672f5d1056eac563c0d6ea8480a660b1475c
|
||||
F src/test_journal.c d3b83f2bcb7792c709e57abddc456a2b1818643a
|
||||
F src/test_journal.c 619f2aa10e0d7a5f87c0f06825bc61dfce1c6b9c7f3ad990fb13de6c3b8874a3
|
||||
F src/test_loadext.c 337056bae59f80b9eb00ba82088b39d0f4fe6dfd
|
||||
F src/test_malloc.c c05f6c40bd6c8bfe5f1718212f81fd5687f91766
|
||||
F src/test_multiplex.c e054459f7633f3ff8ce1245da724f9a8be189e4e
|
||||
@@ -454,29 +461,29 @@ F src/test_windirent.c 17f91f5f2aa1bb7328abb49414c363b5d2a9d3ff
|
||||
F src/test_windirent.h 5d67483a55442e31e1bde0f4a230e6e932ad5906
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c 25ccc63ae2c4163933221f3181c9982b47cd08d2
|
||||
F src/treeview.c 4e44ade3bfe59d82005039f72e09333ce2b4162c
|
||||
F src/tokenize.c 1003d6d90c6783206c711f0a9397656fa5b055209f4d092caa43bb3bf5215db5
|
||||
F src/treeview.c 84d0ac737e1231702679f0289180021e19c5cc186ec413e8dcb704a887c76ec8
|
||||
F src/trigger.c c9f0810043b265724fdb1bdd466894f984dfc182
|
||||
F src/update.c 456d4a4656f8a03c2abc88a51b19172197400e58
|
||||
F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c
|
||||
F src/util.c ca8440ede81e155d15cff7c101654f60b55a9ae6
|
||||
F src/vacuum.c 1fe4555cd8c9b263afb85b5b4ee3a4a4181ad569
|
||||
F src/vdbe.c 16f378640570c24442fd7191b136b5d6380f5c7b
|
||||
F src/vdbe.h 59998ffd71d7caa8886bc78dafaf8caeccd4c13c
|
||||
F src/vdbeInt.h 4e4b15b2e1330e1636e4e01974eab2b0b985092f
|
||||
F src/vdbeapi.c 3e4a8893feeb78620f4aac4ac5b85d92255b97e1
|
||||
F src/vdbeaux.c 4122458d33318ab039c4b5da1ca4e7c9221c38e4
|
||||
F src/vdbe.c b070c9c81a5faff5d9fc9563c7c030e3e1adb69d835259470fd945ef61f3f9fb
|
||||
F src/vdbe.h caa5346d52bae2a3c8c1dcfa60a7a4dc878a9e3865cb8239da55808b316c8158
|
||||
F src/vdbeInt.h 5db089ce18c4feff8820ec6e4cac2d2c82e03d4b1d96f10a6e43832147b8dffe
|
||||
F src/vdbeapi.c 5b08d82592bcff4470601fe78aaabebd50837860
|
||||
F src/vdbeaux.c 0ecacf8c7ca93e430b30819b8fc9b2c1ffe88202d1437e88c08a1f0b6159c58c
|
||||
F src/vdbeblob.c 359891617358deefc85bef7bcf787fa6b77facb9
|
||||
F src/vdbemem.c 3b5a9a5b375458d3e12a50ae1aaa41eeec2175fd
|
||||
F src/vdbesort.c eda25cb2d1727efca6f7862fea32b8aa33c0face
|
||||
F src/vdbemem.c 8bb4dd22837da969bfda25ef3f92d41aaad192328f89a0951290d5e26ad7dbc4
|
||||
F src/vdbesort.c e72fe02a2121386ba767ede8942e9450878b8fc873abf3d1b6824485f092570c
|
||||
F src/vdbetrace.c 41963d5376f0349842b5fc4aaaaacd7d9cdc0834
|
||||
F src/vtab.c 007513c2ef52472fcdea6a741683d50662e82790
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 40c543f0a2195d1b0dc88ef12142bea690009344
|
||||
F src/wal.h 06b2a0b599cc0f53ea97f497cf8c6b758c999f71
|
||||
F src/walker.c 91a6df7435827e41cff6bb7df50ea00934ee78b0
|
||||
F src/where.c 01baf58b72f3ddb7793cdee2871f751e3e09b35e
|
||||
F src/whereInt.h c0b092180f04608d80c258174b0a14a1f9c8d02f
|
||||
F src/walker.c b71a992b413b3a022572eccf29ef4b4890223791
|
||||
F src/where.c 49b48b720184fdde747c468d7270feeb1b88c6a71092cea3a1aa168dc8ac0b0f
|
||||
F src/whereInt.h 2d50c2b74a33be44cb68fdecee30b4d93552f1f4
|
||||
F src/wherecode.c 677e95413c472c0b413023b6b69a47f40fce1b04
|
||||
F src/whereexpr.c 130cdd1a43af71b19755270fb1224874cf55158c
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
@@ -521,6 +528,7 @@ F test/attachmalloc.test 3a4bfca9545bfe906a8d2e622de10fbac5b711b0
|
||||
F test/auth.test c6ede04bee65637ff354b43fc1235aa560c0863e
|
||||
F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1
|
||||
F test/auth3.test 0d48b901cf111c14b4b1b5205c7d28f1a278190f
|
||||
F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec
|
||||
F test/autoinc.test 6ae8fb69c9f656962464ae4e6667045d0dfc3b46
|
||||
F test/autoindex1.test 14b63a9f1e405fe6d5bfc8c8d00249c2ebaf13ea
|
||||
F test/autoindex2.test 12ef578928102baaa0dc23ad397601a2f4ecb0df
|
||||
@@ -575,7 +583,7 @@ F test/capi3d.test 485048dc5cd07bc68011e4917ad035ad6047ab82
|
||||
F test/capi3e.test 3d49c01ef2a1a55f41d73cba2b23b5059ec460fe
|
||||
F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3
|
||||
F test/cffault.test 9d6b20606afe712374952eec4f8fd74b1a8097ef
|
||||
F test/check.test 85a84bfc4be0e83f668747211c7cd45a6721d485
|
||||
F test/check.test 33a698e8c63613449d85d624a38ef669bf20331daabebe3891c9405dd6df463a
|
||||
F test/close.test 83947daf3b700631f90f4850ddaab455be4af73d
|
||||
F test/closure01.test b1703ba40639cfc9b295cf478d70739415eec6a4
|
||||
F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91
|
||||
@@ -589,7 +597,7 @@ F test/collate7.test 8ec29d98f3ee4ccebce6e16ce3863fb6b8c7b868
|
||||
F test/collate8.test cd9b3d3f999b8520ffaa7cc1647061fc5bab1334
|
||||
F test/collate9.test 3adcc799229545940df2f25308dd1ad65869145a
|
||||
F test/collateA.test b8218ab90d1fa5c59dcf156efabb1b2599c580d6
|
||||
F test/collateB.test 8ec2accd2d7166c1eff0d2a39bc90262c6f89632
|
||||
F test/collateB.test 1e68906951b846570f29f20102ed91d29e634854ee47454d725f2151ecac0b95
|
||||
F test/colmeta.test 2c765ea61ee37bc43bbe6d6047f89004e6508eb1
|
||||
F test/colname.test 08948a4809d22817e0e5de89c7c0a8bd90cb551b
|
||||
F test/conflict.test 029faa2d81a0d1cafb5f88614beb663d972c01db
|
||||
@@ -615,6 +623,7 @@ F test/corruptG.test adf79b669cbfd19e28c8191a610d083ae53a6d51
|
||||
F test/corruptH.test 79801d97ec5c2f9f3c87739aa1ec2eb786f96454
|
||||
F test/corruptI.test 075fe1d75aa1d84e2949be56b6264376c41502e4
|
||||
F test/corruptJ.test 4d5ccc4bf959464229a836d60142831ef76a5aa4
|
||||
F test/corruptK.test 814a59ec699d8546b4e29005fba3d16e933ef2fe
|
||||
F test/cost.test 1eedbfd868f806f3fa08ff072b04cf270dcf61c8
|
||||
F test/count.test cb2e0f934c6eb33670044520748d2ecccd46259c
|
||||
F test/coveridxscan.test b629e896b14df2f000a99b8d170d80589c46562c
|
||||
@@ -634,9 +643,8 @@ F test/csv01.test e0ba3caaa57e4c667a0b45977689fb8082f14348
|
||||
F test/ctime.test ff6c38e822459d6ca743c34901caf57740b08b54
|
||||
F test/cursorhint.test 7bc346788390475e77a345da2b92270d04d35856
|
||||
F test/cursorhint2.test 8457e93d97f665f23f97cdbc8477d16e3480331b
|
||||
F test/date.test a6a5a48b90907bca9fbcc79a30be5a715c1ab2fc
|
||||
F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373
|
||||
F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
|
||||
F test/dbselftest.c b2e6cfac59066dbcb7334b66304bb15a5508dd42
|
||||
F test/dbstatus.test 73149851b3aff14fc6db478e58f9083a66422cf5
|
||||
F test/dbstatus2.test e93ab03bfae6d62d4d935f20de928c19ca0ed0ab
|
||||
F test/default.test 0cb49b1c315a0d81c81d775e407f66906a2a604d
|
||||
@@ -805,6 +813,7 @@ F test/fts4growth.test e5390da74619cacc389711bac9349640b32c4f9a
|
||||
F test/fts4growth2.test 13ad4e76451af6e6906c95cdc725d01b00044269
|
||||
F test/fts4incr.test 4e353a0bd886ea984e56fce9e77724fc923b8d0d
|
||||
F test/fts4langid.test 65a7332c9bc257919e259a304aa8a38c41655b9d
|
||||
F test/fts4lastrowid.test fa5e157955a3121615ef3e16ff5196e96c9e1e64
|
||||
F test/fts4merge.test d2b39f6b1bd4a9738a13540e2d044cba11c43d47
|
||||
F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891
|
||||
F test/fts4merge3.test 8d9ccb4a3d41c4c617a149d6c4b13ad02de797d0
|
||||
@@ -825,7 +834,7 @@ F test/fuzz2.test 76dc35b32b6d6f965259508508abce75a6c4d7e1
|
||||
F test/fuzz3.test b47377143f0c80f91ed29d722861077ff34415d5
|
||||
F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
|
||||
F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26
|
||||
F test/fuzzcheck.c a87e6067a8d19844bade916841cb76150ecf24a2
|
||||
F test/fuzzcheck.c 2152602232c96d9c790eff3013e1369ce59de3203fa0b75bc613531448454e61
|
||||
F test/fuzzdata1.db 7ee3227bad0e7ccdeb08a9e6822916777073c664
|
||||
F test/fuzzdata2.db f03a420d3b822cc82e4f894ca957618fbe9c4973
|
||||
F test/fuzzdata3.db c6586d3e3cef0fbc18108f9bb649aa77bfc38aba
|
||||
@@ -874,7 +883,7 @@ F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
|
||||
F test/insert.test 38742b5e9601c8f8d76e9b7555f7270288c2d371
|
||||
F test/insert2.test 4d14b8f1b810a41995f6286b64a6943215d52208
|
||||
F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30
|
||||
F test/insert4.test a20432f1c0fbbcff8f11d0e6ab4acb8c9db58023
|
||||
F test/insert4.test 46bead5f39e181850ee56adcf49d3a3157c460c52249211714612ac89fe34835
|
||||
F test/insert5.test 394f96728d1258f406fe5f5aeb0aaf29487c39a6
|
||||
F test/instr.test 9a8802f28437d8ade53fedfc47b2ca599b4e48ba
|
||||
F test/instrfault.test 0f870b218ea17cd477bb19ed330eecdb460dd53a
|
||||
@@ -904,6 +913,7 @@ F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
|
||||
F test/json101.test c0897616f32d95431f37fd291cb78742181980ac
|
||||
F test/json102.test bf3fe7a706d30936a76a0f7a0375e1e8e73aff5a
|
||||
F test/json103.test c5f6b85e69de05f6b3195f9f9d5ce9cd179099a0
|
||||
F test/json104.test 877d5845f6303899b7889ea5dd1bea99076e3100574d5c536082245c5805dcaa
|
||||
F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff
|
||||
F test/kvtest.c b9a9822dda05a1aa481215a52e2fc93cd8b22ee5
|
||||
F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63
|
||||
@@ -929,7 +939,7 @@ F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
|
||||
F test/malloc.test 21c213365f2cca95ab2d7dc078dc8525f96065f8
|
||||
F test/malloc3.test e3b32c724b5a124b57cb0ed177f675249ad0c66a
|
||||
F test/malloc4.test 957337613002b7058a85116493a262f679f3a261
|
||||
F test/malloc5.test 192d0b5ee1d023a07d5164c34cf47d010da73da1
|
||||
F test/malloc5.test a591be066ebc6ad34adaa4b38939a037a59ebd80ad681e79dedac7b4a9e7bc09
|
||||
F test/malloc6.test 2f039d9821927eacae43e1831f815e157659a151
|
||||
F test/malloc7.test 7c68a32942858bc715284856c5507446bba88c3a
|
||||
F test/malloc8.test 9b7a3f8cb9cf0b12fff566e80a980b1767bd961d
|
||||
@@ -947,6 +957,7 @@ F test/mallocI.test 6c23a71df077fa5d387be90e7e669c5b368ca38a
|
||||
F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e
|
||||
F test/mallocK.test 27cb5566a6e5f2d76f9d4aa2eca45524401fd61e
|
||||
F test/mallocL.test fb311ff80afddf3b1a75e52289081f4754d901dc
|
||||
F test/mallocM.test 78bbe9d3da84a5c679123cdb40d7b2010b18fc46e13897e4f253c6ba6fbff134
|
||||
F test/malloc_common.tcl aac62499b76be719fac31e7a3e54a7fd53272e7f
|
||||
F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e
|
||||
F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f
|
||||
@@ -1000,8 +1011,8 @@ F test/orderby7.test 3d1383d52ade5b9eb3a173b3147fdd296f0202da
|
||||
F test/orderby8.test 23ef1a5d72bd3adcc2f65561c654295d1b8047bd
|
||||
F test/orderby9.test 87fb9548debcc2cd141c5299002dd94672fa76a3
|
||||
F test/oserror.test b32dc34f2363ef18532e3a0a7358e3e7e321974f
|
||||
F test/ossfuzz.c e469138f4be3e92df6173b79b3b216ab6e17b407
|
||||
F test/ossshell.c d9f1a6f43e7bab45d6be857a5800f5d4a1861db3
|
||||
F test/ossfuzz.c f5abed3177f719df3c3109901fcdd26b9fb7f581c8da50fc26f3a81ddfb2c2ae
|
||||
F test/ossshell.c 296ab63067841bd1b1e97b46a0b2af48ee7f69d50d1a723008bee12dd7122622
|
||||
F test/ovfl.test 199c482696defceacee8c8e0e0ef36da62726b2f
|
||||
F test/pager1.test 841868017e9dd3cb459b8d78862091a7d9cff21d
|
||||
F test/pager2.test 67b8f40ae98112bcdba1f2b2d03ea83266418c71
|
||||
@@ -1016,11 +1027,12 @@ F test/parser1.test 391b9bf9a229547a129c61ac345ed1a6f5eb1854
|
||||
F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b
|
||||
F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
|
||||
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
|
||||
F test/permutations.test 46ad98770d3c04ce2418cab2cc527647bfe961a7
|
||||
F test/permutations.test af720e7d139e7e5417341d0f0eef2b911c0b067852138dc2f5b6a451b5725118
|
||||
F test/pragma.test 1e94755164a3a3264cd39836de4bebcb7809e5f8
|
||||
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
|
||||
F test/pragma3.test 14c12bc5352b1e100e0b6b44f371053a81ccf8ed
|
||||
F test/pragma4.test 6e85b6eab8e61ffc9c7db59d842276674e8e3264
|
||||
F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8
|
||||
F test/printf.test b3ff34e73d59124140eaf89f7672e21bc2ca5fcc
|
||||
F test/printf2.test 9e6db85f81c63f2367c34a9d7db384088bd374ad
|
||||
F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb
|
||||
@@ -1103,12 +1115,12 @@ F test/sharedA.test 0cdf1a76dfa00e6beee66af5b534b1e8df2720f5
|
||||
F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e
|
||||
F test/shared_err.test 2f2aee20db294b9924e81f6ccbe60f19e21e8506
|
||||
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
|
||||
F test/shell1.test 52ac23a345772ab0d6d3241a21a633fdaa3ed581
|
||||
F test/shell1.test 50226a3a66bbd42a902e9f7698f768927eb33a56e9cfc55b7c157c38eb3e80ac
|
||||
F test/shell2.test e242a9912f44f4c23c3d1d802a83e934e84c853b
|
||||
F test/shell3.test 9b95ba643eaa228376f06a898fb410ee9b6e57c1
|
||||
F test/shell4.test 89ad573879a745974ff2df20ff97c5d6ffffbd5d
|
||||
F test/shell5.test 50a732c1c2158b1cd62cf53975ce1ea7ce6b9dc9
|
||||
F test/shell6.test cff624fadf71bdb5e3a9b0f86eaf59a43c0622b1
|
||||
F test/shell6.test ab1592ebe881371f651f18ee6a0df21cbfb5310f88cb832ab642d4038f679772
|
||||
F test/shell7.test 07751911b294698e0c5df67bcbd29e7d2f0f2907
|
||||
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
|
||||
@@ -1156,6 +1168,7 @@ F test/subtype1.test 7fe09496352f97053af1437150751be2d0a0cae8
|
||||
F test/superlock.test ec94f0556b6488d97f71c79f9061ae08d9ab8f12
|
||||
F test/symlink.test c9ebe7330d228249e447038276bfc8a7b22f4849
|
||||
F test/sync.test 2f84bdbc2b2df1fcb0220575b4b9f8cea94b7529
|
||||
F test/sync2.test 6be8ed007fa063b147773c1982b5bdba97a32badc536bdc6077eff5cf8710ece
|
||||
F test/syscall.test f59ba4e25f7ba4a4c031026cc2ef8b6e4b4c639c
|
||||
F test/sysfault.test c9f2b0d8d677558f74de750c75e12a5454719d04
|
||||
F test/tabfunc01.test 699251cb99651415218a891384510a685c7ab012
|
||||
@@ -1170,7 +1183,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
|
||||
F test/temptable2.test cd396beb41117a5302fff61767c35fa4270a0d5e
|
||||
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
|
||||
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
|
||||
F test/tester.tcl 67835ac17e90055f24a9cf52e5c5bce0dd511c74
|
||||
F test/tester.tcl 581f0185434daf7026ccede4c07e8d1479186ec5
|
||||
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
|
||||
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
@@ -1348,6 +1361,7 @@ F test/triggerC.test 302d8995f5ffe63bbc15053abb3ef7a39cf5a092
|
||||
F test/triggerD.test 8e7f3921a92a5797d472732108109e44575fa650
|
||||
F test/triggerE.test 15fa63f1097db1f83dd62d121616006978063d1f
|
||||
F test/triggerF.test 55b1eb13433997faac3a4948c1d8252f6c8c636b
|
||||
F test/triggerG.test 175cafdc6399d85231a09e82e051b0e45a2fd1f23dd08ae715bc359716149ab6
|
||||
F test/tt3_checkpoint.c 9e75cf7c1c364f52e1c47fd0f14c4340a9db0fe1
|
||||
F test/tt3_index.c 39eec10a35f57672225be4d182862152896dee4a
|
||||
F test/tt3_lookaside1.c 0377e202c3c2a50d688cb65ba203afeda6fafeb9
|
||||
@@ -1466,10 +1480,10 @@ F test/wordcount.c 06efb84b7c48a4973c2c24ea06c93d00bce24389
|
||||
F test/zeroblob.test 3857870fe681b8185654414a9bccfde80b62a0fa
|
||||
F test/zerodamage.test e59a56443d6298ecf7435f618f0b27654f0c849e
|
||||
F tool/GetFile.cs a15e08acb5dd7539b75ba23501581d7c2b462cb5
|
||||
F tool/GetTclKit.bat f94784e3bdc2f50c539266f5467cbf1f27612cb3
|
||||
F tool/GetTclKit.bat 6afa640edc7810725aec61c3076ac617c4aaf0b7
|
||||
F tool/Replace.cs 02c67258801c2fb5f63231e0ac0f220b4b36ba91
|
||||
F tool/addopcodes.tcl 10c889c4a65ec6c5604e4a47306fa77ff57ae189
|
||||
F tool/build-all-msvc.bat 018c1b273458a90c8ba633c6f0c5654cfcb138bf x
|
||||
F tool/build-all-msvc.bat c12328d06c45fec8baada5949e3d5af54bf8c887 x
|
||||
F tool/build-shell.sh 950f47c6174f1eea171319438b93ba67ff5bf367
|
||||
F tool/cg_anno.tcl f95b0006c52cf7f0496b506343415b6ee3cdcdd3 x
|
||||
F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2
|
||||
@@ -1494,7 +1508,7 @@ F tool/mkmsvcmin.tcl 95b37e202cbed873aa8ffdbb493b9db45927be2b
|
||||
F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
|
||||
F tool/mkopcodeh.tcl a01d2c1d8a6205b03fc635adf3735b4c523befd3
|
||||
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
|
||||
F tool/mkpragmatab.tcl b6ef1997fbc019015cb3f1b078c38b884d1ce4b6
|
||||
F tool/mkpragmatab.tcl 32bb40741df11bddc8451de9ea4d130e7b4476d8064794b1cf402ac110840fba
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
F tool/mksqlite3c-noext.tcl fef88397668ae83166735c41af99d79f56afaabb
|
||||
F tool/mksqlite3c.tcl 06b2e6a0f21cc0a5d70fbbd136b3e0a96470645e
|
||||
@@ -1509,7 +1523,7 @@ F tool/replace.tcl 60f91e8dd06ab81f74d213ecbd9c9945f32ac048
|
||||
F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a
|
||||
F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5
|
||||
F tool/run-speed-test.sh f95d19fd669b68c4c38b6b475242841d47c66076
|
||||
F tool/showdb.c c695a5d5c8110640e0d9fadf5e254da90c79c36e
|
||||
F tool/showdb.c e6bc9dba233bf1b57ca0a525a2bba762db4e223de84990739db3f09c46151b1e
|
||||
F tool/showjournal.c 5bad7ae8784a43d2b270d953060423b8bd480818
|
||||
F tool/showlocks.c 9920bcc64f58378ff1118caead34147201f48c68
|
||||
F tool/showstat4.c b14159aa062f661b394ba37b6b7b94bfb8012ab9
|
||||
@@ -1556,10 +1570,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 1589db012ef1389bf84399fccf96d143b2ac4c0f
|
||||
R 927fcfe986f9d231ee2a8f2fc2e00fd4
|
||||
T *branch * vdbe_cycle_limit
|
||||
T *sym-vdbe_cycle_limit *
|
||||
P 48826b222c110a90996a84605318ea6b1e502b8c5129f4d561f8350dbdbcd264
|
||||
R 33164644836f84aff2e4df2bff5189e1
|
||||
T *branch * shell-fix
|
||||
T *sym-shell-fix *
|
||||
T -sym-trunk *
|
||||
U drh
|
||||
Z 42d28699ae4b43243cadb703ee72bd58
|
||||
Z d4f7ac77bbed43ce1dcbcb86734fd32f
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
9626b41e6ef70631cc1867315e409a2a92ce2a53
|
||||
4c2b572969ea2ed2a925444ecfa356aa877018cbb9c4f57d081ab4b535cd1dd0
|
||||
+47
-31
@@ -290,6 +290,7 @@ struct Stat4Accum {
|
||||
Stat4Sample *aBest; /* Array of nCol best samples */
|
||||
int iMin; /* Index in a[] of entry with minimum score */
|
||||
int nSample; /* Current number of samples */
|
||||
int nMaxEqZero; /* Max leading 0 in anEq[] for any a[] entry */
|
||||
int iGet; /* Index of current sample accessed by stat_get() */
|
||||
Stat4Sample *a; /* Array of mxSample Stat4Sample objects */
|
||||
sqlite3 *db; /* Database connection, for malloc() */
|
||||
@@ -554,6 +555,13 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
|
||||
assert( IsStat4 || nEqZero==0 );
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
/* Stat4Accum.nMaxEqZero is set to the maximum number of leading 0
|
||||
** values in the anEq[] array of any sample in Stat4Accum.a[]. In
|
||||
** other words, if nMaxEqZero is n, then it is guaranteed that there
|
||||
** are no samples with Stat4Sample.anEq[m]==0 for (m>=n). */
|
||||
if( nEqZero>p->nMaxEqZero ){
|
||||
p->nMaxEqZero = nEqZero;
|
||||
}
|
||||
if( pNew->isPSample==0 ){
|
||||
Stat4Sample *pUpgrade = 0;
|
||||
assert( pNew->anEq[pNew->iCol]>0 );
|
||||
@@ -651,12 +659,22 @@ static void samplePushPrevious(Stat4Accum *p, int iChng){
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the anEq[] fields of any samples already collected. */
|
||||
/* Check that no sample contains an anEq[] entry with an index of
|
||||
** p->nMaxEqZero or greater set to zero. */
|
||||
for(i=p->nSample-1; i>=0; i--){
|
||||
int j;
|
||||
for(j=iChng; j<p->nCol; j++){
|
||||
if( p->a[i].anEq[j]==0 ) p->a[i].anEq[j] = p->current.anEq[j];
|
||||
for(j=p->nMaxEqZero; j<p->nCol; j++) assert( p->a[i].anEq[j]>0 );
|
||||
}
|
||||
|
||||
/* Update the anEq[] fields of any samples already collected. */
|
||||
if( iChng<p->nMaxEqZero ){
|
||||
for(i=p->nSample-1; i>=0; i--){
|
||||
int j;
|
||||
for(j=iChng; j<p->nCol; j++){
|
||||
if( p->a[i].anEq[j]==0 ) p->a[i].anEq[j] = p->current.anEq[j];
|
||||
}
|
||||
}
|
||||
p->nMaxEqZero = iChng;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1186,7 +1204,7 @@ static void analyzeOneTable(
|
||||
regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
|
||||
for(j=0; j<pPk->nKeyCol; j++){
|
||||
k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]);
|
||||
assert( k>=0 && k<pTab->nCol );
|
||||
assert( k>=0 && k<pIdx->nColumn );
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
|
||||
VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName));
|
||||
}
|
||||
@@ -1370,27 +1388,14 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
|
||||
if( i==1 ) continue; /* Do not analyze the TEMP database */
|
||||
analyzeDatabase(pParse, i);
|
||||
}
|
||||
}else if( pName2->n==0 ){
|
||||
/* Form 2: Analyze the database or table named */
|
||||
iDb = sqlite3FindDb(db, pName1);
|
||||
if( iDb>=0 ){
|
||||
analyzeDatabase(pParse, iDb);
|
||||
}else{
|
||||
z = sqlite3NameFromToken(db, pName1);
|
||||
if( z ){
|
||||
if( (pIdx = sqlite3FindIndex(db, z, 0))!=0 ){
|
||||
analyzeTable(pParse, pIdx->pTable, pIdx);
|
||||
}else if( (pTab = sqlite3LocateTable(pParse, 0, z, 0))!=0 ){
|
||||
analyzeTable(pParse, pTab, 0);
|
||||
}
|
||||
sqlite3DbFree(db, z);
|
||||
}
|
||||
}
|
||||
}else if( pName2->n==0 && (iDb = sqlite3FindDb(db, pName1))>=0 ){
|
||||
/* Analyze the schema named as the argument */
|
||||
analyzeDatabase(pParse, iDb);
|
||||
}else{
|
||||
/* Form 3: Analyze the fully qualified table name */
|
||||
/* Form 3: Analyze the table or index named as an argument */
|
||||
iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName);
|
||||
if( iDb>=0 ){
|
||||
zDb = db->aDb[iDb].zDbSName;
|
||||
zDb = pName2->n ? db->aDb[iDb].zDbSName : 0;
|
||||
z = sqlite3NameFromToken(db, pTableName);
|
||||
if( z ){
|
||||
if( (pIdx = sqlite3FindIndex(db, z, zDb))!=0 ){
|
||||
@@ -1400,10 +1405,11 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
|
||||
}
|
||||
sqlite3DbFree(db, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if( db->nSqlExec==0 && (v = sqlite3GetVdbe(pParse))!=0 ){
|
||||
sqlite3VdbeAddOp0(v, OP_Expire);
|
||||
}
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v ) sqlite3VdbeAddOp0(v, OP_Expire);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1532,7 +1538,11 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
|
||||
#endif
|
||||
pIndex->bUnordered = 0;
|
||||
decodeIntArray((char*)z, nCol, aiRowEst, pIndex->aiRowLogEst, pIndex);
|
||||
if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0];
|
||||
pIndex->hasStat1 = 1;
|
||||
if( pIndex->pPartIdxWhere==0 ){
|
||||
pTable->nRowLogEst = pIndex->aiRowLogEst[0];
|
||||
pTable->tabFlags |= TF_HasStat1;
|
||||
}
|
||||
}else{
|
||||
Index fakeIdx;
|
||||
fakeIdx.szIdxRow = pTable->szTabRow;
|
||||
@@ -1541,6 +1551,7 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
|
||||
#endif
|
||||
decodeIntArray((char*)z, 1, 0, &pTable->nRowLogEst, &fakeIdx);
|
||||
pTable->szTabRow = fakeIdx.szIdxRow;
|
||||
pTable->tabFlags |= TF_HasStat1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1835,15 +1846,20 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
|
||||
HashElem *i;
|
||||
char *zSql;
|
||||
int rc = SQLITE_OK;
|
||||
Schema *pSchema = db->aDb[iDb].pSchema;
|
||||
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
assert( db->aDb[iDb].pBt!=0 );
|
||||
|
||||
/* Clear any prior statistics */
|
||||
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
||||
for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
|
||||
for(i=sqliteHashFirst(&pSchema->tblHash); i; i=sqliteHashNext(i)){
|
||||
Table *pTab = sqliteHashData(i);
|
||||
pTab->tabFlags &= ~TF_HasStat1;
|
||||
}
|
||||
for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){
|
||||
Index *pIdx = sqliteHashData(i);
|
||||
pIdx->aiRowLogEst[0] = 0;
|
||||
pIdx->hasStat1 = 0;
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
sqlite3DeleteIndexSamples(db, pIdx);
|
||||
pIdx->aSample = 0;
|
||||
@@ -1866,9 +1882,9 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
|
||||
|
||||
/* Set appropriate defaults on all indexes not in the sqlite_stat1 table */
|
||||
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
||||
for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
|
||||
for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){
|
||||
Index *pIdx = sqliteHashData(i);
|
||||
if( pIdx->aiRowLogEst[0]==0 ) sqlite3DefaultRowEst(pIdx);
|
||||
if( !pIdx->hasStat1 ) sqlite3DefaultRowEst(pIdx);
|
||||
}
|
||||
|
||||
/* Load the statistics from the sqlite_stat4 table. */
|
||||
@@ -1878,7 +1894,7 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
|
||||
rc = loadStat4(db, sInfo.zDatabase);
|
||||
db->lookaside.bDisable--;
|
||||
}
|
||||
for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
|
||||
for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){
|
||||
Index *pIdx = sqliteHashData(i);
|
||||
sqlite3_free(pIdx->aiRowEst);
|
||||
pIdx->aiRowEst = 0;
|
||||
|
||||
+161
-72
@@ -499,6 +499,7 @@ static void invalidateAllOverflowCache(BtShared *pBt){
|
||||
*/
|
||||
static void invalidateIncrblobCursors(
|
||||
Btree *pBtree, /* The database file to check */
|
||||
Pgno pgnoRoot, /* The table that might be changing */
|
||||
i64 iRow, /* The rowid that might be changing */
|
||||
int isClearTable /* True if all rows are being deleted */
|
||||
){
|
||||
@@ -509,7 +510,7 @@ static void invalidateIncrblobCursors(
|
||||
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
|
||||
if( (p->curFlags & BTCF_Incrblob)!=0 ){
|
||||
pBtree->hasIncrblobCur = 1;
|
||||
if( isClearTable || p->info.nKey==iRow ){
|
||||
if( p->pgnoRoot==pgnoRoot && (isClearTable || p->info.nKey==iRow) ){
|
||||
p->eState = CURSOR_INVALID;
|
||||
}
|
||||
}
|
||||
@@ -518,7 +519,7 @@ static void invalidateIncrblobCursors(
|
||||
|
||||
#else
|
||||
/* Stub function when INCRBLOB is omitted */
|
||||
#define invalidateIncrblobCursors(x,y,z)
|
||||
#define invalidateIncrblobCursors(w,x,y,z)
|
||||
#endif /* SQLITE_OMIT_INCRBLOB */
|
||||
|
||||
/*
|
||||
@@ -1317,17 +1318,18 @@ static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){
|
||||
|
||||
|
||||
/*
|
||||
** Defragment the page given. All Cells are moved to the
|
||||
** end of the page and all free space is collected into one
|
||||
** big FreeBlk that occurs in between the header and cell
|
||||
** pointer array and the cell content area.
|
||||
** Defragment the page given. This routine reorganizes cells within the
|
||||
** page so that there are no free-blocks on the free-block list.
|
||||
**
|
||||
** Parameter nMaxFrag is the maximum amount of fragmented space that may be
|
||||
** present in the page after this routine returns.
|
||||
**
|
||||
** EVIDENCE-OF: R-44582-60138 SQLite may from time to time reorganize a
|
||||
** b-tree page so that there are no freeblocks or fragment bytes, all
|
||||
** unused bytes are contained in the unallocated space region, and all
|
||||
** cells are packed tightly at the end of the page.
|
||||
*/
|
||||
static int defragmentPage(MemPage *pPage){
|
||||
static int defragmentPage(MemPage *pPage, int nMaxFrag){
|
||||
int i; /* Loop counter */
|
||||
int pc; /* Address of the i-th cell */
|
||||
int hdr; /* Offset to the page header */
|
||||
@@ -1342,7 +1344,6 @@ static int defragmentPage(MemPage *pPage){
|
||||
int iCellFirst; /* First allowable cell index */
|
||||
int iCellLast; /* Last possible cell index */
|
||||
|
||||
|
||||
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
|
||||
assert( pPage->pBt!=0 );
|
||||
assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE );
|
||||
@@ -1354,9 +1355,56 @@ static int defragmentPage(MemPage *pPage){
|
||||
cellOffset = pPage->cellOffset;
|
||||
nCell = pPage->nCell;
|
||||
assert( nCell==get2byte(&data[hdr+3]) );
|
||||
usableSize = pPage->pBt->usableSize;
|
||||
cbrk = usableSize;
|
||||
iCellFirst = cellOffset + 2*nCell;
|
||||
usableSize = pPage->pBt->usableSize;
|
||||
|
||||
/* This block handles pages with two or fewer free blocks and nMaxFrag
|
||||
** or fewer fragmented bytes. In this case it is faster to move the
|
||||
** two (or one) blocks of cells using memmove() and add the required
|
||||
** offsets to each pointer in the cell-pointer array than it is to
|
||||
** reconstruct the entire page. */
|
||||
if( (int)data[hdr+7]<=nMaxFrag ){
|
||||
int iFree = get2byte(&data[hdr+1]);
|
||||
if( iFree ){
|
||||
int iFree2 = get2byte(&data[iFree]);
|
||||
|
||||
/* pageFindSlot() has already verified that free blocks are sorted
|
||||
** in order of offset within the page, and that no block extends
|
||||
** past the end of the page. Provided the two free slots do not
|
||||
** overlap, this guarantees that the memmove() calls below will not
|
||||
** overwrite the usableSize byte buffer, even if the database page
|
||||
** is corrupt. */
|
||||
assert( iFree2==0 || iFree2>iFree );
|
||||
assert( iFree+get2byte(&data[iFree+2]) <= usableSize );
|
||||
assert( iFree2==0 || iFree2+get2byte(&data[iFree2+2]) <= usableSize );
|
||||
|
||||
if( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){
|
||||
u8 *pEnd = &data[cellOffset + nCell*2];
|
||||
u8 *pAddr;
|
||||
int sz2 = 0;
|
||||
int sz = get2byte(&data[iFree+2]);
|
||||
int top = get2byte(&data[hdr+5]);
|
||||
if( iFree2 ){
|
||||
if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_BKPT;
|
||||
sz2 = get2byte(&data[iFree2+2]);
|
||||
assert( iFree+sz+sz2+iFree2-(iFree+sz) <= usableSize );
|
||||
memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz));
|
||||
sz += sz2;
|
||||
}
|
||||
cbrk = top+sz;
|
||||
assert( cbrk+(iFree-top) <= usableSize );
|
||||
memmove(&data[cbrk], &data[top], iFree-top);
|
||||
for(pAddr=&data[cellOffset]; pAddr<pEnd; pAddr+=2){
|
||||
pc = get2byte(pAddr);
|
||||
if( pc<iFree ){ put2byte(pAddr, pc+sz); }
|
||||
else if( pc<iFree2 ){ put2byte(pAddr, pc+sz2); }
|
||||
}
|
||||
goto defragment_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cbrk = usableSize;
|
||||
iCellLast = usableSize - 4;
|
||||
for(i=0; i<nCell; i++){
|
||||
u8 *pAddr; /* The i-th cell pointer */
|
||||
@@ -1390,16 +1438,18 @@ static int defragmentPage(MemPage *pPage){
|
||||
}
|
||||
memcpy(&data[cbrk], &src[pc], size);
|
||||
}
|
||||
data[hdr+7] = 0;
|
||||
|
||||
defragment_out:
|
||||
if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
assert( cbrk>=iCellFirst );
|
||||
put2byte(&data[hdr+5], cbrk);
|
||||
data[hdr+1] = 0;
|
||||
data[hdr+2] = 0;
|
||||
data[hdr+7] = 0;
|
||||
memset(&data[iCellFirst], 0, cbrk-iCellFirst);
|
||||
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
|
||||
if( cbrk-iCellFirst!=pPage->nFree ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -1537,10 +1587,10 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
|
||||
testcase( gap+2+nByte==top );
|
||||
if( gap+2+nByte>top ){
|
||||
assert( pPage->nCell>0 || CORRUPT_DB );
|
||||
rc = defragmentPage(pPage);
|
||||
rc = defragmentPage(pPage, MIN(4, pPage->nFree - (2+nByte)));
|
||||
if( rc ) return rc;
|
||||
top = get2byteNotZero(&data[hdr+5]);
|
||||
assert( gap+nByte<=top );
|
||||
assert( gap+2+nByte<=top );
|
||||
}
|
||||
|
||||
|
||||
@@ -2812,6 +2862,31 @@ int sqlite3BtreeGetAutoVacuum(Btree *p){
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** If the user has not set the safety-level for this database connection
|
||||
** using "PRAGMA synchronous", and if the safety-level is not already
|
||||
** set to the value passed to this function as the second parameter,
|
||||
** set it so.
|
||||
*/
|
||||
#if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS
|
||||
static void setDefaultSyncFlag(BtShared *pBt, u8 safety_level){
|
||||
sqlite3 *db;
|
||||
Db *pDb;
|
||||
if( (db=pBt->db)!=0 && (pDb=db->aDb)!=0 ){
|
||||
while( pDb->pBt==0 || pDb->pBt->pBt!=pBt ){ pDb++; }
|
||||
if( pDb->bSyncSet==0
|
||||
&& pDb->safety_level!=safety_level
|
||||
&& pDb!=&db->aDb[1]
|
||||
){
|
||||
pDb->safety_level = safety_level;
|
||||
sqlite3PagerSetFlags(pBt->pPager,
|
||||
pDb->safety_level | (db->flags & PAGER_FLAGS_MASK));
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define setDefaultSyncFlag(pBt,safety_level)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Get a reference to pPage1 of the database file. This will
|
||||
@@ -2885,26 +2960,15 @@ static int lockBtree(BtShared *pBt){
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto page1_init_failed;
|
||||
}else{
|
||||
#if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS
|
||||
sqlite3 *db;
|
||||
Db *pDb;
|
||||
if( (db=pBt->db)!=0 && (pDb=db->aDb)!=0 ){
|
||||
while( pDb->pBt==0 || pDb->pBt->pBt!=pBt ){ pDb++; }
|
||||
if( pDb->bSyncSet==0
|
||||
&& pDb->safety_level==SQLITE_DEFAULT_SYNCHRONOUS+1
|
||||
){
|
||||
pDb->safety_level = SQLITE_DEFAULT_WAL_SYNCHRONOUS+1;
|
||||
sqlite3PagerSetFlags(pBt->pPager,
|
||||
pDb->safety_level | (db->flags & PAGER_FLAGS_MASK));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
setDefaultSyncFlag(pBt, SQLITE_DEFAULT_WAL_SYNCHRONOUS+1);
|
||||
if( isOpen==0 ){
|
||||
releasePage(pPage1);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
rc = SQLITE_NOTADB;
|
||||
}else{
|
||||
setDefaultSyncFlag(pBt, SQLITE_DEFAULT_SYNCHRONOUS+1);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -4253,7 +4317,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
|
||||
CellInfo info;
|
||||
int iPage = pCur->iPage;
|
||||
memset(&info, 0, sizeof(info));
|
||||
btreeParseCell(pCur->apPage[iPage], pCur->aiIdx[iPage], &info);
|
||||
btreeParseCell(pCur->apPage[iPage], pCur->ix, &info);
|
||||
assert( CORRUPT_DB || memcmp(&info, &pCur->info, sizeof(info))==0 );
|
||||
}
|
||||
#else
|
||||
@@ -4263,7 +4327,7 @@ static SQLITE_NOINLINE void getCellInfo(BtCursor *pCur){
|
||||
if( pCur->info.nSize==0 ){
|
||||
int iPage = pCur->iPage;
|
||||
pCur->curFlags |= BTCF_ValidNKey;
|
||||
btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
|
||||
btreeParseCell(pCur->apPage[iPage],pCur->ix,&pCur->info);
|
||||
}else{
|
||||
assertCellInfo(pCur);
|
||||
}
|
||||
@@ -4470,7 +4534,7 @@ static int accessPayload(
|
||||
assert( pPage );
|
||||
assert( eOp==0 || eOp==1 );
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
|
||||
assert( pCur->ix<pPage->nCell );
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
|
||||
getCellInfo(pCur);
|
||||
@@ -4657,7 +4721,7 @@ int sqlite3BtreePayload(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] );
|
||||
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
|
||||
assert( pCur->ix<pCur->apPage[pCur->iPage]->nCell );
|
||||
return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0);
|
||||
}
|
||||
|
||||
@@ -4719,7 +4783,7 @@ static const void *fetchPayload(
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
||||
assert( cursorOwnsBtShared(pCur) );
|
||||
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
|
||||
assert( pCur->ix<pCur->apPage[pCur->iPage]->nCell );
|
||||
assert( pCur->info.nSize>0 );
|
||||
assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB );
|
||||
assert( pCur->info.pPayload<pCur->apPage[pCur->iPage]->aDataEnd ||CORRUPT_DB);
|
||||
@@ -4770,8 +4834,8 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
|
||||
}
|
||||
pCur->info.nSize = 0;
|
||||
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
|
||||
pCur->iPage++;
|
||||
pCur->aiIdx[pCur->iPage] = 0;
|
||||
pCur->aiIdx[pCur->iPage++] = pCur->ix;
|
||||
pCur->ix = 0;
|
||||
return getAndInitPage(pBt, newPgno, &pCur->apPage[pCur->iPage],
|
||||
pCur, pCur->curPagerFlags);
|
||||
}
|
||||
@@ -4819,6 +4883,7 @@ static void moveToParent(BtCursor *pCur){
|
||||
testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell );
|
||||
pCur->info.nSize = 0;
|
||||
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
|
||||
pCur->ix = pCur->aiIdx[pCur->iPage-1];
|
||||
releasePageNotNull(pCur->apPage[pCur->iPage--]);
|
||||
}
|
||||
|
||||
@@ -4900,7 +4965,7 @@ static int moveToRoot(BtCursor *pCur){
|
||||
}
|
||||
|
||||
skip_init:
|
||||
pCur->aiIdx[0] = 0;
|
||||
pCur->ix = 0;
|
||||
pCur->info.nSize = 0;
|
||||
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl);
|
||||
|
||||
@@ -4934,8 +4999,8 @@ static int moveToLeftmost(BtCursor *pCur){
|
||||
assert( cursorOwnsBtShared(pCur) );
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){
|
||||
assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
|
||||
pgno = get4byte(findCell(pPage, pCur->aiIdx[pCur->iPage]));
|
||||
assert( pCur->ix<pPage->nCell );
|
||||
pgno = get4byte(findCell(pPage, pCur->ix));
|
||||
rc = moveToChild(pCur, pgno);
|
||||
}
|
||||
return rc;
|
||||
@@ -4960,11 +5025,11 @@ static int moveToRightmost(BtCursor *pCur){
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){
|
||||
pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
|
||||
pCur->aiIdx[pCur->iPage] = pPage->nCell;
|
||||
pCur->ix = pPage->nCell;
|
||||
rc = moveToChild(pCur, pgno);
|
||||
if( rc ) return rc;
|
||||
}
|
||||
pCur->aiIdx[pCur->iPage] = pPage->nCell-1;
|
||||
pCur->ix = pPage->nCell-1;
|
||||
assert( pCur->info.nSize==0 );
|
||||
assert( (pCur->curFlags & BTCF_ValidNKey)==0 );
|
||||
return SQLITE_OK;
|
||||
@@ -5012,7 +5077,7 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
|
||||
for(ii=0; ii<pCur->iPage; ii++){
|
||||
assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell );
|
||||
}
|
||||
assert( pCur->aiIdx[pCur->iPage]==pCur->apPage[pCur->iPage]->nCell-1 );
|
||||
assert( pCur->ix==pCur->apPage[pCur->iPage]->nCell-1 );
|
||||
assert( pCur->apPage[pCur->iPage]->leaf );
|
||||
#endif
|
||||
return SQLITE_OK;
|
||||
@@ -5159,7 +5224,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
upr = pPage->nCell-1;
|
||||
assert( biasRight==0 || biasRight==1 );
|
||||
idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
pCur->ix = (u16)idx;
|
||||
if( xRecordCompare==0 ){
|
||||
for(;;){
|
||||
i64 nCellKey;
|
||||
@@ -5178,7 +5243,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
if( lwr>upr ){ c = +1; break; }
|
||||
}else{
|
||||
assert( nCellKey==intKey );
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
pCur->ix = (u16)idx;
|
||||
if( !pPage->leaf ){
|
||||
lwr = idx;
|
||||
goto moveto_next_layer;
|
||||
@@ -5247,7 +5312,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
rc = SQLITE_NOMEM_BKPT;
|
||||
goto moveto_finish;
|
||||
}
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
pCur->ix = (u16)idx;
|
||||
rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0);
|
||||
pCur->curFlags &= ~BTCF_ValidOvfl;
|
||||
if( rc ){
|
||||
@@ -5269,7 +5334,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
assert( c==0 );
|
||||
*pRes = 0;
|
||||
rc = SQLITE_OK;
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
pCur->ix = (u16)idx;
|
||||
if( pIdxKey->errCode ) rc = SQLITE_CORRUPT;
|
||||
goto moveto_finish;
|
||||
}
|
||||
@@ -5281,8 +5346,8 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) );
|
||||
assert( pPage->isInit );
|
||||
if( pPage->leaf ){
|
||||
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
assert( pCur->ix<pCur->apPage[pCur->iPage]->nCell );
|
||||
pCur->ix = (u16)idx;
|
||||
*pRes = c;
|
||||
rc = SQLITE_OK;
|
||||
goto moveto_finish;
|
||||
@@ -5293,7 +5358,7 @@ moveto_next_layer:
|
||||
}else{
|
||||
chldPg = get4byte(findCell(pPage, lwr));
|
||||
}
|
||||
pCur->aiIdx[pCur->iPage] = (u16)lwr;
|
||||
pCur->ix = (u16)lwr;
|
||||
rc = moveToChild(pCur, chldPg);
|
||||
if( rc ) break;
|
||||
}
|
||||
@@ -5319,6 +5384,30 @@ int sqlite3BtreeEof(BtCursor *pCur){
|
||||
return (CURSOR_VALID!=pCur->eState);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return an estimate for the number of rows in the table that pCur is
|
||||
** pointing to. Return a negative number if no estimate is currently
|
||||
** available.
|
||||
*/
|
||||
i64 sqlite3BtreeRowCountEst(BtCursor *pCur){
|
||||
i64 n;
|
||||
u8 i;
|
||||
|
||||
assert( cursorOwnsBtShared(pCur) );
|
||||
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
||||
|
||||
/* Currently this interface is only called by the OP_IfSmaller
|
||||
** opcode, and it that case the cursor will always be valid and
|
||||
** will always point to a leaf node. */
|
||||
if( NEVER(pCur->eState!=CURSOR_VALID) ) return -1;
|
||||
if( NEVER(pCur->apPage[pCur->iPage]->leaf==0) ) return -1;
|
||||
|
||||
for(n=1, i=0; i<=pCur->iPage; i++){
|
||||
n *= pCur->apPage[i]->nCell;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
** Advance the cursor to the next entry in the database. If
|
||||
** successful then set *pRes=0. If the cursor
|
||||
@@ -5370,7 +5459,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
|
||||
}
|
||||
|
||||
pPage = pCur->apPage[pCur->iPage];
|
||||
idx = ++pCur->aiIdx[pCur->iPage];
|
||||
idx = ++pCur->ix;
|
||||
assert( pPage->isInit );
|
||||
|
||||
/* If the database file is corrupt, it is possible for the value of idx
|
||||
@@ -5394,7 +5483,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
|
||||
}
|
||||
moveToParent(pCur);
|
||||
pPage = pCur->apPage[pCur->iPage];
|
||||
}while( pCur->aiIdx[pCur->iPage]>=pPage->nCell );
|
||||
}while( pCur->ix>=pPage->nCell );
|
||||
if( pPage->intKey ){
|
||||
return sqlite3BtreeNext(pCur, pRes);
|
||||
}else{
|
||||
@@ -5418,8 +5507,8 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
||||
*pRes = 0;
|
||||
if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur, pRes);
|
||||
pPage = pCur->apPage[pCur->iPage];
|
||||
if( (++pCur->aiIdx[pCur->iPage])>=pPage->nCell ){
|
||||
pCur->aiIdx[pCur->iPage]--;
|
||||
if( (++pCur->ix)>=pPage->nCell ){
|
||||
pCur->ix--;
|
||||
return btreeNext(pCur, pRes);
|
||||
}
|
||||
if( pPage->leaf ){
|
||||
@@ -5483,12 +5572,12 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
|
||||
pPage = pCur->apPage[pCur->iPage];
|
||||
assert( pPage->isInit );
|
||||
if( !pPage->leaf ){
|
||||
int idx = pCur->aiIdx[pCur->iPage];
|
||||
int idx = pCur->ix;
|
||||
rc = moveToChild(pCur, get4byte(findCell(pPage, idx)));
|
||||
if( rc ) return rc;
|
||||
rc = moveToRightmost(pCur);
|
||||
}else{
|
||||
while( pCur->aiIdx[pCur->iPage]==0 ){
|
||||
while( pCur->ix==0 ){
|
||||
if( pCur->iPage==0 ){
|
||||
pCur->eState = CURSOR_INVALID;
|
||||
*pRes = 1;
|
||||
@@ -5499,7 +5588,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
|
||||
assert( pCur->info.nSize==0 );
|
||||
assert( (pCur->curFlags & (BTCF_ValidOvfl))==0 );
|
||||
|
||||
pCur->aiIdx[pCur->iPage]--;
|
||||
pCur->ix--;
|
||||
pPage = pCur->apPage[pCur->iPage];
|
||||
if( pPage->intKey && !pPage->leaf ){
|
||||
rc = sqlite3BtreePrevious(pCur, pRes);
|
||||
@@ -5518,12 +5607,12 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
|
||||
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey);
|
||||
pCur->info.nSize = 0;
|
||||
if( pCur->eState!=CURSOR_VALID
|
||||
|| pCur->aiIdx[pCur->iPage]==0
|
||||
|| pCur->ix==0
|
||||
|| pCur->apPage[pCur->iPage]->leaf==0
|
||||
){
|
||||
return btreePrevious(pCur, pRes);
|
||||
}
|
||||
pCur->aiIdx[pCur->iPage]--;
|
||||
pCur->ix--;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -7689,7 +7778,7 @@ static int balance_nonroot(
|
||||
** free space needs to be up front.
|
||||
*/
|
||||
assert( nNew==1 || CORRUPT_DB );
|
||||
rc = defragmentPage(apNew[0]);
|
||||
rc = defragmentPage(apNew[0], -1);
|
||||
testcase( rc!=SQLITE_OK );
|
||||
assert( apNew[0]->nFree ==
|
||||
(get2byte(&apNew[0]->aData[5])-apNew[0]->cellOffset-apNew[0]->nCell*2)
|
||||
@@ -7845,8 +7934,8 @@ static int balance(BtCursor *pCur){
|
||||
rc = balance_deeper(pPage, &pCur->apPage[1]);
|
||||
if( rc==SQLITE_OK ){
|
||||
pCur->iPage = 1;
|
||||
pCur->ix = 0;
|
||||
pCur->aiIdx[0] = 0;
|
||||
pCur->aiIdx[1] = 0;
|
||||
assert( pCur->apPage[1]->nOverflow );
|
||||
}
|
||||
}else{
|
||||
@@ -8023,7 +8112,7 @@ int sqlite3BtreeInsert(
|
||||
assert( pX->pKey==0 );
|
||||
/* If this is an insert into a table b-tree, invalidate any incrblob
|
||||
** cursors open on the row being replaced */
|
||||
invalidateIncrblobCursors(p, pX->nKey, 0);
|
||||
invalidateIncrblobCursors(p, pCur->pgnoRoot, pX->nKey, 0);
|
||||
|
||||
/* If BTREE_SAVEPOSITION is set, the cursor must already be pointing
|
||||
** to a row with the same key as the new entry being inserted. */
|
||||
@@ -8075,7 +8164,7 @@ int sqlite3BtreeInsert(
|
||||
if( rc ) goto end_insert;
|
||||
assert( szNew==pPage->xCellSize(pPage, newCell) );
|
||||
assert( szNew <= MX_CELL_SIZE(pBt) );
|
||||
idx = pCur->aiIdx[pCur->iPage];
|
||||
idx = pCur->ix;
|
||||
if( loc==0 ){
|
||||
CellInfo info;
|
||||
assert( idx<pPage->nCell );
|
||||
@@ -8103,7 +8192,7 @@ int sqlite3BtreeInsert(
|
||||
if( rc ) goto end_insert;
|
||||
}else if( loc<0 && pPage->nCell>0 ){
|
||||
assert( pPage->leaf );
|
||||
idx = ++pCur->aiIdx[pCur->iPage];
|
||||
idx = ++pCur->ix;
|
||||
}else{
|
||||
assert( pPage->leaf );
|
||||
}
|
||||
@@ -8199,12 +8288,12 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
||||
assert( pCur->curFlags & BTCF_WriteFlag );
|
||||
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
|
||||
assert( !hasReadConflicts(p, pCur->pgnoRoot) );
|
||||
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
|
||||
assert( pCur->ix<pCur->apPage[pCur->iPage]->nCell );
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 );
|
||||
|
||||
iCellDepth = pCur->iPage;
|
||||
iCellIdx = pCur->aiIdx[iCellDepth];
|
||||
iCellIdx = pCur->ix;
|
||||
pPage = pCur->apPage[iCellDepth];
|
||||
pCell = findCell(pPage, iCellIdx);
|
||||
|
||||
@@ -8253,7 +8342,7 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
||||
/* If this is a delete operation to remove a row from a table b-tree,
|
||||
** invalidate any incrblob cursors open on the row being deleted. */
|
||||
if( pCur->pKeyInfo==0 ){
|
||||
invalidateIncrblobCursors(p, pCur->info.nKey, 0);
|
||||
invalidateIncrblobCursors(p, pCur->pgnoRoot, pCur->info.nKey, 0);
|
||||
}
|
||||
|
||||
/* Make the page containing the entry to be deleted writable. Then free any
|
||||
@@ -8321,7 +8410,7 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
||||
pCur->eState = CURSOR_SKIPNEXT;
|
||||
if( iCellIdx>=pPage->nCell ){
|
||||
pCur->skipNext = -1;
|
||||
pCur->aiIdx[iCellDepth] = pPage->nCell-1;
|
||||
pCur->ix = pPage->nCell-1;
|
||||
}else{
|
||||
pCur->skipNext = 1;
|
||||
}
|
||||
@@ -8580,7 +8669,7 @@ int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){
|
||||
/* Invalidate all incrblob cursors open on table iTable (assuming iTable
|
||||
** is the root of a table b-tree - if it is not, the following call is
|
||||
** a no-op). */
|
||||
invalidateIncrblobCursors(p, 0, 1);
|
||||
invalidateIncrblobCursors(p, (Pgno)iTable, 0, 1);
|
||||
rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange);
|
||||
}
|
||||
sqlite3BtreeLeave(p);
|
||||
@@ -8834,16 +8923,16 @@ int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
|
||||
return moveToRoot(pCur);
|
||||
}
|
||||
moveToParent(pCur);
|
||||
}while ( pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell );
|
||||
}while ( pCur->ix>=pCur->apPage[pCur->iPage]->nCell );
|
||||
|
||||
pCur->aiIdx[pCur->iPage]++;
|
||||
pCur->ix++;
|
||||
pPage = pCur->apPage[pCur->iPage];
|
||||
}
|
||||
|
||||
/* Descend to the child node of the cell that the cursor currently
|
||||
** points at. This is the right-child if (iIdx==pPage->nCell).
|
||||
*/
|
||||
iIdx = pCur->aiIdx[pCur->iPage];
|
||||
iIdx = pCur->ix;
|
||||
if( iIdx==pPage->nCell ){
|
||||
rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
|
||||
}else{
|
||||
|
||||
@@ -296,6 +296,7 @@ u32 sqlite3BtreePayloadSize(BtCursor*);
|
||||
|
||||
char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
|
||||
struct Pager *sqlite3BtreePager(Btree*);
|
||||
i64 sqlite3BtreeRowCountEst(BtCursor*);
|
||||
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
int sqlite3BtreePayloadChecked(BtCursor*, u32 offset, u32 amt, void*);
|
||||
|
||||
+4
-4
@@ -517,10 +517,10 @@ struct BtCursor {
|
||||
** initialized. */
|
||||
i8 iPage; /* Index of current page in apPage */
|
||||
u8 curIntKey; /* Value of apPage[0]->intKey */
|
||||
struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
|
||||
void *padding1; /* Make object size a multiple of 16 */
|
||||
u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */
|
||||
MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
|
||||
u16 ix; /* Current index for apPage[iPage] */
|
||||
u16 aiIdx[BTCURSOR_MAX_DEPTH-1]; /* Current index in apPage[i] */
|
||||
struct KeyInfo *pKeyInfo; /* Arg passed to comparison function */
|
||||
MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+6
-2
@@ -1115,6 +1115,7 @@ void sqlite3AddNotNull(Parse *pParse, int onError){
|
||||
p = pParse->pNewTable;
|
||||
if( p==0 || NEVER(p->nCol<1) ) return;
|
||||
p->aCol[p->nCol-1].notNull = (u8)onError;
|
||||
p->tabFlags |= TF_HasNotNull;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3454,6 +3455,9 @@ void sqlite3DefaultRowEst(Index *pIdx){
|
||||
int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol);
|
||||
int i;
|
||||
|
||||
/* Indexes with default row estimates should not have stat1 data */
|
||||
assert( !pIdx->hasStat1 );
|
||||
|
||||
/* Set the first entry (number of rows in the index) to the estimated
|
||||
** number of rows in the table, or half the number of rows in the table
|
||||
** for a partial index. But do not let the estimate drop below 10. */
|
||||
@@ -3619,7 +3623,7 @@ void sqlite3IdListDelete(sqlite3 *db, IdList *pList){
|
||||
sqlite3DbFree(db, pList->a[i].zName);
|
||||
}
|
||||
sqlite3DbFree(db, pList->a);
|
||||
sqlite3DbFree(db, pList);
|
||||
sqlite3DbFreeNN(db, pList);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3809,7 +3813,7 @@ void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
|
||||
sqlite3ExprDelete(db, pItem->pOn);
|
||||
sqlite3IdListDelete(db, pItem->pUsing);
|
||||
}
|
||||
sqlite3DbFree(db, pList);
|
||||
sqlite3DbFreeNN(db, pList);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -66,6 +66,12 @@ static const char * const azCompileOpt[] = {
|
||||
#if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc)
|
||||
"DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE),
|
||||
#endif
|
||||
#if SQLITE_DEFAULT_SYNCHRONOUS
|
||||
"DEFAULT_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_SYNCHRONOUS),
|
||||
#endif
|
||||
#if SQLITE_DEFAULT_WAL_SYNCHRONOUS
|
||||
"DEFAULT_WAL_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_SYNCHRONOUS),
|
||||
#endif
|
||||
#if SQLITE_DIRECT_OVERFLOW_READ
|
||||
"DIRECT_OVERFLOW_READ",
|
||||
#endif
|
||||
|
||||
+2
-1
@@ -743,18 +743,19 @@ static int parseModifier(
|
||||
** or month or year.
|
||||
*/
|
||||
if( sqlite3_strnicmp(z, "start of ", 9)!=0 ) break;
|
||||
if( !p->validJD && !p->validYMD && !p->validHMS ) break;
|
||||
z += 9;
|
||||
computeYMD(p);
|
||||
p->validHMS = 1;
|
||||
p->h = p->m = 0;
|
||||
p->s = 0.0;
|
||||
p->rawS = 0;
|
||||
p->validTZ = 0;
|
||||
p->validJD = 0;
|
||||
if( sqlite3_stricmp(z,"month")==0 ){
|
||||
p->D = 1;
|
||||
rc = 0;
|
||||
}else if( sqlite3_stricmp(z,"year")==0 ){
|
||||
computeYMD(p);
|
||||
p->M = 1;
|
||||
p->D = 1;
|
||||
rc = 0;
|
||||
|
||||
+37
-44
@@ -1038,7 +1038,7 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
|
||||
}
|
||||
if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken);
|
||||
if( !ExprHasProperty(p, EP_Static) ){
|
||||
sqlite3DbFree(db, p);
|
||||
sqlite3DbFreeNN(db, p);
|
||||
}
|
||||
}
|
||||
void sqlite3ExprDelete(sqlite3 *db, Expr *p){
|
||||
@@ -1305,15 +1305,11 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
|
||||
Expr *pPriorSelectCol = 0;
|
||||
assert( db!=0 );
|
||||
if( p==0 ) return 0;
|
||||
pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
|
||||
pNew = sqlite3DbMallocRawNN(db,
|
||||
sizeof(*pNew)+sizeof(pNew->a[0])*(p->nExpr-1) );
|
||||
if( pNew==0 ) return 0;
|
||||
pNew->nExpr = i = p->nExpr;
|
||||
if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; i<p->nExpr; i+=i){}
|
||||
pNew->a = pItem = sqlite3DbMallocRawNN(db, i*sizeof(p->a[0]) );
|
||||
if( pItem==0 ){
|
||||
sqlite3DbFree(db, pNew);
|
||||
return 0;
|
||||
}
|
||||
pNew->nAlloc = pNew->nExpr = p->nExpr;
|
||||
pItem = pNew->a;
|
||||
pOldItem = p->a;
|
||||
for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){
|
||||
Expr *pOldExpr = pOldItem->pExpr;
|
||||
@@ -1404,7 +1400,7 @@ IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
|
||||
pNew->nId = p->nId;
|
||||
pNew->a = sqlite3DbMallocRawNN(db, p->nId*sizeof(p->a[0]) );
|
||||
if( pNew->a==0 ){
|
||||
sqlite3DbFree(db, pNew);
|
||||
sqlite3DbFreeNN(db, pNew);
|
||||
return 0;
|
||||
}
|
||||
/* Note that because the size of the allocation for p->a[] is not
|
||||
@@ -1475,6 +1471,7 @@ ExprList *sqlite3ExprListAppend(
|
||||
ExprList *pList, /* List to which to append. Might be NULL */
|
||||
Expr *pExpr /* Expression to be appended. Might be NULL */
|
||||
){
|
||||
struct ExprList_item *pItem;
|
||||
sqlite3 *db = pParse->db;
|
||||
assert( db!=0 );
|
||||
if( pList==0 ){
|
||||
@@ -1483,23 +1480,20 @@ ExprList *sqlite3ExprListAppend(
|
||||
goto no_mem;
|
||||
}
|
||||
pList->nExpr = 0;
|
||||
pList->a = sqlite3DbMallocRawNN(db, sizeof(pList->a[0]));
|
||||
if( pList->a==0 ) goto no_mem;
|
||||
}else if( (pList->nExpr & (pList->nExpr-1))==0 ){
|
||||
struct ExprList_item *a;
|
||||
assert( pList->nExpr>0 );
|
||||
a = sqlite3DbRealloc(db, pList->a, pList->nExpr*2*sizeof(pList->a[0]));
|
||||
if( a==0 ){
|
||||
pList->nAlloc = 1;
|
||||
}else if( pList->nExpr==pList->nAlloc ){
|
||||
ExprList *pNew;
|
||||
pNew = sqlite3DbRealloc(db, pList,
|
||||
sizeof(*pList)+(2*pList->nAlloc - 1)*sizeof(pList->a[0]));
|
||||
if( pNew==0 ){
|
||||
goto no_mem;
|
||||
}
|
||||
pList->a = a;
|
||||
}
|
||||
assert( pList->a!=0 );
|
||||
if( 1 ){
|
||||
struct ExprList_item *pItem = &pList->a[pList->nExpr++];
|
||||
memset(pItem, 0, sizeof(*pItem));
|
||||
pItem->pExpr = pExpr;
|
||||
pList = pNew;
|
||||
pList->nAlloc *= 2;
|
||||
}
|
||||
pItem = &pList->a[pList->nExpr++];
|
||||
memset(pItem, 0, sizeof(*pItem));
|
||||
pItem->pExpr = pExpr;
|
||||
return pList;
|
||||
|
||||
no_mem:
|
||||
@@ -1556,20 +1550,19 @@ ExprList *sqlite3ExprListAppendVector(
|
||||
}
|
||||
}
|
||||
|
||||
if( pExpr->op==TK_SELECT ){
|
||||
if( pList && pList->a[iFirst].pExpr ){
|
||||
Expr *pFirst = pList->a[iFirst].pExpr;
|
||||
assert( pFirst->op==TK_SELECT_COLUMN );
|
||||
if( pExpr->op==TK_SELECT && pList ){
|
||||
Expr *pFirst = pList->a[iFirst].pExpr;
|
||||
assert( pFirst!=0 );
|
||||
assert( pFirst->op==TK_SELECT_COLUMN );
|
||||
|
||||
/* Store the SELECT statement in pRight so it will be deleted when
|
||||
** sqlite3ExprListDelete() is called */
|
||||
pFirst->pRight = pExpr;
|
||||
pExpr = 0;
|
||||
/* Store the SELECT statement in pRight so it will be deleted when
|
||||
** sqlite3ExprListDelete() is called */
|
||||
pFirst->pRight = pExpr;
|
||||
pExpr = 0;
|
||||
|
||||
/* Remember the size of the LHS in iTable so that we can check that
|
||||
** the RHS and LHS sizes match during code generation. */
|
||||
pFirst->iTable = pColumns->nId;
|
||||
}
|
||||
/* Remember the size of the LHS in iTable so that we can check that
|
||||
** the RHS and LHS sizes match during code generation. */
|
||||
pFirst->iTable = pColumns->nId;
|
||||
}
|
||||
|
||||
vector_append_error:
|
||||
@@ -1663,16 +1656,16 @@ void sqlite3ExprListCheckLength(
|
||||
** Delete an entire expression list.
|
||||
*/
|
||||
static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){
|
||||
int i;
|
||||
struct ExprList_item *pItem;
|
||||
assert( pList->a!=0 || pList->nExpr==0 );
|
||||
for(pItem=pList->a, i=0; i<pList->nExpr; i++, pItem++){
|
||||
int i = pList->nExpr;
|
||||
struct ExprList_item *pItem = pList->a;
|
||||
assert( pList->nExpr>0 );
|
||||
do{
|
||||
sqlite3ExprDelete(db, pItem->pExpr);
|
||||
sqlite3DbFree(db, pItem->zName);
|
||||
sqlite3DbFree(db, pItem->zSpan);
|
||||
}
|
||||
sqlite3DbFree(db, pList->a);
|
||||
sqlite3DbFree(db, pList);
|
||||
pItem++;
|
||||
}while( --i>0 );
|
||||
sqlite3DbFreeNN(db, pList);
|
||||
}
|
||||
void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
|
||||
if( pList ) exprListDeleteNN(db, pList);
|
||||
@@ -1860,6 +1853,7 @@ int sqlite3ExprContainsSubquery(Expr *p){
|
||||
*/
|
||||
int sqlite3ExprIsInteger(Expr *p, int *pValue){
|
||||
int rc = 0;
|
||||
if( p==0 ) return 0; /* Can only happen following on OOM */
|
||||
|
||||
/* If an expression is an integer literal that fits in a signed 32-bit
|
||||
** integer, then the EP_IntValue flag will have already been set */
|
||||
@@ -2532,7 +2526,6 @@ int sqlite3CodeSubselect(
|
||||
int i;
|
||||
sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
|
||||
dest.zAffSdst = exprINAffinity(pParse, pExpr);
|
||||
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
|
||||
pSelect->iLimit = 0;
|
||||
testcase( pSelect->selFlags & SF_Distinct );
|
||||
testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
|
||||
|
||||
+1
-3
@@ -204,15 +204,13 @@ static void instrFunc(
|
||||
if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){
|
||||
zHaystack = sqlite3_value_blob(argv[0]);
|
||||
zNeedle = sqlite3_value_blob(argv[1]);
|
||||
assert( zNeedle!=0 );
|
||||
assert( zHaystack!=0 || nHaystack==0 );
|
||||
isText = 0;
|
||||
}else{
|
||||
zHaystack = sqlite3_value_text(argv[0]);
|
||||
zNeedle = sqlite3_value_text(argv[1]);
|
||||
isText = 1;
|
||||
if( zHaystack==0 || zNeedle==0 ) return;
|
||||
}
|
||||
if( zNeedle==0 || (nHaystack && zHaystack==0) ) return;
|
||||
while( nNeedle<=nHaystack && memcmp(zHaystack, zNeedle, nNeedle)!=0 ){
|
||||
N++;
|
||||
do{
|
||||
|
||||
@@ -2227,8 +2227,6 @@ static int xferOptimization(
|
||||
** sorted order. */
|
||||
for(i=0; i<pSrcIdx->nColumn; i++){
|
||||
const char *zColl = pSrcIdx->azColl[i];
|
||||
assert( sqlite3_stricmp(sqlite3StrBINARY, zColl)!=0
|
||||
|| sqlite3StrBINARY==zColl );
|
||||
if( sqlite3_stricmp(sqlite3StrBINARY, zColl) ) break;
|
||||
}
|
||||
if( i==pSrcIdx->nColumn ){
|
||||
|
||||
+3
-1
@@ -421,7 +421,9 @@ static const sqlite3_api_routines sqlite3Apis = {
|
||||
sqlite3_system_errno,
|
||||
/* Version 3.14.0 and later */
|
||||
sqlite3_trace_v2,
|
||||
sqlite3_expanded_sql
|
||||
sqlite3_expanded_sql,
|
||||
/* Version 3.18.0 and later */
|
||||
sqlite3_set_last_insert_rowid
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+15
@@ -921,6 +921,21 @@ sqlite_int64 sqlite3_last_insert_rowid(sqlite3 *db){
|
||||
return db->lastRowid;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the value returned by the sqlite3_last_insert_rowid() API function.
|
||||
*/
|
||||
void sqlite3_set_last_insert_rowid(sqlite3 *db, sqlite3_int64 iRowid){
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( !sqlite3SafetyCheckOk(db) ){
|
||||
(void)SQLITE_MISUSE_BKPT;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
db->lastRowid = iRowid;
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of changes in the most recent call to sqlite3_exec().
|
||||
*/
|
||||
|
||||
+15
-3
@@ -230,6 +230,13 @@ static void mallocWithAlarm(int n, void **pp){
|
||||
** following xRoundup() call. */
|
||||
nFull = sqlite3GlobalConfig.m.xRoundup(n);
|
||||
|
||||
#ifdef SQLITE_MAX_MEMORY
|
||||
if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)+nFull>SQLITE_MAX_MEMORY ){
|
||||
*pp = 0;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, n);
|
||||
if( mem0.alarmThreshold>0 ){
|
||||
sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
|
||||
@@ -467,11 +474,12 @@ static SQLITE_NOINLINE void measureAllocationSize(sqlite3 *db, void *p){
|
||||
|
||||
/*
|
||||
** Free memory that might be associated with a particular database
|
||||
** connection.
|
||||
** connection. Calling sqlite3DbFree(D,X) for X==0 is a harmless no-op.
|
||||
** The sqlite3DbFreeNN(D,X) version requires that X be non-NULL.
|
||||
*/
|
||||
void sqlite3DbFree(sqlite3 *db, void *p){
|
||||
void sqlite3DbFreeNN(sqlite3 *db, void *p){
|
||||
assert( db==0 || sqlite3_mutex_held(db->mutex) );
|
||||
if( p==0 ) return;
|
||||
assert( p!=0 );
|
||||
if( db ){
|
||||
if( db->pnBytesFreed ){
|
||||
measureAllocationSize(db, p);
|
||||
@@ -495,6 +503,10 @@ void sqlite3DbFree(sqlite3 *db, void *p){
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
|
||||
sqlite3_free(p);
|
||||
}
|
||||
void sqlite3DbFree(sqlite3 *db, void *p){
|
||||
assert( db==0 || sqlite3_mutex_held(db->mutex) );
|
||||
if( p ) sqlite3DbFreeNN(db, p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Change the size of an existing memory allocation
|
||||
|
||||
+5
-12
@@ -57,7 +57,9 @@
|
||||
*/
|
||||
#include <sys/sysctl.h>
|
||||
#include <malloc/malloc.h>
|
||||
#ifdef SQLITE_MIGHT_BE_SINGLE_CORE
|
||||
#include <libkern/OSAtomic.h>
|
||||
#endif /* SQLITE_MIGHT_BE_SINGLE_CORE */
|
||||
static malloc_zone_t* _sqliteZone_;
|
||||
#define SQLITE_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x))
|
||||
#define SQLITE_FREE(x) malloc_zone_free(_sqliteZone_, (x));
|
||||
@@ -250,19 +252,10 @@ static int sqlite3MemInit(void *NotUsed){
|
||||
}else{
|
||||
/* only 1 core, use our own zone to contention over global locks,
|
||||
** e.g. we have our own dedicated locks */
|
||||
bool success;
|
||||
malloc_zone_t* newzone = malloc_create_zone(4096, 0);
|
||||
malloc_set_zone_name(newzone, "Sqlite_Heap");
|
||||
do{
|
||||
success = OSAtomicCompareAndSwapPtrBarrier(NULL, newzone,
|
||||
(void * volatile *)&_sqliteZone_);
|
||||
}while(!_sqliteZone_);
|
||||
if( !success ){
|
||||
/* somebody registered a zone first */
|
||||
malloc_destroy_zone(newzone);
|
||||
}
|
||||
_sqliteZone_ = malloc_create_zone(4096, 0);
|
||||
malloc_set_zone_name(_sqliteZone_, "Sqlite_Heap");
|
||||
}
|
||||
#endif
|
||||
#endif /* defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC) */
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
+1
-1
@@ -899,7 +899,7 @@ term(A) ::= INTEGER(X). {
|
||||
A.pExpr = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &X, 1);
|
||||
A.zStart = X.z;
|
||||
A.zEnd = X.z + X.n;
|
||||
if( A.pExpr ) A.pExpr->flags |= EP_Leaf;
|
||||
if( A.pExpr ) A.pExpr->flags |= EP_Leaf|EP_Resolved;
|
||||
}
|
||||
expr(A) ::= VARIABLE(X). {
|
||||
if( !(X.z[0]=='#' && sqlite3Isdigit(X.z[1])) ){
|
||||
|
||||
+3
-4
@@ -285,8 +285,7 @@ static int pcache1InitBulk(PCache1 *pCache){
|
||||
sqlite3EndBenignMalloc();
|
||||
if( zBulk ){
|
||||
int nBulk = sqlite3MallocSize(zBulk)/pCache->szAlloc;
|
||||
int i;
|
||||
for(i=0; i<nBulk; i++){
|
||||
do{
|
||||
PgHdr1 *pX = (PgHdr1*)&zBulk[pCache->szPage];
|
||||
pX->page.pBuf = zBulk;
|
||||
pX->page.pExtra = &pX[1];
|
||||
@@ -295,7 +294,7 @@ static int pcache1InitBulk(PCache1 *pCache){
|
||||
pX->pNext = pCache->pFree;
|
||||
pCache->pFree = pX;
|
||||
zBulk += pCache->szAlloc;
|
||||
}
|
||||
}while( --nBulk );
|
||||
}
|
||||
return pCache->pFree!=0;
|
||||
}
|
||||
@@ -1211,7 +1210,7 @@ int sqlite3PcacheReleaseMemory(int nReq){
|
||||
int nFree = 0;
|
||||
assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
|
||||
assert( sqlite3_mutex_notheld(pcache1.mutex) );
|
||||
if( sqlite3GlobalConfig.nPage==0 ){
|
||||
if( sqlite3GlobalConfig.pPage==0 ){
|
||||
PgHdr1 *p;
|
||||
pcache1EnterMutex(&pcache1.grp);
|
||||
while( (nReq<0 || nFree<nReq)
|
||||
|
||||
+199
-70
@@ -296,11 +296,19 @@ static const PragmaName *pragmaLocate(const char *zName){
|
||||
}
|
||||
|
||||
/*
|
||||
** A progress handler callback that interrupts.
|
||||
** Helper subroutine for PRAGMA integrity_check:
|
||||
**
|
||||
** Generate code to output a single-column result row with the result
|
||||
** held in register regResult. Decrement the result count and halt if
|
||||
** the maximum number of result rows have been issued.
|
||||
*/
|
||||
static int interruptProgressHandler(void *pDb){
|
||||
sqlite3_interrupt((sqlite3*)pDb);
|
||||
return 1;
|
||||
static int integrityCheckResultRow(Vdbe *v, int regResult){
|
||||
int addr;
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 1);
|
||||
addr = sqlite3VdbeAddOp3(v, OP_IfPos, 1, sqlite3VdbeCurrentAddr(v)+2, 1);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
|
||||
return addr;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -744,23 +752,6 @@ void sqlite3Pragma(
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** PRAGMA vdbe_cycle_limit=N
|
||||
**
|
||||
** Arrange to interrupt any SQL statement that runs for more than N
|
||||
** virtual machine instructions. If N is zero, allow virtual machines
|
||||
** to run indefinitely.
|
||||
*/
|
||||
case PragTyp_VDBE_CYCLE_LIMIT: {
|
||||
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
||||
if( zRight ){
|
||||
int N = sqlite3Atoi(zRight);
|
||||
sqlite3_progress_handler(db, N, N>0 ? interruptProgressHandler : 0, db);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
/*
|
||||
** PRAGMA [schema.]cache_size
|
||||
@@ -1024,7 +1015,7 @@ void sqlite3Pragma(
|
||||
if( !db->autoCommit ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"Safety level may not be changed inside a transaction");
|
||||
}else{
|
||||
}else if( iDb!=1 ){
|
||||
int iLevel = (getSafetyLevel(zRight,0,1)+1) & PAGER_SYNCHRONOUS_MASK;
|
||||
if( iLevel==0 ) iLevel = 1;
|
||||
pDb->safety_level = iLevel;
|
||||
@@ -1123,29 +1114,33 @@ void sqlite3Pragma(
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
case PragTyp_STATS: {
|
||||
Index *pIdx;
|
||||
HashElem *i;
|
||||
pParse->nMem = 4;
|
||||
pParse->nMem = 5;
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
for(i=sqliteHashFirst(&pDb->pSchema->tblHash); i; i=sqliteHashNext(i)){
|
||||
Table *pTab = sqliteHashData(i);
|
||||
sqlite3VdbeMultiLoad(v, 1, "ssii",
|
||||
sqlite3VdbeMultiLoad(v, 1, "ssiii",
|
||||
pTab->zName,
|
||||
0,
|
||||
pTab->szTabRow,
|
||||
pTab->nRowLogEst);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
|
||||
pTab->nRowLogEst,
|
||||
pTab->tabFlags);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5);
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
sqlite3VdbeMultiLoad(v, 2, "sii",
|
||||
sqlite3VdbeMultiLoad(v, 2, "siii",
|
||||
pIdx->zName,
|
||||
pIdx->szIdxRow,
|
||||
pIdx->aiRowLogEst[0]);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
|
||||
pIdx->aiRowLogEst[0],
|
||||
pIdx->hasStat1);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case PragTyp_INDEX_INFO: if( zRight ){
|
||||
Index *pIdx;
|
||||
@@ -1402,9 +1397,17 @@ void sqlite3Pragma(
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
|
||||
/* Pragma "quick_check" is reduced version of
|
||||
/* PRAGMA integrity_check
|
||||
** PRAGMA integrity_check(N)
|
||||
** PRAGMA quick_check
|
||||
** PRAGMA quick_check(N)
|
||||
**
|
||||
** Verify the integrity of the database.
|
||||
**
|
||||
** The "quick_check" is reduced version of
|
||||
** integrity_check designed to detect most database corruption
|
||||
** without most of the overhead of a full integrity-check.
|
||||
** without the overhead of cross-checking indexes. Quick_check
|
||||
** is linear time wherease integrity_check is O(NlogN).
|
||||
*/
|
||||
case PragTyp_INTEGRITY_CHECK: {
|
||||
int i, j, addr, mxErr;
|
||||
@@ -1435,7 +1438,7 @@ void sqlite3Pragma(
|
||||
mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, mxErr, 1); /* reg[1] holds errors left */
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, mxErr-1, 1); /* reg[1] holds errors left */
|
||||
|
||||
/* Do an integrity check on each database file */
|
||||
for(i=0; i<db->nDb; i++){
|
||||
@@ -1450,10 +1453,6 @@ void sqlite3Pragma(
|
||||
if( iDb>=0 && i!=iDb ) continue;
|
||||
|
||||
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);
|
||||
|
||||
/* Do an integrity check of the B-Tree
|
||||
**
|
||||
@@ -1493,12 +1492,12 @@ void sqlite3Pragma(
|
||||
P4_DYNAMIC);
|
||||
sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1);
|
||||
integrityCheckResultRow(v, 2);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
|
||||
/* Make sure all the indices are constructed correctly.
|
||||
*/
|
||||
for(x=sqliteHashFirst(pTbls); x && !isQuick; x=sqliteHashNext(x)){
|
||||
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
|
||||
Table *pTab = sqliteHashData(x);
|
||||
Index *pIdx, *pPk;
|
||||
Index *pPrior = 0;
|
||||
@@ -1506,12 +1505,14 @@ void sqlite3Pragma(
|
||||
int iDataCur, iIdxCur;
|
||||
int r1 = -1;
|
||||
|
||||
if( pTab->pIndex==0 ) continue;
|
||||
if( pTab->tnum<1 ) continue; /* Skip VIEWs or VIRTUAL TABLEs */
|
||||
if( pTab->pCheck==0
|
||||
&& (pTab->tabFlags & TF_HasNotNull)==0
|
||||
&& (pTab->pIndex==0 || isQuick)
|
||||
){
|
||||
continue; /* No additional checks needed for this table */
|
||||
}
|
||||
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);
|
||||
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
|
||||
1, 0, &iDataCur, &iIdxCur);
|
||||
@@ -1526,24 +1527,45 @@ void sqlite3Pragma(
|
||||
/* Verify that all NOT NULL columns really are NOT NULL */
|
||||
for(j=0; j<pTab->nCol; j++){
|
||||
char *zErr;
|
||||
int jmp2, jmp3;
|
||||
int jmp2;
|
||||
if( j==pTab->iPKey ) continue;
|
||||
if( pTab->aCol[j].notNull==0 ) continue;
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
|
||||
jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
|
||||
zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
|
||||
pTab->aCol[j].zName);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
|
||||
jmp3 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp0(v, OP_Halt);
|
||||
integrityCheckResultRow(v, 3);
|
||||
sqlite3VdbeJumpHere(v, jmp2);
|
||||
sqlite3VdbeJumpHere(v, jmp3);
|
||||
}
|
||||
/* Verify CHECK constraints */
|
||||
if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
|
||||
ExprList *pCheck = sqlite3ExprListDup(db, pTab->pCheck, 0);
|
||||
if( db->mallocFailed==0 ){
|
||||
int addrCkFault = sqlite3VdbeMakeLabel(v);
|
||||
int addrCkOk = sqlite3VdbeMakeLabel(v);
|
||||
char *zErr;
|
||||
int k;
|
||||
pParse->iSelfTab = iDataCur;
|
||||
sqlite3ExprCachePush(pParse);
|
||||
for(k=pCheck->nExpr-1; k>0; k--){
|
||||
sqlite3ExprIfFalse(pParse, pCheck->a[k].pExpr, addrCkFault, 0);
|
||||
}
|
||||
sqlite3ExprIfTrue(pParse, pCheck->a[0].pExpr, addrCkOk,
|
||||
SQLITE_JUMPIFNULL);
|
||||
sqlite3VdbeResolveLabel(v, addrCkFault);
|
||||
zErr = sqlite3MPrintf(db, "CHECK constraint failed in %s",
|
||||
pTab->zName);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
|
||||
integrityCheckResultRow(v, 3);
|
||||
sqlite3VdbeResolveLabel(v, addrCkOk);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
}
|
||||
sqlite3ExprListDelete(db, pCheck);
|
||||
}
|
||||
/* Validate index entries for the current row */
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx && !isQuick; pIdx=pIdx->pNext, j++){
|
||||
int jmp2, jmp3, jmp4, jmp5;
|
||||
int ckUniq = sqlite3VdbeMakeLabel(v);
|
||||
if( pPk==pIdx ) continue;
|
||||
@@ -1554,16 +1576,13 @@ void sqlite3Pragma(
|
||||
/* Verify that an index entry exists for the current table row */
|
||||
jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1,
|
||||
pIdx->nColumn); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
|
||||
sqlite3VdbeLoadString(v, 3, "row ");
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
|
||||
sqlite3VdbeLoadString(v, 4, " missing from index ");
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
|
||||
jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
|
||||
jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp0(v, OP_Halt);
|
||||
jmp4 = integrityCheckResultRow(v, 3);
|
||||
sqlite3VdbeJumpHere(v, jmp2);
|
||||
/* For UNIQUE indexes, verify that only one entry exists with the
|
||||
** current key. The entry is unique if (1) any column is NULL
|
||||
@@ -1584,7 +1603,6 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeJumpHere(v, jmp6);
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1,
|
||||
pIdx->nKeyCol); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
|
||||
sqlite3VdbeLoadString(v, 3, "non-unique entry in index ");
|
||||
sqlite3VdbeGoto(v, jmp5);
|
||||
sqlite3VdbeResolveLabel(v, uniqOk);
|
||||
@@ -1595,19 +1613,18 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, loopTop-1);
|
||||
#ifndef SQLITE_OMIT_BTREECOUNT
|
||||
sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
|
||||
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); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3);
|
||||
sqlite3VdbeAddOp3(v, OP_Eq, 8+j, addr+8, 3); VdbeCoverage(v);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1);
|
||||
sqlite3VdbeLoadString(v, 3, pIdx->zName);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1);
|
||||
if( !isQuick ){
|
||||
sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
if( pPk==pIdx ) continue;
|
||||
sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3);
|
||||
addr = sqlite3VdbeAddOp3(v, OP_Eq, 8+j, 0, 3); VdbeCoverage(v);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
|
||||
sqlite3VdbeLoadString(v, 3, pIdx->zName);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7);
|
||||
integrityCheckResultRow(v, 7);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_OMIT_BTREECOUNT */
|
||||
}
|
||||
@@ -1616,7 +1633,7 @@ void sqlite3Pragma(
|
||||
static const int iLn = VDBE_OFFSET_LINENO(2);
|
||||
static const VdbeOpList endCode[] = {
|
||||
{ OP_AddImm, 1, 0, 0}, /* 0 */
|
||||
{ OP_If, 1, 4, 0}, /* 1 */
|
||||
{ OP_IfNotZero, 1, 4, 0}, /* 1 */
|
||||
{ OP_String8, 0, 3, 0}, /* 2 */
|
||||
{ OP_ResultRow, 3, 1, 0}, /* 3 */
|
||||
};
|
||||
@@ -1624,7 +1641,7 @@ void sqlite3Pragma(
|
||||
|
||||
aOp = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn);
|
||||
if( aOp ){
|
||||
aOp[0].p2 = -mxErr;
|
||||
aOp[0].p2 = 1-mxErr;
|
||||
aOp[2].p4type = P4_STATIC;
|
||||
aOp[2].p4.z = "ok";
|
||||
}
|
||||
@@ -1849,6 +1866,118 @@ void sqlite3Pragma(
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** PRAGMA optimize
|
||||
** PRAGMA optimize(MASK)
|
||||
** PRAGMA schema.optimize
|
||||
** PRAGMA schema.optimize(MASK)
|
||||
**
|
||||
** Attempt to optimize the database. All schemas are optimized in the first
|
||||
** two forms, and only the specified schema is optimized in the latter two.
|
||||
**
|
||||
** The details of optimizations performed by this pragma are expected
|
||||
** to change and improve over time. Applications should anticipate that
|
||||
** this pragma will perform new optimizations in future releases.
|
||||
**
|
||||
** The optional argument is a bitmask of optimizations to perform:
|
||||
**
|
||||
** 0x0001 Debugging mode. Do not actually perform any optimizations
|
||||
** but instead return one line of text for each optimization
|
||||
** that would have been done. Off by default.
|
||||
**
|
||||
** 0x0002 Run ANALYZE on tables that might benefit. On by default.
|
||||
** See below for additional information.
|
||||
**
|
||||
** 0x0004 (Not yet implemented) Record usage and performance
|
||||
** information from the current session in the
|
||||
** database file so that it will be available to "optimize"
|
||||
** pragmas run by future database connections.
|
||||
**
|
||||
** 0x0008 (Not yet implemented) Create indexes that might have
|
||||
** been helpful to recent queries
|
||||
**
|
||||
** The default MASK is and always shall be 0xfffe. 0xfffe means perform all ** of the optimizations listed above except Debug Mode, including new
|
||||
** optimizations that have not yet been invented. If new optimizations are
|
||||
** ever added that should be off by default, those off-by-default
|
||||
** optimizations will have bitmasks of 0x10000 or larger.
|
||||
**
|
||||
** DETERMINATION OF WHEN TO RUN ANALYZE
|
||||
**
|
||||
** In the current implementation, a table is analyzed if only if all of
|
||||
** the following are true:
|
||||
**
|
||||
** (1) MASK bit 0x02 is set.
|
||||
**
|
||||
** (2) The query planner used sqlite_stat1-style statistics for one or
|
||||
** more indexes of the table at some point during the lifetime of
|
||||
** the current connection.
|
||||
**
|
||||
** (3) One or more indexes of the table are currently unanalyzed OR
|
||||
** the number of rows in the table has increased by 25 times or more
|
||||
** since the last time ANALYZE was run.
|
||||
**
|
||||
** The rules for when tables are analyzed are likely to change in
|
||||
** future releases.
|
||||
*/
|
||||
case PragTyp_OPTIMIZE: {
|
||||
int iDbLast; /* Loop termination point for the schema loop */
|
||||
int iTabCur; /* Cursor for a table whose size needs checking */
|
||||
HashElem *k; /* Loop over tables of a schema */
|
||||
Schema *pSchema; /* The current schema */
|
||||
Table *pTab; /* A table in the schema */
|
||||
Index *pIdx; /* An index of the table */
|
||||
LogEst szThreshold; /* Size threshold above which reanalysis is needd */
|
||||
char *zSubSql; /* SQL statement for the OP_SqlExec opcode */
|
||||
u32 opMask; /* Mask of operations to perform */
|
||||
|
||||
if( zRight ){
|
||||
opMask = (u32)sqlite3Atoi(zRight);
|
||||
if( (opMask & 0x02)==0 ) break;
|
||||
}else{
|
||||
opMask = 0xfffe;
|
||||
}
|
||||
iTabCur = pParse->nTab++;
|
||||
for(iDbLast = zDb?iDb:db->nDb-1; iDb<=iDbLast; iDb++){
|
||||
if( iDb==1 ) continue;
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
pSchema = db->aDb[iDb].pSchema;
|
||||
for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
|
||||
pTab = (Table*)sqliteHashData(k);
|
||||
|
||||
/* If table pTab has not been used in a way that would benefit from
|
||||
** having analysis statistics during the current session, then skip it.
|
||||
** This also has the effect of skipping virtual tables and views */
|
||||
if( (pTab->tabFlags & TF_StatsUsed)==0 ) continue;
|
||||
|
||||
/* Reanalyze if the table is 25 times larger than the last analysis */
|
||||
szThreshold = pTab->nRowLogEst + 46; assert( sqlite3LogEst(25)==46 );
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( !pIdx->hasStat1 ){
|
||||
szThreshold = 0; /* Always analyze if any index lacks statistics */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( szThreshold ){
|
||||
sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
|
||||
sqlite3VdbeAddOp3(v, OP_IfSmaller, iTabCur,
|
||||
sqlite3VdbeCurrentAddr(v)+2+(opMask&1), szThreshold);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
zSubSql = sqlite3MPrintf(db, "ANALYZE \"%w\".\"%w\"",
|
||||
db->aDb[iDb].zDbSName, pTab->zName);
|
||||
if( opMask & 0x01 ){
|
||||
int r1 = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, r1, 0, zSubSql, P4_DYNAMIC);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, r1, 1);
|
||||
}else{
|
||||
sqlite3VdbeAddOp4(v, OP_SqlExec, 0, 0, 0, zSubSql, P4_DYNAMIC);
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp0(v, OP_Expire);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** PRAGMA busy_timeout
|
||||
** PRAGMA busy_timeout = N
|
||||
|
||||
+76
-77
@@ -30,25 +30,25 @@
|
||||
#define PragTyp_LOCKING_MODE 22
|
||||
#define PragTyp_PAGE_COUNT 23
|
||||
#define PragTyp_MMAP_SIZE 24
|
||||
#define PragTyp_PAGE_SIZE 25
|
||||
#define PragTyp_SECURE_DELETE 26
|
||||
#define PragTyp_SHRINK_MEMORY 27
|
||||
#define PragTyp_SOFT_HEAP_LIMIT 28
|
||||
#define PragTyp_STATS 29
|
||||
#define PragTyp_OPTIMIZE 25
|
||||
#define PragTyp_PAGE_SIZE 26
|
||||
#define PragTyp_SECURE_DELETE 27
|
||||
#define PragTyp_SHRINK_MEMORY 28
|
||||
#define PragTyp_SOFT_HEAP_LIMIT 29
|
||||
#define PragTyp_SYNCHRONOUS 30
|
||||
#define PragTyp_TABLE_INFO 31
|
||||
#define PragTyp_TEMP_STORE 32
|
||||
#define PragTyp_TEMP_STORE_DIRECTORY 33
|
||||
#define PragTyp_THREADS 34
|
||||
#define PragTyp_VDBE_CYCLE_LIMIT 35
|
||||
#define PragTyp_WAL_AUTOCHECKPOINT 36
|
||||
#define PragTyp_WAL_CHECKPOINT 37
|
||||
#define PragTyp_ACTIVATE_EXTENSIONS 38
|
||||
#define PragTyp_HEXKEY 39
|
||||
#define PragTyp_KEY 40
|
||||
#define PragTyp_REKEY 41
|
||||
#define PragTyp_LOCK_STATUS 42
|
||||
#define PragTyp_PARSER_TRACE 43
|
||||
#define PragTyp_WAL_AUTOCHECKPOINT 35
|
||||
#define PragTyp_WAL_CHECKPOINT 36
|
||||
#define PragTyp_ACTIVATE_EXTENSIONS 37
|
||||
#define PragTyp_HEXKEY 38
|
||||
#define PragTyp_KEY 39
|
||||
#define PragTyp_REKEY 40
|
||||
#define PragTyp_LOCK_STATUS 41
|
||||
#define PragTyp_PARSER_TRACE 42
|
||||
#define PragTyp_STATS 43
|
||||
|
||||
/* Property flags associated with various pragma. */
|
||||
#define PragFlg_NeedSchema 0x01 /* Force schema load before running */
|
||||
@@ -72,47 +72,48 @@ static const char *const pragCName[] = {
|
||||
/* 4 */ "notnull",
|
||||
/* 5 */ "dflt_value",
|
||||
/* 6 */ "pk",
|
||||
/* 7 */ "table", /* Used by: stats */
|
||||
/* 8 */ "index",
|
||||
/* 9 */ "width",
|
||||
/* 10 */ "height",
|
||||
/* 11 */ "seqno", /* Used by: index_info */
|
||||
/* 12 */ "cid",
|
||||
/* 13 */ "name",
|
||||
/* 14 */ "seqno", /* Used by: index_xinfo */
|
||||
/* 15 */ "cid",
|
||||
/* 16 */ "name",
|
||||
/* 17 */ "desc",
|
||||
/* 18 */ "coll",
|
||||
/* 19 */ "key",
|
||||
/* 20 */ "seq", /* Used by: index_list */
|
||||
/* 21 */ "name",
|
||||
/* 22 */ "unique",
|
||||
/* 23 */ "origin",
|
||||
/* 24 */ "partial",
|
||||
/* 25 */ "seq", /* Used by: database_list */
|
||||
/* 26 */ "name",
|
||||
/* 27 */ "file",
|
||||
/* 28 */ "seq", /* Used by: collation_list */
|
||||
/* 29 */ "name",
|
||||
/* 30 */ "id", /* Used by: foreign_key_list */
|
||||
/* 31 */ "seq",
|
||||
/* 32 */ "table",
|
||||
/* 33 */ "from",
|
||||
/* 34 */ "to",
|
||||
/* 35 */ "on_update",
|
||||
/* 36 */ "on_delete",
|
||||
/* 37 */ "match",
|
||||
/* 38 */ "table", /* Used by: foreign_key_check */
|
||||
/* 39 */ "rowid",
|
||||
/* 40 */ "parent",
|
||||
/* 41 */ "fkid",
|
||||
/* 42 */ "busy", /* Used by: wal_checkpoint */
|
||||
/* 43 */ "log",
|
||||
/* 44 */ "checkpointed",
|
||||
/* 45 */ "timeout", /* Used by: busy_timeout */
|
||||
/* 46 */ "database", /* Used by: lock_status */
|
||||
/* 47 */ "status",
|
||||
/* 7 */ "tbl", /* Used by: stats */
|
||||
/* 8 */ "idx",
|
||||
/* 9 */ "wdth",
|
||||
/* 10 */ "hght",
|
||||
/* 11 */ "flgs",
|
||||
/* 12 */ "seqno", /* Used by: index_info */
|
||||
/* 13 */ "cid",
|
||||
/* 14 */ "name",
|
||||
/* 15 */ "seqno", /* Used by: index_xinfo */
|
||||
/* 16 */ "cid",
|
||||
/* 17 */ "name",
|
||||
/* 18 */ "desc",
|
||||
/* 19 */ "coll",
|
||||
/* 20 */ "key",
|
||||
/* 21 */ "seq", /* Used by: index_list */
|
||||
/* 22 */ "name",
|
||||
/* 23 */ "unique",
|
||||
/* 24 */ "origin",
|
||||
/* 25 */ "partial",
|
||||
/* 26 */ "seq", /* Used by: database_list */
|
||||
/* 27 */ "name",
|
||||
/* 28 */ "file",
|
||||
/* 29 */ "seq", /* Used by: collation_list */
|
||||
/* 30 */ "name",
|
||||
/* 31 */ "id", /* Used by: foreign_key_list */
|
||||
/* 32 */ "seq",
|
||||
/* 33 */ "table",
|
||||
/* 34 */ "from",
|
||||
/* 35 */ "to",
|
||||
/* 36 */ "on_update",
|
||||
/* 37 */ "on_delete",
|
||||
/* 38 */ "match",
|
||||
/* 39 */ "table", /* Used by: foreign_key_check */
|
||||
/* 40 */ "rowid",
|
||||
/* 41 */ "parent",
|
||||
/* 42 */ "fkid",
|
||||
/* 43 */ "busy", /* Used by: wal_checkpoint */
|
||||
/* 44 */ "log",
|
||||
/* 45 */ "checkpointed",
|
||||
/* 46 */ "timeout", /* Used by: busy_timeout */
|
||||
/* 47 */ "database", /* Used by: lock_status */
|
||||
/* 48 */ "status",
|
||||
};
|
||||
|
||||
/* Definitions of all built-in pragmas */
|
||||
@@ -158,7 +159,7 @@ static const PragmaName aPragmaName[] = {
|
||||
{/* zName: */ "busy_timeout",
|
||||
/* ePragTyp: */ PragTyp_BUSY_TIMEOUT,
|
||||
/* ePragFlg: */ PragFlg_Result0,
|
||||
/* ColNames: */ 45, 1,
|
||||
/* ColNames: */ 46, 1,
|
||||
/* iArg: */ 0 },
|
||||
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
{/* zName: */ "cache_size",
|
||||
@@ -195,7 +196,7 @@ static const PragmaName aPragmaName[] = {
|
||||
{/* zName: */ "collation_list",
|
||||
/* ePragTyp: */ PragTyp_COLLATION_LIST,
|
||||
/* ePragFlg: */ PragFlg_Result0,
|
||||
/* ColNames: */ 28, 2,
|
||||
/* ColNames: */ 29, 2,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
|
||||
@@ -230,7 +231,7 @@ static const PragmaName aPragmaName[] = {
|
||||
{/* zName: */ "database_list",
|
||||
/* ePragTyp: */ PragTyp_DATABASE_LIST,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0,
|
||||
/* ColNames: */ 25, 3,
|
||||
/* ColNames: */ 26, 3,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
|
||||
@@ -267,14 +268,14 @@ static const PragmaName aPragmaName[] = {
|
||||
{/* zName: */ "foreign_key_check",
|
||||
/* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema,
|
||||
/* ColNames: */ 38, 4,
|
||||
/* ColNames: */ 39, 4,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_FOREIGN_KEY)
|
||||
{/* zName: */ "foreign_key_list",
|
||||
/* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
|
||||
/* ColNames: */ 30, 8,
|
||||
/* ColNames: */ 31, 8,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
||||
@@ -337,17 +338,17 @@ static const PragmaName aPragmaName[] = {
|
||||
{/* zName: */ "index_info",
|
||||
/* ePragTyp: */ PragTyp_INDEX_INFO,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
|
||||
/* ColNames: */ 11, 3,
|
||||
/* ColNames: */ 12, 3,
|
||||
/* iArg: */ 0 },
|
||||
{/* zName: */ "index_list",
|
||||
/* ePragTyp: */ PragTyp_INDEX_LIST,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
|
||||
/* ColNames: */ 20, 5,
|
||||
/* ColNames: */ 21, 5,
|
||||
/* iArg: */ 0 },
|
||||
{/* zName: */ "index_xinfo",
|
||||
/* ePragTyp: */ PragTyp_INDEX_INFO,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
|
||||
/* ColNames: */ 14, 6,
|
||||
/* ColNames: */ 15, 6,
|
||||
/* iArg: */ 1 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
|
||||
@@ -394,7 +395,7 @@ static const PragmaName aPragmaName[] = {
|
||||
{/* zName: */ "lock_status",
|
||||
/* ePragTyp: */ PragTyp_LOCK_STATUS,
|
||||
/* ePragFlg: */ PragFlg_Result0,
|
||||
/* ColNames: */ 46, 2,
|
||||
/* ColNames: */ 47, 2,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
@@ -413,6 +414,13 @@ static const PragmaName aPragmaName[] = {
|
||||
/* ePragFlg: */ 0,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
{/* zName: */ "optimize",
|
||||
/* ePragTyp: */ PragTyp_OPTIMIZE,
|
||||
/* ePragFlg: */ PragFlg_Result1|PragFlg_NeedSchema,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ 0 },
|
||||
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
{/* zName: */ "page_count",
|
||||
/* ePragTyp: */ PragTyp_PAGE_COUNT,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
|
||||
@@ -511,11 +519,11 @@ static const PragmaName aPragmaName[] = {
|
||||
/* iArg: */ SQLITE_SqlTrace },
|
||||
#endif
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
|
||||
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG)
|
||||
{/* zName: */ "stats",
|
||||
/* ePragTyp: */ PragTyp_STATS,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
|
||||
/* ColNames: */ 7, 4,
|
||||
/* ColNames: */ 7, 5,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
@@ -563,15 +571,6 @@ static const PragmaName aPragmaName[] = {
|
||||
/* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ SQLITE_VdbeAddopTrace },
|
||||
#endif
|
||||
#endif
|
||||
{/* zName: */ "vdbe_cycle_limit",
|
||||
/* ePragTyp: */ PragTyp_VDBE_CYCLE_LIMIT,
|
||||
/* ePragFlg: */ PragFlg_NoColumns,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ 0 },
|
||||
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
||||
#if defined(SQLITE_DEBUG)
|
||||
{/* zName: */ "vdbe_debug",
|
||||
/* ePragTyp: */ PragTyp_FLAG,
|
||||
/* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
|
||||
@@ -603,7 +602,7 @@ static const PragmaName aPragmaName[] = {
|
||||
{/* zName: */ "wal_checkpoint",
|
||||
/* ePragTyp: */ PragTyp_WAL_CHECKPOINT,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema,
|
||||
/* ColNames: */ 42, 3,
|
||||
/* ColNames: */ 43, 3,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
||||
@@ -614,4 +613,4 @@ static const PragmaName aPragmaName[] = {
|
||||
/* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
|
||||
#endif
|
||||
};
|
||||
/* Number of pragmas: 61 on by default, 74 total. */
|
||||
/* Number of pragmas: 60 on by default, 74 total. */
|
||||
|
||||
+3
-2
@@ -400,12 +400,13 @@ void sqlite3VXPrintf(
|
||||
nOut = etBUFSIZE;
|
||||
zOut = buf;
|
||||
}else{
|
||||
nOut = precision + 10 + precision/3;
|
||||
zOut = zExtra = sqlite3Malloc( nOut );
|
||||
u64 n = (u64)precision + 10 + precision/3;
|
||||
zOut = zExtra = sqlite3Malloc( n );
|
||||
if( zOut==0 ){
|
||||
setStrAccumError(pAccum, STRACCUM_NOMEM);
|
||||
return;
|
||||
}
|
||||
nOut = (int)n;
|
||||
}
|
||||
bufpt = &zOut[nOut-1];
|
||||
if( xtype==etORDINAL ){
|
||||
|
||||
+29
-23
@@ -229,7 +229,8 @@ static int lookupName(
|
||||
}
|
||||
|
||||
/* Start at the inner-most context and move outward until a match is found */
|
||||
while( pNC && cnt==0 ){
|
||||
assert( pNC && cnt==0 );
|
||||
do{
|
||||
ExprList *pEList;
|
||||
SrcList *pSrcList = pNC->pSrcList;
|
||||
|
||||
@@ -414,11 +415,11 @@ static int lookupName(
|
||||
/* Advance to the next name context. The loop will exit when either
|
||||
** we have a match (cnt>0) or when we run out of name contexts.
|
||||
*/
|
||||
if( cnt==0 ){
|
||||
pNC = pNC->pNext;
|
||||
nSubquery++;
|
||||
}
|
||||
}
|
||||
if( cnt ) break;
|
||||
pNC = pNC->pNext;
|
||||
nSubquery++;
|
||||
}while( pNC );
|
||||
|
||||
|
||||
/*
|
||||
** If X and Y are NULL (in other words if only the column name Z is
|
||||
@@ -608,33 +609,38 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT)
|
||||
&& !defined(SQLITE_OMIT_SUBQUERY) */
|
||||
|
||||
/* A lone identifier is the name of a column.
|
||||
*/
|
||||
case TK_ID: {
|
||||
return lookupName(pParse, 0, 0, pExpr->u.zToken, pNC, pExpr);
|
||||
}
|
||||
|
||||
/* A table name and column name: ID.ID
|
||||
/* A column name: ID
|
||||
** Or table name and column name: ID.ID
|
||||
** Or a database, table and column: ID.ID.ID
|
||||
**
|
||||
** The TK_ID and TK_OUT cases are combined so that there will only
|
||||
** be one call to lookupName(). Then the compiler will in-line
|
||||
** lookupName() for a size reduction and performance increase.
|
||||
*/
|
||||
case TK_ID:
|
||||
case TK_DOT: {
|
||||
const char *zColumn;
|
||||
const char *zTable;
|
||||
const char *zDb;
|
||||
Expr *pRight;
|
||||
|
||||
/* if( pSrcList==0 ) break; */
|
||||
notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr);
|
||||
pRight = pExpr->pRight;
|
||||
if( pRight->op==TK_ID ){
|
||||
if( pExpr->op==TK_ID ){
|
||||
zDb = 0;
|
||||
zTable = pExpr->pLeft->u.zToken;
|
||||
zColumn = pRight->u.zToken;
|
||||
zTable = 0;
|
||||
zColumn = pExpr->u.zToken;
|
||||
}else{
|
||||
assert( pRight->op==TK_DOT );
|
||||
zDb = pExpr->pLeft->u.zToken;
|
||||
zTable = pRight->pLeft->u.zToken;
|
||||
zColumn = pRight->pRight->u.zToken;
|
||||
notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr);
|
||||
pRight = pExpr->pRight;
|
||||
if( pRight->op==TK_ID ){
|
||||
zDb = 0;
|
||||
zTable = pExpr->pLeft->u.zToken;
|
||||
zColumn = pRight->u.zToken;
|
||||
}else{
|
||||
assert( pRight->op==TK_DOT );
|
||||
zDb = pExpr->pLeft->u.zToken;
|
||||
zTable = pRight->pLeft->u.zToken;
|
||||
zColumn = pRight->pRight->u.zToken;
|
||||
}
|
||||
}
|
||||
return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr);
|
||||
}
|
||||
|
||||
+6
-4
@@ -76,7 +76,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
|
||||
sqlite3ExprDelete(db, p->pLimit);
|
||||
sqlite3ExprDelete(db, p->pOffset);
|
||||
if( p->pWith ) sqlite3WithDelete(db, p->pWith);
|
||||
if( bFree ) sqlite3DbFree(db, p);
|
||||
if( bFree ) sqlite3DbFreeNN(db, p);
|
||||
p = pPrior;
|
||||
bFree = 1;
|
||||
}
|
||||
@@ -1055,7 +1055,7 @@ void sqlite3KeyInfoUnref(KeyInfo *p){
|
||||
if( p ){
|
||||
assert( p->nRef>0 );
|
||||
p->nRef--;
|
||||
if( p->nRef==0 ) sqlite3DbFree(p->db, p);
|
||||
if( p->nRef==0 ) sqlite3DbFreeNN(p->db, p);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2900,7 +2900,7 @@ static int multiSelectOrderBy(
|
||||
if( pNew==0 ) return SQLITE_NOMEM_BKPT;
|
||||
pNew->flags |= EP_IntValue;
|
||||
pNew->u.iValue = i;
|
||||
pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
|
||||
p->pOrderBy = pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
|
||||
if( pOrderBy ) pOrderBy->a[nOrderBy++].u.x.iOrderByCol = (u16)i;
|
||||
}
|
||||
}
|
||||
@@ -3749,7 +3749,9 @@ static int flattenSubquery(
|
||||
}else{
|
||||
pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere);
|
||||
}
|
||||
substSelect(pParse, pParent, iParent, pSub->pEList, 0);
|
||||
if( db->mallocFailed==0 ){
|
||||
substSelect(pParse, pParent, iParent, pSub->pEList, 0);
|
||||
}
|
||||
|
||||
/* The flattened query is distinct if either the inner or the
|
||||
** outer query is distinct.
|
||||
|
||||
+1497
-246
File diff suppressed because it is too large
Load Diff
+39
-21
@@ -114,8 +114,8 @@ extern "C" {
|
||||
** system</a>. ^The SQLITE_SOURCE_ID macro evaluates to
|
||||
** a string which identifies a particular check-in of SQLite
|
||||
** within its configuration management system. ^The SQLITE_SOURCE_ID
|
||||
** string contains the date and time of the check-in (UTC) and an SHA1
|
||||
** hash of the entire source tree.
|
||||
** string contains the date and time of the check-in (UTC) and a SHA1
|
||||
** or SHA3-256 hash of the entire source tree.
|
||||
**
|
||||
** See also: [sqlite3_libversion()],
|
||||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||
@@ -2040,20 +2040,30 @@ int sqlite3_extended_result_codes(sqlite3*, int onoff);
|
||||
** the table has a column of type [INTEGER PRIMARY KEY] then that column
|
||||
** is another alias for the rowid.
|
||||
**
|
||||
** ^The sqlite3_last_insert_rowid(D) interface returns the [rowid] of the
|
||||
** most recent successful [INSERT] into a rowid table or [virtual table]
|
||||
** on database connection D.
|
||||
** ^Inserts into [WITHOUT ROWID] tables are not recorded.
|
||||
** ^If no successful [INSERT]s into rowid tables
|
||||
** have ever occurred on the database connection D,
|
||||
** then sqlite3_last_insert_rowid(D) returns zero.
|
||||
** ^The sqlite3_last_insert_rowid(D) interface usually returns the [rowid] of
|
||||
** the most recent successful [INSERT] into a rowid table or [virtual table]
|
||||
** on database connection D. ^Inserts into [WITHOUT ROWID] tables are not
|
||||
** recorded. ^If no successful [INSERT]s into rowid tables have ever occurred
|
||||
** on the database connection D, then sqlite3_last_insert_rowid(D) returns
|
||||
** zero.
|
||||
**
|
||||
** ^(If an [INSERT] occurs within a trigger or within a [virtual table]
|
||||
** method, then this routine will return the [rowid] of the inserted
|
||||
** row as long as the trigger or virtual table method is running.
|
||||
** But once the trigger or virtual table method ends, the value returned
|
||||
** by this routine reverts to what it was before the trigger or virtual
|
||||
** table method began.)^
|
||||
** As well as being set automatically as rows are inserted into database
|
||||
** tables, the value returned by this function may be set explicitly by
|
||||
** [sqlite3_set_last_insert_rowid()]
|
||||
**
|
||||
** Some virtual table implementations may INSERT rows into rowid tables as
|
||||
** part of committing a transaction (e.g. to flush data accumulated in memory
|
||||
** to disk). In this case subsequent calls to this function return the rowid
|
||||
** associated with these internal INSERT operations, which leads to
|
||||
** unintuitive results. Virtual table implementations that do write to rowid
|
||||
** tables in this way can avoid this problem by restoring the original
|
||||
** rowid value using [sqlite3_set_last_insert_rowid()] before returning
|
||||
** control to the user.
|
||||
**
|
||||
** ^(If an [INSERT] occurs within a trigger then this routine will
|
||||
** return the [rowid] of the inserted row as long as the trigger is
|
||||
** running. Once the trigger program ends, the value returned
|
||||
** by this routine reverts to what it was before the trigger was fired.)^
|
||||
**
|
||||
** ^An [INSERT] that fails due to a constraint violation is not a
|
||||
** successful [INSERT] and does not change the value returned by this
|
||||
@@ -2080,6 +2090,16 @@ int sqlite3_extended_result_codes(sqlite3*, int onoff);
|
||||
*/
|
||||
sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Set the Last Insert Rowid value.
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** The sqlite3_set_last_insert_rowid(D, R) method allows the application to
|
||||
** set the value returned by calling sqlite3_last_insert_rowid(D) to R
|
||||
** without inserting a row into the database.
|
||||
*/
|
||||
void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Count The Number Of Rows Modified
|
||||
** METHOD: sqlite3
|
||||
@@ -2191,9 +2211,6 @@ int sqlite3_total_changes(sqlite3*);
|
||||
** ^A call to sqlite3_interrupt(D) that occurs when there are no running
|
||||
** SQL statements is a no-op and has no effect on SQL statements
|
||||
** that are started after the sqlite3_interrupt() call returns.
|
||||
**
|
||||
** If the database connection closes while [sqlite3_interrupt()]
|
||||
** is running then bad things will likely happen.
|
||||
*/
|
||||
void sqlite3_interrupt(sqlite3*);
|
||||
|
||||
@@ -3404,9 +3421,9 @@ int sqlite3_limit(sqlite3*, int id, int newVal);
|
||||
**
|
||||
** [[SQLITE_LIMIT_VDBE_OP]] ^(<dt>SQLITE_LIMIT_VDBE_OP</dt>
|
||||
** <dd>The maximum number of instructions in a virtual machine program
|
||||
** used to implement an SQL statement. This limit is not currently
|
||||
** enforced, though that might be added in some future release of
|
||||
** SQLite.</dd>)^
|
||||
** used to implement an SQL statement. If [sqlite3_prepare_v2()] or
|
||||
** the equivalent tries to allocate space for more than this many opcodes
|
||||
** in a single prepared statement, an SQLITE_NOMEM error is returned.</dd>)^
|
||||
**
|
||||
** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt>
|
||||
** <dd>The maximum number of arguments on a function.</dd>)^
|
||||
@@ -3444,6 +3461,7 @@ int sqlite3_limit(sqlite3*, int id, int newVal);
|
||||
#define SQLITE_LIMIT_TRIGGER_DEPTH 10
|
||||
#define SQLITE_LIMIT_WORKER_THREADS 11
|
||||
|
||||
|
||||
/*
|
||||
** CAPI3REF: Compiling An SQL Statement
|
||||
** KEYWORDS: {SQL statement compiler}
|
||||
|
||||
@@ -282,6 +282,8 @@ struct sqlite3_api_routines {
|
||||
/* Version 3.14.0 and later */
|
||||
int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
|
||||
char *(*expanded_sql)(sqlite3_stmt*);
|
||||
/* Version 3.18.0 and later */
|
||||
void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -540,6 +542,8 @@ typedef int (*sqlite3_loadext_entry)(
|
||||
/* Version 3.14.0 and later */
|
||||
#define sqlite3_trace_v2 sqlite3_api->trace_v2
|
||||
#define sqlite3_expanded_sql sqlite3_api->expanded_sql
|
||||
/* Version 3.18.0 and later */
|
||||
#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
|
||||
+17
-11
@@ -1127,7 +1127,7 @@ typedef int VList;
|
||||
** and the one-based values are used internally.
|
||||
*/
|
||||
#ifndef SQLITE_DEFAULT_SYNCHRONOUS
|
||||
# define SQLITE_DEFAULT_SYNCHRONOUS (PAGER_SYNCHRONOUS_FULL-1)
|
||||
# define SQLITE_DEFAULT_SYNCHRONOUS 2
|
||||
#endif
|
||||
#ifndef SQLITE_DEFAULT_WAL_SYNCHRONOUS
|
||||
# define SQLITE_DEFAULT_WAL_SYNCHRONOUS SQLITE_DEFAULT_SYNCHRONOUS
|
||||
@@ -1333,6 +1333,7 @@ struct sqlite3 {
|
||||
u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */
|
||||
u8 mTrace; /* zero or more SQLITE_TRACE flags */
|
||||
u8 skipBtreeMutex; /* True if no shared-cache backends */
|
||||
u8 nSqlExec; /* Number of pending OP_SqlExec opcodes */
|
||||
int nextPagesize; /* Pagesize after VACUUM if >0 */
|
||||
u32 magic; /* Magic number for detect library misuse */
|
||||
int nChange; /* Value returned by sqlite3_changes() */
|
||||
@@ -1879,15 +1880,17 @@ struct Table {
|
||||
** the TF_OOOHidden attribute would apply in this case. Such tables require
|
||||
** special handling during INSERT processing.
|
||||
*/
|
||||
#define TF_Readonly 0x01 /* Read-only system table */
|
||||
#define TF_Ephemeral 0x02 /* An ephemeral table */
|
||||
#define TF_HasPrimaryKey 0x04 /* Table has a primary key */
|
||||
#define TF_Autoincrement 0x08 /* Integer primary key is autoincrement */
|
||||
/* available for reuse: 0x10 */
|
||||
#define TF_WithoutRowid 0x20 /* No rowid. PRIMARY KEY is the key */
|
||||
#define TF_NoVisibleRowid 0x40 /* No user-visible "rowid" column */
|
||||
#define TF_OOOHidden 0x80 /* Out-of-Order hidden columns */
|
||||
|
||||
#define TF_Readonly 0x0001 /* Read-only system table */
|
||||
#define TF_Ephemeral 0x0002 /* An ephemeral table */
|
||||
#define TF_HasPrimaryKey 0x0004 /* Table has a primary key */
|
||||
#define TF_Autoincrement 0x0008 /* Integer primary key is autoincrement */
|
||||
#define TF_HasStat1 0x0010 /* nRowLogEst set from sqlite_stat1 */
|
||||
#define TF_WithoutRowid 0x0020 /* No rowid. PRIMARY KEY is the key */
|
||||
#define TF_NoVisibleRowid 0x0040 /* No user-visible "rowid" column */
|
||||
#define TF_OOOHidden 0x0080 /* Out-of-Order hidden columns */
|
||||
#define TF_StatsUsed 0x0100 /* Query planner decisions affected by
|
||||
** Index.aiRowLogEst[] values */
|
||||
#define TF_HasNotNull 0x0200 /* Contains NOT NULL constraints */
|
||||
|
||||
/*
|
||||
** Test to see whether or not a table is a virtual table. This is
|
||||
@@ -2130,6 +2133,7 @@ struct Index {
|
||||
unsigned isResized:1; /* True if resizeIndexObject() has been called */
|
||||
unsigned isCovering:1; /* True if this is a covering index */
|
||||
unsigned noSkipScan:1; /* Do not try to use skip-scan if true */
|
||||
unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
int nSample; /* Number of elements in aSample[] */
|
||||
int nSampleCol; /* Size of IndexSample.anEq[] and so on */
|
||||
@@ -2439,6 +2443,7 @@ struct Expr {
|
||||
*/
|
||||
struct ExprList {
|
||||
int nExpr; /* Number of expressions on the list */
|
||||
int nAlloc; /* Number of a[] slots allocated */
|
||||
struct ExprList_item { /* For each expression in the list */
|
||||
Expr *pExpr; /* The parse tree for this expression */
|
||||
char *zName; /* Token associated with this expression */
|
||||
@@ -2454,7 +2459,7 @@ struct ExprList {
|
||||
} x;
|
||||
int iConstExprReg; /* Register in which Expr value is cached */
|
||||
} u;
|
||||
} *a; /* Alloc a power of two greater or equal to nExpr */
|
||||
} a[1]; /* One slot for each expression in the list */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -3472,6 +3477,7 @@ void *sqlite3Realloc(void*, u64);
|
||||
void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64);
|
||||
void *sqlite3DbRealloc(sqlite3 *, void *, u64);
|
||||
void sqlite3DbFree(sqlite3*, void*);
|
||||
void sqlite3DbFreeNN(sqlite3*, void*);
|
||||
int sqlite3MallocSize(void*);
|
||||
int sqlite3DbMallocSize(sqlite3*, void*);
|
||||
void *sqlite3ScratchMalloc(int);
|
||||
|
||||
+1
-1
@@ -87,7 +87,7 @@
|
||||
** Not currently enforced.
|
||||
*/
|
||||
#ifndef SQLITE_MAX_VDBE_OP
|
||||
# define SQLITE_MAX_VDBE_OP 25000
|
||||
# define SQLITE_MAX_VDBE_OP 250000000
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
+11
-6
@@ -315,8 +315,9 @@ static int writeListSync(CrashFile *pFile, int isCrash){
|
||||
assert(pWrite->zBuf);
|
||||
|
||||
#ifdef TRACE_CRASHTEST
|
||||
printf("Trashing %d sectors @ %lld (sector %d) (%s)\n",
|
||||
1+iLast-iFirst, pWrite->iOffset, iFirst, pWrite->pFile->zName
|
||||
printf("Trashing %d sectors (%d bytes) @ %lld (sector %d) (%s)\n",
|
||||
1+iLast-iFirst, (1+iLast-iFirst)*g.iSectorSize,
|
||||
pWrite->iOffset, iFirst, pWrite->pFile->zName
|
||||
);
|
||||
#endif
|
||||
|
||||
@@ -827,7 +828,7 @@ static int SQLITE_TCLAPI crashNowCmd(
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite_crash_enable ENABLE
|
||||
** tclcmd: sqlite_crash_enable ENABLE ?DEFAULT?
|
||||
**
|
||||
** Parameter ENABLE must be a boolean value. If true, then the "crash"
|
||||
** vfs is added to the system. If false, it is removed.
|
||||
@@ -839,6 +840,7 @@ static int SQLITE_TCLAPI crashEnableCmd(
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
int isEnable;
|
||||
int isDefault = 0;
|
||||
static sqlite3_vfs crashVfs = {
|
||||
2, /* iVersion */
|
||||
0, /* szOsFile */
|
||||
@@ -862,14 +864,17 @@ static int SQLITE_TCLAPI crashEnableCmd(
|
||||
0, /* xCurrentTimeInt64 */
|
||||
};
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "ENABLE");
|
||||
if( objc!=2 && objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "ENABLE ?DEFAULT?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( Tcl_GetBooleanFromObj(interp, objv[1], &isEnable) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( objc==3 && Tcl_GetBooleanFromObj(interp, objv[2], &isDefault) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( (isEnable && crashVfs.pAppData) || (!isEnable && !crashVfs.pAppData) ){
|
||||
return TCL_OK;
|
||||
@@ -880,7 +885,7 @@ static int SQLITE_TCLAPI crashEnableCmd(
|
||||
crashVfs.mxPathname = pOriginalVfs->mxPathname;
|
||||
crashVfs.pAppData = (void *)pOriginalVfs;
|
||||
crashVfs.szOsFile = sizeof(CrashFile) + pOriginalVfs->szOsFile;
|
||||
sqlite3_vfs_register(&crashVfs, 0);
|
||||
sqlite3_vfs_register(&crashVfs, isDefault);
|
||||
}else{
|
||||
crashVfs.pAppData = 0;
|
||||
sqlite3_vfs_unregister(&crashVfs);
|
||||
|
||||
@@ -740,6 +740,8 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY);
|
||||
LINKVAR( DEFAULT_CACHE_SIZE );
|
||||
LINKVAR( DEFAULT_PAGE_SIZE );
|
||||
LINKVAR( DEFAULT_FILE_FORMAT );
|
||||
LINKVAR( DEFAULT_SYNCHRONOUS );
|
||||
LINKVAR( DEFAULT_WAL_SYNCHRONOUS );
|
||||
LINKVAR( MAX_ATTACHED );
|
||||
LINKVAR( MAX_DEFAULT_PAGE_SIZE );
|
||||
LINKVAR( MAX_WORKER_THREADS );
|
||||
|
||||
@@ -557,6 +557,9 @@ static int jtWrite(
|
||||
u32 pgno = (u32)(iOfst/p->nPagesize + 1);
|
||||
assert( (iAmt==1||iAmt==(int)p->nPagesize) &&
|
||||
((iOfst+iAmt)%p->nPagesize)==0 );
|
||||
/* The following assert() statements may fail if this layer is used
|
||||
** with a connection in "PRAGMA synchronous=off" mode. If they
|
||||
** fail with sync=normal or sync=full, this may indicate problem. */
|
||||
assert( pgno<=p->nPage || p->nSync>0 );
|
||||
assert( pgno>p->nPage || sqlite3BitvecTest(p->pWritable, pgno) );
|
||||
}
|
||||
|
||||
+15
-14
@@ -475,14 +475,14 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
||||
*/
|
||||
int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
int nErr = 0; /* Number of errors encountered */
|
||||
int i; /* Loop counter */
|
||||
void *pEngine; /* The LEMON-generated LALR(1) parser */
|
||||
int n = 0; /* Length of the next token token */
|
||||
int tokenType; /* type of the next token */
|
||||
int lastTokenParsed = -1; /* type of the previous token */
|
||||
sqlite3 *db = pParse->db; /* The database connection */
|
||||
int mxSqlLen; /* Max length of an SQL string */
|
||||
#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
|
||||
unsigned char zSpace[sizeof(yyParser)]; /* Space for parser engine object */
|
||||
yyParser sEngine; /* Space to hold the Lemon-generated Parser object */
|
||||
#endif
|
||||
|
||||
assert( zSql!=0 );
|
||||
@@ -492,11 +492,10 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
}
|
||||
pParse->rc = SQLITE_OK;
|
||||
pParse->zTail = zSql;
|
||||
i = 0;
|
||||
assert( pzErrMsg!=0 );
|
||||
/* sqlite3ParserTrace(stdout, "parser: "); */
|
||||
#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
|
||||
pEngine = zSpace;
|
||||
pEngine = &sEngine;
|
||||
sqlite3ParserInit(pEngine);
|
||||
#else
|
||||
pEngine = sqlite3ParserAlloc(sqlite3Malloc);
|
||||
@@ -510,12 +509,10 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
assert( pParse->nVar==0 );
|
||||
assert( pParse->pVList==0 );
|
||||
while( 1 ){
|
||||
assert( i>=0 );
|
||||
if( zSql[i]!=0 ){
|
||||
pParse->sLastToken.z = &zSql[i];
|
||||
pParse->sLastToken.n = sqlite3GetToken((u8*)&zSql[i],&tokenType);
|
||||
i += pParse->sLastToken.n;
|
||||
if( i>mxSqlLen ){
|
||||
if( zSql[0]!=0 ){
|
||||
n = sqlite3GetToken((u8*)zSql, &tokenType);
|
||||
mxSqlLen -= n;
|
||||
if( mxSqlLen<0 ){
|
||||
pParse->rc = SQLITE_TOOBIG;
|
||||
break;
|
||||
}
|
||||
@@ -529,6 +526,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
}else{
|
||||
tokenType = TK_SEMI;
|
||||
}
|
||||
zSql -= n;
|
||||
}
|
||||
if( tokenType>=TK_SPACE ){
|
||||
assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL );
|
||||
@@ -537,18 +535,21 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
break;
|
||||
}
|
||||
if( tokenType==TK_ILLEGAL ){
|
||||
sqlite3ErrorMsg(pParse, "unrecognized token: \"%T\"",
|
||||
&pParse->sLastToken);
|
||||
sqlite3ErrorMsg(pParse, "unrecognized token: \"%.*s\"", n, zSql);
|
||||
break;
|
||||
}
|
||||
zSql += n;
|
||||
}else{
|
||||
pParse->sLastToken.z = zSql;
|
||||
pParse->sLastToken.n = n;
|
||||
sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse);
|
||||
lastTokenParsed = tokenType;
|
||||
zSql += n;
|
||||
if( pParse->rc!=SQLITE_OK || db->mallocFailed ) break;
|
||||
}
|
||||
}
|
||||
assert( nErr==0 );
|
||||
pParse->zTail = &zSql[i];
|
||||
pParse->zTail = zSql;
|
||||
#ifdef YYTRACKMAXSTACKDEPTH
|
||||
sqlite3_mutex_enter(sqlite3MallocMutex());
|
||||
sqlite3StatusHighwater(SQLITE_STATUS_PARSER_STACK,
|
||||
@@ -603,7 +604,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
while( pParse->pAinc ){
|
||||
AutoincInfo *p = pParse->pAinc;
|
||||
pParse->pAinc = p->pNext;
|
||||
sqlite3DbFree(db, p);
|
||||
sqlite3DbFreeNN(db, p);
|
||||
}
|
||||
while( pParse->pZombieTab ){
|
||||
Table *p = pParse->pZombieTab;
|
||||
|
||||
@@ -126,6 +126,10 @@ void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){
|
||||
void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
|
||||
int n = 0;
|
||||
int cnt = 0;
|
||||
if( p==0 ){
|
||||
sqlite3TreeViewLine(pView, "nil-SELECT");
|
||||
return;
|
||||
}
|
||||
pView = sqlite3TreeViewPush(pView, moreToFollow);
|
||||
if( p->pWith ){
|
||||
sqlite3TreeViewWith(pView, p->pWith, 1);
|
||||
|
||||
+103
-37
@@ -403,9 +403,7 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
|
||||
}else{
|
||||
c = 's';
|
||||
}
|
||||
|
||||
sqlite3_snprintf(100, zCsr, "%c", c);
|
||||
zCsr += sqlite3Strlen30(zCsr);
|
||||
*(zCsr++) = c;
|
||||
sqlite3_snprintf(100, zCsr, "%d[", pMem->n);
|
||||
zCsr += sqlite3Strlen30(zCsr);
|
||||
for(i=0; i<16 && i<pMem->n; i++){
|
||||
@@ -417,9 +415,7 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
|
||||
if( z<32 || z>126 ) *zCsr++ = '.';
|
||||
else *zCsr++ = z;
|
||||
}
|
||||
|
||||
sqlite3_snprintf(100, zCsr, "]%s", encnames[pMem->enc]);
|
||||
zCsr += sqlite3Strlen30(zCsr);
|
||||
*(zCsr++) = ']';
|
||||
if( f & MEM_Zero ){
|
||||
sqlite3_snprintf(100, zCsr,"+%dz",pMem->u.nZero);
|
||||
zCsr += sqlite3Strlen30(zCsr);
|
||||
@@ -1669,21 +1665,21 @@ case OP_Function: {
|
||||
for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i];
|
||||
}
|
||||
|
||||
memAboutToChange(p, pCtx->pOut);
|
||||
memAboutToChange(p, pOut);
|
||||
#ifdef SQLITE_DEBUG
|
||||
for(i=0; i<pCtx->argc; i++){
|
||||
assert( memIsValid(pCtx->argv[i]) );
|
||||
REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]);
|
||||
}
|
||||
#endif
|
||||
MemSetTypeFlag(pCtx->pOut, MEM_Null);
|
||||
MemSetTypeFlag(pOut, MEM_Null);
|
||||
pCtx->fErrorOrAux = 0;
|
||||
(*pCtx->pFunc->xSFunc)(pCtx, pCtx->argc, pCtx->argv);/* IMP: R-24505-23230 */
|
||||
|
||||
/* If the function returned an error, throw an exception */
|
||||
if( pCtx->fErrorOrAux ){
|
||||
if( pCtx->isError ){
|
||||
sqlite3VdbeError(p, "%s", sqlite3_value_text(pCtx->pOut));
|
||||
sqlite3VdbeError(p, "%s", sqlite3_value_text(pOut));
|
||||
rc = pCtx->isError;
|
||||
}
|
||||
sqlite3VdbeDeleteAuxData(db, &p->pAuxData, pCtx->iOp, pOp->p1);
|
||||
@@ -1692,12 +1688,12 @@ case OP_Function: {
|
||||
|
||||
/* Copy the result of the function into register P3 */
|
||||
if( pOut->flags & (MEM_Str|MEM_Blob) ){
|
||||
sqlite3VdbeChangeEncoding(pCtx->pOut, encoding);
|
||||
if( sqlite3VdbeMemTooBig(pCtx->pOut) ) goto too_big;
|
||||
sqlite3VdbeChangeEncoding(pOut, encoding);
|
||||
if( sqlite3VdbeMemTooBig(pOut) ) goto too_big;
|
||||
}
|
||||
|
||||
REGISTER_TRACE(pOp->p3, pCtx->pOut);
|
||||
UPDATE_MAX_BLOBSIZE(pCtx->pOut);
|
||||
REGISTER_TRACE(pOp->p3, pOut);
|
||||
UPDATE_MAX_BLOBSIZE(pOut);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2336,19 +2332,39 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
|
||||
|
||||
/* Opcode: Once P1 P2 * * *
|
||||
**
|
||||
** If the P1 value is equal to the P1 value on the OP_Init opcode at
|
||||
** instruction 0, then jump to P2. If the two P1 values differ, then
|
||||
** set the P1 value on this opcode to equal the P1 value on the OP_Init
|
||||
** and fall through.
|
||||
** Fall through to the next instruction the first time this opcode is
|
||||
** encountered on each invocation of the byte-code program. Jump to P2
|
||||
** on the second and all subsequent encounters during the same invocation.
|
||||
**
|
||||
** Top-level programs determine first invocation by comparing the P1
|
||||
** operand against the P1 operand on the OP_Init opcode at the beginning
|
||||
** of the program. If the P1 values differ, then fall through and make
|
||||
** the P1 of this opcode equal to the P1 of OP_Init. If P1 values are
|
||||
** the same then take the jump.
|
||||
**
|
||||
** For subprograms, there is a bitmask in the VdbeFrame that determines
|
||||
** whether or not the jump should be taken. The bitmask is necessary
|
||||
** because the self-altering code trick does not work for recursive
|
||||
** triggers.
|
||||
*/
|
||||
case OP_Once: { /* jump */
|
||||
u32 iAddr; /* Address of this instruction */
|
||||
assert( p->aOp[0].opcode==OP_Init );
|
||||
VdbeBranchTaken(p->aOp[0].p1==pOp->p1, 2);
|
||||
if( p->aOp[0].p1==pOp->p1 ){
|
||||
goto jump_to_p2;
|
||||
if( p->pFrame ){
|
||||
iAddr = (int)(pOp - p->aOp);
|
||||
if( (p->pFrame->aOnce[iAddr/8] & (1<<(iAddr & 7)))!=0 ){
|
||||
VdbeBranchTaken(1, 2);
|
||||
goto jump_to_p2;
|
||||
}
|
||||
p->pFrame->aOnce[iAddr/8] |= 1<<(iAddr & 7);
|
||||
}else{
|
||||
pOp->p1 = p->aOp[0].p1;
|
||||
if( p->aOp[0].p1==pOp->p1 ){
|
||||
VdbeBranchTaken(1, 2);
|
||||
goto jump_to_p2;
|
||||
}
|
||||
}
|
||||
VdbeBranchTaken(0, 2);
|
||||
pOp->p1 = p->aOp[0].p1;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2424,7 +2440,7 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
|
||||
**
|
||||
** The value extracted is stored in register P3.
|
||||
**
|
||||
** If the column contains fewer than P2 fields, then extract a NULL. Or,
|
||||
** If the record contains fewer than P2 fields, then extract a NULL. Or,
|
||||
** if the P4 argument is a P4_MEM use the value of the P4 argument as
|
||||
** the result.
|
||||
**
|
||||
@@ -2433,7 +2449,7 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
|
||||
** The first OP_Column against a pseudo-table after the value of the content
|
||||
** register has changed should have this bit set.
|
||||
**
|
||||
** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 when
|
||||
** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 then
|
||||
** the result is guaranteed to only be used as the argument of a length()
|
||||
** or typeof() function, respectively. The loading of large blobs can be
|
||||
** skipped for length() and all content loading can be skipped for typeof().
|
||||
@@ -2661,8 +2677,13 @@ case OP_Column: {
|
||||
** 2. the length(X) function if X is a blob, and
|
||||
** 3. if the content length is zero.
|
||||
** So we might as well use bogus content rather than reading
|
||||
** content from disk. */
|
||||
static u8 aZero[8]; /* This is the bogus content */
|
||||
** content from disk.
|
||||
**
|
||||
** Although sqlite3VdbeSerialGet() may read at most 8 bytes from the
|
||||
** buffer passed to it, debugging function VdbeMemPrettyPrint() may
|
||||
** read up to 16. So 16 bytes of bogus content is supplied.
|
||||
*/
|
||||
static u8 aZero[16]; /* This is the bogus content */
|
||||
sqlite3VdbeSerialGet(aZero, t, pDest);
|
||||
}else{
|
||||
rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, aOffset[p2], len, pDest);
|
||||
@@ -2689,18 +2710,18 @@ op_column_out:
|
||||
*/
|
||||
case OP_Affinity: {
|
||||
const char *zAffinity; /* The affinity to be applied */
|
||||
char cAff; /* A single character of affinity */
|
||||
|
||||
zAffinity = pOp->p4.z;
|
||||
assert( zAffinity!=0 );
|
||||
assert( pOp->p2>0 );
|
||||
assert( zAffinity[pOp->p2]==0 );
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
while( (cAff = *(zAffinity++))!=0 ){
|
||||
do{
|
||||
assert( pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)] );
|
||||
assert( memIsValid(pIn1) );
|
||||
applyAffinity(pIn1, cAff, encoding);
|
||||
applyAffinity(pIn1, *(zAffinity++), encoding);
|
||||
pIn1++;
|
||||
}
|
||||
}while( zAffinity[0] );
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2871,7 +2892,6 @@ case OP_MakeRecord: {
|
||||
pOut->u.nZero = nZero;
|
||||
pOut->flags |= MEM_Zero;
|
||||
}
|
||||
pOut->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */
|
||||
REGISTER_TRACE(pOp->p3, pOut);
|
||||
UPDATE_MAX_BLOBSIZE(pOut);
|
||||
break;
|
||||
@@ -4056,7 +4076,7 @@ case OP_Found: { /* jump, in3 */
|
||||
}
|
||||
}
|
||||
rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, pIdxKey, 0, 0, &res);
|
||||
if( pFree ) sqlite3DbFree(db, pFree);
|
||||
if( pFree ) sqlite3DbFreeNN(db, pFree);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
@@ -4847,6 +4867,33 @@ case OP_Last: { /* jump */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: IfSmaller P1 P2 P3 * *
|
||||
**
|
||||
** Estimate the number of rows in the table P1. Jump to P2 if that
|
||||
** estimate is less than approximately 2**(0.1*P3).
|
||||
*/
|
||||
case OP_IfSmaller: { /* jump */
|
||||
VdbeCursor *pC;
|
||||
BtCursor *pCrsr;
|
||||
int res;
|
||||
i64 sz;
|
||||
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
pCrsr = pC->uc.pCursor;
|
||||
assert( pCrsr );
|
||||
rc = sqlite3BtreeFirst(pCrsr, &res);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
if( res==0 ){
|
||||
sz = sqlite3BtreeRowCountEst(pCrsr);
|
||||
if( ALWAYS(sz>=0) && sqlite3LogEst((u64)sz)<pOp->p3 ) res = 1;
|
||||
}
|
||||
VdbeBranchTaken(res!=0,2);
|
||||
if( res ) goto jump_to_p2;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* Opcode: SorterSort P1 P2 * * *
|
||||
**
|
||||
@@ -5491,6 +5538,18 @@ case OP_CreateTable: { /* out2 */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: SqlExec * * * P4 *
|
||||
**
|
||||
** Run the SQL statement or statements specified in the P4 string.
|
||||
*/
|
||||
case OP_SqlExec: {
|
||||
db->nSqlExec++;
|
||||
rc = sqlite3_exec(db, pOp->p4.z, 0, 0, 0);
|
||||
db->nSqlExec--;
|
||||
if( rc ) goto abort_due_to_error;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: ParseSchema P1 * * P4 *
|
||||
**
|
||||
** Read and parse all entries from the SQLITE_MASTER table of database P1
|
||||
@@ -5535,7 +5594,7 @@ case OP_ParseSchema: {
|
||||
assert( !db->mallocFailed );
|
||||
rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
|
||||
if( rc==SQLITE_OK ) rc = initData.rc;
|
||||
sqlite3DbFree(db, zSql);
|
||||
sqlite3DbFreeNN(db, zSql);
|
||||
db->init.busy = 0;
|
||||
}
|
||||
}
|
||||
@@ -5611,7 +5670,7 @@ case OP_DropTrigger: {
|
||||
** register P1 the text of an error message describing any problems.
|
||||
** If no problems are found, store a NULL in register P1.
|
||||
**
|
||||
** The register P3 contains the maximum number of allowed errors.
|
||||
** The register P3 contains one less than the maximum number of allowed errors.
|
||||
** At most reg(P3) errors will be reported.
|
||||
** In other words, the analysis stops as soon as reg(P1) errors are
|
||||
** seen. Reg(P1) is updated with the number of errors remaining.
|
||||
@@ -5644,14 +5703,14 @@ case OP_IntegrityCk: {
|
||||
assert( pOp->p5<db->nDb );
|
||||
assert( DbMaskTest(p->btreeMask, pOp->p5) );
|
||||
z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, aRoot, nRoot,
|
||||
(int)pnErr->u.i, &nErr);
|
||||
pnErr->u.i -= nErr;
|
||||
(int)pnErr->u.i+1, &nErr);
|
||||
sqlite3VdbeMemSetNull(pIn1);
|
||||
if( nErr==0 ){
|
||||
assert( z==0 );
|
||||
}else if( z==0 ){
|
||||
goto no_mem;
|
||||
}else{
|
||||
pnErr->u.i -= nErr-1;
|
||||
sqlite3VdbeMemSetStr(pIn1, z, -1, SQLITE_UTF8, sqlite3_free);
|
||||
}
|
||||
UPDATE_MAX_BLOBSIZE(pIn1);
|
||||
@@ -5830,7 +5889,8 @@ case OP_Program: { /* jump */
|
||||
if( pProgram->nCsr==0 ) nMem++;
|
||||
nByte = ROUND8(sizeof(VdbeFrame))
|
||||
+ nMem * sizeof(Mem)
|
||||
+ pProgram->nCsr * sizeof(VdbeCursor *);
|
||||
+ pProgram->nCsr * sizeof(VdbeCursor*)
|
||||
+ (pProgram->nOp + 7)/8;
|
||||
pFrame = sqlite3DbMallocZero(db, nByte);
|
||||
if( !pFrame ){
|
||||
goto no_mem;
|
||||
@@ -5881,6 +5941,8 @@ case OP_Program: { /* jump */
|
||||
p->nMem = pFrame->nChildMem;
|
||||
p->nCursor = (u16)pFrame->nChildCsr;
|
||||
p->apCsr = (VdbeCursor **)&aMem[p->nMem];
|
||||
pFrame->aOnce = (u8*)&p->apCsr[pProgram->nCsr];
|
||||
memset(pFrame->aOnce, 0, (pProgram->nOp + 7)/8);
|
||||
p->aOp = aOp = pProgram->aOp;
|
||||
p->nOp = pProgram->nOp;
|
||||
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
||||
@@ -6910,7 +6972,11 @@ case OP_Init: { /* jump */
|
||||
sqlite3_free(z);
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
if( db->nVdbeExec>1 ){
|
||||
char *z = sqlite3MPrintf(db, "-- %s", zTrace);
|
||||
(void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, z);
|
||||
sqlite3DbFree(db, z);
|
||||
}else{
|
||||
(void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +87,7 @@ struct SubProgram {
|
||||
int nOp; /* Elements in aOp[] */
|
||||
int nMem; /* Number of memory cells required */
|
||||
int nCsr; /* Number of cursors required */
|
||||
u8 *aOnce; /* Array of OP_Once flags */
|
||||
void *token; /* id that may be used to recursive triggers */
|
||||
SubProgram *pNext; /* Next sub-program already visited */
|
||||
};
|
||||
|
||||
@@ -164,6 +164,7 @@ struct VdbeFrame {
|
||||
i64 *anExec; /* Event counters from parent frame */
|
||||
Mem *aMem; /* Array of memory cells for parent frame */
|
||||
VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
|
||||
u8 *aOnce; /* Bitmask used by OP_Once */
|
||||
void *token; /* Copy of SubProgram.token */
|
||||
i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
|
||||
AuxData *pAuxData; /* Linked list of auxdata allocations */
|
||||
|
||||
+8
-6
@@ -154,7 +154,8 @@ int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
|
||||
sqlite3VdbeMemRelease(&p->aVar[i]);
|
||||
p->aVar[i].flags = MEM_Null;
|
||||
}
|
||||
if( p->isPrepareV2 && p->expmask ){
|
||||
assert( p->isPrepareV2 || p->expmask==0 );
|
||||
if( p->expmask ){
|
||||
p->expired = 1;
|
||||
}
|
||||
sqlite3_mutex_leave(mutex);
|
||||
@@ -1258,9 +1259,8 @@ static int vdbeUnbind(Vdbe *p, int i){
|
||||
** as if there had been a schema change, on the first sqlite3_step() call
|
||||
** following any change to the bindings of that parameter.
|
||||
*/
|
||||
if( p->isPrepareV2 &&
|
||||
((i<32 && p->expmask & ((u32)1 << i)) || p->expmask==0xffffffff)
|
||||
){
|
||||
assert( p->isPrepareV2 || p->expmask==0 );
|
||||
if( p->expmask!=0 && (p->expmask & (i>=31 ? 0x80000000 : (u32)1<<i))!=0 ){
|
||||
p->expired = 1;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
@@ -1523,10 +1523,12 @@ int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
|
||||
if( pFrom->nVar!=pTo->nVar ){
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
if( pTo->isPrepareV2 && pTo->expmask ){
|
||||
assert( pTo->isPrepareV2 || pTo->expmask==0 );
|
||||
if( pTo->expmask ){
|
||||
pTo->expired = 1;
|
||||
}
|
||||
if( pFrom->isPrepareV2 && pFrom->expmask ){
|
||||
assert( pFrom->isPrepareV2 || pFrom->expmask==0 );
|
||||
if( pFrom->expmask ){
|
||||
pFrom->expired = 1;
|
||||
}
|
||||
return sqlite3TransferBindings(pFromStmt, pToStmt);
|
||||
|
||||
+21
-14
@@ -57,6 +57,7 @@ void sqlite3VdbeError(Vdbe *p, const char *zFormat, ...){
|
||||
void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){
|
||||
assert( isPrepareV2==1 || isPrepareV2==0 );
|
||||
if( p==0 ) return;
|
||||
if( !isPrepareV2 ) p->expmask = 0;
|
||||
#if defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_ENABLE_SQLLOG)
|
||||
if( !isPrepareV2 ) return;
|
||||
#endif
|
||||
@@ -85,6 +86,7 @@ void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
|
||||
pA->zSql = pB->zSql;
|
||||
pB->zSql = zTmp;
|
||||
pB->isPrepareV2 = pA->isPrepareV2;
|
||||
pB->expmask = pA->expmask;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -115,6 +117,12 @@ static int growOpArray(Vdbe *v, int nOp){
|
||||
UNUSED_PARAMETER(nOp);
|
||||
#endif
|
||||
|
||||
/* Ensure that the size of a VDBE does not grow too large */
|
||||
if( nNew > p->db->aLimit[SQLITE_LIMIT_VDBE_OP] ){
|
||||
sqlite3OomFault(p->db);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
assert( nOp<=(1024/sizeof(Op)) );
|
||||
assert( nNew>=(p->nOpAlloc+nOp) );
|
||||
pNew = sqlite3DbRealloc(p->db, v->aOp, nNew*sizeof(Op));
|
||||
@@ -803,7 +811,7 @@ void sqlite3VdbeJumpHere(Vdbe *p, int addr){
|
||||
*/
|
||||
static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
|
||||
if( (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){
|
||||
sqlite3DbFree(db, pDef);
|
||||
sqlite3DbFreeNN(db, pDef);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -814,11 +822,11 @@ static void vdbeFreeOpArray(sqlite3 *, Op *, int);
|
||||
*/
|
||||
static SQLITE_NOINLINE void freeP4Mem(sqlite3 *db, Mem *p){
|
||||
if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
|
||||
sqlite3DbFree(db, p);
|
||||
sqlite3DbFreeNN(db, p);
|
||||
}
|
||||
static SQLITE_NOINLINE void freeP4FuncCtx(sqlite3 *db, sqlite3_context *p){
|
||||
freeEphemeralFunction(db, p->pFunc);
|
||||
sqlite3DbFree(db, p);
|
||||
sqlite3DbFreeNN(db, p);
|
||||
}
|
||||
static void freeP4(sqlite3 *db, int p4type, void *p4){
|
||||
assert( db );
|
||||
@@ -877,8 +885,8 @@ static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
|
||||
sqlite3DbFree(db, pOp->zComment);
|
||||
#endif
|
||||
}
|
||||
sqlite3DbFreeNN(db, aOp);
|
||||
}
|
||||
sqlite3DbFree(db, aOp);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1551,7 +1559,7 @@ static void releaseMemArray(Mem *p, int N){
|
||||
if( p->flags&(MEM_Agg|MEM_Dyn|MEM_Frame|MEM_RowSet) ){
|
||||
sqlite3VdbeMemRelease(p);
|
||||
}else if( p->szMalloc ){
|
||||
sqlite3DbFree(db, p->zMalloc);
|
||||
sqlite3DbFreeNN(db, p->zMalloc);
|
||||
p->szMalloc = 0;
|
||||
}
|
||||
|
||||
@@ -2609,13 +2617,13 @@ int sqlite3VdbeHalt(Vdbe *p){
|
||||
** one, or the complete transaction if there is no statement transaction.
|
||||
*/
|
||||
|
||||
if( p->magic!=VDBE_MAGIC_RUN ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( db->mallocFailed ){
|
||||
p->rc = SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
closeAllCursors(p);
|
||||
if( p->magic!=VDBE_MAGIC_RUN ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
checkActiveVdbeCnt(db);
|
||||
|
||||
/* No commit or rollback needed if the program never started or if the
|
||||
@@ -2922,7 +2930,6 @@ int sqlite3VdbeReset(Vdbe *p){
|
||||
}
|
||||
}
|
||||
#endif
|
||||
p->iCurrentTime = 0;
|
||||
p->magic = VDBE_MAGIC_RESET;
|
||||
return p->rc & db->errMask;
|
||||
}
|
||||
@@ -3032,7 +3039,7 @@ void sqlite3VdbeDelete(Vdbe *p){
|
||||
}
|
||||
p->magic = VDBE_MAGIC_DEAD;
|
||||
p->db = 0;
|
||||
sqlite3DbFree(db, p);
|
||||
sqlite3DbFreeNN(db, p);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4550,8 +4557,8 @@ sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff){
|
||||
*/
|
||||
void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){
|
||||
assert( iVar>0 );
|
||||
if( iVar>32 ){
|
||||
v->expmask = 0xffffffff;
|
||||
if( iVar>=32 ){
|
||||
v->expmask |= 0x80000000;
|
||||
}else{
|
||||
v->expmask |= ((u32)1 << (iVar-1));
|
||||
}
|
||||
@@ -4591,7 +4598,7 @@ static void vdbeFreeUnpacked(sqlite3 *db, int nField, UnpackedRecord *p){
|
||||
Mem *pMem = &p->aMem[i];
|
||||
if( pMem->zMalloc ) sqlite3VdbeMemRelease(pMem);
|
||||
}
|
||||
sqlite3DbFree(db, p);
|
||||
sqlite3DbFreeNN(db, p);
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
|
||||
@@ -4658,7 +4665,7 @@ void sqlite3VdbePreUpdateHook(
|
||||
for(i=0; i<pCsr->nField; i++){
|
||||
sqlite3VdbeMemRelease(&preupdate.aNew[i]);
|
||||
}
|
||||
sqlite3DbFree(db, preupdate.aNew);
|
||||
sqlite3DbFreeNN(db, preupdate.aNew);
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
|
||||
|
||||
+22
-16
@@ -131,7 +131,7 @@ SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
|
||||
pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
|
||||
bPreserve = 0;
|
||||
}else{
|
||||
if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc);
|
||||
if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc);
|
||||
pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n);
|
||||
}
|
||||
if( pMem->zMalloc==0 ){
|
||||
@@ -341,7 +341,7 @@ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
|
||||
ctx.pFunc = pFunc;
|
||||
pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */
|
||||
assert( (pMem->flags & MEM_Dyn)==0 );
|
||||
if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc);
|
||||
if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc);
|
||||
memcpy(pMem, &t, sizeof(t));
|
||||
rc = ctx.isError;
|
||||
}
|
||||
@@ -392,7 +392,7 @@ static SQLITE_NOINLINE void vdbeMemClear(Mem *p){
|
||||
vdbeMemClearExternAndSetNull(p);
|
||||
}
|
||||
if( p->szMalloc ){
|
||||
sqlite3DbFree(p->db, p->zMalloc);
|
||||
sqlite3DbFreeNN(p->db, p->zMalloc);
|
||||
p->szMalloc = 0;
|
||||
}
|
||||
p->z = 0;
|
||||
@@ -420,7 +420,7 @@ void sqlite3VdbeMemRelease(Mem *p){
|
||||
** If the double is out of range of a 64-bit signed integer then
|
||||
** return the closest available 64-bit signed integer.
|
||||
*/
|
||||
static i64 doubleToInt64(double r){
|
||||
static SQLITE_NOINLINE i64 doubleToInt64(double r){
|
||||
#ifdef SQLITE_OMIT_FLOATING_POINT
|
||||
/* When floating-point is omitted, double and int64 are the same thing */
|
||||
return r;
|
||||
@@ -456,6 +456,11 @@ static i64 doubleToInt64(double r){
|
||||
**
|
||||
** If pMem represents a string value, its encoding might be changed.
|
||||
*/
|
||||
static SQLITE_NOINLINE i64 memIntValue(Mem *pMem){
|
||||
i64 value = 0;
|
||||
sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
|
||||
return value;
|
||||
}
|
||||
i64 sqlite3VdbeIntValue(Mem *pMem){
|
||||
int flags;
|
||||
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
||||
@@ -466,10 +471,8 @@ i64 sqlite3VdbeIntValue(Mem *pMem){
|
||||
}else if( flags & MEM_Real ){
|
||||
return doubleToInt64(pMem->u.r);
|
||||
}else if( flags & (MEM_Str|MEM_Blob) ){
|
||||
i64 value = 0;
|
||||
assert( pMem->z || pMem->n==0 );
|
||||
sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
|
||||
return value;
|
||||
return memIntValue(pMem);
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
@@ -481,6 +484,12 @@ i64 sqlite3VdbeIntValue(Mem *pMem){
|
||||
** value. If it is a string or blob, try to convert it to a double.
|
||||
** If it is a NULL, return 0.0.
|
||||
*/
|
||||
static SQLITE_NOINLINE double memRealValue(Mem *pMem){
|
||||
/* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
|
||||
double val = (double)0;
|
||||
sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc);
|
||||
return val;
|
||||
}
|
||||
double sqlite3VdbeRealValue(Mem *pMem){
|
||||
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
||||
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
|
||||
@@ -489,10 +498,7 @@ double sqlite3VdbeRealValue(Mem *pMem){
|
||||
}else if( pMem->flags & MEM_Int ){
|
||||
return (double)pMem->u.i;
|
||||
}else if( pMem->flags & (MEM_Str|MEM_Blob) ){
|
||||
/* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
|
||||
double val = (double)0;
|
||||
sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc);
|
||||
return val;
|
||||
return memRealValue(pMem);
|
||||
}else{
|
||||
/* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
|
||||
return (double)0;
|
||||
@@ -1117,7 +1123,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
|
||||
pRec->aMem[i].db = db;
|
||||
}
|
||||
}else{
|
||||
sqlite3DbFree(db, pRec);
|
||||
sqlite3DbFreeNN(db, pRec);
|
||||
pRec = 0;
|
||||
}
|
||||
}
|
||||
@@ -1229,7 +1235,7 @@ static int valueFromFunction(
|
||||
for(i=0; i<nVal; i++){
|
||||
sqlite3ValueFree(apVal[i]);
|
||||
}
|
||||
sqlite3DbFree(db, apVal);
|
||||
sqlite3DbFreeNN(db, apVal);
|
||||
}
|
||||
|
||||
*ppVal = pVal;
|
||||
@@ -1428,7 +1434,7 @@ static void recordFunc(
|
||||
putVarint32(&aRet[1], iSerial);
|
||||
sqlite3VdbeSerialPut(&aRet[1+nSerial], argv[0], iSerial);
|
||||
sqlite3_result_blob(context, aRet, nRet, SQLITE_TRANSIENT);
|
||||
sqlite3DbFree(db, aRet);
|
||||
sqlite3DbFreeNN(db, aRet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1655,7 +1661,7 @@ void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){
|
||||
sqlite3VdbeMemRelease(&aMem[i]);
|
||||
}
|
||||
sqlite3KeyInfoUnref(pRec->pKeyInfo);
|
||||
sqlite3DbFree(db, pRec);
|
||||
sqlite3DbFreeNN(db, pRec);
|
||||
}
|
||||
}
|
||||
#endif /* ifdef SQLITE_ENABLE_STAT4 */
|
||||
@@ -1679,7 +1685,7 @@ void sqlite3ValueSetStr(
|
||||
void sqlite3ValueFree(sqlite3_value *v){
|
||||
if( !v ) return;
|
||||
sqlite3VdbeMemRelease((Mem *)v);
|
||||
sqlite3DbFree(((Mem*)v)->db, v);
|
||||
sqlite3DbFreeNN(((Mem*)v)->db, v);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+26
-27
@@ -858,37 +858,36 @@ static int vdbeSorterCompareInt(
|
||||
assert( (s1>0 && s1<7) || s1==8 || s1==9 );
|
||||
assert( (s2>0 && s2<7) || s2==8 || s2==9 );
|
||||
|
||||
if( s1>7 && s2>7 ){
|
||||
if( s1==s2 ){
|
||||
/* The two values have the same sign. Compare using memcmp(). */
|
||||
static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8, 0, 0, 0 };
|
||||
const u8 n = aLen[s1];
|
||||
int i;
|
||||
res = 0;
|
||||
for(i=0; i<n; i++){
|
||||
if( (res = v1[i] - v2[i])!=0 ){
|
||||
if( ((v1[0] ^ v2[0]) & 0x80)!=0 ){
|
||||
res = v1[0] & 0x80 ? -1 : +1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else if( s1>7 && s2>7 ){
|
||||
res = s1 - s2;
|
||||
}else{
|
||||
if( s1==s2 ){
|
||||
if( (*v1 ^ *v2) & 0x80 ){
|
||||
/* The two values have different signs */
|
||||
res = (*v1 & 0x80) ? -1 : +1;
|
||||
}else{
|
||||
/* The two values have the same sign. Compare using memcmp(). */
|
||||
static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8 };
|
||||
int i;
|
||||
res = 0;
|
||||
for(i=0; i<aLen[s1]; i++){
|
||||
if( (res = v1[i] - v2[i]) ) break;
|
||||
}
|
||||
}
|
||||
if( s2>7 ){
|
||||
res = +1;
|
||||
}else if( s1>7 ){
|
||||
res = -1;
|
||||
}else{
|
||||
if( s2>7 ){
|
||||
res = +1;
|
||||
}else if( s1>7 ){
|
||||
res = -1;
|
||||
}else{
|
||||
res = s1 - s2;
|
||||
}
|
||||
assert( res!=0 );
|
||||
res = s1 - s2;
|
||||
}
|
||||
assert( res!=0 );
|
||||
|
||||
if( res>0 ){
|
||||
if( *v1 & 0x80 ) res = -1;
|
||||
}else{
|
||||
if( *v2 & 0x80 ) res = +1;
|
||||
}
|
||||
if( res>0 ){
|
||||
if( *v1 & 0x80 ) res = -1;
|
||||
}else{
|
||||
if( *v2 & 0x80 ) res = +1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -27,11 +27,11 @@
|
||||
**
|
||||
** WRC_Continue Continue descending down the tree.
|
||||
**
|
||||
** WRC_Prune Do not descend into child nodes. But allow
|
||||
** WRC_Prune Do not descend into child nodes, but allow
|
||||
** the walk to continue with sibling nodes.
|
||||
**
|
||||
** WRC_Abort Do no more callbacks. Unwind the stack and
|
||||
** return the top-level walk call.
|
||||
** return from the top-level walk call.
|
||||
**
|
||||
** The return value from this routine is WRC_Abort to abandon the tree walk
|
||||
** and WRC_Continue to continue.
|
||||
|
||||
+32
-13
@@ -517,14 +517,16 @@ static LogEst estLog(LogEst N){
|
||||
** value stored in its output register.
|
||||
*/
|
||||
static void translateColumnToCopy(
|
||||
Vdbe *v, /* The VDBE containing code to translate */
|
||||
Parse *pParse, /* Parsing context */
|
||||
int iStart, /* Translate from this opcode to the end */
|
||||
int iTabCur, /* OP_Column/OP_Rowid references to this table */
|
||||
int iRegister, /* The first column is in this register */
|
||||
int bIncrRowid /* If non-zero, transform OP_rowid to OP_AddImm(1) */
|
||||
){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
VdbeOp *pOp = sqlite3VdbeGetOp(v, iStart);
|
||||
int iEnd = sqlite3VdbeCurrentAddr(v);
|
||||
if( pParse->db->mallocFailed ) return;
|
||||
for(; iStart<iEnd; iStart++, pOp++){
|
||||
if( pOp->p1!=iTabCur ) continue;
|
||||
if( pOp->opcode==OP_Column ){
|
||||
@@ -802,7 +804,9 @@ static void constructAutomaticIndex(
|
||||
if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue);
|
||||
if( pTabItem->fg.viaCoroutine ){
|
||||
sqlite3VdbeChangeP2(v, addrCounter, regBase+n);
|
||||
translateColumnToCopy(v, addrTop, pLevel->iTabCur, pTabItem->regResult, 1);
|
||||
testcase( pParse->db->mallocFailed );
|
||||
translateColumnToCopy(pParse, addrTop, pLevel->iTabCur,
|
||||
pTabItem->regResult, 1);
|
||||
sqlite3VdbeGoto(v, addrTop);
|
||||
pTabItem->fg.viaCoroutine = 0;
|
||||
}else{
|
||||
@@ -1782,7 +1786,7 @@ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){
|
||||
p->u.vtab.idxStr = 0;
|
||||
}else if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 && p->u.btree.pIndex!=0 ){
|
||||
sqlite3DbFree(db, p->u.btree.pIndex->zColAff);
|
||||
sqlite3DbFree(db, p->u.btree.pIndex);
|
||||
sqlite3DbFreeNN(db, p->u.btree.pIndex);
|
||||
p->u.btree.pIndex = 0;
|
||||
}
|
||||
}
|
||||
@@ -1792,7 +1796,7 @@ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){
|
||||
** Deallocate internal memory used by a WhereLoop object
|
||||
*/
|
||||
static void whereLoopClear(sqlite3 *db, WhereLoop *p){
|
||||
if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm);
|
||||
if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm);
|
||||
whereLoopClearUnion(db, p);
|
||||
whereLoopInit(p);
|
||||
}
|
||||
@@ -1807,7 +1811,7 @@ static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){
|
||||
paNew = sqlite3DbMallocRawNN(db, sizeof(p->aLTerm[0])*n);
|
||||
if( paNew==0 ) return SQLITE_NOMEM_BKPT;
|
||||
memcpy(paNew, p->aLTerm, sizeof(p->aLTerm[0])*p->nLSlot);
|
||||
if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm);
|
||||
if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm);
|
||||
p->aLTerm = paNew;
|
||||
p->nLSlot = n;
|
||||
return SQLITE_OK;
|
||||
@@ -1837,7 +1841,7 @@ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){
|
||||
*/
|
||||
static void whereLoopDelete(sqlite3 *db, WhereLoop *p){
|
||||
whereLoopClear(db, p);
|
||||
sqlite3DbFree(db, p);
|
||||
sqlite3DbFreeNN(db, p);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1858,7 +1862,7 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
|
||||
pWInfo->pLoops = p->pNextLoop;
|
||||
whereLoopDelete(db, p);
|
||||
}
|
||||
sqlite3DbFree(db, pWInfo);
|
||||
sqlite3DbFreeNN(db, pWInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2387,6 +2391,11 @@ static int whereLoopAddBtreeIndex(
|
||||
continue;
|
||||
}
|
||||
|
||||
if( IsUniqueIndex(pProbe) && saved_nEq==pProbe->nKeyCol-1 ){
|
||||
pBuilder->bldFlags |= SQLITE_BLDF_UNIQUE;
|
||||
}else{
|
||||
pBuilder->bldFlags |= SQLITE_BLDF_INDEXED;
|
||||
}
|
||||
pNew->wsFlags = saved_wsFlags;
|
||||
pNew->u.btree.nEq = saved_nEq;
|
||||
pNew->u.btree.nBtm = saved_nBtm;
|
||||
@@ -2934,7 +2943,15 @@ static int whereLoopAddBtree(
|
||||
}
|
||||
}
|
||||
|
||||
pBuilder->bldFlags = 0;
|
||||
rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 0);
|
||||
if( pBuilder->bldFlags==SQLITE_BLDF_INDEXED ){
|
||||
/* If a non-unique index is used, or if a prefix of the key for
|
||||
** unique index is used (making the index functionally non-unique)
|
||||
** then the sqlite_stat1 data becomes important for scoring the
|
||||
** plan */
|
||||
pTab->tabFlags |= TF_StatsUsed;
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
sqlite3Stat4ProbeFree(pBuilder->pRec);
|
||||
pBuilder->nRecValid = 0;
|
||||
@@ -3236,7 +3253,7 @@ static int whereLoopAddVirtual(
|
||||
}
|
||||
|
||||
if( p->needToFreeIdxStr ) sqlite3_free(p->idxStr);
|
||||
sqlite3DbFree(pParse->db, p);
|
||||
sqlite3DbFreeNN(pParse->db, p);
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
@@ -4091,7 +4108,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
||||
|
||||
if( nFrom==0 ){
|
||||
sqlite3ErrorMsg(pParse, "no query solution");
|
||||
sqlite3DbFree(db, pSpace);
|
||||
sqlite3DbFreeNN(db, pSpace);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
@@ -4167,7 +4184,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
||||
pWInfo->nRowOut = pFrom->nRow;
|
||||
|
||||
/* Free temporary memory and return success */
|
||||
sqlite3DbFree(db, pSpace);
|
||||
sqlite3DbFreeNN(db, pSpace);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -4245,7 +4262,8 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
|
||||
if( pLoop->wsFlags ){
|
||||
pLoop->nOut = (LogEst)1;
|
||||
pWInfo->a[0].pWLoop = pLoop;
|
||||
pLoop->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
|
||||
assert( pWInfo->sMaskSet.n==1 && iCur==pWInfo->sMaskSet.ix[0] );
|
||||
pLoop->maskSelf = 1; /* sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); */
|
||||
pWInfo->a[0].iTabCur = iCur;
|
||||
pWInfo->nRowOut = 1;
|
||||
if( pWInfo->pOrderBy ) pWInfo->nOBSat = pWInfo->pOrderBy->nExpr;
|
||||
@@ -4907,8 +4925,9 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
** the co-routine into OP_Copy of result contained in a register.
|
||||
** OP_Rowid becomes OP_Null.
|
||||
*/
|
||||
if( pTabItem->fg.viaCoroutine && !db->mallocFailed ){
|
||||
translateColumnToCopy(v, pLevel->addrBody, pLevel->iTabCur,
|
||||
if( pTabItem->fg.viaCoroutine ){
|
||||
testcase( pParse->db->mallocFailed );
|
||||
translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur,
|
||||
pTabItem->regResult, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -395,8 +395,13 @@ struct WhereLoopBuilder {
|
||||
UnpackedRecord *pRec; /* Probe for stat4 (if required) */
|
||||
int nRecValid; /* Number of valid fields currently in pRec */
|
||||
#endif
|
||||
unsigned int bldFlags; /* SQLITE_BLDF_* flags */
|
||||
};
|
||||
|
||||
/* Allowed values for WhereLoopBuider.bldFlags */
|
||||
#define SQLITE_BLDF_INDEXED 0x0001 /* An index is used */
|
||||
#define SQLITE_BLDF_UNIQUE 0x0002 /* All keys of a UNIQUE index used */
|
||||
|
||||
/*
|
||||
** The WHERE clause processing routine has two halves. The
|
||||
** first part does the start of the WHERE loop and the second
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
# 2017-02-17
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file implements tests for the logic used to estimate when
|
||||
# running ANALYZE would be beneficial.
|
||||
#
|
||||
# Note that this test uses some hard-coded bitmask values from sqliteInt.h.
|
||||
# If any of the following constants changes:
|
||||
#
|
||||
# define TF_HasStat1 0x0010
|
||||
# define TF_StatsUsed 0x0100
|
||||
#
|
||||
# then some of the magic numbers in test results below might need to be
|
||||
# adjusted.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# There is nothing to test if ANALYZE is disable for this build.
|
||||
# These tests also use "PRAGMA stats" which are only enabled for
|
||||
# debugging builds.
|
||||
#
|
||||
ifcapable {!debug || !analyze || !vtab} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test autoanalyze1-100 {
|
||||
-- Build up a test table with some indexes
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d);
|
||||
CREATE UNIQUE INDEX t1bc ON t1(b,c);
|
||||
CREATE INDEX t1d ON t1(d);
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
|
||||
INSERT INTO t1(a,b,c,d) SELECT x, x, x, x FROM c;
|
||||
-- Verify that the hasStat1 flag is clear on on indexes
|
||||
SELECT idx, flgs FROM pragma_stats
|
||||
WHERE idx IS NOT NULL
|
||||
ORDER BY idx;
|
||||
-- Verify that the TF_HasStat1 flag is clear on the table
|
||||
SELECT tbl, (flgs & 0x10)!=0 FROM pragma_stats WHERE tbl='t1' AND idx IS NULL;
|
||||
} {t1bc 0 t1d 0 t1 0}
|
||||
|
||||
# No use of stat1 recorded so far
|
||||
do_execsql_test autoanalyze1-110 {
|
||||
SELECT (flgs & 0x0100)!=0 FROM pragma_stats WHERE tbl='t1' AND idx IS NULL;
|
||||
} {0}
|
||||
|
||||
# Access using a unique index does not set the TF_StatsUsed flag.
|
||||
#
|
||||
do_execsql_test autoanalyze1-200 {
|
||||
SELECT * FROM t1 WHERE a=55;
|
||||
} {55 55 55 55}
|
||||
do_execsql_test autoanalyze1-201 {
|
||||
SELECT (flgs & 0x0100)!=0 FROM pragma_stats WHERE tbl='t1' AND idx IS NULL;
|
||||
} {0}
|
||||
|
||||
do_execsql_test autoanalyze1-210 {
|
||||
SELECT * FROM t1 WHERE a IN (55,199,299);
|
||||
} {55 55 55 55}
|
||||
do_execsql_test autoanalyze1-211 {
|
||||
SELECT (flgs & 0x0100)!=0 FROM pragma_stats WHERE tbl='t1' AND idx IS NULL;
|
||||
} {0}
|
||||
|
||||
do_execsql_test autoanalyze1-220 {
|
||||
SELECT * FROM t1 WHERE (b,c)=(45,45);
|
||||
} {45 45 45 45}
|
||||
do_execsql_test autoanalyze1-221 {
|
||||
SELECT (flgs & 0x0100)!=0 FROM pragma_stats WHERE tbl='t1' AND idx IS NULL;
|
||||
} {0}
|
||||
|
||||
# Any use of the non-unique t1d index triggers the use of stats.
|
||||
#
|
||||
sqlite3 db test.db
|
||||
do_execsql_test autoanalyze1-300 {
|
||||
SELECT * FROM t1 WHERE d=45;
|
||||
} {45 45 45 45}
|
||||
do_execsql_test autoanalyze1-301 {
|
||||
SELECT (flgs & 0x0100)!=0 FROM pragma_stats WHERE tbl='t1' AND idx IS NULL;
|
||||
} {1}
|
||||
|
||||
sqlite3 db test.db
|
||||
do_execsql_test autoanalyze1-310 {
|
||||
SELECT * FROM t1 WHERE d=45 AND a=45;
|
||||
} {45 45 45 45}
|
||||
do_execsql_test autoanalyze1-311 {
|
||||
SELECT (flgs & 0x0100)!=0 FROM pragma_stats WHERE tbl='t1' AND idx IS NULL;
|
||||
} {0} ;# The ROWID lookup short-circuits the d=45 constraint
|
||||
|
||||
sqlite3 db test.db
|
||||
do_execsql_test autoanalyze1-320 {
|
||||
SELECT * FROM t1 WHERE d=45 AND a IN (45,46);
|
||||
} {45 45 45 45}
|
||||
do_execsql_test autoanalyze1-321 {
|
||||
SELECT (flgs & 0x0100)!=0 FROM pragma_stats WHERE tbl='t1' AND idx IS NULL;
|
||||
} {1}
|
||||
|
||||
# Any use of prefix of a unique index triggers the use of stats
|
||||
#
|
||||
sqlite3 db test.db
|
||||
do_execsql_test autoanalyze1-400 {
|
||||
SELECT * FROM t1 WHERE b=45;
|
||||
} {45 45 45 45}
|
||||
do_execsql_test autoanalyze1-401 {
|
||||
SELECT (flgs & 0x0100)!=0 FROM pragma_stats WHERE tbl='t1' AND idx IS NULL;
|
||||
} {1}
|
||||
|
||||
# The TF_StatsUsed flag is reset when the database is reopened
|
||||
#
|
||||
sqlite3 db test.db
|
||||
do_execsql_test autoanalyze1-500 {
|
||||
SELECT (flgs & 0x0100)!=0 FROM pragma_stats WHERE tbl='t1' AND idx IS NULL;
|
||||
} {0}
|
||||
|
||||
finish_test
|
||||
+17
-3
@@ -309,11 +309,15 @@ do_test check-4.8 {
|
||||
PRAGMA ignore_check_constraints=ON;
|
||||
UPDATE t4 SET x=0, y=1;
|
||||
SELECT * FROM t4;
|
||||
PRAGMA integrity_check;
|
||||
}
|
||||
} {0 1}
|
||||
} {0 1 ok}
|
||||
do_execsql_test check-4.8.1 {
|
||||
PRAGMA ignore_check_constraints=OFF;
|
||||
PRAGMA integrity_check;
|
||||
} {{CHECK constraint failed in t4}}
|
||||
do_test check-4.9 {
|
||||
catchsql {
|
||||
PRAGMA ignore_check_constraints=OFF;
|
||||
UPDATE t4 SET x=0, y=2;
|
||||
}
|
||||
} {1 {CHECK constraint failed: t4}}
|
||||
@@ -477,6 +481,16 @@ do_catchsql_test 9.3 {
|
||||
UPDATE t1 SET c=a*2 WHERE a=1;
|
||||
} {1 {CHECK constraint failed: c-check}}
|
||||
|
||||
|
||||
# Integrity check on a VIEW with columns.
|
||||
#
|
||||
db close
|
||||
db2 close
|
||||
forcedelete test.db
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 10.1 {
|
||||
CREATE TABLE t1(x);
|
||||
CREATE VIEW v1(y) AS SELECT x FROM t1;
|
||||
PRAGMA integrity_check;
|
||||
} {ok}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix collateB
|
||||
|
||||
do_execsql_test collateB-1.1 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY);
|
||||
@@ -60,4 +61,17 @@ do_execsql_test collateB-1.17 {
|
||||
SELECT *,'|' FROM t1, t2, t3 WHERE b=x2 AND a=x1 AND 1=a;
|
||||
} {1 11 1 11 |}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test an assert() failure that was occuring if an index were created
|
||||
# on a column explicitly declared "COLLATE binary".
|
||||
reset_db
|
||||
do_execsql_test 2.1 {
|
||||
CREATE TABLE t4(a COLLATE binary);
|
||||
CREATE INDEX i4 ON t4(a);
|
||||
INSERT INTO t4 VALUES('one'), ('two'), ('three');
|
||||
VACUUM;
|
||||
}
|
||||
|
||||
integrity_check 2.2
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
# 2017-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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix corruptK
|
||||
|
||||
if {[permutation]=="mmap"} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# This module uses hard-coded offsets which do not work if the reserved_bytes
|
||||
# value is nonzero.
|
||||
if {[nonzero_reserved_bytes]} {finish_test; return;}
|
||||
database_may_be_corrupt
|
||||
|
||||
# Initialize the database.
|
||||
#
|
||||
do_execsql_test 1.1 {
|
||||
PRAGMA page_size=1024;
|
||||
PRAGMA auto_vacuum=0;
|
||||
CREATE TABLE t1(x);
|
||||
|
||||
INSERT INTO t1 VALUES(randomblob(20));
|
||||
INSERT INTO t1 VALUES(randomblob(100)); -- make this into a free slot
|
||||
INSERT INTO t1 VALUES(randomblob(27)); -- this one will be corrupt
|
||||
INSERT INTO t1 VALUES(randomblob(800));
|
||||
|
||||
DELETE FROM t1 WHERE rowid=2; -- free the 100 byte slot
|
||||
PRAGMA page_count
|
||||
} {2}
|
||||
|
||||
|
||||
# Corrupt the database so that the blob stored immediately before
|
||||
# the free slot (rowid==3) has an overlarge length field. So that
|
||||
# we can use sqlite3_blob_write() to manipulate the size field of
|
||||
# the free slot.
|
||||
#
|
||||
# Then use sqlite3_blob_write() to set the size of said free slot
|
||||
# to 24 bytes (instead of the actual 100).
|
||||
#
|
||||
# Then use the new 24 byte slot. Leaving the in-memory version of
|
||||
# the page with zero free slots and a large nFree value. Then try
|
||||
# to allocate another slot to get to defragmentPage().
|
||||
#
|
||||
do_test 1.2 {
|
||||
db close
|
||||
hexio_write test.db [expr 1024 + 0x360] 21
|
||||
hexio_write test.db [expr 1024 + 0x363] [format %x [expr 31*2 + 12]]
|
||||
sqlite3 db test.db
|
||||
|
||||
set fd [db incrblob t1 x 3]
|
||||
fconfigure $fd -translation binary -encoding binary
|
||||
seek $fd 30
|
||||
puts -nonewline $fd "\x18"
|
||||
close $fd
|
||||
} {}
|
||||
do_execsql_test 1.3 {
|
||||
INSERT INTO t1 VALUES(randomblob(20));
|
||||
}
|
||||
do_catchsql_test 1.4 {
|
||||
INSERT INTO t1 VALUES(randomblob(90));
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 2.1 {
|
||||
PRAGMA page_size=1024;
|
||||
PRAGMA auto_vacuum=0;
|
||||
CREATE TABLE t1(x);
|
||||
|
||||
INSERT INTO t1 VALUES(randomblob(20));
|
||||
INSERT INTO t1 VALUES(randomblob(20)); -- free this one
|
||||
INSERT INTO t1 VALUES(randomblob(20));
|
||||
INSERT INTO t1 VALUES(randomblob(20)); -- and this one
|
||||
INSERT INTO t1 VALUES(randomblob(20)); -- corrupt this one.
|
||||
|
||||
DELETE FROM t1 WHERE rowid IN(2, 4);
|
||||
PRAGMA page_count
|
||||
} {2}
|
||||
|
||||
do_test 2.2 {
|
||||
db close
|
||||
hexio_write test.db [expr 1024 + 0x388] 53
|
||||
hexio_write test.db [expr 1024 + 0x38A] 03812C
|
||||
|
||||
sqlite3 db test.db
|
||||
set fd [db incrblob t1 x 5]
|
||||
fconfigure $fd -translation binary -encoding binary
|
||||
|
||||
seek $fd 22
|
||||
puts -nonewline $fd "\x5d"
|
||||
close $fd
|
||||
} {}
|
||||
|
||||
do_catchsql_test 2.3 {
|
||||
INSERT INTO t1 VALUES(randomblob(900));
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -596,5 +596,17 @@ datetest 16.29 {datetime(5373484,'-176546 months')} NULL
|
||||
datetest 16.30 {datetime(5373484,'-14712 years')} {-4713-12-31 12:00:00}
|
||||
datetest 16.31 {datetime(5373484,'-14713 years')} NULL
|
||||
|
||||
# 2017-03-02: Wrong 'start of day' computation.
|
||||
# https://www.sqlite.org/src/info/6097cb92745327a1
|
||||
#
|
||||
datetest 17.1 {datetime(2457754, 'start of day')} {2016-12-31 00:00:00}
|
||||
datetest 17.2 {datetime(2457828)} {2017-03-15 12:00:00}
|
||||
datetest 17.3 {datetime(2457828,'start of day')} {2017-03-15 00:00:00}
|
||||
datetest 17.4 {datetime(2457828,'start of month')} {2017-03-01 00:00:00}
|
||||
datetest 17.5 {datetime(2457828,'start of year')} {2017-01-01 00:00:00}
|
||||
datetest 17.6 {datetime(37,'start of year')} NULL
|
||||
datetest 17.7 {datetime(38,'start of year')} {-4712-01-01 00:00:00}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -1,786 +0,0 @@
|
||||
/*
|
||||
** 2017-02-07
|
||||
**
|
||||
** 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 program implements an SQLite database self-verification utility.
|
||||
** Usage:
|
||||
**
|
||||
** dbselftest DATABASE ...
|
||||
**
|
||||
** This program reads the "selftest" table in DATABASE, in rowid order,
|
||||
** and runs each of the tests described there, reporting results at the
|
||||
** end.
|
||||
**
|
||||
** The intent of this program is to have a set of test database files that
|
||||
** can be run using future versions of SQLite in order to verify that
|
||||
** legacy database files continue to be readable. In other words, the
|
||||
** intent is to confirm that there have been no breaking changes in the
|
||||
** file format. The program can also be used to verify that database files
|
||||
** are fully compatible between different architectures.
|
||||
**
|
||||
** The selftest table looks like this:
|
||||
**
|
||||
** CREATE TABLE selftest (
|
||||
** id INTEGER PRIMARY KEY, -- Run tests in ascending order
|
||||
** op TEXT, -- "test", "regexp", "print", etc.
|
||||
** cmdtxt TEXT, -- Usually the SQL to be run
|
||||
** expected TEXT -- Expected results
|
||||
** );
|
||||
**
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
static const char zHelp[] =
|
||||
"Usage: dbselftest [OPTIONS] DBFILE ...\n"
|
||||
"\n"
|
||||
" --init Create the selftest table\n"
|
||||
" -q Suppress most output. Errors only\n"
|
||||
" -v Show extra output\n"
|
||||
;
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
** The following code from ext/misc/sha1.c
|
||||
**
|
||||
** Context for the SHA1 hash
|
||||
*/
|
||||
typedef struct SHA1Context SHA1Context;
|
||||
struct SHA1Context {
|
||||
unsigned int state[5];
|
||||
unsigned int count[2];
|
||||
unsigned char buffer[64];
|
||||
};
|
||||
|
||||
|
||||
#if __GNUC__ && (defined(__i386__) || defined(__x86_64__))
|
||||
/*
|
||||
* GCC by itself only generates left rotates. Use right rotates if
|
||||
* possible to be kinder to dinky implementations with iterative rotate
|
||||
* instructions.
|
||||
*/
|
||||
#define SHA_ROT(op, x, k) \
|
||||
({ unsigned int y; asm(op " %1,%0" : "=r" (y) : "I" (k), "0" (x)); y; })
|
||||
#define rol(x,k) SHA_ROT("roll", x, k)
|
||||
#define ror(x,k) SHA_ROT("rorl", x, k)
|
||||
|
||||
#else
|
||||
/* Generic C equivalent */
|
||||
#define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r))
|
||||
#define rol(x,k) SHA_ROT(x,k,32-(k))
|
||||
#define ror(x,k) SHA_ROT(x,32-(k),k)
|
||||
#endif
|
||||
|
||||
|
||||
#define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \
|
||||
|(rol(block[i],8)&0x00FF00FF))
|
||||
#define blk0be(i) block[i]
|
||||
#define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \
|
||||
^block[(i+2)&15]^block[i&15],1))
|
||||
|
||||
/*
|
||||
* (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
|
||||
*
|
||||
* Rl0() for little-endian and Rb0() for big-endian. Endianness is
|
||||
* determined at run-time.
|
||||
*/
|
||||
#define Rl0(v,w,x,y,z,i) \
|
||||
z+=((w&(x^y))^y)+blk0le(i)+0x5A827999+rol(v,5);w=ror(w,2);
|
||||
#define Rb0(v,w,x,y,z,i) \
|
||||
z+=((w&(x^y))^y)+blk0be(i)+0x5A827999+rol(v,5);w=ror(w,2);
|
||||
#define R1(v,w,x,y,z,i) \
|
||||
z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=ror(w,2);
|
||||
#define R2(v,w,x,y,z,i) \
|
||||
z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=ror(w,2);
|
||||
#define R3(v,w,x,y,z,i) \
|
||||
z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=ror(w,2);
|
||||
#define R4(v,w,x,y,z,i) \
|
||||
z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=ror(w,2);
|
||||
|
||||
/*
|
||||
* Hash a single 512-bit block. This is the core of the algorithm.
|
||||
*/
|
||||
void SHA1Transform(unsigned int state[5], const unsigned char buffer[64]){
|
||||
unsigned int qq[5]; /* a, b, c, d, e; */
|
||||
static int one = 1;
|
||||
unsigned int block[16];
|
||||
memcpy(block, buffer, 64);
|
||||
memcpy(qq,state,5*sizeof(unsigned int));
|
||||
|
||||
#define a qq[0]
|
||||
#define b qq[1]
|
||||
#define c qq[2]
|
||||
#define d qq[3]
|
||||
#define e qq[4]
|
||||
|
||||
/* Copy p->state[] to working vars */
|
||||
/*
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
*/
|
||||
|
||||
/* 4 rounds of 20 operations each. Loop unrolled. */
|
||||
if( 1 == *(unsigned char*)&one ){
|
||||
Rl0(a,b,c,d,e, 0); Rl0(e,a,b,c,d, 1); Rl0(d,e,a,b,c, 2); Rl0(c,d,e,a,b, 3);
|
||||
Rl0(b,c,d,e,a, 4); Rl0(a,b,c,d,e, 5); Rl0(e,a,b,c,d, 6); Rl0(d,e,a,b,c, 7);
|
||||
Rl0(c,d,e,a,b, 8); Rl0(b,c,d,e,a, 9); Rl0(a,b,c,d,e,10); Rl0(e,a,b,c,d,11);
|
||||
Rl0(d,e,a,b,c,12); Rl0(c,d,e,a,b,13); Rl0(b,c,d,e,a,14); Rl0(a,b,c,d,e,15);
|
||||
}else{
|
||||
Rb0(a,b,c,d,e, 0); Rb0(e,a,b,c,d, 1); Rb0(d,e,a,b,c, 2); Rb0(c,d,e,a,b, 3);
|
||||
Rb0(b,c,d,e,a, 4); Rb0(a,b,c,d,e, 5); Rb0(e,a,b,c,d, 6); Rb0(d,e,a,b,c, 7);
|
||||
Rb0(c,d,e,a,b, 8); Rb0(b,c,d,e,a, 9); Rb0(a,b,c,d,e,10); Rb0(e,a,b,c,d,11);
|
||||
Rb0(d,e,a,b,c,12); Rb0(c,d,e,a,b,13); Rb0(b,c,d,e,a,14); Rb0(a,b,c,d,e,15);
|
||||
}
|
||||
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
|
||||
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
|
||||
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
|
||||
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
|
||||
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
|
||||
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
|
||||
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
|
||||
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
|
||||
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
|
||||
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
|
||||
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
|
||||
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
|
||||
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
|
||||
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
|
||||
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
|
||||
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
|
||||
|
||||
/* Add the working vars back into context.state[] */
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
|
||||
#undef a
|
||||
#undef b
|
||||
#undef c
|
||||
#undef d
|
||||
#undef e
|
||||
}
|
||||
|
||||
|
||||
/* Initialize a SHA1 context */
|
||||
static void hash_init(SHA1Context *p){
|
||||
/* SHA1 initialization constants */
|
||||
p->state[0] = 0x67452301;
|
||||
p->state[1] = 0xEFCDAB89;
|
||||
p->state[2] = 0x98BADCFE;
|
||||
p->state[3] = 0x10325476;
|
||||
p->state[4] = 0xC3D2E1F0;
|
||||
p->count[0] = p->count[1] = 0;
|
||||
}
|
||||
|
||||
/* Add new content to the SHA1 hash */
|
||||
static void hash_step(
|
||||
SHA1Context *p, /* Add content to this context */
|
||||
const unsigned char *data, /* Data to be added */
|
||||
unsigned int len /* Number of bytes in data */
|
||||
){
|
||||
unsigned int i, j;
|
||||
|
||||
j = p->count[0];
|
||||
if( (p->count[0] += len << 3) < j ){
|
||||
p->count[1] += (len>>29)+1;
|
||||
}
|
||||
j = (j >> 3) & 63;
|
||||
if( (j + len) > 63 ){
|
||||
(void)memcpy(&p->buffer[j], data, (i = 64-j));
|
||||
SHA1Transform(p->state, p->buffer);
|
||||
for(; i + 63 < len; i += 64){
|
||||
SHA1Transform(p->state, &data[i]);
|
||||
}
|
||||
j = 0;
|
||||
}else{
|
||||
i = 0;
|
||||
}
|
||||
(void)memcpy(&p->buffer[j], &data[i], len - i);
|
||||
}
|
||||
|
||||
/* Compute a string using sqlite3_vsnprintf() and hash it */
|
||||
static void hash_step_vformat(
|
||||
SHA1Context *p, /* Add content to this context */
|
||||
const char *zFormat,
|
||||
...
|
||||
){
|
||||
va_list ap;
|
||||
int n;
|
||||
char zBuf[50];
|
||||
va_start(ap, zFormat);
|
||||
sqlite3_vsnprintf(sizeof(zBuf),zBuf,zFormat,ap);
|
||||
va_end(ap);
|
||||
n = (int)strlen(zBuf);
|
||||
hash_step(p, (unsigned char*)zBuf, n);
|
||||
}
|
||||
|
||||
|
||||
/* Add padding and compute the message digest. Render the
|
||||
** message digest as lower-case hexadecimal and put it into
|
||||
** zOut[]. zOut[] must be at least 41 bytes long. */
|
||||
static void hash_finish(
|
||||
SHA1Context *p, /* The SHA1 context to finish and render */
|
||||
char *zOut /* Store hexadecimal hash here */
|
||||
){
|
||||
unsigned int i;
|
||||
unsigned char finalcount[8];
|
||||
unsigned char digest[20];
|
||||
static const char zEncode[] = "0123456789abcdef";
|
||||
|
||||
for (i = 0; i < 8; i++){
|
||||
finalcount[i] = (unsigned char)((p->count[(i >= 4 ? 0 : 1)]
|
||||
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
|
||||
}
|
||||
hash_step(p, (const unsigned char *)"\200", 1);
|
||||
while ((p->count[0] & 504) != 448){
|
||||
hash_step(p, (const unsigned char *)"\0", 1);
|
||||
}
|
||||
hash_step(p, finalcount, 8); /* Should cause a SHA1Transform() */
|
||||
for (i = 0; i < 20; i++){
|
||||
digest[i] = (unsigned char)((p->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
|
||||
}
|
||||
for(i=0; i<20; i++){
|
||||
zOut[i*2] = zEncode[(digest[i]>>4)&0xf];
|
||||
zOut[i*2+1] = zEncode[digest[i] & 0xf];
|
||||
}
|
||||
zOut[i*2]= 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the sha1(X) function.
|
||||
**
|
||||
** Return a lower-case hexadecimal rendering of the SHA1 hash of the
|
||||
** argument X. If X is a BLOB, it is hashed as is. For all other
|
||||
** types of input, X is converted into a UTF-8 string and the string
|
||||
** is hash without the trailing 0x00 terminator. The hash of a NULL
|
||||
** value is NULL.
|
||||
*/
|
||||
static void sha1Func(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
SHA1Context cx;
|
||||
int eType = sqlite3_value_type(argv[0]);
|
||||
int nByte = sqlite3_value_bytes(argv[0]);
|
||||
char zOut[44];
|
||||
|
||||
assert( argc==1 );
|
||||
if( eType==SQLITE_NULL ) return;
|
||||
hash_init(&cx);
|
||||
if( eType==SQLITE_BLOB ){
|
||||
hash_step(&cx, sqlite3_value_blob(argv[0]), nByte);
|
||||
}else{
|
||||
hash_step(&cx, sqlite3_value_text(argv[0]), nByte);
|
||||
}
|
||||
hash_finish(&cx, zOut);
|
||||
sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/*
|
||||
** Run a prepared statement and compute the SHA1 hash on the
|
||||
** result rows.
|
||||
*/
|
||||
static void sha1RunStatement(SHA1Context *pCtx, sqlite3_stmt *pStmt){
|
||||
int nCol = sqlite3_column_count(pStmt);
|
||||
const char *z = sqlite3_sql(pStmt);
|
||||
int n = (int)strlen(z);
|
||||
|
||||
hash_step_vformat(pCtx,"S%d:",n);
|
||||
hash_step(pCtx,(unsigned char*)z,n);
|
||||
|
||||
/* Compute a hash over the result of the query */
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
int i;
|
||||
hash_step(pCtx,(const unsigned char*)"R",1);
|
||||
for(i=0; i<nCol; i++){
|
||||
switch( sqlite3_column_type(pStmt,i) ){
|
||||
case SQLITE_NULL: {
|
||||
hash_step(pCtx, (const unsigned char*)"N",1);
|
||||
break;
|
||||
}
|
||||
case SQLITE_INTEGER: {
|
||||
sqlite3_uint64 u;
|
||||
int j;
|
||||
unsigned char x[9];
|
||||
sqlite3_int64 v = sqlite3_column_int64(pStmt,i);
|
||||
memcpy(&u, &v, 8);
|
||||
for(j=8; j>=1; j--){
|
||||
x[j] = u & 0xff;
|
||||
u >>= 8;
|
||||
}
|
||||
x[0] = 'I';
|
||||
hash_step(pCtx, x, 9);
|
||||
break;
|
||||
}
|
||||
case SQLITE_FLOAT: {
|
||||
sqlite3_uint64 u;
|
||||
int j;
|
||||
unsigned char x[9];
|
||||
double r = sqlite3_column_double(pStmt,i);
|
||||
memcpy(&u, &r, 8);
|
||||
for(j=8; j>=1; j--){
|
||||
x[j] = u & 0xff;
|
||||
u >>= 8;
|
||||
}
|
||||
x[0] = 'F';
|
||||
hash_step(pCtx,x,9);
|
||||
break;
|
||||
}
|
||||
case SQLITE_TEXT: {
|
||||
int n2 = sqlite3_column_bytes(pStmt, i);
|
||||
const unsigned char *z2 = sqlite3_column_text(pStmt, i);
|
||||
hash_step_vformat(pCtx,"T%d:",n2);
|
||||
hash_step(pCtx, z2, n2);
|
||||
break;
|
||||
}
|
||||
case SQLITE_BLOB: {
|
||||
int n2 = sqlite3_column_bytes(pStmt, i);
|
||||
const unsigned char *z2 = sqlite3_column_blob(pStmt, i);
|
||||
hash_step_vformat(pCtx,"B%d:",n2);
|
||||
hash_step(pCtx, z2, n2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Run one or more statements of SQL. Compute a SHA1 hash of the output.
|
||||
*/
|
||||
static int sha1Exec(
|
||||
sqlite3 *db, /* Run against this database connection */
|
||||
const char *zSql, /* The SQL to be run */
|
||||
char *zOut /* Store the SHA1 hash as hexadecimal in this buffer */
|
||||
){
|
||||
sqlite3_stmt *pStmt = 0; /* A prepared statement */
|
||||
int rc; /* Result of an API call */
|
||||
SHA1Context cx; /* The SHA1 hash context */
|
||||
|
||||
hash_init(&cx);
|
||||
while( zSql[0] ){
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql);
|
||||
if( rc ){
|
||||
sqlite3_finalize(pStmt);
|
||||
return rc;
|
||||
}
|
||||
sha1RunStatement(&cx, pStmt);
|
||||
sqlite3_finalize(pStmt);
|
||||
}
|
||||
hash_finish(&cx, zOut);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the sha1_query(SQL) function.
|
||||
**
|
||||
** This function compiles and runs the SQL statement(s) given in the
|
||||
** argument. The results are hashed using SHA1 and that hash is returned.
|
||||
**
|
||||
** The original SQL text is included as part of the hash.
|
||||
**
|
||||
** The hash is not just a concatenation of the outputs. Each query
|
||||
** is delimited and each row and value within the query is delimited,
|
||||
** with all values being marked with their datatypes.
|
||||
*/
|
||||
static void sha1QueryFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
const char *zSql = (const char*)sqlite3_value_text(argv[0]);
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
int rc;
|
||||
SHA1Context cx;
|
||||
char zOut[44];
|
||||
|
||||
assert( argc==1 );
|
||||
if( zSql==0 ) return;
|
||||
hash_init(&cx);
|
||||
while( zSql[0] ){
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql);
|
||||
if( rc ){
|
||||
char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s",
|
||||
zSql, sqlite3_errmsg(db));
|
||||
sqlite3_finalize(pStmt);
|
||||
sqlite3_result_error(context, zMsg, -1);
|
||||
sqlite3_free(zMsg);
|
||||
return;
|
||||
}
|
||||
if( !sqlite3_stmt_readonly(pStmt) ){
|
||||
char *zMsg = sqlite3_mprintf("non-query: [%s]", sqlite3_sql(pStmt));
|
||||
sqlite3_finalize(pStmt);
|
||||
sqlite3_result_error(context, zMsg, -1);
|
||||
sqlite3_free(zMsg);
|
||||
return;
|
||||
}
|
||||
sha1RunStatement(&cx, pStmt);
|
||||
sqlite3_finalize(pStmt);
|
||||
}
|
||||
hash_finish(&cx, zOut);
|
||||
sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
|
||||
}
|
||||
/* End of ext/misc/sha1.c
|
||||
******************************************************************************/
|
||||
|
||||
/* How much output to display */
|
||||
#define VOLUME_MIN 0
|
||||
#define VOLUME_OFF 0
|
||||
#define VOLUME_ERROR_ONLY 1
|
||||
#define VOLUME_LOW 2
|
||||
#define VOLUME_ECHO 3
|
||||
#define VOLUME_VERBOSE 4
|
||||
#define VOLUME_MAX 4
|
||||
|
||||
/* A string accumulator
|
||||
*/
|
||||
typedef struct Str {
|
||||
char *z; /* Accumulated text */
|
||||
int n; /* Bytes of z[] used so far */
|
||||
int nAlloc; /* Bytes allocated for z[] */
|
||||
} Str;
|
||||
|
||||
/* Append text to the Str object
|
||||
*/
|
||||
static void strAppend(Str *p, const char *z){
|
||||
int n = (int)strlen(z);
|
||||
if( p->n+n >= p->nAlloc ){
|
||||
p->nAlloc += p->n+n + 100;
|
||||
p->z = sqlite3_realloc(p->z, p->nAlloc);
|
||||
if( z==0 ){
|
||||
printf("Could not allocate %d bytes\n", p->nAlloc);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
memcpy(p->z+p->n, z, n+1);
|
||||
p->n += n;
|
||||
}
|
||||
|
||||
/* This is an sqlite3_exec() callback that will capture all
|
||||
** output in a Str.
|
||||
**
|
||||
** Columns are separated by ",". Rows are separated by "|".
|
||||
*/
|
||||
static int execCallback(void *pStr, int argc, char **argv, char **colv){
|
||||
int i;
|
||||
Str *p = (Str*)pStr;
|
||||
if( p->n ) strAppend(p, "|");
|
||||
for(i=0; i<argc; i++){
|
||||
const char *z = (const char*)argv[i];
|
||||
if( z==0 ) z = "NULL";
|
||||
if( i>0 ) strAppend(p, ",");
|
||||
strAppend(p, z);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Run an SQL statement constructing using sqlite3_vmprintf().
|
||||
** Return the number of errors.
|
||||
*/
|
||||
static int runSql(sqlite3 *db, const char *zFormat, ...){
|
||||
char *zSql;
|
||||
char *zErr = 0;
|
||||
int rc;
|
||||
int nErr = 0;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, zFormat);
|
||||
zSql = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
if( zSql==0 ){
|
||||
printf("Out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
rc = sqlite3_exec(db, zSql, 0, 0, &zErr);
|
||||
if( rc || zErr ){
|
||||
printf("SQL error in [%s]: code=%d: %s\n", zSql, rc, zErr);
|
||||
nErr++;
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
return nErr;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate a prepared statement using a formatted string.
|
||||
*/
|
||||
static sqlite3_stmt *prepareSql(sqlite3 *db, const char *zFormat, ...){
|
||||
char *zSql;
|
||||
int rc;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, zFormat);
|
||||
zSql = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
if( zSql==0 ){
|
||||
printf("Out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
|
||||
if( rc ){
|
||||
printf("SQL error in [%s]: code=%d: %s\n", zSql, rc, sqlite3_errmsg(db));
|
||||
sqlite3_finalize(pStmt);
|
||||
pStmt = 0;
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
return pStmt;
|
||||
}
|
||||
|
||||
/*
|
||||
** Construct the standard selftest configuration for the database.
|
||||
*/
|
||||
static int buildSelftestTable(sqlite3 *db){
|
||||
int rc;
|
||||
sqlite3_stmt *pStmt;
|
||||
int tno = 110;
|
||||
char *zSql;
|
||||
char zHash[50];
|
||||
|
||||
rc = runSql(db,
|
||||
"CREATE TABLE IF NOT EXISTS selftest(\n"
|
||||
" tno INTEGER PRIMARY KEY, -- test number\n"
|
||||
" op TEXT, -- what kind of test\n"
|
||||
" sql TEXT, -- SQL text for the test\n"
|
||||
" ans TEXT -- expected answer\n"
|
||||
");"
|
||||
"INSERT INTO selftest"
|
||||
" VALUES(100,'memo','Hashes generated using --init',NULL);"
|
||||
);
|
||||
if( rc ) return 1;
|
||||
tno = 110;
|
||||
zSql = "SELECT type,name,tbl_name,sql FROM sqlite_master ORDER BY name";
|
||||
sha1Exec(db, zSql, zHash);
|
||||
rc = runSql(db,
|
||||
"INSERT INTO selftest(tno,op,sql,ans)"
|
||||
" VALUES(%d,'sha1',%Q,%Q)", tno, zSql, zHash);
|
||||
tno += 10;
|
||||
pStmt = prepareSql(db,
|
||||
"SELECT lower(name) FROM sqlite_master"
|
||||
" WHERE type='table' AND sql NOT GLOB 'CREATE VIRTUAL*'"
|
||||
" AND name<>'selftest'"
|
||||
" ORDER BY 1");
|
||||
if( pStmt==0 ) return 1;
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
zSql = sqlite3_mprintf("SELECT * FROM \"%w\" NOT INDEXED",
|
||||
sqlite3_column_text(pStmt, 0));
|
||||
if( zSql==0 ){
|
||||
printf("Of of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
sha1Exec(db, zSql, zHash);
|
||||
rc = runSql(db,
|
||||
"INSERT INTO selftest(tno,op,sql,ans)"
|
||||
" VALUES(%d,'sha1',%Q,%Q)", tno, zSql, zHash);
|
||||
tno += 10;
|
||||
sqlite3_free(zSql);
|
||||
if( rc ) break;
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
if( rc ) return 1;
|
||||
rc = runSql(db,
|
||||
"INSERT INTO selftest(tno,op,sql,ans)"
|
||||
" VALUES(%d,'run','PRAGMA integrity_check','ok');", tno);
|
||||
if( rc ) return 1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if the named table exists
|
||||
*/
|
||||
static int tableExists(sqlite3 *db, const char *zTab){
|
||||
return sqlite3_table_column_metadata(db, "main", zTab, 0, 0, 0, 0, 0, 0)
|
||||
== SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Default selftest table content, for use when there is no selftest table
|
||||
*/
|
||||
static char *azDefaultTest[] = {
|
||||
0, 0, 0, 0,
|
||||
"0", "memo", "Missing SELFTEST table - default checks only", "",
|
||||
"1", "run", "PRAGMA integrity_check", "ok"
|
||||
};
|
||||
|
||||
int main(int argc, char **argv){
|
||||
int eVolume = VOLUME_LOW; /* How much output to display */
|
||||
const char **azDb = 0; /* Name of the database file */
|
||||
int nDb = 0; /* Number of database files to check */
|
||||
int doInit = 0; /* True if --init is present */
|
||||
sqlite3 *db = 0; /* Open database connection */
|
||||
int rc; /* Return code from API calls */
|
||||
char *zErrMsg = 0; /* An error message return */
|
||||
char **azTest; /* Content of the selftest table */
|
||||
int nRow = 0, nCol = 0; /* Rows and columns in azTest[] */
|
||||
int i; /* Loop counter */
|
||||
int nErr = 0; /* Number of errors */
|
||||
int iDb; /* Loop counter for databases */
|
||||
Str str; /* Result accumulator */
|
||||
int nTest = 0; /* Number of tests run */
|
||||
|
||||
for(i=1; i<argc; i++){
|
||||
const char *z = argv[i];
|
||||
if( z[0]=='-' ){
|
||||
if( z[1]=='-' ) z++;
|
||||
if( strcmp(z, "-help")==0 ){
|
||||
printf("%s", zHelp);
|
||||
return 0;
|
||||
}else
|
||||
if( strcmp(z, "-init")==0 ){
|
||||
doInit = 1;
|
||||
}else
|
||||
if( strcmp(z, "-a")==0 ){
|
||||
if( eVolume>VOLUME_MIN) eVolume--;
|
||||
}else
|
||||
if( strcmp(z, "-v")==0 ){
|
||||
if( eVolume<VOLUME_MAX) eVolume++;
|
||||
}else
|
||||
{
|
||||
printf("unknown option: \"%s\"\nUse --help for more information\n",
|
||||
argv[i]);
|
||||
return 1;
|
||||
}
|
||||
}else{
|
||||
nDb++;
|
||||
azDb = sqlite3_realloc(azDb, nDb*sizeof(azDb[0]));
|
||||
if( azDb==0 ){
|
||||
printf("out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
azDb[nDb-1] = argv[i];
|
||||
}
|
||||
}
|
||||
if( nDb==0 ){
|
||||
printf("No databases specified. Use --help for more info\n");
|
||||
return 1;
|
||||
}
|
||||
if( eVolume>=VOLUME_LOW ){
|
||||
printf("SQLite %s\n", sqlite3_sourceid());
|
||||
}
|
||||
memset(&str, 0, sizeof(str));
|
||||
strAppend(&str, "\n");
|
||||
for(iDb=0; iDb<nDb; iDb++, sqlite3_close(db)){
|
||||
rc = sqlite3_open_v2(azDb[iDb], &db,
|
||||
doInit ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY, 0);
|
||||
if( rc ){
|
||||
printf("Cannot open \"%s\": %s\n", azDb[iDb], sqlite3_errmsg(db));
|
||||
return 1;
|
||||
}
|
||||
rc = sqlite3_create_function(db, "sha1", 1, SQLITE_UTF8, 0,
|
||||
sha1Func, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "sha1_query", 1, SQLITE_UTF8, 0,
|
||||
sha1QueryFunc, 0, 0);
|
||||
}
|
||||
if( rc ){
|
||||
printf("Initialization error: %s\n", sqlite3_errmsg(db));
|
||||
sqlite3_close(db);
|
||||
return 1;
|
||||
}
|
||||
if( doInit && !tableExists(db, "selftest") ){
|
||||
buildSelftestTable(db);
|
||||
}
|
||||
if( !tableExists(db, "selftest") ){
|
||||
azTest = azDefaultTest;
|
||||
nCol = 4;
|
||||
nRow = 2;
|
||||
}else{
|
||||
rc = sqlite3_get_table(db,
|
||||
"SELECT tno,op,sql,ans FROM selftest ORDER BY tno",
|
||||
&azTest, &nRow, &nCol, &zErrMsg);
|
||||
if( rc || zErrMsg ){
|
||||
printf("Error querying selftest: %s\n", zErrMsg);
|
||||
sqlite3_free_table(azTest);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
for(i=1; i<=nRow; i++){
|
||||
int tno = atoi(azTest[i*nCol]);
|
||||
const char *zOp = azTest[i*nCol+1];
|
||||
const char *zSql = azTest[i*nCol+2];
|
||||
const char *zAns = azTest[i*nCol+3];
|
||||
|
||||
if( eVolume>=VOLUME_ECHO ){
|
||||
char *zQuote = sqlite3_mprintf("%q", zSql);
|
||||
printf("%d: %s %s\n", tno, zOp, zSql);
|
||||
sqlite3_free(zQuote);
|
||||
}
|
||||
if( strcmp(zOp,"memo")==0 ){
|
||||
if( eVolume>=VOLUME_LOW ){
|
||||
printf("%s: %s\n", azDb[iDb], zSql);
|
||||
}
|
||||
}else
|
||||
if( strcmp(zOp,"sha1")==0 ){
|
||||
char zOut[44];
|
||||
rc = sha1Exec(db, zSql, zOut);
|
||||
nTest++;
|
||||
if( eVolume>=VOLUME_VERBOSE ){
|
||||
printf("Result: %s\n", zOut);
|
||||
}
|
||||
if( rc ){
|
||||
nErr++;
|
||||
if( eVolume>=VOLUME_ERROR_ONLY ){
|
||||
printf("%d: error-code-%d: %s\n", tno, rc, sqlite3_errmsg(db));
|
||||
}
|
||||
}else if( strcmp(zAns,zOut)!=0 ){
|
||||
nErr++;
|
||||
if( eVolume>=VOLUME_ERROR_ONLY ){
|
||||
printf("%d: Expected: [%s]\n", tno, zAns);
|
||||
printf("%d: Got: [%s]\n", tno, zOut);
|
||||
}
|
||||
}
|
||||
}else
|
||||
if( strcmp(zOp,"run")==0 ){
|
||||
str.n = 0;
|
||||
str.z[0] = 0;
|
||||
zErrMsg = 0;
|
||||
rc = sqlite3_exec(db, zSql, execCallback, &str, &zErrMsg);
|
||||
nTest++;
|
||||
if( eVolume>=VOLUME_VERBOSE ){
|
||||
printf("Result: %s\n", str.z);
|
||||
}
|
||||
if( rc || zErrMsg ){
|
||||
nErr++;
|
||||
if( eVolume>=VOLUME_ERROR_ONLY ){
|
||||
printf("%d: error-code-%d: %s\n", tno, rc, zErrMsg);
|
||||
}
|
||||
sqlite3_free(zErrMsg);
|
||||
}else if( strcmp(zAns,str.z)!=0 ){
|
||||
nErr++;
|
||||
if( eVolume>=VOLUME_ERROR_ONLY ){
|
||||
printf("%d: Expected: [%s]\n", tno, zAns);
|
||||
printf("%d: Got: [%s]\n", tno, str.z);
|
||||
}
|
||||
}
|
||||
}else
|
||||
{
|
||||
printf("Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if( azTest!=azDefaultTest ) sqlite3_free_table(azTest);
|
||||
}
|
||||
if( eVolume>=VOLUME_LOW || (nErr>0 && eVolume>=VOLUME_ERROR_ONLY) ){
|
||||
printf("%d errors out of %d tests on %d databases\n", nErr, nTest, nDb);
|
||||
}
|
||||
return nErr;
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
# 2017 Feb 27
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Tests of the last_insert_rowid functionality with fts4.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source [file join [file dirname [info script]] tester.tcl]
|
||||
set testprefix fts4lastrowid
|
||||
|
||||
ifcapable !fts3 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts4(str);
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
INSERT INTO t1 VALUES('one string');
|
||||
INSERT INTO t1 VALUES('two string');
|
||||
INSERT INTO t1 VALUES('three string');
|
||||
SELECT last_insert_rowid();
|
||||
} {3}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES('one string');
|
||||
INSERT INTO t1 VALUES('two string');
|
||||
INSERT INTO t1 VALUES('three string');
|
||||
COMMIT;
|
||||
SELECT last_insert_rowid();
|
||||
} {6}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
INSERT INTO t1(rowid, str) VALUES(-22, 'some more text');
|
||||
SELECT last_insert_rowid();
|
||||
} {-22}
|
||||
|
||||
do_execsql_test 1.4 {
|
||||
BEGIN;
|
||||
INSERT INTO t1(rowid, str) VALUES(45, 'some more text');
|
||||
INSERT INTO t1(rowid, str) VALUES(46, 'some more text');
|
||||
INSERT INTO t1(rowid, str) VALUES(222, 'some more text');
|
||||
SELECT last_insert_rowid();
|
||||
COMMIT;
|
||||
SELECT last_insert_rowid();
|
||||
} {222 222}
|
||||
|
||||
do_execsql_test 1.5 {
|
||||
CREATE TABLE x1(x);
|
||||
INSERT INTO x1 VALUES('john'), ('paul'), ('george'), ('ringo');
|
||||
INSERT INTO t1 SELECT x FROM x1;
|
||||
SELECT last_insert_rowid();
|
||||
} {226}
|
||||
|
||||
do_execsql_test 1.6 {
|
||||
INSERT INTO t1(rowid, str) SELECT rowid+10, x FROM x1;
|
||||
SELECT last_insert_rowid();
|
||||
} {14}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+21
-5
@@ -805,6 +805,7 @@ static void showHelp(void){
|
||||
" --load-db ARGS... Load template databases from files into SOURCE_DB\n"
|
||||
" -m TEXT Add a description to the database\n"
|
||||
" --native-vfs Use the native VFS for initially empty database files\n"
|
||||
" --native-malloc Turn off MEMSYS3/5 and Lookaside\n"
|
||||
" --oss-fuzz Enable OSS-FUZZ testing\n"
|
||||
" --prng-seed N Seed value for the PRGN inside of SQLite\n"
|
||||
" --rebuild Rebuild and vacuum the database file\n"
|
||||
@@ -851,6 +852,7 @@ int main(int argc, char **argv){
|
||||
void *pHeap = 0; /* Heap for use by SQLite */
|
||||
int ossFuzz = 0; /* enable OSS-FUZZ testing */
|
||||
int ossFuzzThisDb = 0; /* ossFuzz value for this particular database */
|
||||
int nativeMalloc = 0; /* Turn off MEMSYS3/5 and lookaside if true */
|
||||
sqlite3_vfs *pDfltVfs; /* The default VFS */
|
||||
|
||||
iBegin = timeOfDay();
|
||||
@@ -911,6 +913,9 @@ int main(int argc, char **argv){
|
||||
if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]);
|
||||
zMsg = argv[++i];
|
||||
}else
|
||||
if( strcmp(z,"native-malloc")==0 ){
|
||||
nativeMalloc = 1;
|
||||
}else
|
||||
if( strcmp(z,"native-vfs")==0 ){
|
||||
nativeFlag = 1;
|
||||
}else
|
||||
@@ -972,7 +977,7 @@ int main(int argc, char **argv){
|
||||
/* Process each source database separately */
|
||||
for(iSrcDb=0; iSrcDb<nSrcDb; iSrcDb++){
|
||||
rc = sqlite3_open_v2(azSrcDb[iSrcDb], &db,
|
||||
SQLITE_OPEN_READONLY, pDfltVfs->zName);
|
||||
SQLITE_OPEN_READWRITE, pDfltVfs->zName);
|
||||
if( rc ){
|
||||
fatalError("cannot open source database %s - %s",
|
||||
azSrcDb[iSrcDb], sqlite3_errmsg(db));
|
||||
@@ -1013,7 +1018,7 @@ int main(int argc, char **argv){
|
||||
ossFuzzThisDb = sqlite3_column_int(pStmt,1);
|
||||
if( verboseFlag ) printf("Config: oss-fuzz=%d\n", ossFuzzThisDb);
|
||||
}
|
||||
if( strcmp(zName, "limit-mem")==0 ){
|
||||
if( strcmp(zName, "limit-mem")==0 && !nativeMalloc ){
|
||||
#if !defined(SQLITE_ENABLE_MEMSYS3) && !defined(SQLITE_ENABLE_MEMSYS5)
|
||||
fatalError("the limit-mem option requires -DSQLITE_ENABLE_MEMSYS5"
|
||||
" or _MEMSYS3");
|
||||
@@ -1047,6 +1052,8 @@ int main(int argc, char **argv){
|
||||
sqlite3_close(db);
|
||||
return 0;
|
||||
}
|
||||
rc = sqlite3_exec(db, "PRAGMA query_only=1;", 0, 0, 0);
|
||||
if( rc ) fatalError("cannot set database to query-only");
|
||||
if( zExpDb!=0 || zExpSql!=0 ){
|
||||
sqlite3_create_function(db, "writefile", 2, SQLITE_UTF8, 0,
|
||||
writefileFunc, 0, 0);
|
||||
@@ -1141,14 +1148,19 @@ int main(int argc, char **argv){
|
||||
}
|
||||
|
||||
/* Limit available memory, if requested */
|
||||
if( nMemThisDb>0 ){
|
||||
sqlite3_shutdown();
|
||||
sqlite3_shutdown();
|
||||
if( nMemThisDb>0 && !nativeMalloc ){
|
||||
pHeap = realloc(pHeap, nMemThisDb);
|
||||
if( pHeap==0 ){
|
||||
fatalError("failed to allocate %d bytes of heap memory", nMem);
|
||||
}
|
||||
sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nMemThisDb, 128);
|
||||
}
|
||||
|
||||
/* Disable lookaside with the --native-malloc option */
|
||||
if( nativeMalloc ){
|
||||
sqlite3_config(SQLITE_CONFIG_LOOKASIDE, 0, 0);
|
||||
}
|
||||
|
||||
/* Reset the in-memory virtual filesystem */
|
||||
formatVfs();
|
||||
@@ -1205,9 +1217,13 @@ int main(int argc, char **argv){
|
||||
runSql(db, (char*)pSql->a, runFlags);
|
||||
}while( timeoutTest );
|
||||
setAlarm(0);
|
||||
sqlite3_exec(db, "PRAGMA temp_store_directory=''", 0, 0, 0);
|
||||
sqlite3_close(db);
|
||||
}
|
||||
if( sqlite3_memory_used()>0 ) fatalError("memory leak");
|
||||
if( sqlite3_memory_used()>0 ){
|
||||
fatalError("memory leak: %lld bytes outstanding",
|
||||
sqlite3_memory_used());
|
||||
}
|
||||
reformatVfs();
|
||||
nTest++;
|
||||
g.zTestName[0] = 0;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix insert4
|
||||
|
||||
ifcapable !view||!subquery {
|
||||
finish_test
|
||||
@@ -566,4 +567,36 @@ do_catchsql_test insert4-9.1 {
|
||||
INSERT INTO t1(x) VALUES(5 COLLATE xyzzy) UNION SELECT 0;
|
||||
} {1 {no such collation sequence: xyzzy}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check that running an integrity-check does not disable the xfer
|
||||
# optimization for tables with CHECK constraints.
|
||||
#
|
||||
do_execsql_test 10.1 {
|
||||
CREATE TABLE t8(
|
||||
rid INTEGER,
|
||||
pid INTEGER,
|
||||
mid INTEGER,
|
||||
px INTEGER DEFAULT(0) CHECK(px IN(0, 1))
|
||||
);
|
||||
CREATE TEMP TABLE x(
|
||||
rid INTEGER,
|
||||
pid INTEGER,
|
||||
mid INTEGER,
|
||||
px INTEGER DEFAULT(0) CHECK(px IN(0, 1))
|
||||
);
|
||||
}
|
||||
do_test 10.2 {
|
||||
set sqlite3_xferopt_count 0
|
||||
execsql { INSERT INTO x SELECT * FROM t8 }
|
||||
set sqlite3_xferopt_count
|
||||
} {1}
|
||||
|
||||
do_test 10.3 {
|
||||
execsql { PRAGMA integrity_check }
|
||||
set sqlite3_xferopt_count 0
|
||||
execsql { INSERT INTO x SELECT * FROM t8 }
|
||||
set sqlite3_xferopt_count
|
||||
} {1}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
# 2017-03-22
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements tests for json_patch(A,B) SQL function.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !json1 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# This is the example from pages 2 and 3 of RFC-7396
|
||||
do_execsql_test json104-100 {
|
||||
SELECT json_patch('{
|
||||
"a": "b",
|
||||
"c": {
|
||||
"d": "e",
|
||||
"f": "g"
|
||||
}
|
||||
}','{
|
||||
"a":"z",
|
||||
"c": {
|
||||
"f": null
|
||||
}
|
||||
}');
|
||||
} {{{"a":"z","c":{"d":"e"}}}}
|
||||
|
||||
|
||||
# This is the example from pages 4 and 5 of RFC-7396
|
||||
do_execsql_test json104-110 {
|
||||
SELECT json_patch('{
|
||||
"title": "Goodbye!",
|
||||
"author" : {
|
||||
"givenName" : "John",
|
||||
"familyName" : "Doe"
|
||||
},
|
||||
"tags":[ "example", "sample" ],
|
||||
"content": "This will be unchanged"
|
||||
}','{
|
||||
"title": "Hello!",
|
||||
"phoneNumber": "+01-123-456-7890",
|
||||
"author": {
|
||||
"familyName": null
|
||||
},
|
||||
"tags": [ "example" ]
|
||||
}');
|
||||
} {{{"title":"Hello!","author":{"givenName":"John"},"tags":["example"],"content":"This will be unchanged","phoneNumber":"+01-123-456-7890"}}}
|
||||
|
||||
do_execsql_test json104-200 {
|
||||
SELECT json_patch('[1,2,3]','{"x":null}');
|
||||
} {{{}}}
|
||||
do_execsql_test json104-210 {
|
||||
SELECT json_patch('[1,2,3]','{"x":null,"y":1,"z":null}');
|
||||
} {{{"y":1}}}
|
||||
do_execsql_test json104-220 {
|
||||
SELECT json_patch('{}','{"a":{"bb":{"ccc":null}}}');
|
||||
} {{{"a":{"bb":{}}}}}
|
||||
do_execsql_test json104-221 {
|
||||
SELECT json_patch('{}','{"a":{"bb":{"ccc":[1,null,3]}}}');
|
||||
} {{{"a":{"bb":{"ccc":[1,null,3]}}}}}
|
||||
do_execsql_test json104-222 {
|
||||
SELECT json_patch('{}','{"a":{"bb":{"ccc":[1,{"dddd":null},3]}}}');
|
||||
} {{{"a":{"bb":{"ccc":[1,{"dddd":null},3]}}}}}
|
||||
|
||||
# Example test cases at the end of the RFC-7396 document
|
||||
do_execsql_test json104-300 {
|
||||
SELECT json_patch('{"a":"b"}','{"a":"c"}');
|
||||
} {{{"a":"c"}}}
|
||||
do_execsql_test json104-300a {
|
||||
SELECT coalesce(json_patch(null,'{"a":"c"}'), 'real-null');
|
||||
} {{real-null}}
|
||||
do_execsql_test json104-301 {
|
||||
SELECT json_patch('{"a":"b"}','{"b":"c"}');
|
||||
} {{{"a":"b","b":"c"}}}
|
||||
do_execsql_test json104-302 {
|
||||
SELECT json_patch('{"a":"b"}','{"a":null}');
|
||||
} {{{}}}
|
||||
do_execsql_test json104-303 {
|
||||
SELECT json_patch('{"a":"b","b":"c"}','{"a":null}');
|
||||
} {{{"b":"c"}}}
|
||||
do_execsql_test json104-304 {
|
||||
SELECT json_patch('{"a":["b"]}','{"a":"c"}');
|
||||
} {{{"a":"c"}}}
|
||||
do_execsql_test json104-305 {
|
||||
SELECT json_patch('{"a":"c"}','{"a":["b"]}');
|
||||
} {{{"a":["b"]}}}
|
||||
do_execsql_test json104-306 {
|
||||
SELECT json_patch('{"a":{"b":"c"}}','{"a":{"b":"d","c":null}}');
|
||||
} {{{"a":{"b":"d"}}}}
|
||||
do_execsql_test json104-307 {
|
||||
SELECT json_patch('{"a":[{"b":"c"}]}','{"a":[1]}');
|
||||
} {{{"a":[1]}}}
|
||||
do_execsql_test json104-308 {
|
||||
SELECT json_patch('["a","b"]','["c","d"]');
|
||||
} {{["c","d"]}}
|
||||
do_execsql_test json104-309 {
|
||||
SELECT json_patch('{"a":"b"}','["c"]');
|
||||
} {{["c"]}}
|
||||
do_execsql_test json104-310 {
|
||||
SELECT json_patch('{"a":"foo"}','null');
|
||||
} {{null}}
|
||||
do_execsql_test json104-310a {
|
||||
SELECT coalesce(json_patch('{"a":"foo"}',null), 'real-null');
|
||||
} {{real-null}}
|
||||
do_execsql_test json104-311 {
|
||||
SELECT json_patch('{"a":"foo"}','"bar"');
|
||||
} {{"bar"}}
|
||||
do_execsql_test json104-312 {
|
||||
SELECT json_patch('{"e":null}','{"a":1}');
|
||||
} {{{"e":null,"a":1}}}
|
||||
do_execsql_test json104-313 {
|
||||
SELECT json_patch('[1,2]','{"a":"b","c":null}');
|
||||
} {{{"a":"b"}}}
|
||||
do_execsql_test json104-314 {
|
||||
SELECT json_patch('{}','{"a":{"bb":{"ccc":null}}}');
|
||||
} {{{"a":{"bb":{}}}}}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
+30
-28
@@ -39,11 +39,27 @@ ifcapable !memorymanage {
|
||||
return
|
||||
}
|
||||
|
||||
# The sizes of memory allocations from system malloc() might vary,
|
||||
# depending on the memory allocator algorithms used. The following
|
||||
# routine is designed to support answers that fall within a range
|
||||
# of values while also supplying easy-to-understand "expected" values
|
||||
# when errors occur.
|
||||
#
|
||||
proc value_in_range {target x args} {
|
||||
set v [lindex $args 0]
|
||||
if {$v!=""} {
|
||||
if {$v<$target*$x} {return $v}
|
||||
if {$v>$target/$x} {return $v}
|
||||
}
|
||||
return "number between [expr {int($target*$x)}] and [expr {int($target/$x)}]"
|
||||
}
|
||||
set mrange 0.98 ;# plus or minus 2%
|
||||
|
||||
test_set_config_pagecache 0 100
|
||||
|
||||
sqlite3_soft_heap_limit 0
|
||||
sqlite3 db test.db
|
||||
db eval {PRAGMA cache_size=1}
|
||||
# db eval {PRAGMA cache_size=1}
|
||||
|
||||
do_test malloc5-1.1 {
|
||||
# Simplest possible test. Call sqlite3_release_memory when there is exactly
|
||||
@@ -71,24 +87,8 @@ do_test malloc5-1.3 {
|
||||
# in the cache belonging to db2.
|
||||
#
|
||||
set ::pgalloc [sqlite3_release_memory]
|
||||
} {0}
|
||||
|
||||
# The sizes of memory allocations from system malloc() might vary,
|
||||
# depending on the memory allocator algorithms used. The following
|
||||
# routine is designed to support answers that fall within a range
|
||||
# of values while also supplying easy-to-understand "expected" values
|
||||
# when errors occur.
|
||||
#
|
||||
proc value_in_range {target x args} {
|
||||
set v [lindex $args 0]
|
||||
if {$v!=""} {
|
||||
if {$v<$target*$x} {return $v}
|
||||
if {$v>$target/$x} {return $v}
|
||||
}
|
||||
return "number between [expr {int($target*$x)}] and [expr {int($target/$x)}]"
|
||||
}
|
||||
set mrange 0.98 ;# plus or minus 2%
|
||||
|
||||
value_in_range 1288 0.75
|
||||
} [value_in_range 1288 0.75]
|
||||
|
||||
do_test malloc5-1.4 {
|
||||
# Commit the transaction and open a new one. Read 1 page into the cache.
|
||||
@@ -117,12 +117,12 @@ do_test malloc5-1.6 {
|
||||
db2 close
|
||||
execsql {
|
||||
BEGIN;
|
||||
SELECT * FROM abc;
|
||||
CREATE TABLE def(d, e, f);
|
||||
SELECT * FROM abc;
|
||||
}
|
||||
breakpoint
|
||||
value_in_range $::pgalloc $::mrange [sqlite3_release_memory 500]
|
||||
} [value_in_range $::pgalloc $::mrange]
|
||||
|
||||
do_test malloc5-1.7 {
|
||||
# Database should not be locked this time.
|
||||
sqlite3 db2 test.db
|
||||
@@ -346,7 +346,7 @@ do_test malloc5-6.2.2 {
|
||||
# If we now try to reclaim some memory, it should come from the db2 cache.
|
||||
sqlite3_release_memory 3000
|
||||
expr [nPage db] + [nPage db2]
|
||||
} {4}
|
||||
} {1}
|
||||
do_test malloc5-6.2.3 {
|
||||
# Access the db2 cache again, so that all the db2 pages have been used
|
||||
# more recently than all the db pages. Then try to reclaim 3000 bytes.
|
||||
@@ -354,7 +354,7 @@ do_test malloc5-6.2.3 {
|
||||
execsql { SELECT * FROM abc } db2
|
||||
sqlite3_release_memory 3000
|
||||
expr [nPage db] + [nPage db2]
|
||||
} {4}
|
||||
} {0}
|
||||
|
||||
do_test malloc5-6.3.1 {
|
||||
# Now open a transaction and update 2 pages in the db2 cache. Then
|
||||
@@ -364,6 +364,8 @@ do_test malloc5-6.3.1 {
|
||||
# sync() to free up the dirty db2 pages. The only page that cannot be
|
||||
# freed is page1 of db2. Because there is an open transaction, the
|
||||
# btree layer holds a reference to page 1 in the db2 cache.
|
||||
#
|
||||
# UPDATE: No longer. As release_memory() does not cause a sync()
|
||||
execsql {
|
||||
BEGIN;
|
||||
UPDATE abc SET c = randstr(100,100)
|
||||
@@ -377,13 +379,13 @@ do_test malloc5-6.3.2 {
|
||||
# non-dirty pages held by db2.
|
||||
sqlite3_release_memory [expr 7*1132]
|
||||
list [nPage db] [nPage db2]
|
||||
} {1 3}
|
||||
} {0 3}
|
||||
do_test malloc5-6.3.3 {
|
||||
# Try to release another 1000 bytes. This should come fromt the db
|
||||
# cache, since all three pages held by db2 are either in-use or diry.
|
||||
sqlite3_release_memory 1000
|
||||
list [nPage db] [nPage db2]
|
||||
} {1 3}
|
||||
} {0 3}
|
||||
do_test malloc5-6.3.4 {
|
||||
# Now release 9900 more (about 9 pages worth). This should expunge
|
||||
# the rest of the db cache. But the db2 cache remains intact, because
|
||||
@@ -394,20 +396,20 @@ do_test malloc5-6.3.4 {
|
||||
sqlite3_release_memory 9900
|
||||
}
|
||||
list [nPage db] [nPage db2]
|
||||
} {1 3}
|
||||
} {0 3}
|
||||
do_test malloc5-6.3.5 {
|
||||
# But if we are really insistent, SQLite will consent to call sync()
|
||||
# if there is no other option. UPDATE: As of 3.6.2, SQLite will not
|
||||
# call sync() in this scenario. So no further memory can be reclaimed.
|
||||
sqlite3_release_memory 1000
|
||||
list [nPage db] [nPage db2]
|
||||
} {1 3}
|
||||
} {0 3}
|
||||
do_test malloc5-6.3.6 {
|
||||
# The referenced page (page 1 of the db2 cache) will not be freed no
|
||||
# matter how much memory we ask for:
|
||||
sqlite3_release_memory 31459
|
||||
list [nPage db] [nPage db2]
|
||||
} {1 3}
|
||||
} {0 3}
|
||||
|
||||
db2 close
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# 2017 March 13
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# Further OOM tests.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
set testprefix mallocM
|
||||
|
||||
sqlite3_db_config_lookaside db 0 0 0
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(x);
|
||||
}
|
||||
do_faultsim_test 1 -faults oom* -body {
|
||||
execsql {
|
||||
SELECT 'abc' FROM ( SELECT 'xyz' FROM t1 WHERE (SELECT 1) )
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
do_execsql_test 2.0.1 { SELECT instr(x'', x'') } {1}
|
||||
do_execsql_test 2.0.2 { SELECT instr(x'12345678', x'') } {1}
|
||||
do_execsql_test 2.0.3 { SELECT instr(x'', x'1234') } {0}
|
||||
|
||||
do_faultsim_test 2.1 -faults oom* -body {
|
||||
execsql { SELECT instr (x'00', zeroblob(1)) }
|
||||
} -test {
|
||||
faultsim_test_result {0 1}
|
||||
}
|
||||
|
||||
do_faultsim_test 2.2 -faults oom* -body {
|
||||
execsql { SELECT instr (zeroblob(1), x'00') }
|
||||
} -test {
|
||||
faultsim_test_result {0 1}
|
||||
}
|
||||
|
||||
finish_test
|
||||
+87
-17
@@ -4,14 +4,69 @@
|
||||
*/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
/* Global debugging settings. OSS-Fuzz will have all debugging turned
|
||||
** off. But if LLVMFuzzerTestOneInput() is called interactively from
|
||||
** the ossshell utility program, then these flags might be set.
|
||||
*/
|
||||
static unsigned mDebug = 0;
|
||||
#define FUZZ_SQL_TRACE 0x0001 /* Set an sqlite3_trace() callback */
|
||||
#define FUZZ_SHOW_MAX_DELAY 0x0002 /* Show maximum progress callback delay */
|
||||
#define FUZZ_SHOW_ERRORS 0x0004 /* Print error messages from SQLite */
|
||||
|
||||
/* The ossshell utility program invokes this interface to see the
|
||||
** debugging flags. Unused by OSS-Fuzz.
|
||||
*/
|
||||
void ossfuzz_set_debug_flags(unsigned x){
|
||||
mDebug = x;
|
||||
}
|
||||
|
||||
/* Return the current real-world time in milliseconds since the
|
||||
** Julian epoch (-4714-11-24).
|
||||
*/
|
||||
static sqlite3_int64 timeOfDay(void){
|
||||
static sqlite3_vfs *clockVfs = 0;
|
||||
sqlite3_int64 t;
|
||||
if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
|
||||
if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){
|
||||
clockVfs->xCurrentTimeInt64(clockVfs, &t);
|
||||
}else{
|
||||
double r;
|
||||
clockVfs->xCurrentTime(clockVfs, &r);
|
||||
t = (sqlite3_int64)(r*86400000.0);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/* An instance of the following object is passed by pointer as the
|
||||
** client data to various callbacks.
|
||||
*/
|
||||
typedef struct FuzzCtx {
|
||||
sqlite3 *db; /* The database connection */
|
||||
sqlite3_int64 iCutoffTime; /* Stop processing at this time. */
|
||||
sqlite3_int64 iLastCb; /* Time recorded for previous progress callback */
|
||||
sqlite3_int64 mxInterval; /* Longest interval between two progress calls */
|
||||
unsigned nCb; /* Number of progress callbacks */
|
||||
} FuzzCtx;
|
||||
|
||||
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
/*
|
||||
** Progress handler callback
|
||||
** Progress handler callback.
|
||||
**
|
||||
** The argument is the cutoff-time after which all processing should
|
||||
** stop. So return non-zero if the cut-off time is exceeded.
|
||||
*/
|
||||
static int progress_handler(void *pReturn) {
|
||||
return *(int*)pReturn;
|
||||
static int progress_handler(void *pClientData) {
|
||||
FuzzCtx *p = (FuzzCtx*)pClientData;
|
||||
sqlite3_int64 iNow = timeOfDay();
|
||||
int rc = iNow>=p->iCutoffTime;
|
||||
sqlite3_int64 iDiff = iNow - p->iLastCb;
|
||||
if( iDiff > p->mxInterval ) p->mxInterval = iDiff;
|
||||
p->nCb++;
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -31,14 +86,14 @@ static int exec_handler(void *pCnt, int argc, char **argv, char **namev){
|
||||
** fuzzed input.
|
||||
*/
|
||||
int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
int progressArg = 0; /* 1 causes progress handler abort */
|
||||
int execCnt = 0; /* Abort row callback when count reaches zero */
|
||||
char *zErrMsg = 0; /* Error message returned by sqlite_exec() */
|
||||
sqlite3 *db; /* The database connection */
|
||||
uint8_t uSelector; /* First byte of input data[] */
|
||||
int rc; /* Return code from various interfaces */
|
||||
char *zSql; /* Zero-terminated copy of data[] */
|
||||
FuzzCtx cx; /* Fuzzing context */
|
||||
|
||||
memset(&cx, 0, sizeof(cx));
|
||||
if( size<3 ) return 0; /* Early out if unsufficient data */
|
||||
|
||||
/* Extract the selector byte from the beginning of the input. But only
|
||||
@@ -51,22 +106,26 @@ int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
}
|
||||
|
||||
/* Open the database connection. Only use an in-memory database. */
|
||||
rc = sqlite3_open_v2("fuzz.db", &db,
|
||||
rc = sqlite3_open_v2("fuzz.db", &cx.db,
|
||||
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MEMORY, 0);
|
||||
if( rc ) return 0;
|
||||
|
||||
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
/* Bit 0 of the selector enables progress callbacks. Bit 1 is the
|
||||
** return code from progress callbacks */
|
||||
if( uSelector & 1 ){
|
||||
sqlite3_progress_handler(db, 4, progress_handler, (void*)&progressArg);
|
||||
}
|
||||
/* Invoke the progress handler frequently to check to see if we
|
||||
** are taking too long. The progress handler will return true
|
||||
** (which will block further processing) if more than 10 seconds have
|
||||
** elapsed since the start of the test.
|
||||
*/
|
||||
cx.iLastCb = timeOfDay();
|
||||
cx.iCutoffTime = cx.iLastCb + 10000; /* Now + 10 seconds */
|
||||
sqlite3_progress_handler(cx.db, 10, progress_handler, (void*)&cx);
|
||||
#endif
|
||||
uSelector >>= 1;
|
||||
progressArg = uSelector & 1; uSelector >>= 1;
|
||||
|
||||
/* Bit 2 of the selector enables foreign key constraints */
|
||||
sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_FKEY, uSelector&1, &rc);
|
||||
/* Set a limit on the maximum size of a prepared statement */
|
||||
sqlite3_limit(cx.db, SQLITE_LIMIT_VDBE_OP, 25000);
|
||||
|
||||
/* Bit 1 of the selector enables foreign key constraints */
|
||||
sqlite3_db_config(cx.db, SQLITE_DBCONFIG_ENABLE_FKEY, uSelector&1, &rc);
|
||||
uSelector >>= 1;
|
||||
|
||||
/* Remaining bits of the selector determine a limit on the number of
|
||||
@@ -76,11 +135,22 @@ int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
/* Run the SQL. The sqlite_exec() interface expects a zero-terminated
|
||||
** string, so make a copy. */
|
||||
zSql = sqlite3_mprintf("%.*s", (int)size, data);
|
||||
sqlite3_exec(db, zSql, exec_handler, (void*)&execCnt, &zErrMsg);
|
||||
sqlite3_exec(cx.db, zSql, exec_handler, (void*)&execCnt, &zErrMsg);
|
||||
|
||||
/* Show any errors */
|
||||
if( (mDebug & FUZZ_SHOW_ERRORS)!=0 && zErrMsg ){
|
||||
printf("Error: %s\n", zErrMsg);
|
||||
}
|
||||
|
||||
/* Cleanup and return */
|
||||
sqlite3_free(zErrMsg);
|
||||
sqlite3_free(zSql);
|
||||
sqlite3_close(db);
|
||||
sqlite3_exec(cx.db, "PRAGMA temp_store_directory=''", 0, 0, 0);
|
||||
sqlite3_close(cx.db);
|
||||
|
||||
if( mDebug & FUZZ_SHOW_MAX_DELAY ){
|
||||
printf("Progress callback count....... %d\n", cx.nCb);
|
||||
printf("Max time between callbacks.... %d ms\n", (int)cx.mxInterval);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
/*
|
||||
@@ -16,6 +17,13 @@
|
||||
*/
|
||||
int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
|
||||
|
||||
/* Must match equivalent #defines in ossfuzz.c */
|
||||
#define FUZZ_SQL_TRACE 0x0001 /* Set an sqlite3_trace() callback */
|
||||
#define FUZZ_SHOW_MAX_DELAY 0x0002 /* Show maximum progress callback delay */
|
||||
#define FUZZ_SHOW_ERRORS 0x0004 /* Show SQL errors */
|
||||
extern void ossfuzz_set_debug_flags(unsigned);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Read files named on the command-line and invoke the fuzzer for
|
||||
@@ -27,9 +35,32 @@ int main(int argc, char **argv){
|
||||
int nErr = 0;
|
||||
uint8_t *zBuf = 0;
|
||||
size_t sz;
|
||||
unsigned mDebug = 0;
|
||||
|
||||
for(i=1; i<argc; i++){
|
||||
const char *zFilename = argv[i];
|
||||
if( zFilename[0]=='-' ){
|
||||
if( zFilename[1]=='-' ) zFilename++;
|
||||
if( strcmp(zFilename, "-show-errors")==0 ){
|
||||
mDebug |= FUZZ_SHOW_ERRORS;
|
||||
ossfuzz_set_debug_flags(mDebug);
|
||||
}else
|
||||
if( strcmp(zFilename, "-show-max-delay")==0 ){
|
||||
mDebug |= FUZZ_SHOW_MAX_DELAY;
|
||||
ossfuzz_set_debug_flags(mDebug);
|
||||
}else
|
||||
if( strcmp(zFilename, "-sql-trace")==0 ){
|
||||
mDebug |= FUZZ_SQL_TRACE;
|
||||
ossfuzz_set_debug_flags(mDebug);
|
||||
}else
|
||||
{
|
||||
printf("unknown option \"%s\"\n", argv[i]);
|
||||
printf("should be one of: --show-errors --show-max-delay"
|
||||
" --sql-trace\n");
|
||||
exit(1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
in = fopen(zFilename, "rb");
|
||||
if( in==0 ){
|
||||
fprintf(stderr, "cannot open \"%s\"\n", zFilename);
|
||||
@@ -50,8 +81,10 @@ int main(int argc, char **argv){
|
||||
nErr++;
|
||||
}else{
|
||||
printf("%s... ", zFilename);
|
||||
if( mDebug ) printf("\n");
|
||||
fflush(stdout);
|
||||
(void)LLVMFuzzerTestOneInput(zBuf, sz);
|
||||
if( mDebug ) printf("%s: ", zFilename);
|
||||
printf("ok\n");
|
||||
}
|
||||
fclose(in);
|
||||
|
||||
+18
-16
@@ -247,22 +247,24 @@ test_suite "threads" -prefix "" -description {
|
||||
test_suite "fts3" -prefix "" -description {
|
||||
All FTS3 tests except fts3rnd.test.
|
||||
} -files {
|
||||
fts3aa.test fts3ab.test fts3ac.test fts3ad.test fts3ae.test
|
||||
fts3af.test fts3ag.test fts3ah.test fts3ai.test fts3aj.test
|
||||
fts3ak.test fts3al.test fts3am.test fts3an.test fts3ao.test
|
||||
fts3atoken.test fts3b.test fts3c.test fts3cov.test fts3d.test
|
||||
fts3defer.test fts3defer2.test fts3e.test fts3expr.test fts3expr2.test
|
||||
fts3expr3.test
|
||||
fts3near.test fts3query.test fts3shared.test fts3snippet.test
|
||||
fts3sort.test
|
||||
fts3fault.test fts3malloc.test fts3matchinfo.test
|
||||
fts3aux1.test fts3comp1.test fts3auto.test
|
||||
fts4aa.test fts4content.test
|
||||
fts3conf.test fts3prefix.test fts3fault2.test fts3corrupt.test
|
||||
fts3corrupt2.test fts3first.test fts4langid.test fts4merge.test
|
||||
fts4check.test fts4unicode.test fts4noti.test
|
||||
fts3varint.test
|
||||
fts4growth.test fts4growth2.test
|
||||
fts3aa.test fts3ab.test fts3ac.test fts3ad.test
|
||||
fts3ae.test fts3af.test fts3ag.test fts3ah.test
|
||||
fts3ai.test fts3aj.test fts3ak.test fts3al.test
|
||||
fts3am.test fts3an.test fts3ao.test fts3atoken.test
|
||||
fts3auto.test fts3aux1.test fts3aux2.test fts3b.test
|
||||
fts3comp1.test fts3conf.test fts3corrupt2.test fts3corrupt.test
|
||||
fts3cov.test fts3c.test fts3defer2.test fts3defer3.test
|
||||
fts3defer.test fts3drop.test fts3d.test fts3e.test
|
||||
fts3expr2.test fts3expr3.test fts3expr4.test fts3expr5.test
|
||||
fts3expr.test fts3fault2.test fts3fault.test fts3first.test
|
||||
fts3join.test fts3malloc.test fts3matchinfo.test fts3near.test
|
||||
fts3offsets.test fts3prefix2.test fts3prefix.test fts3query.test
|
||||
fts3shared.test fts3snippet.test fts3sort.test fts3tok1.test
|
||||
fts3tok_err.test fts3varint.test fts4aa.test fts4check.test
|
||||
fts4content.test fts4docid.test fts4growth2.test fts4growth.test
|
||||
fts4incr.test fts4langid.test fts4lastrowid.test fts4merge2.test
|
||||
fts4merge4.test fts4merge.test fts4noti.test fts4onepass.test
|
||||
fts4opt.test fts4unicode.test
|
||||
}
|
||||
|
||||
test_suite "fts5" -prefix "" -description {
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
# 2010 June 15
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/lock_common.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
set testprefix pragmafault
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
sqlite3_db_config_lookaside db 0 0 0
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a, b, CHECK(a!=b));
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
INSERT INTO t1 VALUES(3, 4);
|
||||
}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 1 -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
catchsql { PRAGMA integrity_check }
|
||||
set {} 0
|
||||
} -test {
|
||||
faultsim_test_result {0 0}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
+146
-13
@@ -300,7 +300,7 @@ do_test shell1-3.4.2 {
|
||||
do_test shell1-3.4.3 {
|
||||
# too many arguments
|
||||
catchcmd "test.db" ".dump FOO BAD"
|
||||
} {1 {Usage: .dump ?LIKE-PATTERN?}}
|
||||
} {1 {Usage: .dump ?--preserve-rowids? ?LIKE-PATTERN?}}
|
||||
|
||||
# .echo ON|OFF Turn command echo on or off
|
||||
do_test shell1-3.5.1 {
|
||||
@@ -740,21 +740,154 @@ do_test shell1-4.1 {
|
||||
} {0 {PRAGMA foreign_keys=OFF;
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO "t1" VALUES(NULL);
|
||||
INSERT INTO "t1" VALUES('');
|
||||
INSERT INTO "t1" VALUES(1);
|
||||
INSERT INTO "t1" VALUES(2.25);
|
||||
INSERT INTO "t1" VALUES('hello');
|
||||
INSERT INTO "t1" VALUES(X'807F');
|
||||
INSERT INTO t1 VALUES(NULL);
|
||||
INSERT INTO t1 VALUES('');
|
||||
INSERT INTO t1 VALUES(1);
|
||||
INSERT INTO t1 VALUES(2.25);
|
||||
INSERT INTO t1 VALUES('hello');
|
||||
INSERT INTO t1 VALUES(X'807f');
|
||||
CREATE TABLE t3(x,y);
|
||||
INSERT INTO "t3" VALUES(1,NULL);
|
||||
INSERT INTO "t3" VALUES(2,'');
|
||||
INSERT INTO "t3" VALUES(3,1);
|
||||
INSERT INTO "t3" VALUES(4,2.25);
|
||||
INSERT INTO "t3" VALUES(5,'hello');
|
||||
INSERT INTO "t3" VALUES(6,X'807F');
|
||||
INSERT INTO t3 VALUES(1,NULL);
|
||||
INSERT INTO t3 VALUES(2,'');
|
||||
INSERT INTO t3 VALUES(3,1);
|
||||
INSERT INTO t3 VALUES(4,2.25);
|
||||
INSERT INTO t3 VALUES(5,'hello');
|
||||
INSERT INTO t3 VALUES(6,X'807f');
|
||||
COMMIT;}}
|
||||
|
||||
|
||||
ifcapable vtab {
|
||||
|
||||
# The --preserve-rowids option to .dump
|
||||
#
|
||||
do_test shell1-4.1.1 {
|
||||
catchcmd test.db {.dump --preserve-rowids}
|
||||
} {0 {PRAGMA foreign_keys=OFF;
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1(rowid,x) VALUES(1,NULL);
|
||||
INSERT INTO t1(rowid,x) VALUES(2,'');
|
||||
INSERT INTO t1(rowid,x) VALUES(3,1);
|
||||
INSERT INTO t1(rowid,x) VALUES(4,2.25);
|
||||
INSERT INTO t1(rowid,x) VALUES(5,'hello');
|
||||
INSERT INTO t1(rowid,x) VALUES(6,X'807f');
|
||||
CREATE TABLE t3(x,y);
|
||||
INSERT INTO t3(rowid,x,y) VALUES(1,1,NULL);
|
||||
INSERT INTO t3(rowid,x,y) VALUES(2,2,'');
|
||||
INSERT INTO t3(rowid,x,y) VALUES(3,3,1);
|
||||
INSERT INTO t3(rowid,x,y) VALUES(4,4,2.25);
|
||||
INSERT INTO t3(rowid,x,y) VALUES(5,5,'hello');
|
||||
INSERT INTO t3(rowid,x,y) VALUES(6,6,X'807f');
|
||||
COMMIT;}}
|
||||
|
||||
# If the table contains an INTEGER PRIMARY KEY, do not record a separate
|
||||
# rowid column in the output.
|
||||
#
|
||||
do_test shell1-4.1.2 {
|
||||
db close
|
||||
forcedelete test2.db
|
||||
sqlite3 db test2.db
|
||||
db eval {
|
||||
CREATE TABLE t1(x INTEGER PRIMARY KEY, y);
|
||||
INSERT INTO t1 VALUES(1,null), (2,''), (3,1),
|
||||
(4,2.25), (5,'hello'), (6,x'807f');
|
||||
}
|
||||
catchcmd test2.db {.dump --preserve-rowids}
|
||||
} {0 {PRAGMA foreign_keys=OFF;
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE t1(x INTEGER PRIMARY KEY, y);
|
||||
INSERT INTO t1 VALUES(1,NULL);
|
||||
INSERT INTO t1 VALUES(2,'');
|
||||
INSERT INTO t1 VALUES(3,1);
|
||||
INSERT INTO t1 VALUES(4,2.25);
|
||||
INSERT INTO t1 VALUES(5,'hello');
|
||||
INSERT INTO t1 VALUES(6,X'807f');
|
||||
COMMIT;}}
|
||||
|
||||
# Verify that the table named [table] is correctly quoted and that
|
||||
# an INTEGER PRIMARY KEY DESC is not an alias for the rowid.
|
||||
#
|
||||
do_test shell1-4.1.3 {
|
||||
db close
|
||||
forcedelete test2.db
|
||||
sqlite3 db test2.db
|
||||
db eval {
|
||||
CREATE TABLE [table](x INTEGER PRIMARY KEY DESC, y);
|
||||
INSERT INTO [table] VALUES(1,null), (12,''), (23,1),
|
||||
(34,2.25), (45,'hello'), (56,x'807f');
|
||||
}
|
||||
catchcmd test2.db {.dump --preserve-rowids}
|
||||
} {0 {PRAGMA foreign_keys=OFF;
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE [table](x INTEGER PRIMARY KEY DESC, y);
|
||||
INSERT INTO "table"(rowid,x,y) VALUES(1,1,NULL);
|
||||
INSERT INTO "table"(rowid,x,y) VALUES(2,12,'');
|
||||
INSERT INTO "table"(rowid,x,y) VALUES(3,23,1);
|
||||
INSERT INTO "table"(rowid,x,y) VALUES(4,34,2.25);
|
||||
INSERT INTO "table"(rowid,x,y) VALUES(5,45,'hello');
|
||||
INSERT INTO "table"(rowid,x,y) VALUES(6,56,X'807f');
|
||||
COMMIT;}}
|
||||
|
||||
# Do not record rowids for a WITHOUT ROWID table. Also check correct quoting
|
||||
# of table names that contain odd characters.
|
||||
#
|
||||
do_test shell1-4.1.4 {
|
||||
db close
|
||||
forcedelete test2.db
|
||||
sqlite3 db test2.db
|
||||
db eval {
|
||||
CREATE TABLE [ta<>ble](x INTEGER PRIMARY KEY, y) WITHOUT ROWID;
|
||||
INSERT INTO [ta<>ble] VALUES(1,null), (12,''), (23,1),
|
||||
(34,2.25), (45,'hello'), (56,x'807f');
|
||||
}
|
||||
catchcmd test2.db {.dump --preserve-rowids}
|
||||
} {0 {PRAGMA foreign_keys=OFF;
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE [ta<>ble](x INTEGER PRIMARY KEY, y) WITHOUT ROWID;
|
||||
INSERT INTO "ta<>ble" VALUES(1,NULL);
|
||||
INSERT INTO "ta<>ble" VALUES(12,'');
|
||||
INSERT INTO "ta<>ble" VALUES(23,1);
|
||||
INSERT INTO "ta<>ble" VALUES(34,2.25);
|
||||
INSERT INTO "ta<>ble" VALUES(45,'hello');
|
||||
INSERT INTO "ta<>ble" VALUES(56,X'807f');
|
||||
COMMIT;}}
|
||||
|
||||
# Do not record rowids if the rowid is inaccessible
|
||||
#
|
||||
do_test shell1-4.1.5 {
|
||||
db close
|
||||
forcedelete test2.db
|
||||
sqlite3 db test2.db
|
||||
db eval {
|
||||
CREATE TABLE t1(_ROWID_,rowid,oid);
|
||||
INSERT INTO t1 VALUES(1,null,'alpha'), (12,'',99), (23,1,x'b0b1b2');
|
||||
}
|
||||
catchcmd test2.db {.dump --preserve-rowids}
|
||||
} {0 {PRAGMA foreign_keys=OFF;
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE t1(_ROWID_,rowid,oid);
|
||||
INSERT INTO t1 VALUES(1,NULL,'alpha');
|
||||
INSERT INTO t1 VALUES(12,'',99);
|
||||
INSERT INTO t1 VALUES(23,1,X'b0b1b2');
|
||||
COMMIT;}}
|
||||
|
||||
} else {
|
||||
|
||||
do_test shell1-4.1.6 {
|
||||
db close
|
||||
forcedelete test2.db
|
||||
sqlite3 db test2.db
|
||||
db eval {
|
||||
CREATE TABLE t1(x INTEGER PRIMARY KEY, y);
|
||||
INSERT INTO t1 VALUES(1,null), (2,''), (3,1),
|
||||
(4,2.25), (5,'hello'), (6,x'807f');
|
||||
}
|
||||
catchcmd test2.db {.dump --preserve-rowids}
|
||||
} {1 {The --preserve-rowids option is not compatible with SQLITE_OMIT_VIRTUALTABLE}}
|
||||
|
||||
}
|
||||
|
||||
|
||||
# Test the output of ".mode insert"
|
||||
#
|
||||
do_test shell1-4.2.1 {
|
||||
|
||||
@@ -73,6 +73,26 @@ foreach {tn schema output} {
|
||||
CREATE INDEX 'y1_a' ON 'y1'('a' COLLATE nocase); --> x1(a)
|
||||
}
|
||||
|
||||
7 {
|
||||
CREATE TABLE x1(a PRIMARY KEY COLLATE nocase, b);
|
||||
CREATE TABLE y1(a REFERENCES x1);
|
||||
} {
|
||||
CREATE INDEX 'y1_a' ON 'y1'('a' COLLATE nocase); --> x1(a)
|
||||
}
|
||||
|
||||
8 {
|
||||
CREATE TABLE x1(a, b COLLATE nocase, c COLLATE rtrim, PRIMARY KEY(c, b, a));
|
||||
CREATE TABLE y1(d, e, f, FOREIGN KEY(d, e, f) REFERENCES x1);
|
||||
} {
|
||||
CREATE INDEX 'y1_d_e_f' ON 'y1'('d' COLLATE rtrim, 'e' COLLATE nocase, 'f'); --> x1(c,b,a)
|
||||
}
|
||||
|
||||
9 {
|
||||
CREATE TABLE p1(a, b UNIQUE);
|
||||
CREATE TABLE c1(x INTEGER PRIMARY KEY REFERENCES p1(b));
|
||||
} {
|
||||
}
|
||||
|
||||
} {
|
||||
forcedelete test.db
|
||||
sqlite3 db test.db
|
||||
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
# 2017 March 16
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# Specificly, it tests that "PRAGMA synchronous" appears to work.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix sync2
|
||||
|
||||
#
|
||||
# These tests are only applicable when pager pragma are
|
||||
# enabled. Also, since every test uses an ATTACHed database, they
|
||||
# are only run when ATTACH is enabled.
|
||||
#
|
||||
ifcapable !pager_pragmas||!attach||!dirsync {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
if {$::tcl_platform(platform)!="unix"
|
||||
|| [permutation] == "journaltest"
|
||||
|| [permutation] == "inmemory_journal"
|
||||
} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
proc execsql_sync {sql} {
|
||||
set s $::sqlite_sync_count
|
||||
set res [execsql $sql]
|
||||
concat [expr $::sqlite_sync_count-$s] $res
|
||||
}
|
||||
|
||||
proc do_execsql_sync_test {tn sql res} {
|
||||
uplevel [list do_test $tn [list execsql_sync $sql] [list {*}$res]]
|
||||
}
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Tests for journal mode.
|
||||
#
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
}
|
||||
|
||||
do_execsql_sync_test 1.1 { INSERT INTO t1 VALUES(3, 4) } 4
|
||||
|
||||
# synchronous=normal. So, 1 sync on the directory, 1 on the journal, 1
|
||||
# on the db file. 3 in total.
|
||||
do_execsql_test 1.2.1 { PRAGMA main.synchronous = NORMAL }
|
||||
do_execsql_test 1.2.2 { PRAGMA main.synchronous } 1
|
||||
do_execsql_sync_test 1.2.3 { INSERT INTO t1 VALUES(5, 6) } 3
|
||||
|
||||
# synchronous=off. No syncs.
|
||||
do_execsql_test 1.3.1 { PRAGMA main.synchronous = OFF }
|
||||
do_execsql_test 1.3.2 { PRAGMA main.synchronous } 0
|
||||
do_execsql_sync_test 1.3.3 { INSERT INTO t1 VALUES(7, 8) } 0
|
||||
|
||||
# synchronous=full, journal_mode=delete. So, 1 sync on the directory,
|
||||
# 2 on the journal, 1 on the db file. 4 in total.
|
||||
do_execsql_test 1.4.1 { PRAGMA main.synchronous = FULL }
|
||||
do_execsql_test 1.4.2 { PRAGMA main.synchronous } 2
|
||||
do_execsql_sync_test 1.4.3 { INSERT INTO t1 VALUES(9, 10) } 4
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Tests for wal mode.
|
||||
#
|
||||
do_execsql_test 1.5 { PRAGMA journal_mode = wal } {wal}
|
||||
|
||||
# sync=full, journal_mode=wal. One sync on the directory, two on the
|
||||
# wal file.
|
||||
do_execsql_sync_test 1.6 { INSERT INTO t1 VALUES(11, 12) } 3
|
||||
|
||||
# One sync on the wal file.
|
||||
do_execsql_sync_test 1.7 { INSERT INTO t1 VALUES(13, 14) } 1
|
||||
|
||||
# No syncs.
|
||||
do_execsql_test 1.8.1 { PRAGMA main.synchronous = NORMAL }
|
||||
do_execsql_test 1.8.2 { PRAGMA main.synchronous } 1
|
||||
do_execsql_sync_test 1.8.3 { INSERT INTO t1 VALUES(15, 16) } 0
|
||||
|
||||
# One sync on wal file, one on the db file.
|
||||
do_execsql_sync_test 1.9 { PRAGMA wal_checkpoint } {2 0 3 3}
|
||||
|
||||
# No syncs.
|
||||
do_execsql_test 1.10.1 { PRAGMA main.synchronous = OFF }
|
||||
do_execsql_test 1.10.2 { PRAGMA main.synchronous } 0
|
||||
do_execsql_sync_test 1.10.3 { INSERT INTO t1 VALUES(17, 18) } 0
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Tests for the compile time settings SQLITE_DEFAULT_SYNCHRONOUS and
|
||||
# SQLITE_DEFAULT_WAL_SYNCHRONOUS. These tests only run if the former
|
||||
# is set to "2" and the latter to "1". This is not the default, but
|
||||
# it is currently the recommended configuration.
|
||||
#
|
||||
# https://sqlite.org/compile.html#recommended_compile_time_options
|
||||
#
|
||||
if {$SQLITE_DEFAULT_SYNCHRONOUS==2 && $SQLITE_DEFAULT_WAL_SYNCHRONOUS==1} {
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
|
||||
# Wal mode, sync=normal. The first transaction does one sync on directory,
|
||||
# one on the wal file. The second does no syncs.
|
||||
do_execsql_sync_test 1.11.1 { INSERT INTO t1 VALUES(19, 20) } 2
|
||||
do_execsql_sync_test 1.11.2 { INSERT INTO t1 VALUES(21, 22) } 0
|
||||
do_execsql_test 1.11.3 { PRAGMA main.synchronous } 1
|
||||
|
||||
# One sync on wal file, one on the db file.
|
||||
do_execsql_sync_test 1.12 { PRAGMA wal_checkpoint } {2 0 2 2}
|
||||
|
||||
# First transaction syncs the wal file once, the second not at all.
|
||||
# one on the wal file. The second does no syncs.
|
||||
do_execsql_sync_test 1.13.1 { INSERT INTO t1 VALUES(22, 23) } 1
|
||||
do_execsql_sync_test 1.13.2 { INSERT INTO t1 VALUES(24, 25) } 0
|
||||
|
||||
do_execsql_test 1.14 { PRAGMA journal_mode = delete } {delete}
|
||||
|
||||
# Delete mode, sync=full. The first transaction does one sync on
|
||||
# directory, two on the journal file, one on the db. The second does
|
||||
# the same.
|
||||
do_execsql_sync_test 1.15.1 { INSERT INTO t1 VALUES(26, 27) } 4
|
||||
do_execsql_sync_test 1.15.2 { INSERT INTO t1 VALUES(28, 29) } 4
|
||||
do_execsql_test 1.15.3 { PRAGMA main.synchronous } 2
|
||||
|
||||
# Switch back to wal mode.
|
||||
do_execsql_test 1.16 { PRAGMA journal_mode = wal } {wal}
|
||||
|
||||
do_execsql_sync_test 1.17.1 { INSERT INTO t1 VALUES(30, 31) } 2
|
||||
do_execsql_sync_test 1.17.2 { INSERT INTO t1 VALUES(32, 33) } 0
|
||||
do_execsql_test 1.17.3 { PRAGMA main.synchronous } 1
|
||||
|
||||
# Now set synchronous=off, then switch back to delete mode. Check
|
||||
# that the db handle is still using synchronous=off.
|
||||
do_execsql_test 1.18.3 { PRAGMA main.synchronous=off }
|
||||
do_execsql_test 1.18 { PRAGMA journal_mode = delete } {delete}
|
||||
|
||||
do_execsql_sync_test 1.19.1 { INSERT INTO t1 VALUES(34, 35) } 0
|
||||
do_execsql_sync_test 1.19.2 { INSERT INTO t1 VALUES(36, 37) } 0
|
||||
do_execsql_test 1.19.3 { PRAGMA main.synchronous } 0
|
||||
|
||||
# Close and reopen the db. Back to synchronous=normal.
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_execsql_sync_test 1.20.1 { INSERT INTO t1 VALUES(38, 39) } 4
|
||||
do_execsql_sync_test 1.20.2 { INSERT INTO t1 VALUES(40, 41) } 4
|
||||
do_execsql_test 1.20.3 { PRAGMA main.synchronous } 2
|
||||
}
|
||||
|
||||
finish_test
|
||||
+4
-2
@@ -1533,6 +1533,7 @@ proc crashsql {args} {
|
||||
set tclbody {}
|
||||
set crashfile ""
|
||||
set dc ""
|
||||
set dfltvfs 0
|
||||
set sql [lindex $args end]
|
||||
|
||||
for {set ii 0} {$ii < [llength $args]-1} {incr ii 2} {
|
||||
@@ -1546,7 +1547,8 @@ proc crashsql {args} {
|
||||
elseif {$n>1 && [string first $z -file]==0} {set crashfile $z2} \
|
||||
elseif {$n>1 && [string first $z -tclbody]==0} {set tclbody $z2} \
|
||||
elseif {$n>1 && [string first $z -blocksize]==0} {set blocksize "-s $z2" } \
|
||||
elseif {$n>1 && [string first $z -characteristics]==0} {set dc "-c {$z2}" } \
|
||||
elseif {$n>1 && [string first $z -characteristics]==0} {set dc "-c {$z2}" }\
|
||||
elseif {$n>1 && [string first $z -dfltvfs]==0} {set dfltvfs $z2 }\
|
||||
else { error "Unrecognized option: $z" }
|
||||
}
|
||||
|
||||
@@ -1560,7 +1562,7 @@ proc crashsql {args} {
|
||||
set cfile [string map {\\ \\\\} [file nativename [file join [get_pwd] $crashfile]]]
|
||||
|
||||
set f [open crash.tcl w]
|
||||
puts $f "sqlite3_crash_enable 1"
|
||||
puts $f "sqlite3_crash_enable 1 $dfltvfs"
|
||||
puts $f "sqlite3_crashparams $blocksize $dc $crashdelay $cfile"
|
||||
puts $f "sqlite3_test_control_pending_byte $::sqlite_pending_byte"
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
# 2017-03-24
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice', here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix triggerG
|
||||
ifcapable {!trigger} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# Test cases for ticket
|
||||
# https://www.sqlite.org/src/tktview/06796225f59c057cd120f
|
||||
#
|
||||
# The OP_Once opcode was not working correctly for recursive triggers.
|
||||
#
|
||||
do_execsql_test 100 {
|
||||
PRAGMA recursive_triggers = 1;
|
||||
|
||||
CREATE TABLE t1(a);
|
||||
CREATE INDEX i1 ON t1(a);
|
||||
INSERT INTO t1(a) VALUES(0),(2),(3),(8),(9);
|
||||
CREATE TABLE t2(b);
|
||||
CREATE TABLE t3(c);
|
||||
|
||||
CREATE TRIGGER tr AFTER INSERT ON t3 BEGIN
|
||||
INSERT INTO t3 SELECT new.c+1 WHERE new.c<5;
|
||||
INSERT INTO t2 SELECT new.c*100+a FROM t1 WHERE a IN (1, 2, 3, 4);
|
||||
END;
|
||||
|
||||
INSERT INTO t3 VALUES(2);
|
||||
SELECT c FROM t3 ORDER BY c;;
|
||||
} {2 3 4 5}
|
||||
do_execsql_test 110 {
|
||||
SELECT b FROM t2 ORDER BY b;
|
||||
} {202 203 302 303 402 403 502 503}
|
||||
|
||||
do_execsql_test 200 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a) VALUES(0),(2),(3),(8),(9);
|
||||
DELETE FROM t2;
|
||||
DELETE FROM t3;
|
||||
DROP TRIGGER tr;
|
||||
CREATE TRIGGER tr AFTER INSERT ON t3 BEGIN
|
||||
INSERT INTO t3 SELECT new.c+1 WHERE new.c<5;
|
||||
INSERT INTO t2 SELECT new.c*10000+xx.a*100+yy.a
|
||||
FROM t1 AS xx, t1 AS yy
|
||||
WHERE xx.a IN (1,2,3,4)
|
||||
AND yy.a IN (2,3,4,5);
|
||||
END;
|
||||
|
||||
INSERT INTO t3 VALUES(2);
|
||||
SELECT b FROM t2 ORDER BY b;
|
||||
} {20202 20203 20302 20303 30202 30203 30302 30303 40202 40203 40302 40303 50202 50203 50302 50303}
|
||||
|
||||
finish_test
|
||||
+13
-1
@@ -124,7 +124,7 @@ IF NOT EXIST "%FRAMEWORKDIR%\csc.exe" (
|
||||
GOTO errors
|
||||
)
|
||||
|
||||
SET PATH=%FRAMEWORKDIR%;%PATH%
|
||||
CALL :fn_PrependToPath FRAMEWORKDIR
|
||||
|
||||
:skip_addToPath
|
||||
|
||||
@@ -246,6 +246,18 @@ GOTO no_errors
|
||||
ENDLOCAL && SET %1=%VALUE%
|
||||
GOTO :EOF
|
||||
|
||||
:fn_PrependToPath
|
||||
IF NOT DEFINED %1 GOTO :EOF
|
||||
SETLOCAL
|
||||
SET __ECHO_CMD=ECHO %%%1%%
|
||||
FOR /F "delims=" %%V IN ('%__ECHO_CMD%') DO (
|
||||
SET VALUE=%%V
|
||||
)
|
||||
SET VALUE=%VALUE:"=%
|
||||
REM "
|
||||
ENDLOCAL && SET PATH=%VALUE%;%PATH%
|
||||
GOTO :EOF
|
||||
|
||||
:fn_ResetErrorLevel
|
||||
VERIFY > NUL
|
||||
GOTO :EOF
|
||||
|
||||
@@ -460,7 +460,7 @@ FOR %%P IN (%PLATFORMS%) DO (
|
||||
REM
|
||||
REM NOTE: Reset the PATH here to the absolute bare minimum required.
|
||||
REM
|
||||
SET PATH=%TOOLPATH%;%SystemRoot%\System32;%SystemRoot%
|
||||
CALL :fn_ResetPath
|
||||
|
||||
REM
|
||||
REM NOTE: This is the inner loop. There are normally two iterations, one
|
||||
@@ -818,6 +818,10 @@ GOTO no_errors
|
||||
CALL :fn_ResetErrorLevel
|
||||
GOTO :EOF
|
||||
|
||||
:fn_ResetPath
|
||||
SET PATH=%TOOLPATH%;%SystemRoot%\System32;%SystemRoot%
|
||||
GOTO :EOF
|
||||
|
||||
:fn_AppendVariable
|
||||
SET __ECHO_CMD=ECHO %%%1%%
|
||||
IF DEFINED %1 (
|
||||
|
||||
@@ -225,8 +225,8 @@ set pragma_def {
|
||||
|
||||
NAME: stats
|
||||
FLAG: NeedSchema Result0 SchemaReq
|
||||
COLS: table index width height
|
||||
IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
|
||||
COLS: tbl idx wdth hght flgs
|
||||
IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG)
|
||||
|
||||
NAME: index_info
|
||||
TYPE: INDEX_INFO
|
||||
@@ -331,9 +331,6 @@ set pragma_def {
|
||||
NAME: shrink_memory
|
||||
FLAG: NoColumns
|
||||
|
||||
NAME: vdbe_cycle_limit
|
||||
FLAG: NoColumns
|
||||
|
||||
NAME: busy_timeout
|
||||
FLAG: Result0
|
||||
COLS: timeout
|
||||
@@ -364,6 +361,9 @@ set pragma_def {
|
||||
|
||||
NAME: threads
|
||||
FLAG: Result0
|
||||
|
||||
NAME: optimize
|
||||
FLAG: Result1 NeedSchema
|
||||
}
|
||||
|
||||
# Open the output file
|
||||
|
||||
+1
-1
@@ -535,7 +535,7 @@ static void decodeCell(
|
||||
j = i;
|
||||
nCol = 0;
|
||||
k = nHdr;
|
||||
while( x+j<end && j<nHdr ){
|
||||
while( x+j<=end && j<nHdr ){
|
||||
const char *zTypeName;
|
||||
int sz = 0;
|
||||
char zNm[30];
|
||||
|
||||
Reference in New Issue
Block a user