diff --git a/Makefile.in b/Makefile.in
index 95c6498651..1d29625117 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -444,6 +444,7 @@ TESTSRC += \
$(TOP)/ext/misc/carray.c \
$(TOP)/ext/misc/closure.c \
$(TOP)/ext/misc/csv.c \
+ $(TOP)/ext/misc/decimal.c \
$(TOP)/ext/misc/eval.c \
$(TOP)/ext/misc/explain.c \
$(TOP)/ext/misc/fileio.c \
@@ -1069,6 +1070,12 @@ parse.c: $(TOP)/src/parse.y lemon$(BEXE)
sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest mksourceid$(BEXE) $(TOP)/VERSION
$(TCLSH_CMD) $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
+sqlite3rc.h: $(TOP)/src/sqlite3.rc $(TOP)/VERSION
+ echo '#ifndef SQLITE_RESOURCE_VERSION' >$@
+ echo -n '#define SQLITE_RESOURCE_VERSION ' >>$@
+ cat $(TOP)/VERSION | $(TCLSH_CMD) $(TOP)/tool/replace.tcl exact . , >>$@
+ echo '#endif' >>sqlite3rc.h
+
keywordhash.h: $(TOP)/tool/mkkeywordhash.c
$(BCC) -o mkkeywordhash$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) $(TOP)/tool/mkkeywordhash.c
./mkkeywordhash$(BEXE) >keywordhash.h
@@ -1077,9 +1084,11 @@ keywordhash.h: $(TOP)/tool/mkkeywordhash.c
SHELL_SRC = \
$(TOP)/src/shell.c.in \
$(TOP)/ext/misc/appendvfs.c \
- $(TOP)/ext/misc/shathree.c \
- $(TOP)/ext/misc/fileio.c \
$(TOP)/ext/misc/completion.c \
+ $(TOP)/ext/misc/decimal.c \
+ $(TOP)/ext/misc/fileio.c \
+ $(TOP)/ext/misc/ieee754.c \
+ $(TOP)/ext/misc/shathree.c \
$(TOP)/ext/misc/sqlar.c \
$(TOP)/ext/misc/uint.c \
$(TOP)/ext/expert/sqlite3expert.c \
@@ -1288,6 +1297,9 @@ valgrindtest: $(TESTPROGS) valgrindfuzz
smoketest: $(TESTPROGS) fuzzcheck$(TEXE)
./testfixture$(TEXE) $(TOP)/test/main.test $(TESTOPTS)
+shelltest: $(TESTPROGS)
+ ./testfixture$(TEXT) $(TOP)/test/permutations.test shell
+
sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in
$(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in >sqlite3_analyzer.c
@@ -1390,10 +1402,10 @@ checksymbols: sqlite3.o
# a tarball named for the version number. Ex: sqlite-autoconf-3110000.tar.gz.
# The snapshot-tarball target builds a tarball named by the SHA1 hash
#
-amalgamation-tarball: sqlite3.c
+amalgamation-tarball: sqlite3.c sqlite3rc.h
TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --normal
-snapshot-tarball: sqlite3.c
+snapshot-tarball: sqlite3.c sqlite3rc.h
TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --snapshot
# The next two rules are used to support the "threadtest" target. Building
diff --git a/Makefile.msc b/Makefile.msc
index a049e83fc4..d3b5c60893 100644
--- a/Makefile.msc
+++ b/Makefile.msc
@@ -1495,7 +1495,7 @@ SRC12 =
# All source code files.
#
-SRC = $(SRC00) $(SRC01) $(SRC03) $(SRC04) $(SRC05) $(SRC06) $(SRC07) $(SRC08) $(SRC09) $(SRC10) $(SRC11)
+SRC = $(SRC00) $(SRC01) $(SRC03) $(SRC04) $(SRC05) $(SRC06) $(SRC07) $(SRC08) $(SRC09) $(SRC10) $(SRC11) $(SRC12)
# Source code to the test files.
#
@@ -1561,6 +1561,7 @@ TESTEXT = \
$(TOP)\ext\misc\carray.c \
$(TOP)\ext\misc\closure.c \
$(TOP)\ext\misc\csv.c \
+ $(TOP)\ext\misc\decimal.c \
$(TOP)\ext\misc\eval.c \
$(TOP)\ext\misc\explain.c \
$(TOP)\ext\misc\fileio.c \
@@ -1847,15 +1848,16 @@ mptest: mptester.exe
for %i in ($(SRC11)) do copy /Y %i tsrc
for %i in ($(SRC12)) do copy /Y %i tsrc
copy /Y fts5.c tsrc
+ copy /B tsrc\fts5.c +,,
copy /Y fts5.h tsrc
+ copy /B tsrc\fts5.h +,,
del /Q tsrc\sqlite.h.in tsrc\parse.y 2>NUL
$(TCLSH_CMD) $(TOP)\tool\vdbe-compress.tcl $(OPTS) < tsrc\vdbe.c > vdbe.new
move vdbe.new tsrc\vdbe.c
echo > .target_source
-sqlite3.c: .target_source sqlite3ext.h $(MKSQLITE3C_TOOL)
+sqlite3.c: .target_source sqlite3ext.h sqlite3session.h $(MKSQLITE3C_TOOL)
$(TCLSH_CMD) $(MKSQLITE3C_TOOL) $(MKSQLITE3C_ARGS)
- copy $(TOP)\ext\session\sqlite3session.h .
sqlite3-all.c: sqlite3.c $(TOP)\tool\split-sqlite3c.tcl
$(TCLSH_CMD) $(TOP)\tool\split-sqlite3c.tcl
@@ -1870,7 +1872,8 @@ sqlite3.lo: $(SQLITE3C)
# Rules to build the LEMON compiler generator
#
lempar.c: $(TOP)\tool\lempar.c
- copy $(TOP)\tool\lempar.c .
+ copy /Y $(TOP)\tool\lempar.c .
+ copy /B lempar.c +,,
lemon.exe: $(TOP)\tool\lemon.c lempar.c
$(BCC) $(NO_WARN) -Daccess=_access \
@@ -2170,7 +2173,8 @@ parse.h: parse.c
parse.c: $(TOP)\src\parse.y lemon.exe
del /Q parse.y parse.h parse.h.temp 2>NUL
- copy $(TOP)\src\parse.y .
+ copy /Y $(TOP)\src\parse.y .
+ copy /B parse.y +,,
.\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) -S parse.y
$(SQLITE3H): $(TOP)\src\sqlite.h.in $(TOP)\manifest mksourceid.exe $(TOP)\VERSION
@@ -2183,8 +2187,13 @@ sqlite3ext.h: .target_source
copy /Y sqlite3ext.h tsrc\sqlite3ext.h
!ELSE
copy /Y tsrc\sqlite3ext.h sqlite3ext.h
+ copy /B sqlite3ext.h +,,
!ENDIF
+sqlite3session.h: $(TOP)\ext\session\sqlite3session.h
+ copy /Y $(TOP)\ext\session\sqlite3session.h .
+ copy /B sqlite3session.h +,,
+
mkkeywordhash.exe: $(TOP)\tool\mkkeywordhash.c
$(BCC) $(NO_WARN) -Fe$@ $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) \
$(TOP)\tool\mkkeywordhash.c /link $(LDFLAGS) $(NLTLINKOPTS) $(NLTLIBPATHS)
@@ -2196,10 +2205,12 @@ keywordhash.h: $(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe
SHELL_SRC = \
$(TOP)\src\shell.c.in \
$(TOP)\ext\misc\appendvfs.c \
- $(TOP)\ext\misc\shathree.c \
- $(TOP)\ext\misc\fileio.c \
$(TOP)\ext\misc\completion.c \
- $(TOP)\ext\misc\uint.c \
+ $(TOP)\ext\misc\decimal.c \
+ $(TOP)\ext\misc\fileio.c \
+ $(TOP)\ext\misc\ieee754.c \
+ $(TOP)\ext\misc\shathree.c \
+ $(TOP)\ext\misc\uint.c \
$(TOP)\ext\expert\sqlite3expert.c \
$(TOP)\ext\expert\sqlite3expert.h \
$(TOP)\ext\misc\memtrace.c \
@@ -2330,7 +2341,8 @@ LSM1_SRC = \
$(TOP)\ext\lsm1\lsm_win32.c
fts5parse.c: $(TOP)\ext\fts5\fts5parse.y lemon.exe
- copy $(TOP)\ext\fts5\fts5parse.y .
+ copy /Y $(TOP)\ext\fts5\fts5parse.y .
+ copy /B fts5parse.y +,,
del /Q fts5parse.h 2>NUL
.\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) -S fts5parse.y
@@ -2338,11 +2350,13 @@ fts5parse.h: fts5parse.c
fts5.c: $(FTS5_SRC)
$(TCLSH_CMD) $(TOP)\ext\fts5\tool\mkfts5c.tcl
- copy $(TOP)\ext\fts5\fts5.h .
+ copy /Y $(TOP)\ext\fts5\fts5.h .
+ copy /B fts5.h +,,
lsm1.c: $(LSM1_SRC)
$(TCLSH_CMD) $(TOP)\ext\lsm1\tool\mklsm1c.tcl
- copy $(TOP)\ext\lsm1\lsm.h .
+ copy /Y $(TOP)\ext\lsm1\lsm.h .
+ copy /B lsm.h +,,
fts5.lo: fts5.c $(HDR) $(EXTHDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c fts5.c
@@ -2453,6 +2467,9 @@ smoketest: $(TESTPROGS)
@set PATH=$(LIBTCLPATH);$(PATH)
.\testfixture.exe $(TOP)\test\main.test $(TESTOPTS)
+shelltest: $(TESTPROGS)
+ .\testfixture.exe $(TOP)\test\permutations.test shell
+
sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in $(SQLITE_TCL_DEP)
$(TCLSH_CMD) $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in > $@
diff --git a/VERSION b/VERSION
index 1367bf750d..949654dc3e 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.32.1
+3.33.0
diff --git a/autoconf/Makefile.am b/autoconf/Makefile.am
index 20af7433be..694419b27d 100644
--- a/autoconf/Makefile.am
+++ b/autoconf/Makefile.am
@@ -13,7 +13,7 @@ sqlite3_CFLAGS = $(AM_CFLAGS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_D
include_HEADERS = sqlite3.h sqlite3ext.h
-EXTRA_DIST = sqlite3.1 tea Makefile.msc sqlite3.rc README.txt Replace.cs Makefile.fallback
+EXTRA_DIST = sqlite3.1 tea Makefile.msc sqlite3.rc sqlite3rc.h README.txt Replace.cs Makefile.fallback
pkgconfigdir = ${libdir}/pkgconfig
pkgconfig_DATA = sqlite3.pc
diff --git a/configure b/configure
index 854b2460a6..9ba67e99ef 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for sqlite 3.32.1.
+# Generated by GNU Autoconf 2.69 for sqlite 3.33.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.32.1'
-PACKAGE_STRING='sqlite 3.32.1'
+PACKAGE_VERSION='3.33.0'
+PACKAGE_STRING='sqlite 3.33.0'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -1467,7 +1467,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.32.1 to adapt to many kinds of systems.
+\`configure' configures sqlite 3.33.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1532,7 +1532,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of sqlite 3.32.1:";;
+ short | recursive ) echo "Configuration of sqlite 3.33.0:";;
esac
cat <<\_ACEOF
@@ -1659,7 +1659,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-sqlite configure 3.32.1
+sqlite configure 3.33.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2078,7 +2078,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.32.1, which was
+It was created by sqlite $as_me 3.33.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -11268,7 +11268,7 @@ if test "${enable_amalgamation+set}" = set; then :
enableval=$enable_amalgamation;
fi
-if test "${enable_amalgamation}" == "no" ; then
+if test "${enable_amalgamation}" = "no" ; then
USE_AMALGAMATION=0
fi
@@ -11619,7 +11619,7 @@ if test "${enable_update_limit+set}" = set; then :
enableval=$enable_update_limit;
fi
-if test "${enable_udlimit}" = "yes" ; then
+if test "${enable_update_limit}" = "yes" ; then
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT"
fi
@@ -12243,7 +12243,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.32.1, which was
+This file was extended by sqlite $as_me 3.33.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -12309,7 +12309,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.32.1
+sqlite config.status 3.33.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index ef70a4f0d1..6c1fdb6b27 100644
--- a/configure.ac
+++ b/configure.ac
@@ -569,7 +569,7 @@ AC_SUBST(TARGET_DEBUG)
# See whether we should use the amalgamation to build
AC_ARG_ENABLE(amalgamation, AC_HELP_STRING([--disable-amalgamation],
[Disable the amalgamation and instead build all files separately]))
-if test "${enable_amalgamation}" == "no" ; then
+if test "${enable_amalgamation}" = "no" ; then
USE_AMALGAMATION=0
fi
AC_SUBST(USE_AMALGAMATION)
@@ -651,7 +651,7 @@ fi
# statements.
AC_ARG_ENABLE(update-limit, AC_HELP_STRING([--enable-update-limit],
[Enable the UPDATE/DELETE LIMIT clause]))
-if test "${enable_udlimit}" = "yes" ; then
+if test "${enable_update_limit}" = "yes" ; then
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT"
fi
diff --git a/doc/lemon.html b/doc/lemon.html
index 17988deef4..714cbfa5b2 100644
--- a/doc/lemon.html
+++ b/doc/lemon.html
@@ -104,9 +104,13 @@ Write all output files into directory. Normally, output files
are written into the directory that contains the input grammar file.
-Dname
Define C preprocessor macro name. This macro is usable by
-"%ifdef" and
-"%ifndef" lines
+"%ifdef",
+"%ifndef", and
+"%if lines
in the grammar file.
+-E
+Run the "%if" preprocessor step only and print the revised grammar
+file.
-g
Do not generate a parser. Instead write the input grammar to standard
output with all comments, actions, and other extraneous text removed.
@@ -555,9 +559,11 @@ other than that, the order of directives in Lemon is arbitrary.
%default_destructor
%default_type
%destructor
+%else
%endif
%extra_argument
%fallback
+%if
%ifdef
%ifndef
%include
@@ -737,10 +743,11 @@ arguments are tokens which fall back to the token identified by the first
argument.
-The %ifdef, %ifndef, and %endif directives
+The %if directive and its friends
-The %ifdef, %ifndef, and %endif directives
-are similar to #ifdef, #ifndef, and #endif in the C-preprocessor,
+
The %if, %ifdef, %ifndef, %else,
+and %endif directives
+are similar to #if, #ifdef, #ifndef, #else, and #endif in the C-preprocessor,
just not as general.
Each of these directives must begin at the left margin. No whitespace
is allowed between the "%" and the directive name.
@@ -749,12 +756,22 @@ is allowed between the "%" and the directive name.
"%endif" is
ignored unless the "-DMACRO" command-line option is used. Grammar text
betwen "%ifndef MACRO" and the next nested "%endif" is
-included except when the "-DMACRO" command-line option is used.
+included except when the "-DMACRO" command-line option is used.
-
Note that the argument to %ifdef and %ifndef must
-be a single preprocessor symbol name, not a general expression.
-There is no "%else" directive.
+The text in between "%if CONDITIONAL" and its
+corresponding %endif is included only if CONDITIONAL
+is true. The CONDITION is one or more macro names, optionally connected
+using the "||" and "&&" binary operators, the "!" unary operator,
+and grouped using balanced parentheses. Each term is true if the
+corresponding macro exists, and false if it does not exist.
+An optional "%else" directive can occur anywhere in between a
+%ifdef, %ifndef, or %if directive and
+its corresponding %endif.
+
+Note that the argument to %ifdef and %ifndef is
+intended to be a single preprocessor symbol name, not a general expression.
+Use the "%if" directive for general expressions.
The %include directive
diff --git a/doc/wal-lock.md b/doc/wal-lock.md
new file mode 100644
index 0000000000..d74bb88b63
--- /dev/null
+++ b/doc/wal-lock.md
@@ -0,0 +1,88 @@
+# Wal-Mode Blocking Locks
+
+On some Unix-like systems, SQLite may be configured to use POSIX blocking locks
+by:
+
+ * building the library with SQLITE\_ENABLE\_SETLK\_TIMEOUT defined, and
+ * configuring a timeout in ms using the sqlite3\_busy\_timeout() API.
+
+Blocking locks may be advantageous as (a) waiting database clients do not
+need to continuously poll the database lock, and (b) using blocking locks
+facilitates transfer of OS priority between processes when a high priority
+process is blocked by a lower priority one.
+
+Only read/write clients use blocking locks. Clients that have read-only access
+to the \*-shm file nevery use blocking locks.
+
+Threads or processes that access a single database at a time never deadlock as
+a result of blocking database locks. But it is of course possible for threads
+that lock multiple databases simultaneously to do so. In most cases the OS will
+detect the deadlock and return an error.
+
+## Wal Recovery
+
+Wal database "recovery" is a process required when the number of connected
+database clients changes from zero to one. In this case, a client is
+considered to connect to the database when it first reads data from it.
+Before recovery commences, an exclusive WRITER lock is taken.
+
+Without blocking locks, if two clients attempt recovery simultaneously, one
+fails to obtain the WRITER lock and either invokes the busy-handler callback or
+returns SQLITE\_BUSY to the user. With blocking locks configured, the second
+client blocks on the WRITER lock.
+
+## Database Readers
+
+Usually, read-only are not blocked by any other database clients, so they
+have no need of blocking locks.
+
+If a read-only transaction is being opened on a snapshot, the CHECKPOINTER
+lock is required briefly as part of opening the transaction (to check that a
+checkpointer is not currently overwriting the snapshot being opened). A
+blocking lock is used to obtain the CHECKPOINTER lock in this case. A snapshot
+opener may therefore block on and transfer priority to a checkpointer in some
+cases.
+
+## Database Writers
+
+A database writer must obtain the exclusive WRITER lock. It uses a blocking
+lock to do so if any of the following are true:
+
+ * the transaction is an implicit one consisting of a single DML or DDL
+ statement, or
+ * the transaction is opened using BEGIN IMMEDIATE or BEGIN EXCLUSIVE, or
+ * the first SQL statement executed following the BEGIN command is a DML or
+ DDL statement (not a read-only statement like a SELECT).
+
+In other words, in all cases except when an open read-transaction is upgraded
+to a write-transaction. In that case a non-blocking lock is used.
+
+## Database Checkpointers
+
+Database checkpointers takes the following locks, in order:
+
+ * The exclusive CHECKPOINTER lock.
+ * The exclusive WRITER lock (FULL, RESTART and TRUNCATE only).
+ * Exclusive lock on read-mark slots 1-N. These are immediately released after being taken.
+ * Exclusive lock on read-mark 0.
+ * Exclusive lock on read-mark slots 1-N again. These are immediately released
+ after being taken (RESTART and TRUNCATE only).
+
+All of the above use blocking locks.
+
+## Summary
+
+With blocking locks configured, the only cases in which clients should see an
+SQLITE\_BUSY error are:
+
+ * if the OS does not grant a blocking lock before the configured timeout
+ expires, and
+ * when an open read-transaction is upgraded to a write-transaction.
+
+In all other cases the blocking locks implementation should prevent clients
+from having to handle SQLITE\_BUSY errors and facilitate appropriate transfer
+of priorities between competing clients.
+
+Clients that lock multiple databases simultaneously must be wary of deadlock.
+
+
diff --git a/ext/async/sqlite3async.c b/ext/async/sqlite3async.c
index b6f4a4bd36..eed7c8d738 100644
--- a/ext/async/sqlite3async.c
+++ b/ext/async/sqlite3async.c
@@ -1704,4 +1704,3 @@ int sqlite3async_control(int op, ...){
}
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ASYNCIO) */
-
diff --git a/ext/async/sqlite3async.h b/ext/async/sqlite3async.h
index 5b20d7189a..13b23bc6a2 100644
--- a/ext/async/sqlite3async.h
+++ b/ext/async/sqlite3async.h
@@ -220,4 +220,3 @@ int sqlite3async_control(int op, ...);
} /* End of the 'extern "C"' block */
#endif
#endif /* ifndef __SQLITEASYNC_H_ */
-
diff --git a/ext/expert/sqlite3expert.c b/ext/expert/sqlite3expert.c
index b5a6fd2ab4..1dd0700893 100644
--- a/ext/expert/sqlite3expert.c
+++ b/ext/expert/sqlite3expert.c
@@ -1223,7 +1223,7 @@ static int idxProcessOneTrigger(
IdxTable *pTab = pWrite->pTab;
const char *zTab = pTab->zName;
const char *zSql =
- "SELECT 'CREATE TEMP' || substr(sql, 7) FROM sqlite_master "
+ "SELECT 'CREATE TEMP' || substr(sql, 7) FROM sqlite_schema "
"WHERE tbl_name = %Q AND type IN ('table', 'trigger') "
"ORDER BY type;";
sqlite3_stmt *pSelect = 0;
@@ -1323,12 +1323,12 @@ static int idxCreateVtabSchema(sqlite3expert *p, char **pzErrmsg){
** 2) Create the equivalent virtual table in dbv.
*/
rc = idxPrepareStmt(p->db, &pSchema, pzErrmsg,
- "SELECT type, name, sql, 1 FROM sqlite_master "
+ "SELECT type, name, sql, 1 FROM sqlite_schema "
"WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%%' "
" UNION ALL "
- "SELECT type, name, sql, 2 FROM sqlite_master "
+ "SELECT type, name, sql, 2 FROM sqlite_schema "
"WHERE type = 'trigger'"
- " AND tbl_name IN(SELECT name FROM sqlite_master WHERE type = 'view') "
+ " AND tbl_name IN(SELECT name FROM sqlite_schema WHERE type = 'view') "
"ORDER BY 4, 1"
);
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSchema) ){
@@ -1498,7 +1498,7 @@ static int idxLargestIndex(sqlite3 *db, int *pnMax, char **pzErr){
int rc = SQLITE_OK;
const char *zMax =
"SELECT max(i.seqno) FROM "
- " sqlite_master AS s, "
+ " sqlite_schema AS s, "
" pragma_index_list(s.name) AS l, "
" pragma_index_info(l.name) AS i "
"WHERE s.type = 'table'";
@@ -1651,7 +1651,7 @@ static int idxPopulateStat1(sqlite3expert *p, char **pzErr){
const char *zAllIndex =
"SELECT s.rowid, s.name, l.name FROM "
- " sqlite_master AS s, "
+ " sqlite_schema AS s, "
" pragma_index_list(s.name) AS l "
"WHERE s.type = 'table'";
const char *zIndexXInfo =
@@ -1725,7 +1725,7 @@ static int idxPopulateStat1(sqlite3expert *p, char **pzErr){
sqlite3_free(pCtx);
if( rc==SQLITE_OK ){
- rc = sqlite3_exec(p->dbm, "ANALYZE sqlite_master", 0, 0, 0);
+ rc = sqlite3_exec(p->dbm, "ANALYZE sqlite_schema", 0, 0, 0);
}
sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp."UNIQUE_TABLE_NAME,0,0,0);
@@ -1764,7 +1764,7 @@ sqlite3expert *sqlite3_expert_new(sqlite3 *db, char **pzErrmsg){
if( rc==SQLITE_OK ){
sqlite3_stmt *pSql;
rc = idxPrintfPrepareStmt(pNew->db, &pSql, pzErrmsg,
- "SELECT sql FROM sqlite_master WHERE name NOT LIKE 'sqlite_%%'"
+ "SELECT sql FROM sqlite_schema WHERE name NOT LIKE 'sqlite_%%'"
" AND sql NOT LIKE 'CREATE VIRTUAL %%'"
);
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
diff --git a/ext/fts3/README.content b/ext/fts3/README.content
index ab986754df..b6a75399be 100644
--- a/ext/fts3/README.content
+++ b/ext/fts3/README.content
@@ -174,5 +174,3 @@ EXTERNAL CONTENT FTS4 TABLES
only be useful if the full-text index has somehow become corrupt. It is an
error to attempt to rebuild the full-text index maintained by a contentless
FTS4 table.
-
-
diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c
index e6092a215e..79dc5c88ce 100644
--- a/ext/fts3/fts3.c
+++ b/ext/fts3/fts3.c
@@ -2068,7 +2068,7 @@ static void fts3PutDeltaVarint(
sqlite3_int64 *piPrev, /* IN/OUT: Previous value written to list */
sqlite3_int64 iVal /* Write this value to the list */
){
- assert( iVal-*piPrev > 0 || (*piPrev==0 && iVal==0) );
+ assert_fts3_nc( iVal-*piPrev > 0 || (*piPrev==0 && iVal==0) );
*pp += sqlite3Fts3PutVarint(*pp, iVal-*piPrev);
*piPrev = iVal;
}
@@ -2267,6 +2267,9 @@ static int fts3PoslistMerge(
*/
fts3GetDeltaVarint(&p1, &i1);
fts3GetDeltaVarint(&p2, &i2);
+ if( i1<2 || i2<2 ){
+ break;
+ }
do {
fts3PutDeltaVarint(&p, &iPrev, (i1nColumn;
- /* fall-through */
+ /* no break */ deliberate_fall_through
}
default:
@@ -3719,9 +3722,13 @@ static void fts3SnippetFunc(
switch( nVal ){
case 6: nToken = sqlite3_value_int(apVal[5]);
+ /* no break */ deliberate_fall_through
case 5: iCol = sqlite3_value_int(apVal[4]);
+ /* no break */ deliberate_fall_through
case 4: zEllipsis = (const char*)sqlite3_value_text(apVal[3]);
+ /* no break */ deliberate_fall_through
case 3: zEnd = (const char*)sqlite3_value_text(apVal[2]);
+ /* no break */ deliberate_fall_through
case 2: zStart = (const char*)sqlite3_value_text(apVal[1]);
}
if( !zEllipsis || !zEnd || !zStart ){
@@ -4520,7 +4527,7 @@ void sqlite3Fts3DoclistNext(
assert( nDoclist>0 );
assert( *pbEof==0 );
- assert( p || *piDocid==0 );
+ assert_fts3_nc( p || *piDocid==0 );
assert( !p || (p>=aDoclist && p<=&aDoclist[nDoclist]) );
if( p==0 ){
@@ -5170,7 +5177,7 @@ static void fts3EvalInvalidatePoslist(Fts3Phrase *pPhrase){
**
** Parameter nNear is passed the NEAR distance of the expression (5 in
** the example above). When this function is called, *paPoslist points to
-** the position list, and *pnToken is the number of phrase tokens in, the
+** the position list, and *pnToken is the number of phrase tokens in the
** phrase on the other side of the NEAR operator to pPhrase. For example,
** if pPhrase refers to the "def ghi" phrase, then *paPoslist points to
** the position list associated with phrase "abc".
@@ -5205,10 +5212,12 @@ static int fts3EvalNearTrim(
);
if( res ){
nNew = (int)(pOut - pPhrase->doclist.pList) - 1;
- assert( pPhrase->doclist.pList[nNew]=='\0' );
- assert( nNew<=pPhrase->doclist.nList && nNew>0 );
- memset(&pPhrase->doclist.pList[nNew], 0, pPhrase->doclist.nList - nNew);
- pPhrase->doclist.nList = nNew;
+ if( nNew>=0 ){
+ assert( pPhrase->doclist.pList[nNew]=='\0' );
+ assert( nNew<=pPhrase->doclist.nList && nNew>0 );
+ memset(&pPhrase->doclist.pList[nNew], 0, pPhrase->doclist.nList - nNew);
+ pPhrase->doclist.nList = nNew;
+ }
*paPoslist = pPhrase->doclist.pList;
*pnToken = pPhrase->nToken;
}
@@ -5560,7 +5569,10 @@ static int fts3EvalTestExpr(
}else
#endif
{
- bHit = (pExpr->bEof==0 && pExpr->iDocid==pCsr->iPrevId);
+ bHit = (
+ pExpr->bEof==0 && pExpr->iDocid==pCsr->iPrevId
+ && pExpr->pPhrase->doclist.nList>0
+ );
}
break;
}
@@ -5823,7 +5835,8 @@ static int fts3EvalGatherStats(
fts3EvalRestart(pCsr, pRoot, &rc);
do {
fts3EvalNextRow(pCsr, pRoot, &rc);
- assert( pRoot->bEof==0 );
+ assert_fts3_nc( pRoot->bEof==0 );
+ if( pRoot->bEof ) rc = FTS_CORRUPT_VTAB;
}while( pRoot->iDocid!=iDocid && rc==SQLITE_OK );
}
}
diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h
index 453afcebfd..b3e0ec85fb 100644
--- a/ext/fts3/fts3Int.h
+++ b/ext/fts3/fts3Int.h
@@ -199,6 +199,8 @@ typedef sqlite3_int64 i64; /* 8-byte signed integer */
#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
+#define deliberate_fall_through
+
#endif /* SQLITE_AMALGAMATION */
#ifdef SQLITE_DEBUG
diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c
index b9acc47dc5..092cad9ac5 100644
--- a/ext/fts3/fts3_write.c
+++ b/ext/fts3/fts3_write.c
@@ -341,7 +341,9 @@ static int fts3SqlStmt(
** created by merging the oldest :2 segments from absolute level :1. See
** function sqlite3Fts3Incrmerge() for details. */
/* 29 */ "SELECT 2 * total(1 + leaves_end_block - start_block) "
- " FROM %Q.'%q_segdir' WHERE level = ? AND idx < ?",
+ " FROM (SELECT * FROM %Q.'%q_segdir' "
+ " WHERE level = ? ORDER BY idx ASC LIMIT ?"
+ " )",
/* SQL_DELETE_SEGDIR_ENTRY
** Delete the %_segdir entry on absolute level :1 with index :2. */
@@ -2853,6 +2855,19 @@ int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr){
return SQLITE_OK;
}
+static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, int nReq){
+ if( nReq>pCsr->nBuffer ){
+ char *aNew;
+ pCsr->nBuffer = nReq*2;
+ aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer);
+ if( !aNew ){
+ return SQLITE_NOMEM;
+ }
+ pCsr->aBuffer = aNew;
+ }
+ return SQLITE_OK;
+}
+
int sqlite3Fts3SegReaderStep(
Fts3Table *p, /* Virtual table handle */
@@ -2987,15 +3002,9 @@ int sqlite3Fts3SegReaderStep(
}
nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0);
- if( nDoclist+nByte>pCsr->nBuffer ){
- char *aNew;
- pCsr->nBuffer = (nDoclist+nByte)*2;
- aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer);
- if( !aNew ){
- return SQLITE_NOMEM;
- }
- pCsr->aBuffer = aNew;
- }
+
+ rc = fts3GrowSegReaderBuffer(pCsr, nByte+nDoclist);
+ if( rc ) return rc;
if( isFirst ){
char *a = &pCsr->aBuffer[nDoclist];
@@ -3020,6 +3029,9 @@ int sqlite3Fts3SegReaderStep(
fts3SegReaderSort(apSegment, nMerge, j, xCmp);
}
if( nDoclist>0 ){
+ rc = fts3GrowSegReaderBuffer(pCsr, nDoclist+FTS3_NODE_PADDING);
+ if( rc ) return rc;
+ memset(&pCsr->aBuffer[nDoclist], 0, FTS3_NODE_PADDING);
pCsr->aDoclist = pCsr->aBuffer;
pCsr->nDoclist = nDoclist;
rc = SQLITE_ROW;
@@ -4288,7 +4300,7 @@ static int fts3IncrmergeLoad(
int i;
int nHeight = (int)aRoot[0];
NodeWriter *pNode;
- if( nHeight<1 || nHeight>FTS_MAX_APPENDABLE_HEIGHT ){
+ if( nHeight<1 || nHeight>=FTS_MAX_APPENDABLE_HEIGHT ){
sqlite3_reset(pSelect);
return FTS_CORRUPT_VTAB;
}
diff --git a/ext/fts3/tool/fts3view.c b/ext/fts3/tool/fts3view.c
index 37f9b7396d..9558cde0d0 100644
--- a/ext/fts3/tool/fts3view.c
+++ b/ext/fts3/tool/fts3view.c
@@ -93,7 +93,7 @@ static int runSql(sqlite3 *db, const char *zFormat, ...){
static void showSchema(sqlite3 *db, const char *zTab){
sqlite3_stmt *pStmt;
pStmt = prepare(db,
- "SELECT sql FROM sqlite_master"
+ "SELECT sql FROM sqlite_schema"
" WHERE name LIKE '%q%%'"
" ORDER BY 1",
zTab);
@@ -831,7 +831,7 @@ int main(int argc, char **argv){
sqlite3_stmt *pStmt;
int cnt = 0;
pStmt = prepare(db, "SELECT b.sql"
- " FROM sqlite_master a, sqlite_master b"
+ " FROM sqlite_schema a, sqlite_schema b"
" WHERE a.name GLOB '*_segdir'"
" AND b.name=substr(a.name,1,length(a.name)-7)"
" ORDER BY 1");
diff --git a/ext/fts5/fts5_index.c b/ext/fts5/fts5_index.c
index f33617465d..5e1155c2a9 100644
--- a/ext/fts5/fts5_index.c
+++ b/ext/fts5/fts5_index.c
@@ -2321,11 +2321,11 @@ static void fts5LeafSeek(
}
search_success:
- pIter->iLeafOffset = iOff + nNew;
- if( pIter->iLeafOffset>n || nNew<1 ){
+ if( (i64)iOff+nNew>n || nNew<1 ){
p->rc = FTS5_CORRUPT;
return;
}
+ pIter->iLeafOffset = iOff + nNew;
pIter->iTermLeafOffset = pIter->iLeafOffset;
pIter->iTermLeafPgno = pIter->iLeafPgno;
diff --git a/ext/fts5/test/fts5corrupt3.test b/ext/fts5/test/fts5corrupt3.test
index 4e0ae64a9a..25aa094e97 100644
--- a/ext/fts5/test/fts5corrupt3.test
+++ b/ext/fts5/test/fts5corrupt3.test
@@ -10108,6 +10108,221 @@ do_catchsql_test 68.1 {
INSERT INTO t1(t1) SELECT x FROM t2;
} {1 {database disk image is malformed}}
+#-------------------------------------------------------------------------
+reset_db
+do_test 69.0 {
+ sqlite3 db {}
+ db deserialize [decode_hexdb {
+.open --hexdb
+| size 32768 pagesize 4096 filename crash-31c462b8b665d0.db
+| page 1 offset 0
+| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
+| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 08 .....@ ........
+| 32: 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 ................
+| 96: 00 00 00 00 0d 0f c7 00 07 0d 92 00 0f 8d 0f 36 ...............6
+| 112: 0e cb 0e 6b 0e 0e 0d b6 0d 92 00 00 00 00 00 00 ...k............
+| 3472: 00 00 22 08 06 17 11 11 01 31 74 61 62 6c 65 74 .........1tablet
+| 3488: 32 74 32 08 43 52 45 41 54 45 20 54 41 42 4c 45 2t2.CREATE TABLE
+| 3504: 20 74 32 28 78 29 56 07 06 17 1f 1f 01 7d 74 61 t2(x)V.......ta
+| 3520: 62 6c 65 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 blet1_configt1_c
+| 3536: 6f 6e 66 69 67 07 43 52 45 41 54 45 20 54 41 42 onfig.CREATE TAB
+| 3552: 4c 45 20 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b LE 't1_config'(k
+| 3568: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 PRIMARY KEY, v)
+| 3584: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5b 06 WITHOUT ROWID[.
+| 3600: 07 17 21 21 01 81 01 74 61 62 6c 65 74 31 5f 64 ..!!...tablet1_d
+| 3616: 6f 63 73 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 ocsizet1_docsize
+| 3632: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 .CREATE TABLE 't
+| 3648: 31 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 1_docsize'(id IN
+| 3664: 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 TEGER PRIMARY KE
+| 3680: 59 2c 20 73 7a 20 42 4c 4f 42 29 5e 05 07 17 21 Y, sz BLOB)^...!
+| 3696: 21 01 81 07 74 61 62 6c 65 74 31 5f 63 6f 6e 74 !...tablet1_cont
+| 3712: 65 6e 74 74 31 5f 63 6f 6e 74 65 6e 74 05 43 52 entt1_content.CR
+| 3728: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 EATE TABLE 't1_c
+| 3744: 6f 6e 74 65 6e 74 27 28 69 64 20 49 4e 54 45 47 ontent'(id INTEG
+| 3760: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY,
+| 3776: 63 39 2c 20 63 31 2c 20 63 32 29 69 04 07 17 19 c9, c1, c2)i....
+| 3792: 19 01 81 2d 74 61 62 6c 65 74 31 5f 69 64 78 74 ...-tablet1_idxt
+| 3808: 31 5f 69 64 78 04 43 52 45 41 54 45 20 54 41 42 1_idx.CREATE TAB
+| 3824: 4c 45 20 27 74 31 5f 69 64 78 27 28 73 65 67 69 LE 't1_idx'(segi
+| 3840: 64 2c 20 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 50 d, term, pgno, P
+| 3856: 52 49 4d 41 52 59 20 4b 45 59 28 73 65 67 69 64 RIMARY KEY(segid
+| 3872: 2c 20 74 65 72 6d 29 29 20 57 49 54 48 4f 55 54 , term)) WITHOUT
+| 3888: 20 52 4f 57 49 44 55 03 07 17 1b 1b 01 81 01 74 ROWIDU........t
+| 3904: 61 62 6c 65 74 31 5f 64 61 74 61 74 31 5f 64 61 ablet1_datat1_da
+| 3920: 74 61 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 ta.CREATE TABLE
+| 3936: 27 74 31 5f 64 61 74 61 27 28 69 64 20 49 4e 54 't1_data'(id INT
+| 3952: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY
+| 3968: 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 38 02 06 , block BLOB)8..
+| 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR
+| 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB
+| 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 35 LE t1 USING fts5
+| 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c).........
+| page 3 offset 8192
+| 0: 0d 00 00 00 03 0c 94 00 0f e6 0f ef 0c 94 00 00 ................
+| 3216: 00 00 00 00 86 4a 84 80 80 80 80 01 04 00 8d 18 .....J..........
+| 3232: 00 00 03 2b 02 30 30 01 02 06 01 02 06 01 02 06 ...+.00.........
+| 3248: 1f 02 03 01 02 03 01 02 03 01 08 32 30 31 36 30 ...........20160
+| 3264: 36 30 39 01 02 07 01 02 07 01 02 07 01 01 34 01 609...........4.
+| 3280: 02 05 01 02 05 01 02 05 01 01 35 01 02 04 01 02 ..........5.....
+| 3296: 04 01 02 04 02 07 30 30 30 30 30 30 30 1c 02 04 ......0000000...
+| 3312: 01 02 04 01 02 04 01 06 62 69 6e 61 72 79 03 06 ........binary..
+| 3328: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
+| 3344: 02 02 03 06 00 02 02 03 06 01 02 02 03 06 01 02 ................
+| 3360: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
+| 3376: 03 06 01 02 02 03 06 01 02 02 01 08 63 6f 6d 70 ............comp
+| 3392: 69 6c 65 72 01 02 02 01 02 02 01 02 02 01 06 64 iler...........d
+| 3408: 62 73 74 61 74 07 02 03 01 02 03 01 02 03 02 04 bstat...........
+| 3424: 65 62 75 67 04 02 02 01 02 02 01 02 02 01 06 65 ebug...........e
+| 3440: 6e 61 62 6c 65 07 02 02 01 02 02 01 02 02 01 02 nable...........
+| 3456: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
+| 3472: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
+| 3488: 01 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
+| 3504: 02 01 02 02 02 08 78 74 65 6e 73 69 6f 6e 1f 02 ......xtension..
+| 3520: 04 01 02 04 01 02 04 01 04 66 74 73 34 1a 02 03 .........fts4...
+| 3536: 01 02 03 01 02 03 04 01 35 0d 02 03 01 02 03 01 ........5.......
+| 3552: 02 03 01 03 67 63 63 01 aa 03 01 02 03 01 02 03 ....gcc.........
+| 3568: 02 06 65 6f 70 6f 6c 79 10 02 03 02 02 03 01 02 ..eopoly........
+| 3584: 03 01 05 6a 73 6f 6e 31 13 02 03 01 02 03 01 02 ...json1........
+| 3600: 03 01 04 6c 6f 61 64 1f 02 03 01 02 03 01 02 03 ...load.........
+| 3616: 01 03 6d 61 78 1c 02 02 01 02 02 01 02 02 02 05 ..max...........
+| 3632: 65 6d 6f 72 79 1c 02 03 01 02 03 01 02 03 04 04 emory...........
+| 3648: 73 79 73 35 16 02 03 01 02 03 01 02 03 01 06 6e sys5...........n
+| 3664: 6f 63 61 73 65 02 06 01 02 02 03 06 01 02 02 03 ocase...........
+| 3680: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
+| 3696: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
+| 3712: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
+| 3728: 02 01 04 6f 6d 69 74 1f 02 02 01 02 02 01 02 01 ...omit.........
+| 3744: ff ff ff ff ff ff ff ff f0 00 00 00 00 00 01 02 ................
+| 3760: 58 81 96 4d 01 06 01 02 02 03 06 01 02 02 03 06 X..M............
+| 3776: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
+| 3792: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
+| 3808: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
+| 3824: 01 0a 74 68 72 65 61 64 73 61 66 65 22 02 02 01 ..threadsafe....
+| 3840: 02 02 01 02 02 01 04 76 74 61 62 07 02 04 01 02 .......vtab.....
+| 3856: 04 01 02 04 01 01 78 01 06 01 01 02 01 06 01 01 ......x.........
+| 3872: 02 01 06 01 1e 02 01 06 01 01 02 01 06 01 01 02 ................
+| 3888: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
+| 3904: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
+| 3920: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
+| 3936: 00 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
+| 3952: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
+| 3968: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
+| 3984: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
+| 4000: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
+| 4016: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
+| 4032: 02 01 06 01 01 02 01 06 01 01 02 04 15 13 0c 0c ................
+| 4048: 12 44 13 11 0f 47 13 0f 0b 0e 11 10 0f 0e 10 0f .D...G..........
+| 4064: 44 0f 10 40 15 0f 07 01 03 00 14 24 5a 24 24 0f D..@.......$Z$$.
+| 4080: 0a 03 00 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............
+| page 4 offset 12288
+| 0: 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................
+| page 5 offset 16384
+| 0: 0d 00 00 00 24 0c 0a 00 0f d8 0f af 0f 86 0f 74 ....$..........t
+| 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./..........
+| 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$......
+| 48: 0d bb 0d a0 0d 84 0d 68 0d 4f 0d 00 00 00 00 00 .......h.O......
+| 3072: 00 00 00 00 00 00 00 00 00 00 18 24 05 00 25 0f ...........$..%.
+| 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI
+| 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA
+| 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE..
+| 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 45 3d ..%..THREADSAFE=
+| 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM
+| 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO
+| 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 d3 19 4f NXBINARY. ..3..O
+| 3200: 4d 49 54 28 2c 4f 41 44 b2 04 55 85 44 54 e5 34 MIT(,OAD..U.DT.4
+| 3216: 94 f4 e5 84 e4 f4 34 15 34 51 e1 f0 50 03 30 f1 ......4.4Q..P.0.
+| 3232: 74 f4 d4 95 42 04 c4 f4 14 42 04 55 85 44 54 e5 t...B....B.U.DT.
+| 3248: 34 94 f4 e5 85 25 45 24 94 d1 f1 e0 50 03 30 f1 4....%E$....P.0.
+| 3264: 94 d4 15 82 04 d4 54 d4 f5 25 93 d3 53 03 03 03 ......T..%..S...
+| 3280: 03 03 03 05 84 24 94 e4 15 25 91 f1 d0 50 03 30 .....$...%...P.0
+| 3296: f1 94 d4 15 82 04 d4 54 d4 f5 25 93 d3 53 03 03 .......T..%..S..
+| 3312: 03 03 03 03 05 84 e4 f4 34 15 34 51 e1 c0 50 03 ........4.4Q..P.
+| 3328: 30 f1 74 d4 15 82 04 d4 54 d4 f5 25 93 d3 53 03 0.t.....T..%..S.
+| 3344: 03 03 03 03 03 05 85 25 45 24 94 d1 81 b0 50 02 .......%E$....P.
+| 3360: 50 f1 94 54 e4 14 24 c4 52 05 25 45 24 54 55 84 P..T..$.R.%E$TU.
+| 3376: 24 94 e4 15 25 91 81 a0 50 02 50 f1 94 54 e4 14 $...%...P.P..T..
+| 3392: 24 c4 52 05 25 45 24 54 55 84 e4 f4 34 15 34 51 $.R.%E$TU...4.4Q
+| 3408: 71 90 50 02 50 f1 74 54 e4 14 24 c4 52 05 25 45 q.P.P.tT..$.R.%E
+| 3424: 24 54 55 85 25 45 24 94 d1 a1 80 50 02 90 f1 94 $TU.%E$....P....
+| 3440: 54 e4 14 24 c4 52 04 d4 54 d5 35 95 33 55 84 24 T..$.R..T.5.3U.$
+| 3456: 94 e4 15 25 91 a1 70 50 02 90 f1 94 54 e4 14 24 ...%..pP....T..$
+| 3472: c4 52 04 d4 54 d5 35 95 33 55 84 e4 f4 34 15 34 .R..T.5.3U...4.4
+| 3488: 51 91 60 50 02 90 f1 74 54 e4 14 24 c4 52 04 d4 Q.`P...tT..$.R..
+| 3504: 54 d5 35 95 33 55 85 25 45 24 94 d1 81 50 50 02 T.5.3U.%E$...PP.
+| 3520: 50 f1 94 54 e4 14 24 c4 52 04 a5 34 f4 e3 15 84 P..T..$.R..4....
+| 3536: 24 94 e4 15 25 91 81 40 50 02 50 f1 94 54 e4 14 $...%..@P.P..T..
+| 3552: 24 c4 52 04 a5 34 f4 e3 15 84 e4 f4 34 15 34 51 $.R..4......4.4Q
+| 3568: 71 30 50 02 4f f1 74 54 e4 14 24 c4 52 04 a5 34 q0P.O.tT..$.R..4
+| 3584: f4 e3 15 85 25 45 24 94 d1 a1 20 50 02 90 f1 94 ....%E$... P....
+| 3600: 54 e4 14 24 c4 52 04 74 54 f5 04 f4 c5 95 84 24 T..$.R.tT......$
+| 3616: 94 e4 15 25 91 a1 10 50 02 90 f1 94 54 e4 14 24 ...%...P....T..$
+| 3632: c4 52 04 74 54 f5 04 f4 c5 95 84 e4 f4 34 15 34 .R.tT........4.4
+| 3648: 51 91 00 50 02 90 f1 74 54 e4 14 24 c4 51 f4 74 Q..P...tT..$.Q.t
+| 3664: 54 f5 04 f4 c5 95 85 25 45 24 94 d1 70 f0 50 02 T......%E$..p.P.
+| 3680: 30 f1 94 54 e4 14 24 c5 20 46 54 53 35 58 42 49 0..T..$. FTS5XBI
+| 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL
+| 3712: 45 20 46 54 53 35 58 4f 4f 43 41 53 45 16 0d 05 E FTS5XOOCASE...
+| 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X
+| 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB
+| 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 97 0b LE FTS4XBINARY..
+| 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34 ..#..ENABLE FTS4
+| 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN
+| 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM.
+| 3824: 09 05 00 3e 5f 19 45 4e 41 42 4c 45 20 44 42 53 ...>_.ENABLE DBS
+| 3840: 44 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e DAT VTABXBINARY.
+| 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
+| 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 4d e3 45 1d TAT VTABXNOCM.E.
+| 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
+| 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM..
+| 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR
+| 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO
+| 3952: 43 41 53 45 10 02 02 50 08 5f 17 44 45 42 55 47 CASE...P._.DEBUG
+| 3968: 58 52 54 52 49 4d 27 03 05 00 44 0f 19 43 4f 4d XRTRIM'...D..COM
+| 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0
+| 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY'
+| 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g
+| 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060
+| 4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 c9 17 43 9XNOCASE&...C..C
+| 4064: 4f 4d 50 49 4c 47 02 3d 67 63 63 2d 35 2e 34 2e OMPILG.=gcc-5.4.
+| 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM
+| page 6 offset 20480
+| 0: 0d 00 00 00 24 0e e0 00 0f f8 0f f0 0f e8 0f e0 ....$...........
+| 16: 0f d8 0f d0 0f c8 0f c0 0f b8 0f b0 0f a8 0f a0 ................
+| 32: 0f 98 0f 90 0f 88 0f 80 0f 78 0f 70 0f 68 0f 60 .........x.p.h.`
+| 48: 0f 58 0f 50 0f 48 0f 40 0f 38 00 00 00 00 00 00 .X.P.H.@.8......
+| 3808: 06 24 03 00 12 02 01 01 06 23 03 00 12 02 01 01 .$.......#......
+| 3824: 06 22 03 00 12 02 01 01 06 21 03 00 12 03 01 01 .........!......
+| 3840: 06 20 03 00 12 03 01 01 06 1f 03 00 12 03 01 01 . ..............
+| 3856: 06 1e 03 00 12 03 01 01 06 1d 03 00 12 03 01 01 ................
+| 3872: 06 1c 03 00 12 03 01 01 06 1b 03 00 12 02 01 01 ................
+| 3888: 06 1a 03 00 12 02 01 01 06 19 03 00 12 02 01 01 ................
+| 3904: 06 18 03 00 12 02 01 01 06 17 03 00 12 02 01 01 ................
+| 3920: 06 16 03 00 12 02 01 01 06 15 03 00 12 02 01 01 ................
+| 3936: 06 14 03 00 12 02 01 01 06 13 03 00 12 02 01 01 ................
+| 3952: 06 12 03 00 12 02 01 01 06 11 03 00 12 02 01 01 ................
+| 3968: 06 10 03 00 12 02 01 01 06 1f 03 00 12 02 01 01 ................
+| 3984: 06 0e 03 00 12 02 01 01 06 0d 03 00 12 02 01 01 ................
+| 4000: 06 0c 03 00 12 02 01 01 06 0b 03 00 12 02 01 01 ................
+| 4016: 06 0a 03 00 12 02 01 01 06 09 03 00 12 03 01 01 ................
+| 4032: 06 08 03 00 12 03 01 01 06 07 03 00 12 03 01 01 ................
+| 4048: 06 06 03 00 12 01 01 01 06 05 03 00 12 01 01 01 ................
+| 4064: 06 04 03 00 12 01 01 01 06 03 03 00 12 06 01 01 ................
+| 4080: 06 02 03 00 12 06 01 01 06 01 03 00 12 06 01 01 ................
+| page 7 offset 24576
+| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
+| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
+| page 8 offset 28672
+| 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+| 4048: 00 00 00 00 00 00 11 03 02 2b 69 6e 74 65 67 72 .........+integr
+| 4064: 69 74 79 2d 63 68 65 63 6b 09 00 00 00 00 00 00 ity-check.......
+| end crash-31c462b8b665d0.db
+}]} {}
+
+
+do_catchsql_test 69.2 {
+ SELECT * FROM t1 WHERE a MATCH 'fx*'
+} {1 {database disk image is malformed}}
sqlite3_fts5_may_be_corrupt 0
finish_test
diff --git a/ext/icu/sqliteicu.h b/ext/icu/sqliteicu.h
index 69b42f9821..24a4d623bd 100644
--- a/ext/icu/sqliteicu.h
+++ b/ext/icu/sqliteicu.h
@@ -24,4 +24,3 @@ int sqlite3IcuInit(sqlite3 *db);
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
-
diff --git a/ext/lsm1/lsm-test/lsmtest1.c b/ext/lsm1/lsm-test/lsmtest1.c
index dcbc718424..1ce2cc0588 100644
--- a/ext/lsm1/lsm-test/lsmtest1.c
+++ b/ext/lsm1/lsm-test/lsmtest1.c
@@ -654,5 +654,3 @@ void test_data_3(
testFree(zName);
}
}
-
-
diff --git a/ext/lsm1/lsm-test/lsmtest8.c b/ext/lsm1/lsm-test/lsmtest8.c
index f734ac6aba..7efa0dfa6c 100644
--- a/ext/lsm1/lsm-test/lsmtest8.c
+++ b/ext/lsm1/lsm-test/lsmtest8.c
@@ -322,5 +322,3 @@ void do_writer_crash_test(const char *zPattern, int *pRc){
}
}
-
-
diff --git a/ext/lsm1/lsm-test/lsmtest9.c b/ext/lsm1/lsm-test/lsmtest9.c
index 144cae7203..b01de0d4e5 100644
--- a/ext/lsm1/lsm-test/lsmtest9.c
+++ b/ext/lsm1/lsm-test/lsmtest9.c
@@ -138,6 +138,3 @@ void test_data_4(
testFree(zName);
}
}
-
-
-
diff --git a/ext/lsm1/lsm-test/lsmtest_bt.c b/ext/lsm1/lsm-test/lsmtest_bt.c
index 5135dd0559..8a4f54a8cd 100644
--- a/ext/lsm1/lsm-test/lsmtest_bt.c
+++ b/ext/lsm1/lsm-test/lsmtest_bt.c
@@ -69,7 +69,3 @@ int do_bt(int nArg, char **azArg){
sqlite4_buffer_clear(&buf.output);
return 0;
}
-
-
-
-
diff --git a/ext/lsm1/lsm-test/lsmtest_tdb.c b/ext/lsm1/lsm-test/lsmtest_tdb.c
index 9c4f9df8a4..8f63f64acb 100644
--- a/ext/lsm1/lsm-test/lsmtest_tdb.c
+++ b/ext/lsm1/lsm-test/lsmtest_tdb.c
@@ -553,7 +553,7 @@ static int sql_begin(TestDb *pTestDb, int iLevel){
/* If there are no transactions at all open, open a read transaction. */
if( pDb->nOpenTrans==0 ){
int rc = sqlite3_exec(pDb->db,
- "BEGIN; SELECT * FROM sqlite_master LIMIT 1;" , 0, 0, 0
+ "BEGIN; SELECT * FROM sqlite_schema LIMIT 1;" , 0, 0, 0
);
if( rc!=0 ) return rc;
pDb->nOpenTrans = 1;
diff --git a/ext/lsm1/lsm-test/lsmtest_tdb2.cc b/ext/lsm1/lsm-test/lsmtest_tdb2.cc
index 307c2b5f07..86ebb49583 100644
--- a/ext/lsm1/lsm-test/lsmtest_tdb2.cc
+++ b/ext/lsm1/lsm-test/lsmtest_tdb2.cc
@@ -367,4 +367,3 @@ int test_mdb_scan(
}
#endif /* HAVE_MDB */
-
diff --git a/ext/lsm1/lsm-test/lsmtest_tdb4.c b/ext/lsm1/lsm-test/lsmtest_tdb4.c
index c45b0529ab..1f92928522 100644
--- a/ext/lsm1/lsm-test/lsmtest_tdb4.c
+++ b/ext/lsm1/lsm-test/lsmtest_tdb4.c
@@ -978,5 +978,3 @@ static int bgc_detach(BtDb *pDb){
/*
** End of background checkpointer.
*************************************************************************/
-
-
diff --git a/ext/lsm1/lsm_unix.c b/ext/lsm1/lsm_unix.c
index 22240771ea..88952d15fc 100644
--- a/ext/lsm1/lsm_unix.c
+++ b/ext/lsm1/lsm_unix.c
@@ -228,6 +228,10 @@ static int lsmPosixOsRemap(
}
p->pMap = mmap(0, iSz, PROT_READ|PROT_WRITE, MAP_SHARED, p->fd, 0);
+ if( p->pMap==MAP_FAILED ){
+ p->pMap = 0;
+ return LSM_IOERR_BKPT;
+ }
p->nMap = iSz;
}
@@ -413,7 +417,10 @@ static int lsmPosixOsShmMap(lsm_file *pFile, int iChunk, int sz, void **ppShm){
p->apShm[iChunk] = mmap(0, LSM_SHM_CHUNK_SIZE,
PROT_READ|PROT_WRITE, MAP_SHARED, p->shmfd, iChunk*LSM_SHM_CHUNK_SIZE
);
- if( p->apShm[iChunk]==0 ) return LSM_IOERR_BKPT;
+ if( p->apShm[iChunk]==MAP_FAILED ){
+ p->apShm[iChunk] = 0;
+ return LSM_IOERR_BKPT;
+ }
}
*ppShm = p->apShm[iChunk];
diff --git a/ext/misc/appendvfs.c b/ext/misc/appendvfs.c
index b224245f3d..14260efb52 100644
--- a/ext/misc/appendvfs.c
+++ b/ext/misc/appendvfs.c
@@ -439,7 +439,7 @@ static int apndOpen(
p = (ApndFile*)pFile;
memset(p, 0, sizeof(*p));
pSubFile = ORIGFILE(pFile);
- p->base.pMethods = &apnd_io_methods;
+ pFile->pMethods = &apnd_io_methods;
rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags);
if( rc ) goto apnd_open_done;
rc = pSubFile->pMethods->xFileSize(pSubFile, &sz);
diff --git a/ext/misc/btreeinfo.c b/ext/misc/btreeinfo.c
index 0624fc1771..22f8268139 100644
--- a/ext/misc/btreeinfo.c
+++ b/ext/misc/btreeinfo.c
@@ -21,7 +21,7 @@
** name TEXT, -- Name of table or index for this btree.
** tbl_name TEXT, -- Associated table
** rootpage INT, -- The root page of the btree
-** sql TEXT, -- SQL for this btree - from sqlite_master
+** sql TEXT, -- SQL for this btree - from sqlite_schema
** hasRowid BOOLEAN, -- True if the btree has a rowid
** nEntry INT, -- Estimated number of entries
** nPage INT, -- Estimated number of pages
@@ -30,9 +30,9 @@
** zSchema TEXT HIDDEN -- The schema to which this btree belongs
** );
**
-** The first 5 fields are taken directly from the sqlite_master table.
+** The first 5 fields are taken directly from the sqlite_schema table.
** Considering only the first 5 fields, the only difference between
-** this virtual table and the sqlite_master table is that this virtual
+** this virtual table and the sqlite_schema table is that this virtual
** table omits all entries that have a 0 or NULL rowid - in other words
** it omits triggers and views.
**
@@ -88,7 +88,7 @@ typedef struct BinfoCursor BinfoCursor;
/* A cursor for the sqlite_btreeinfo table */
struct BinfoCursor {
sqlite3_vtab_cursor base; /* Base class. Must be first */
- sqlite3_stmt *pStmt; /* Query against sqlite_master */
+ sqlite3_stmt *pStmt; /* Query against sqlite_schema */
int rc; /* Result of previous sqlite_step() call */
int hasRowid; /* hasRowid value. Negative if unknown. */
sqlite3_int64 nEntry; /* nEntry value */
@@ -242,10 +242,10 @@ static int binfoFilter(
pCsr->zSchema = sqlite3_mprintf("main");
}
zSql = sqlite3_mprintf(
- "SELECT 0, 'table','sqlite_master','sqlite_master',1,NULL "
+ "SELECT 0, 'table','sqlite_schema','sqlite_schema',1,NULL "
"UNION ALL "
"SELECT rowid, type, name, tbl_name, rootpage, sql"
- " FROM \"%w\".sqlite_master WHERE rootpage>=1",
+ " FROM \"%w\".sqlite_schema WHERE rootpage>=1",
pCsr->zSchema);
sqlite3_finalize(pCsr->pStmt);
pCsr->pStmt = 0;
diff --git a/ext/misc/cksumvfs.c b/ext/misc/cksumvfs.c
index 2cc8148b2e..64cd37f251 100644
--- a/ext/misc/cksumvfs.c
+++ b/ext/misc/cksumvfs.c
@@ -634,7 +634,7 @@ static int cksmOpen(
p = (CksmFile*)pFile;
memset(p, 0, sizeof(*p));
pSubFile = ORIGFILE(pFile);
- p->base.pMethods = &cksm_io_methods;
+ pFile->pMethods = &cksm_io_methods;
rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags);
if( rc ) goto cksm_open_done;
if( flags & SQLITE_OPEN_WAL ){
@@ -743,7 +743,7 @@ static int cksmRegisterFunc(
static int cksmRegisterVfs(void){
int rc = SQLITE_OK;
sqlite3_vfs *pOrig;
- if( sqlite3_vfs_find("cksum")!=0 ) return SQLITE_OK;
+ if( sqlite3_vfs_find("cksmvfs")!=0 ) return SQLITE_OK;
pOrig = sqlite3_vfs_find(0);
cksm_vfs.iVersion = pOrig->iVersion;
cksm_vfs.pAppData = pOrig;
diff --git a/ext/misc/completion.c b/ext/misc/completion.c
index b624b6d476..d9e7b85972 100644
--- a/ext/misc/completion.c
+++ b/ext/misc/completion.c
@@ -226,7 +226,7 @@ static int completionNext(sqlite3_vtab_cursor *cur){
const char *zDb = (const char*)sqlite3_column_text(pS2, 1);
zSql = sqlite3_mprintf(
"%z%s"
- "SELECT name FROM \"%w\".sqlite_master",
+ "SELECT name FROM \"%w\".sqlite_schema",
zSql, zSep, zDb
);
if( zSql==0 ) return SQLITE_NOMEM;
@@ -250,7 +250,7 @@ static int completionNext(sqlite3_vtab_cursor *cur){
const char *zDb = (const char*)sqlite3_column_text(pS2, 1);
zSql = sqlite3_mprintf(
"%z%s"
- "SELECT pti.name FROM \"%w\".sqlite_master AS sm"
+ "SELECT pti.name FROM \"%w\".sqlite_schema AS sm"
" JOIN pragma_table_info(sm.name,%Q) AS pti"
" WHERE sm.type='table'",
zSql, zSep, zDb, zDb
diff --git a/ext/misc/dbdump.c b/ext/misc/dbdump.c
index 157e646bbc..ecf7d810d5 100644
--- a/ext/misc/dbdump.c
+++ b/ext/misc/dbdump.c
@@ -395,7 +395,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
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);
+ p->xCallback("ANALYZE sqlite_schema;\n", p->pArg);
}else if( strncmp(zTable, "sqlite_", 7)==0 ){
return 0;
}else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
@@ -404,7 +404,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
p->writableSchema = 1;
}
output_formatted(p,
- "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
+ "INSERT INTO sqlite_schema(type,name,tbl_name,rootpage,sql)"
"VALUES('table','%q','%q',0,'%q');",
zTable, zTable, zSql);
return 0;
@@ -646,27 +646,27 @@ int sqlite3_db_dump(
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 "
+ "SELECT name, type, sql FROM \"%w\".sqlite_schema "
"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 "
+ "SELECT name, type, sql FROM \"%w\".sqlite_schema "
"WHERE name=='sqlite_sequence'", zSchema
);
output_sql_from_query(&x,
- "SELECT sql FROM sqlite_master "
+ "SELECT sql FROM sqlite_schema "
"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 "
+ "SELECT name, type, sql FROM \"%w\".sqlite_schema "
"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 "
+ "SELECT sql FROM \"%w\".sqlite_schema "
"WHERE sql NOT NULL"
" AND type IN ('index','trigger','view')"
" AND tbl_name=%Q COLLATE nocase",
diff --git a/ext/misc/decimal.c b/ext/misc/decimal.c
new file mode 100644
index 0000000000..a8d68ac72f
--- /dev/null
+++ b/ext/misc/decimal.c
@@ -0,0 +1,634 @@
+/*
+** 2020-06-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.
+**
+******************************************************************************
+**
+** Routines to implement arbitrary-precision decimal math.
+**
+** The focus here is on simplicity and correctness, not performance.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include
+#include
+#include
+#include
+
+/* Mark a function parameter as unused, to suppress nuisance compiler
+** warnings. */
+#ifndef UNUSED_PARAMETER
+# define UNUSED_PARAMETER(X) (void)(X)
+#endif
+
+
+/* A decimal object */
+typedef struct Decimal Decimal;
+struct Decimal {
+ char sign; /* 0 for positive, 1 for negative */
+ char oom; /* True if an OOM is encountered */
+ char isNull; /* True if holds a NULL rather than a number */
+ char isInit; /* True upon initialization */
+ int nDigit; /* Total number of digits */
+ int nFrac; /* Number of digits to the right of the decimal point */
+ signed char *a; /* Array of digits. Most significant first. */
+};
+
+/*
+** Release memory held by a Decimal, but do not free the object itself.
+*/
+static void decimal_clear(Decimal *p){
+ sqlite3_free(p->a);
+}
+
+/*
+** Destroy a Decimal object
+*/
+static void decimal_free(Decimal *p){
+ if( p ){
+ decimal_clear(p);
+ sqlite3_free(p);
+ }
+}
+
+/*
+** Allocate a new Decimal object. Initialize it to the number given
+** by the input string.
+*/
+static Decimal *decimal_new(
+ sqlite3_context *pCtx,
+ sqlite3_value *pIn,
+ int nAlt,
+ const unsigned char *zAlt
+){
+ Decimal *p;
+ int n, i;
+ const unsigned char *zIn;
+ int iExp = 0;
+ p = sqlite3_malloc( sizeof(*p) );
+ if( p==0 ) goto new_no_mem;
+ p->sign = 0;
+ p->oom = 0;
+ p->isInit = 1;
+ p->isNull = 0;
+ p->nDigit = 0;
+ p->nFrac = 0;
+ if( zAlt ){
+ n = nAlt,
+ zIn = zAlt;
+ }else{
+ if( sqlite3_value_type(pIn)==SQLITE_NULL ){
+ p->a = 0;
+ p->isNull = 1;
+ return p;
+ }
+ n = sqlite3_value_bytes(pIn);
+ zIn = sqlite3_value_text(pIn);
+ }
+ p->a = sqlite3_malloc64( n+1 );
+ if( p->a==0 ) goto new_no_mem;
+ for(i=0; isspace(zIn[i]); i++){}
+ if( zIn[i]=='-' ){
+ p->sign = 1;
+ i++;
+ }else if( zIn[i]=='+' ){
+ i++;
+ }
+ while( i='0' && c<='9' ){
+ p->a[p->nDigit++] = c - '0';
+ }else if( c=='.' ){
+ p->nFrac = p->nDigit + 1;
+ }else if( c=='e' || c=='E' ){
+ int j = i+1;
+ int neg = 0;
+ if( j>=n ) break;
+ if( zIn[j]=='-' ){
+ neg = 1;
+ j++;
+ }else if( zIn[j]=='+' ){
+ j++;
+ }
+ while( j='0' && zIn[j]<='9' ){
+ iExp = iExp*10 + zIn[j] - '0';
+ }
+ j++;
+ }
+ if( neg ) iExp = -iExp;
+ break;
+ }
+ i++;
+ }
+ if( p->nFrac ){
+ p->nFrac = p->nDigit - (p->nFrac - 1);
+ }
+ if( iExp>0 ){
+ if( p->nFrac>0 ){
+ if( iExp<=p->nFrac ){
+ p->nFrac -= iExp;
+ iExp = 0;
+ }else{
+ iExp -= p->nFrac;
+ p->nFrac = 0;
+ }
+ }
+ if( iExp>0 ){
+ p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 );
+ if( p->a==0 ) goto new_no_mem;
+ memset(p->a+p->nDigit, 0, iExp);
+ p->nDigit += iExp;
+ }
+ }else if( iExp<0 ){
+ int nExtra;
+ iExp = -iExp;
+ nExtra = p->nDigit - p->nFrac - 1;
+ if( nExtra ){
+ if( nExtra>=iExp ){
+ p->nFrac += iExp;
+ iExp = 0;
+ }else{
+ iExp -= nExtra;
+ p->nFrac = p->nDigit - 1;
+ }
+ }
+ if( iExp>0 ){
+ p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 );
+ if( p->a==0 ) goto new_no_mem;
+ memmove(p->a+iExp, p->a, p->nDigit);
+ memset(p->a, 0, iExp);
+ p->nDigit += iExp;
+ p->nFrac += iExp;
+ }
+ }
+ return p;
+
+new_no_mem:
+ if( pCtx ) sqlite3_result_error_nomem(pCtx);
+ sqlite3_free(p);
+ return 0;
+}
+
+/*
+** Make the given Decimal the result.
+*/
+static void decimal_result(sqlite3_context *pCtx, Decimal *p){
+ char *z;
+ int i, j;
+ int n;
+ if( p==0 || p->oom ){
+ sqlite3_result_error_nomem(pCtx);
+ return;
+ }
+ if( p->isNull ){
+ sqlite3_result_null(pCtx);
+ return;
+ }
+ z = sqlite3_malloc( p->nDigit+4 );
+ if( z==0 ){
+ sqlite3_result_error_nomem(pCtx);
+ return;
+ }
+ i = 0;
+ if( p->nDigit==0 || (p->nDigit==1 && p->a[0]==0) ){
+ p->sign = 0;
+ }
+ if( p->sign ){
+ z[0] = '-';
+ i = 1;
+ }
+ n = p->nDigit - p->nFrac;
+ if( n<=0 ){
+ z[i++] = '0';
+ }
+ j = 0;
+ while( n>1 && p->a[j]==0 ){
+ j++;
+ n--;
+ }
+ while( n>0 ){
+ z[i++] = p->a[j] + '0';
+ j++;
+ n--;
+ }
+ if( p->nFrac ){
+ z[i++] = '.';
+ do{
+ z[i++] = p->a[j] + '0';
+ j++;
+ }while( jnDigit );
+ }
+ z[i] = 0;
+ sqlite3_result_text(pCtx, z, i, sqlite3_free);
+}
+
+/*
+** SQL Function: decimal(X)
+**
+** Convert input X into decimal and then back into text
+*/
+static void decimalFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ Decimal *p = decimal_new(context, argv[0], 0, 0);
+ UNUSED_PARAMETER(argc);
+ decimal_result(context, p);
+ decimal_free(p);
+}
+
+/*
+** Compare to Decimal objects. Return negative, 0, or positive if the
+** first object is less than, equal to, or greater than the second.
+**
+** Preconditions for this routine:
+**
+** pA!=0
+** pA->isNull==0
+** pB!=0
+** pB->isNull==0
+*/
+static int decimal_cmp(const Decimal *pA, const Decimal *pB){
+ int nASig, nBSig, rc, n;
+ if( pA->sign!=pB->sign ){
+ return pA->sign ? -1 : +1;
+ }
+ if( pA->sign ){
+ const Decimal *pTemp = pA;
+ pA = pB;
+ pB = pTemp;
+ }
+ nASig = pA->nDigit - pA->nFrac;
+ nBSig = pB->nDigit - pB->nFrac;
+ if( nASig!=nBSig ){
+ return nASig - nBSig;
+ }
+ n = pA->nDigit;
+ if( n>pB->nDigit ) n = pB->nDigit;
+ rc = memcmp(pA->a, pB->a, n);
+ if( rc==0 ){
+ rc = pA->nDigit - pB->nDigit;
+ }
+ return rc;
+}
+
+/*
+** SQL Function: decimal_cmp(X, Y)
+**
+** Return negative, zero, or positive if X is less then, equal to, or
+** greater than Y.
+*/
+static void decimalCmpFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ Decimal *pA = 0, *pB = 0;
+ int rc;
+
+ UNUSED_PARAMETER(argc);
+ pA = decimal_new(context, argv[0], 0, 0);
+ if( pA==0 || pA->isNull ) goto cmp_done;
+ pB = decimal_new(context, argv[1], 0, 0);
+ if( pB==0 || pB->isNull ) goto cmp_done;
+ rc = decimal_cmp(pA, pB);
+ if( rc<0 ) rc = -1;
+ else if( rc>0 ) rc = +1;
+ sqlite3_result_int(context, rc);
+cmp_done:
+ decimal_free(pA);
+ decimal_free(pB);
+}
+
+/*
+** Expand the Decimal so that it has a least nDigit digits and nFrac
+** digits to the right of the decimal point.
+*/
+static void decimal_expand(Decimal *p, int nDigit, int nFrac){
+ int nAddSig;
+ int nAddFrac;
+ if( p==0 ) return;
+ nAddFrac = nFrac - p->nFrac;
+ nAddSig = (nDigit - p->nDigit) - nAddFrac;
+ if( nAddFrac==0 && nAddSig==0 ) return;
+ p->a = sqlite3_realloc64(p->a, nDigit+1);
+ if( p->a==0 ){
+ p->oom = 1;
+ return;
+ }
+ if( nAddSig ){
+ memmove(p->a+nAddSig, p->a, p->nDigit);
+ memset(p->a, 0, nAddSig);
+ p->nDigit += nAddSig;
+ }
+ if( nAddFrac ){
+ memset(p->a+p->nDigit, 0, nAddFrac);
+ p->nDigit += nAddFrac;
+ p->nFrac += nAddFrac;
+ }
+}
+
+/*
+** Add the value pB into pA.
+**
+** Both pA and pB might become denormalized by this routine.
+*/
+static void decimal_add(Decimal *pA, Decimal *pB){
+ int nSig, nFrac, nDigit;
+ int i, rc;
+ if( pA==0 ){
+ return;
+ }
+ if( pA->oom || pB==0 || pB->oom ){
+ pA->oom = 1;
+ return;
+ }
+ if( pA->isNull || pB->isNull ){
+ pA->isNull = 1;
+ return;
+ }
+ nSig = pA->nDigit - pA->nFrac;
+ if( nSig && pA->a[0]==0 ) nSig--;
+ if( nSignDigit-pB->nFrac ){
+ nSig = pB->nDigit - pB->nFrac;
+ }
+ nFrac = pA->nFrac;
+ if( nFracnFrac ) nFrac = pB->nFrac;
+ nDigit = nSig + nFrac + 1;
+ decimal_expand(pA, nDigit, nFrac);
+ decimal_expand(pB, nDigit, nFrac);
+ if( pA->oom || pB->oom ){
+ pA->oom = 1;
+ }else{
+ if( pA->sign==pB->sign ){
+ int carry = 0;
+ for(i=nDigit-1; i>=0; i--){
+ int x = pA->a[i] + pB->a[i] + carry;
+ if( x>=10 ){
+ carry = 1;
+ pA->a[i] = x - 10;
+ }else{
+ carry = 0;
+ pA->a[i] = x;
+ }
+ }
+ }else{
+ signed char *aA, *aB;
+ int borrow = 0;
+ rc = memcmp(pA->a, pB->a, nDigit);
+ if( rc<0 ){
+ aA = pB->a;
+ aB = pA->a;
+ pA->sign = !pA->sign;
+ }else{
+ aA = pA->a;
+ aB = pB->a;
+ }
+ for(i=nDigit-1; i>=0; i--){
+ int x = aA[i] - aB[i] - borrow;
+ if( x<0 ){
+ pA->a[i] = x+10;
+ borrow = 1;
+ }else{
+ pA->a[i] = x;
+ borrow = 0;
+ }
+ }
+ }
+ }
+}
+
+/*
+** Compare text in decimal order.
+*/
+static int decimalCollFunc(
+ void *notUsed,
+ int nKey1, const void *pKey1,
+ int nKey2, const void *pKey2
+){
+ const unsigned char *zA = (const unsigned char*)pKey1;
+ const unsigned char *zB = (const unsigned char*)pKey2;
+ Decimal *pA = decimal_new(0, 0, nKey1, zA);
+ Decimal *pB = decimal_new(0, 0, nKey2, zB);
+ int rc;
+ UNUSED_PARAMETER(notUsed);
+ if( pA==0 || pB==0 ){
+ rc = 0;
+ }else{
+ rc = decimal_cmp(pA, pB);
+ }
+ decimal_free(pA);
+ decimal_free(pB);
+ return rc;
+}
+
+
+/*
+** SQL Function: decimal_add(X, Y)
+** decimal_sub(X, Y)
+**
+** Return the sum or difference of X and Y.
+*/
+static void decimalAddFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ Decimal *pA = decimal_new(context, argv[0], 0, 0);
+ Decimal *pB = decimal_new(context, argv[1], 0, 0);
+ UNUSED_PARAMETER(argc);
+ decimal_add(pA, pB);
+ decimal_result(context, pA);
+ decimal_free(pA);
+ decimal_free(pB);
+}
+static void decimalSubFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ Decimal *pA = decimal_new(context, argv[0], 0, 0);
+ Decimal *pB = decimal_new(context, argv[1], 0, 0);
+ UNUSED_PARAMETER(argc);
+ if( pB==0 ) return;
+ pB->sign = !pB->sign;
+ decimal_add(pA, pB);
+ decimal_result(context, pA);
+ decimal_free(pA);
+ decimal_free(pB);
+}
+
+/* Aggregate funcion: decimal_sum(X)
+**
+** Works like sum() except that it uses decimal arithmetic for unlimited
+** precision.
+*/
+static void decimalSumStep(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ Decimal *p;
+ Decimal *pArg;
+ UNUSED_PARAMETER(argc);
+ p = sqlite3_aggregate_context(context, sizeof(*p));
+ if( p==0 ) return;
+ if( !p->isInit ){
+ p->isInit = 1;
+ p->a = sqlite3_malloc(2);
+ if( p->a==0 ){
+ p->oom = 1;
+ }else{
+ p->a[0] = 0;
+ }
+ p->nDigit = 1;
+ p->nFrac = 0;
+ }
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
+ pArg = decimal_new(context, argv[0], 0, 0);
+ decimal_add(p, pArg);
+ decimal_free(pArg);
+}
+static void decimalSumInverse(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ Decimal *p;
+ Decimal *pArg;
+ UNUSED_PARAMETER(argc);
+ p = sqlite3_aggregate_context(context, sizeof(*p));
+ if( p==0 ) return;
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
+ pArg = decimal_new(context, argv[0], 0, 0);
+ if( pArg ) pArg->sign = !pArg->sign;
+ decimal_add(p, pArg);
+ decimal_free(pArg);
+}
+static void decimalSumValue(sqlite3_context *context){
+ Decimal *p = sqlite3_aggregate_context(context, 0);
+ if( p==0 ) return;
+ decimal_result(context, p);
+}
+static void decimalSumFinalize(sqlite3_context *context){
+ Decimal *p = sqlite3_aggregate_context(context, 0);
+ if( p==0 ) return;
+ decimal_result(context, p);
+ decimal_clear(p);
+}
+
+/*
+** SQL Function: decimal_mul(X, Y)
+**
+** Return the product of X and Y.
+**
+** All significant digits after the decimal point are retained.
+** Trailing zeros after the decimal point are omitted as long as
+** the number of digits after the decimal point is no less than
+** either the number of digits in either input.
+*/
+static void decimalMulFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ Decimal *pA = decimal_new(context, argv[0], 0, 0);
+ Decimal *pB = decimal_new(context, argv[1], 0, 0);
+ signed char *acc = 0;
+ int i, j, k;
+ int minFrac;
+ UNUSED_PARAMETER(argc);
+ if( pA==0 || pA->oom || pA->isNull
+ || pB==0 || pB->oom || pB->isNull
+ ){
+ goto mul_end;
+ }
+ acc = sqlite3_malloc64( pA->nDigit + pB->nDigit + 2 );
+ if( acc==0 ){
+ sqlite3_result_error_nomem(context);
+ goto mul_end;
+ }
+ memset(acc, 0, pA->nDigit + pB->nDigit + 2);
+ minFrac = pA->nFrac;
+ if( pB->nFracnFrac;
+ for(i=pA->nDigit-1; i>=0; i--){
+ signed char f = pA->a[i];
+ int carry = 0, x;
+ for(j=pB->nDigit-1, k=i+j+3; j>=0; j--, k--){
+ x = acc[k] + f*pB->a[j] + carry;
+ acc[k] = x%10;
+ carry = x/10;
+ }
+ x = acc[k] + carry;
+ acc[k] = x%10;
+ acc[k-1] += x/10;
+ }
+ sqlite3_free(pA->a);
+ pA->a = acc;
+ acc = 0;
+ pA->nDigit += pB->nDigit + 2;
+ pA->nFrac += pB->nFrac;
+ pA->sign ^= pB->sign;
+ while( pA->nFrac>minFrac && pA->a[pA->nDigit-1]==0 ){
+ pA->nFrac--;
+ pA->nDigit--;
+ }
+ decimal_result(context, pA);
+
+mul_end:
+ sqlite3_free(acc);
+ decimal_free(pA);
+ decimal_free(pB);
+}
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_decimal_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ static const struct {
+ const char *zFuncName;
+ int nArg;
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
+ } aFunc[] = {
+ { "decimal", 1, decimalFunc },
+ { "decimal_cmp", 2, decimalCmpFunc },
+ { "decimal_add", 2, decimalAddFunc },
+ { "decimal_sub", 2, decimalSubFunc },
+ { "decimal_mul", 2, decimalMulFunc },
+ };
+ unsigned int i;
+ (void)pzErrMsg; /* Unused parameter */
+
+ SQLITE_EXTENSION_INIT2(pApi);
+
+ for(i=0; i 'ieee754(2,0)'
-** ieee754(45.25) -> 'ieee754(181,-2)'
-** ieee754(2, 0) -> 2.0
-** ieee754(181, -2) -> 45.25
+** ieee754(2.0) -> 'ieee754(2,0)'
+** ieee754(45.25) -> 'ieee754(181,-2)'
+** ieee754(2, 0) -> 2.0
+** ieee754(181, -2) -> 45.25
+**
+** Two additional functions break apart the one-argument ieee754()
+** result into separate integer values:
+**
+** ieee754_mantissa(45.25) -> 181
+** ieee754_exponent(45.25) -> -2
+**
+** These functions convert binary64 numbers into blobs and back again.
+**
+** ieee754_from_blob(x'3ff0000000000000') -> 1.0
+** ieee754_to_blob(1.0) -> x'3ff0000000000000'
+**
+** In all single-argument functions, if the argument is an 8-byte blob
+** then that blob is interpreted as a big-endian binary64 value.
+**
+**
+** EXACT DECIMAL REPRESENTATION OF BINARY64 VALUES
+** -----------------------------------------------
+**
+** This extension in combination with the separate 'decimal' extension
+** can be used to compute the exact decimal representation of binary64
+** values. To begin, first compute a table of exponent values:
+**
+** CREATE TABLE pow2(x INTEGER PRIMARY KEY, v TEXT);
+** WITH RECURSIVE c(x,v) AS (
+** VALUES(0,'1')
+** UNION ALL
+** SELECT x+1, decimal_mul(v,'2') FROM c WHERE x+1<=971
+** ) INSERT INTO pow2(x,v) SELECT x, v FROM c;
+** WITH RECURSIVE c(x,v) AS (
+** VALUES(-1,'0.5')
+** UNION ALL
+** SELECT x-1, decimal_mul(v,'0.5') FROM c WHERE x-1>=-1075
+** ) INSERT INTO pow2(x,v) SELECT x, v FROM c;
+**
+** Then, to compute the exact decimal representation of a floating
+** point value (the value 47.49 is used in the example) do:
+**
+** WITH c(n) AS (VALUES(47.49))
+** ---------------^^^^^---- Replace with whatever you want
+** SELECT decimal_mul(ieee754_mantissa(c.n),pow2.v)
+** FROM pow2, c WHERE pow2.x=ieee754_exponent(c.n);
+**
+** Here is a query to show various boundry values for the binary64
+** number format:
+**
+** WITH c(name,bin) AS (VALUES
+** ('minimum positive value', x'0000000000000001'),
+** ('maximum subnormal value', x'000fffffffffffff'),
+** ('mininum positive nornal value', x'0010000000000000'),
+** ('maximum value', x'7fefffffffffffff'))
+** SELECT c.name, decimal_mul(ieee754_mantissa(c.bin),pow2.v)
+** FROM pow2, c WHERE pow2.x=ieee754_exponent(c.bin);
+**
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include
#include
+/* Mark a function parameter as unused, to suppress nuisance compiler
+** warnings. */
+#ifndef UNUSED_PARAMETER
+# define UNUSED_PARAMETER(X) (void)(X)
+#endif
+
/*
** Implementation of the ieee754() function
*/
@@ -51,8 +111,19 @@ static void ieee754func(
int isNeg;
char zResult[100];
assert( sizeof(m)==sizeof(r) );
- if( sqlite3_value_type(argv[0])!=SQLITE_FLOAT ) return;
- r = sqlite3_value_double(argv[0]);
+ if( sqlite3_value_type(argv[0])==SQLITE_BLOB
+ && sqlite3_value_bytes(argv[0])==sizeof(r)
+ ){
+ const unsigned char *x = sqlite3_value_blob(argv[0]);
+ unsigned int i;
+ sqlite3_uint64 v = 0;
+ for(i=0; i>52;
m = a & ((((sqlite3_int64)1)<<52)-1);
- m |= ((sqlite3_int64)1)<<52;
+ if( e==0 ){
+ m <<= 1;
+ }else{
+ m |= ((sqlite3_int64)1)<<52;
+ }
while( e<1075 && m>0 && (m&1)==0 ){
m >>= 1;
e++;
}
if( isNeg ) m = -m;
}
- sqlite3_snprintf(sizeof(zResult), zResult, "ieee754(%lld,%d)",
- m, e-1075);
- sqlite3_result_text(context, zResult, -1, SQLITE_TRANSIENT);
- }else if( argc==2 ){
+ switch( *(int*)sqlite3_user_data(context) ){
+ case 0:
+ sqlite3_snprintf(sizeof(zResult), zResult, "ieee754(%lld,%d)",
+ m, e-1075);
+ sqlite3_result_text(context, zResult, -1, SQLITE_TRANSIENT);
+ break;
+ case 1:
+ sqlite3_result_int64(context, m);
+ break;
+ case 2:
+ sqlite3_result_int(context, e-1075);
+ break;
+ }
+ }else{
sqlite3_int64 m, e, a;
double r;
int isNeg = 0;
@@ -86,7 +171,7 @@ static void ieee754func(
isNeg = 1;
m = -m;
if( m<0 ) return;
- }else if( m==0 && e>1000 && e<1000 ){
+ }else if( m==0 && e>-1000 && e<1000 ){
sqlite3_result_double(context, 0.0);
return;
}
@@ -99,8 +184,13 @@ static void ieee754func(
e--;
}
e += 1075;
- if( e<0 ) e = m = 0;
- if( e>0x7ff ) e = 0x7ff;
+ if( e<=0 ){
+ /* Subnormal */
+ m >>= 1-e;
+ e = 0;
+ }else if( e>0x7ff ){
+ e = 0x7ff;
+ }
a = m & ((((sqlite3_int64)1)<<52)-1);
a |= e<<52;
if( isNeg ) a |= ((sqlite3_uint64)1)<<63;
@@ -109,6 +199,51 @@ static void ieee754func(
}
}
+/*
+** Functions to convert between blobs and floats.
+*/
+static void ieee754func_from_blob(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ UNUSED_PARAMETER(argc);
+ if( sqlite3_value_type(argv[0])==SQLITE_BLOB
+ && sqlite3_value_bytes(argv[0])==sizeof(double)
+ ){
+ double r;
+ const unsigned char *x = sqlite3_value_blob(argv[0]);
+ unsigned int i;
+ sqlite3_uint64 v = 0;
+ for(i=0; i>= 8;
+ }
+ sqlite3_result_blob(context, a, sizeof(r), SQLITE_TRANSIENT);
+ }
+}
+
#ifdef _WIN32
__declspec(dllexport)
@@ -118,16 +253,29 @@ int sqlite3_ieee_init(
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
+ static const struct {
+ char *zFName;
+ int nArg;
+ int iAux;
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
+ } aFunc[] = {
+ { "ieee754", 1, 0, ieee754func },
+ { "ieee754", 2, 0, ieee754func },
+ { "ieee754_mantissa", 1, 1, ieee754func },
+ { "ieee754_exponent", 1, 2, ieee754func },
+ { "ieee754_to_blob", 1, 0, ieee754func_to_blob },
+ { "ieee754_from_blob", 1, 0, ieee754func_from_blob },
+
+ };
+ unsigned int i;
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
- rc = sqlite3_create_function(db, "ieee754", 1,
- SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
- ieee754func, 0, 0);
- if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(db, "ieee754", 2,
- SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
- ieee754func, 0, 0);
+ for(i=0; iu.zJContent, pNode->n);
break;
}
- /* Fall through into the next case */
+ /* no break */ deliberate_fall_through
}
case JSON_REAL:
case JSON_INT: {
@@ -601,7 +605,7 @@ static void jsonReturn(
sqlite3_result_int64(pCtx, i);
int_done:
break;
- int_as_real: /* fall through to real */;
+ int_as_real: i=0; /* no break */ deliberate_fall_through
}
case JSON_REAL: {
double r;
@@ -2304,6 +2308,7 @@ static int jsonEachColumn(
}
/* For json_each() path and root are the same so fall through
** into the root case */
+ /* no break */ deliberate_fall_through
}
default: {
const char *zRoot = p->zRoot;
diff --git a/ext/misc/mmapwarm.c b/ext/misc/mmapwarm.c
index 970a873f56..5afa47bf7a 100644
--- a/ext/misc/mmapwarm.c
+++ b/ext/misc/mmapwarm.c
@@ -43,7 +43,7 @@ int sqlite3_mmap_warm(sqlite3 *db, const char *zDb){
if( 0==sqlite3_get_autocommit(db) ) return SQLITE_MISUSE;
/* Open a read-only transaction on the file in question */
- zSql = sqlite3_mprintf("BEGIN; SELECT * FROM %s%q%ssqlite_master",
+ zSql = sqlite3_mprintf("BEGIN; SELECT * FROM %s%q%ssqlite_schema",
(zDb ? "'" : ""), (zDb ? zDb : ""), (zDb ? "'." : "")
);
if( zSql==0 ) return SQLITE_NOMEM;
diff --git a/ext/misc/normalize.c b/ext/misc/normalize.c
index 5997ec12e2..08d7733b96 100644
--- a/ext/misc/normalize.c
+++ b/ext/misc/normalize.c
@@ -286,6 +286,13 @@ static const unsigned char sqlite3CtypeMap[256] = {
#define TK_VARIABLE TK_LITERAL
#define TK_BLOB TK_LITERAL
+/* Disable nuisence warnings about case fall-through */
+#if !defined(deliberate_fall_through) && defined(__GCC__) && __GCC__>=7
+# define deliberate_fall_through __attribute__((fallthrough));
+#else
+# define deliberate_fall_through
+#endif
+
/*
** Return the length (in bytes) of the token that begins at z[0].
** Store the token type in *tokenType before returning.
@@ -436,6 +443,7 @@ static int sqlite3GetToken(const unsigned char *z, int *tokenType){
}
/* If the next character is a digit, this is a floating point
** number that begins with ".". Fall thru into the next case */
+ /* no break */ deliberate_fall_through
}
case CC_DIGIT: {
*tokenType = TK_INTEGER;
@@ -528,6 +536,7 @@ static int sqlite3GetToken(const unsigned char *z, int *tokenType){
}
/* If it is not a BLOB literal, then it must be an ID, since no
** SQL keywords start with the letter 'x'. Fall through */
+ /* no break */ deliberate_fall_through
}
case CC_ID: {
i = 1;
diff --git a/ext/misc/scrub.c b/ext/misc/scrub.c
index 4eb56b0fc2..9fbf2aed4a 100644
--- a/ext/misc/scrub.c
+++ b/ext/misc/scrub.c
@@ -166,7 +166,7 @@ static void scrubBackupOpenSrc(ScrubState *p){
sqlite3_errmsg(p->dbSrc));
return;
}
- p->rcErr = sqlite3_exec(p->dbSrc, "SELECT 1 FROM sqlite_master; BEGIN;",
+ p->rcErr = sqlite3_exec(p->dbSrc, "SELECT 1 FROM sqlite_schema; BEGIN;",
0, 0, 0);
if( p->rcErr ){
scrubBackupErr(p,
@@ -535,7 +535,7 @@ int sqlite3_scrub_backup(
/* Copy all of the btrees */
scrubBackupBtree(&s, 1, 0);
pStmt = scrubBackupPrepare(&s, s.dbSrc,
- "SELECT rootpage FROM sqlite_master WHERE coalesce(rootpage,0)>0");
+ "SELECT rootpage FROM sqlite_schema WHERE coalesce(rootpage,0)>0");
if( pStmt==0 ) goto scrub_abort;
while( sqlite3_step(pStmt)==SQLITE_ROW ){
i = (u32)sqlite3_column_int(pStmt, 0);
diff --git a/ext/rbu/sqlite3rbu.c b/ext/rbu/sqlite3rbu.c
index 8e82cd8b92..12a0a46603 100644
--- a/ext/rbu/sqlite3rbu.c
+++ b/ext/rbu/sqlite3rbu.c
@@ -975,7 +975,7 @@ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){
rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg,
sqlite3_mprintf(
"SELECT rbu_target_name(name, type='view') AS target, name "
- "FROM sqlite_master "
+ "FROM sqlite_schema "
"WHERE type IN ('table', 'view') AND target IS NOT NULL "
" %s "
"ORDER BY name"
@@ -984,7 +984,7 @@ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){
if( rc==SQLITE_OK ){
rc = prepareAndCollectError(p->dbMain, &pIter->pIdxIter, &p->zErrmsg,
"SELECT name, rootpage, sql IS NULL OR substr(8, 6)=='UNIQUE' "
- " FROM main.sqlite_master "
+ " FROM main.sqlite_schema "
" WHERE type='index' AND tbl_name = ?"
);
}
@@ -1156,12 +1156,12 @@ static void rbuFinalize(sqlite3rbu *p, sqlite3_stmt *pStmt){
**
** ALGORITHM:
**
-** if( no entry exists in sqlite_master ){
+** if( no entry exists in sqlite_schema ){
** return RBU_PK_NOTABLE
** }else if( sql for the entry starts with "CREATE VIRTUAL" ){
** return RBU_PK_VTAB
** }else if( "PRAGMA index_list()" for the table contains a "pk" index ){
-** if( the index that is the pk exists in sqlite_master ){
+** if( the index that is the pk exists in sqlite_schema ){
** *piPK = rootpage of that index.
** return RBU_PK_EXTERNAL
** }else{
@@ -1181,9 +1181,9 @@ static void rbuTableType(
int *piPk
){
/*
- ** 0) SELECT count(*) FROM sqlite_master where name=%Q AND IsVirtual(%Q)
+ ** 0) SELECT count(*) FROM sqlite_schema where name=%Q AND IsVirtual(%Q)
** 1) PRAGMA index_list = ?
- ** 2) SELECT count(*) FROM sqlite_master where name=%Q
+ ** 2) SELECT count(*) FROM sqlite_schema where name=%Q
** 3) PRAGMA table_info = ?
*/
sqlite3_stmt *aStmt[4] = {0, 0, 0, 0};
@@ -1195,7 +1195,7 @@ static void rbuTableType(
p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[0], &p->zErrmsg,
sqlite3_mprintf(
"SELECT (sql LIKE 'create virtual%%'), rootpage"
- " FROM sqlite_master"
+ " FROM sqlite_schema"
" WHERE name=%Q", zTab
));
if( p->rc!=SQLITE_OK || sqlite3_step(aStmt[0])!=SQLITE_ROW ){
@@ -1218,7 +1218,7 @@ static void rbuTableType(
if( zOrig && zIdx && zOrig[0]=='p' ){
p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[2], &p->zErrmsg,
sqlite3_mprintf(
- "SELECT rootpage FROM sqlite_master WHERE name = %Q", zIdx
+ "SELECT rootpage FROM sqlite_schema WHERE name = %Q", zIdx
));
if( p->rc==SQLITE_OK ){
if( sqlite3_step(aStmt[2])==SQLITE_ROW ){
@@ -2038,7 +2038,7 @@ static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){
** This is needed for the argument to "PRAGMA index_xinfo". Set
** zIdx to point to a nul-terminated string containing this name. */
p->rc = prepareAndCollectError(p->dbMain, &pQuery, &p->zErrmsg,
- "SELECT name FROM sqlite_master WHERE rootpage = ?"
+ "SELECT name FROM sqlite_schema WHERE rootpage = ?"
);
if( p->rc==SQLITE_OK ){
sqlite3_bind_int(pQuery, 1, tnum);
@@ -2211,7 +2211,7 @@ static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){
if( rc==SQLITE_OK ){
rc = prepareAndCollectError(p->dbMain, &pStmt, &p->zErrmsg,
- "SELECT trim(sql) FROM sqlite_master WHERE type='index' AND name=?"
+ "SELECT trim(sql) FROM sqlite_schema WHERE type='index' AND name=?"
);
}
if( rc==SQLITE_OK ){
@@ -2793,7 +2793,7 @@ static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){
int bOk = 0;
sqlite3_stmt *pCnt = 0;
p->rc = prepareAndCollectError(p->dbRbu, &pCnt, &p->zErrmsg,
- "SELECT count(*) FROM stat.sqlite_master"
+ "SELECT count(*) FROM stat.sqlite_schema"
);
if( p->rc==SQLITE_OK
&& sqlite3_step(pCnt)==SQLITE_ROW
@@ -2897,7 +2897,7 @@ static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){
if( p->rc==SQLITE_OK ){
p->rc = sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_RBU, (void*)p);
}
- rbuMPrintfExec(p, p->dbMain, "SELECT * FROM sqlite_master");
+ rbuMPrintfExec(p, p->dbMain, "SELECT * FROM sqlite_schema");
/* Mark the database file just opened as an RBU target database. If
** this call returns SQLITE_NOTFOUND, then the RBU vfs is not in use.
@@ -2990,7 +2990,7 @@ static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){
if( pState==0 ){
p->eStage = 0;
if( p->rc==SQLITE_OK ){
- p->rc = sqlite3_exec(p->dbMain, "SELECT * FROM sqlite_master", 0, 0, 0);
+ p->rc = sqlite3_exec(p->dbMain, "SELECT * FROM sqlite_schema", 0, 0, 0);
}
}
@@ -3581,7 +3581,7 @@ static void rbuCreateTargetSchema(sqlite3rbu *p){
p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=1", 0,0, &p->zErrmsg);
if( p->rc==SQLITE_OK ){
p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg,
- "SELECT sql FROM sqlite_master WHERE sql!='' AND rootpage!=0"
+ "SELECT sql FROM sqlite_schema WHERE sql!='' AND rootpage!=0"
" AND name!='sqlite_sequence' "
" ORDER BY type DESC"
);
@@ -3596,13 +3596,13 @@ static void rbuCreateTargetSchema(sqlite3rbu *p){
if( p->rc==SQLITE_OK ){
p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg,
- "SELECT * FROM sqlite_master WHERE rootpage=0 OR rootpage IS NULL"
+ "SELECT * FROM sqlite_schema WHERE rootpage=0 OR rootpage IS NULL"
);
}
if( p->rc==SQLITE_OK ){
p->rc = prepareAndCollectError(p->dbMain, &pInsert, &p->zErrmsg,
- "INSERT INTO sqlite_master VALUES(?,?,?,?,?)"
+ "INSERT INTO sqlite_schema VALUES(?,?,?,?,?)"
);
}
@@ -3865,7 +3865,7 @@ static void rbuIndexCntFunc(
assert( nVal==1 );
rc = prepareFreeAndCollectError(db, &pStmt, &zErrmsg,
- sqlite3_mprintf("SELECT count(*) FROM sqlite_master "
+ sqlite3_mprintf("SELECT count(*) FROM sqlite_schema "
"WHERE type='index' AND tbl_name = %Q", sqlite3_value_text(apVal[0]))
);
if( rc!=SQLITE_OK ){
@@ -3916,7 +3916,7 @@ static void rbuInitPhaseOneSteps(sqlite3rbu *p){
** occurs, nPhaseOneStep will be left set to -1. */
if( p->rc==SQLITE_OK ){
p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
- "SELECT 1 FROM sqlite_master WHERE tbl_name = 'rbu_count'"
+ "SELECT 1 FROM sqlite_schema WHERE tbl_name = 'rbu_count'"
);
}
if( p->rc==SQLITE_OK ){
diff --git a/ext/repair/checkindex.c b/ext/repair/checkindex.c
index 58706c1aab..080a51530d 100644
--- a/ext/repair/checkindex.c
+++ b/ext/repair/checkindex.c
@@ -473,7 +473,7 @@ static int cidxLookupIndex(
/* Find the table for this index. */
pFindTab = cidxPrepare(&rc, pCsr,
- "SELECT tbl_name, sql FROM sqlite_master WHERE name=%Q AND type='index'",
+ "SELECT tbl_name, sql FROM sqlite_schema WHERE name=%Q AND type='index'",
zIdx
);
if( rc==SQLITE_OK && sqlite3_step(pFindTab)==SQLITE_ROW ){
diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c
index 14facad534..35294c8d85 100644
--- a/ext/rtree/geopoly.c
+++ b/ext/rtree/geopoly.c
@@ -683,6 +683,8 @@ static GeoPoly *geopolyBBox(
aCoord[2].f = mnY;
aCoord[3].f = mxY;
}
+ }else{
+ memset(aCoord, 0, sizeof(RtreeCoord)*4);
}
return pOut;
}
diff --git a/ext/rtree/rtree.c b/ext/rtree/rtree.c
index efaef813db..df0f6c2e27 100644
--- a/ext/rtree/rtree.c
+++ b/ext/rtree/rtree.c
@@ -82,6 +82,7 @@ typedef unsigned int u32;
#include
#include
#include
+#include
/* The following macro is used to suppress compiler warnings.
*/
@@ -419,6 +420,23 @@ struct RtreeMatchArg {
# define testcase(X)
#endif
+/*
+** Make sure that the compiler intrinsics we desire are enabled when
+** compiling with an appropriate version of MSVC unless prevented by
+** the SQLITE_DISABLE_INTRINSIC define.
+*/
+#if !defined(SQLITE_DISABLE_INTRINSIC)
+# if defined(_MSC_VER) && _MSC_VER>=1400
+# if !defined(_WIN32_WCE)
+# include
+# pragma intrinsic(_byteswap_ulong)
+# pragma intrinsic(_byteswap_uint64)
+# else
+# include
+# endif
+# endif
+#endif
+
/*
** Macros to determine whether the machine is big or little endian,
** and whether or not that determination is run-time or compile-time.
diff --git a/ext/session/session_common.tcl b/ext/session/session_common.tcl
index ceffdad4ba..c52ac457c0 100644
--- a/ext/session/session_common.tcl
+++ b/ext/session/session_common.tcl
@@ -172,8 +172,8 @@ proc compare_db {db1 db2} {
set data1 [$db1 eval $sql]
set data2 [$db2 eval $sql]
if {$data1 != $data2} {
- puts "$data1"
- puts "$data2"
+ puts "$db1: $data1"
+ puts "$db2: $data2"
error "table $tbl data mismatch"
}
}
diff --git a/ext/session/sessioninvert.test b/ext/session/sessioninvert.test
index 49205f6b26..b7c157d2e7 100644
--- a/ext/session/sessioninvert.test
+++ b/ext/session/sessioninvert.test
@@ -155,5 +155,29 @@ do_test 3.2 {
compare_db db db2
} {}
+#-------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 4.0 {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE);
+ INSERT INTO t1 VALUES(1, 'one');
+ INSERT INTO t1 VALUES(2, 'two');
+ INSERT INTO t1 VALUES(3, 'three');
+ INSERT INTO t1 VALUES(4, 'four');
+}
+
+do_invert_test 4.1 {
+ DELETE FROM t1;
+ INSERT INTO t1 VALUES(1, 'two');
+ INSERT INTO t1 VALUES(2, 'five');
+ INSERT INTO t1 VALUES(3, 'one');
+ INSERT INTO t1 VALUES(4, 'three');
+} {
+ {UPDATE t1 0 X. {i 1 t two} {{} {} t one}}
+ {UPDATE t1 0 X. {i 2 t five} {{} {} t two}}
+ {UPDATE t1 0 X. {i 3 t one} {{} {} t three}}
+ {UPDATE t1 0 X. {i 4 t three} {{} {} t four}}
+}
+
finish_test
diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c
index 78cc5875cd..cb350ab2d4 100644
--- a/ext/session/sqlite3session.c
+++ b/ext/session/sqlite3session.c
@@ -3479,6 +3479,7 @@ struct SessionApplyCtx {
u8 *abPK; /* Boolean array - true if column is in PK */
int bStat1; /* True if table is sqlite_stat1 */
int bDeferConstraints; /* True to defer constraints */
+ int bInvertConstraints; /* Invert when iterating constraints buffer */
SessionBuffer constraints; /* Deferred constraints are stored here */
SessionBuffer rebase; /* Rebase information (if any) here */
u8 bRebaseStarted; /* If table header is already in rebase */
@@ -4251,7 +4252,9 @@ static int sessionRetryConstraints(
SessionBuffer cons = pApply->constraints;
memset(&pApply->constraints, 0, sizeof(SessionBuffer));
- rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf, 0);
+ rc = sessionChangesetStart(
+ &pIter2, 0, 0, cons.nBuf, cons.aBuf, pApply->bInvertConstraints
+ );
if( rc==SQLITE_OK ){
size_t nByte = 2*pApply->nCol*sizeof(sqlite3_value*);
int rc2;
@@ -4318,6 +4321,7 @@ static int sessionChangesetApply(
pIter->in.bNoDiscard = 1;
memset(&sApply, 0, sizeof(sApply));
sApply.bRebase = (ppRebase && pnRebase);
+ sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
sqlite3_mutex_enter(sqlite3_db_mutex(db));
if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
diff --git a/main.mk b/main.mk
index d1711bb59d..9976d22a52 100644
--- a/main.mk
+++ b/main.mk
@@ -364,6 +364,7 @@ TESTSRC += \
$(TOP)/ext/misc/carray.c \
$(TOP)/ext/misc/closure.c \
$(TOP)/ext/misc/csv.c \
+ $(TOP)/ext/misc/decimal.c \
$(TOP)/ext/misc/eval.c \
$(TOP)/ext/misc/explain.c \
$(TOP)/ext/misc/fileio.c \
@@ -729,6 +730,12 @@ parse.c: $(TOP)/src/parse.y lemon
sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest mksourceid $(TOP)/VERSION $(TOP)/ext/rtree/sqlite3rtree.h
tclsh $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
+sqlite3rc.h: $(TOP)/src/sqlite3.rc $(TOP)/VERSION
+ echo '#ifndef SQLITE_RESOURCE_VERSION' >$@
+ echo -n '#define SQLITE_RESOURCE_VERSION ' >>$@
+ cat $(TOP)/VERSION | tclsh $(TOP)/tool/replace.tcl exact . , >>$@
+ echo '#endif' >>sqlite3rc.h
+
keywordhash.h: $(TOP)/tool/mkkeywordhash.c
$(BCC) -o mkkeywordhash $(OPTS) $(TOP)/tool/mkkeywordhash.c
./mkkeywordhash >keywordhash.h
@@ -737,9 +744,11 @@ keywordhash.h: $(TOP)/tool/mkkeywordhash.c
SHELL_SRC = \
$(TOP)/src/shell.c.in \
$(TOP)/ext/misc/appendvfs.c \
- $(TOP)/ext/misc/shathree.c \
- $(TOP)/ext/misc/fileio.c \
$(TOP)/ext/misc/completion.c \
+ $(TOP)/ext/misc/decimal.c \
+ $(TOP)/ext/misc/fileio.c \
+ $(TOP)/ext/misc/ieee754.c \
+ $(TOP)/ext/misc/shathree.c \
$(TOP)/ext/misc/sqlar.c \
$(TOP)/ext/misc/uint.c \
$(TOP)/ext/expert/sqlite3expert.c \
@@ -977,6 +986,9 @@ valgrindtest: $(TESTPROGS) valgrindfuzz
smoketest: $(TESTPROGS) fuzzcheck$(EXE)
./testfixture$(EXE) $(TOP)/test/main.test $(TESTOPTS)
+shelltest: $(TESTPROGS)
+ ./testfixture$(EXT) $(TOP)/test/permutations.test shell
+
# The next two rules are used to support the "threadtest" target. Building
# threadtest runs a few thread-safety tests that are implemented in C. This
# target is invoked by the releasetest.tcl script.
@@ -1078,10 +1090,10 @@ checksymbols: sqlite3.o
# a tarball named for the version number. Ex: sqlite-autoconf-3110000.tar.gz.
# The snapshot-tarball target builds a tarball named by the SHA1 hash
#
-amalgamation-tarball: sqlite3.c
+amalgamation-tarball: sqlite3.c sqlite3rc.h
TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --normal
-snapshot-tarball: sqlite3.c
+snapshot-tarball: sqlite3.c sqlite3rc.h
TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --snapshot
diff --git a/manifest b/manifest
index baaeebf776..30327e0d5a 100644
--- a/manifest
+++ b/manifest
@@ -1,19 +1,19 @@
-C Update\sthe\sreuse-schema\sbranch\sto\sversion\s3.32.1
-D 2020-05-25T16:34:57.038
+C Merge\sall\schanges\ssince\sthe\s3.32.0\srelease\sinto\sthe\sreuse-schema\sbranch.
+D 2020-08-11T14:55:17.027
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
-F Makefile.in 201a181c0a852139bbb7e74a28d3d24d03953b91c372ed24a644b17070836bea
+F Makefile.in 270f76ae25d3bc5027121b3cd0d498b484b9f8c98ef91c81cf9db3f48a68035e
F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241
-F Makefile.msc 5f9b4709c8d5d089a1e7264682c58c7b95a377aa12fdcba9a57e72f021d3d1f8
+F Makefile.msc 9333691b59996201408f3e006d9ef6abaabc9a8cb444c14add736a4c37ed70f1
F README.md 1514a365ffca3c138e00c5cc839906108a01011a6b082bad19b09781e3aa498a
-F VERSION 7d1da8465e06354a9ffb67a9ef3f933552767d8e239b507cb2a08ba417048322
+F VERSION 5db2ee2cfcc790af73775fa485c13b2e8ccaa5936c6e1f47aedeba7056041ca5
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 e14b629addaa1ce372b72043f28f40de2e32b7e211b6e0fc18dbb87989197e40
+F autoconf/Makefile.am a8d1d24affe52ebf8d7ddcf91aa973fa0316618ab95bb68c87cabf8faf527dc8
F autoconf/Makefile.fallback 22fe523eb36dfce31e0f6349f782eb084e86a5620b2b0b4f84a2d6133f53f5ac
F autoconf/Makefile.msc e0f1dafc48d000fd6ddfdb01815271528db55cbc7299ca888df5b93367f0d5a4
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
@@ -34,23 +34,24 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63
F config.guess 883205ddf25b46f10c181818bf42c09da9888884af96f79e1719264345053bd6
F config.h.in 6376abec766e9a0785178b1823b5a587e9f1ccbc
F config.sub c2d0260f17f3e4bc0b6808fccf1b291cb5e9126c14fc5890efc77b9fd0175559
-F configure 4705718305e176b707e65047b69dca834fe7bc5475584e30fe1f63c8e33751b8 x
-F configure.ac 798a24cee2879325ca5b688a618199eb32cc77ed8136edbaa43d9137b470d54e
+F configure a97f98dfff699495aef66ae3d9c424345778a663f583e0d6e7522670518f87c1 x
+F configure.ac 40d01e89cb325c28b33f5957e61fede0bd17da2b5e37d9b223a90c8a318e88d4
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd
-F doc/lemon.html 857495c0ce060a4e2f2ad7111135ad7e28041a32c10612279ab398eddf678f58
+F doc/lemon.html 1edc0f916e771212792d4d077aedc05168bf13fd65d64d41b2c13e46ac0063a8
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
F doc/shared_schema.md 759fc374709fccf4e5d2d0cbd05f8fedd38fb022bdd8a6c5b5f492684c7023b9
F doc/trusted-schema.md 33625008620e879c7bcfbbfa079587612c434fa094d338b08242288d358c3e8a
F doc/vfs-shm.txt e101f27ea02a8387ce46a05be2b1a902a021d37a
+F doc/wal-lock.md 781726aaba20bafeceb7ba9f91d5c98c6731691b30c954e37cf0b49a053d461d
F ext/README.md fd5f78013b0a2bc6f0067afb19e6ad040e89a10179b4f6f03eee58fac5f169bd
F ext/async/README.txt e12275968f6fde133a80e04387d0e839b0c51f91
-F ext/async/sqlite3async.c 0f3070cc3f5ede78f2b9361fb3b629ce200d7d74
-F ext/async/sqlite3async.h f489b080af7e72aec0e1ee6f1d98ab6cf2e4dcef
+F ext/async/sqlite3async.c 6f247666b495c477628dd19364d279c78ea48cd90c72d9f9b98ad1aff3294f94
+F ext/async/sqlite3async.h 46b47c79357b97ad85d20d2795942c0020dc20c532114a49808287f04aa5309a
F ext/expert/README.md b321c2762bb93c18ea102d5a5f7753a4b8bac646cb392b3b437f633caf2020c3
F ext/expert/expert.c d548d603a4cc9e61f446cc179c120c6713511c413f82a4a32b1e1e69d3f086a4
F ext/expert/expert1.test 2e10ff875c31c9e6fc5e324767624181273859771fe34c5daeeadf3f2974a4f7
-F ext/expert/sqlite3expert.c ac008c72c00e6ded0f5116914d22ebd57f415fc0a7ea04738f4e9766dbdd3117
+F ext/expert/sqlite3expert.c b5eae75862d34a204d16c45dcb813888b5f86bdc156c6136b0f79094c0da4f79
F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b
F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72
F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e
@@ -79,13 +80,13 @@ F ext/fts2/fts2_tokenizer.c b529493d55e55497213c37e1f31680a77746be26
F ext/fts2/fts2_tokenizer.h 27a1a99ca2d615cf7e142839b8d79e8751b4529e
F ext/fts2/fts2_tokenizer1.c 07e223eecb483d448313b5f1553a4f299a7fb7a1
F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0
-F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
+F ext/fts3/README.content b9078d0843a094d86af0d48dffbff13c906702b4c3558012e67b9c7cc3bf59ee
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
F ext/fts3/README.tokenizers b92bdeb8b46503f0dd301d364efc5ef59ef9fa8e2758b8e742f39fa93a2e422d
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
-F ext/fts3/fts3.c 45f5774987a68d36355799503b6d02dbff5286ffb42bec14d928b295d2b93c1b
+F ext/fts3/fts3.c 4809e0b05af4519ad8bfa13d684f7ad635d1390a758299d2302f7e85c48ec160
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
-F ext/fts3/fts3Int.h 2c59cc46aefde134c1782e89a6a5384710ddcd4e783071337aa5d43d07269be3
+F ext/fts3/fts3Int.h 045179f538c478ced266ca14327269cde8ad8d573c5be902230a5ebaa5636c59
F ext/fts3/fts3_aux.c 96708c8b3a7d9b8ca1b68ea2b7e503e283f20e95f145becadedfad096dbd0f34
F ext/fts3/fts3_expr.c f081e38da641724cd72c20e23b71db2bf4d0c9517c14637442f6910259f11a34
F ext/fts3/fts3_hash.c 8b6e31bfb0844c27dc6092c2620bdb1fca17ed613072db057d96952c6bdb48b7
@@ -101,11 +102,11 @@ F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3
F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004
F ext/fts3/fts3_unicode.c 4b9af6151c29b35ed09574937083cece7c31e911f69615e168a39677569b684d
F ext/fts3/fts3_unicode2.c 416eb7e1e81142703520d284b768ca2751d40e31fa912cae24ba74860532bf0f
-F ext/fts3/fts3_write.c ed869b24d074f2498bdbef915d6db1f88c604ca5811502112061932a0bed5133
+F ext/fts3/fts3_write.c 723ed1b11ed46ad1b3a23c0d69fa39e77986783a82d5711bf87a5ce29e0a3b52
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/tool/fts3view.c 413c346399159df81f86c4928b7c4a455caab73bfbc8cd68f950f632e5751674
F ext/fts3/unicode/CaseFolding.txt 8c678ca52ecc95e16bc7afc2dbf6fc9ffa05db8c
F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7
F ext/fts3/unicode/mkunicode.tcl bf7fcaa6d68e6d38223467983785d054f1cff4d9e3905dd51f6ed8801bb590d5
@@ -118,7 +119,7 @@ F ext/fts5/fts5_buffer.c 5a5fe0159752c0fb0a5a93c722e9db2662822709490769d482b76a6
F ext/fts5/fts5_config.c b447948f35ad3354e8fe5e242e0a7e7b5b941555400b9404259944e3aa570037
F ext/fts5/fts5_expr.c 2be456484786333d559dc2987a00f2750981fab91d52db8452a8046278c5f22e
F ext/fts5/fts5_hash.c 1cc0095646f5f3b46721aa112fb4f9bf29ae175cb5338f89dcec66ed97acfe75
-F ext/fts5/fts5_index.c f25bec3c00bf050fa2d702d97b773d0706692661172026ddac8df1f164b8b198
+F ext/fts5/fts5_index.c de14c9a30f45e2b847ff9284b14776d9d07961e545e8f1546a6aa3f915af721f
F ext/fts5/fts5_main.c e881a2ea0bf01b3a3ff0bc1b31373c58fd54b6c9f3c43ea3d431bea4e5d4025e
F ext/fts5/fts5_storage.c 3ecda8edadc1f62a355d6789776be0da609f8658c50d72e422674093ab7e1528
F ext/fts5/fts5_tcl.c 39bcbae507f594aad778172fa914cad0f585bf92fd3b078c686e249282db0d95
@@ -159,7 +160,7 @@ F ext/fts5/test/fts5connect.test 08030168fc96fc278fa81f28654fb7e90566f33aff269c0
F ext/fts5/test/fts5content.test 213506436fb2c87567b8e31f6d43ab30aab99354cec74ed679f22aad0cdbf283
F ext/fts5/test/fts5corrupt.test 77ae6f41a7eba10620efb921cf7dbe218b0ef232b04519deb43581cb17a57ebe
F ext/fts5/test/fts5corrupt2.test 7453752ba12ce91690c469a6449d412561cc604b1dec994e16ab132952e7805f
-F ext/fts5/test/fts5corrupt3.test fab4ea761b2df254fb3909423989320772a3a757de4d151ddcfa2a40a3b93328
+F ext/fts5/test/fts5corrupt3.test 7afe0fea5b2160798fdc3306395048768c6fc13acefc0e7129d4075b6e1bb224
F ext/fts5/test/fts5corrupt4.test ea805c4d7c68b5f185b9db5d2060a7ae5875339738dd48203c92162f41e7ca91
F ext/fts5/test/fts5delete.test cbf87e3b8867c4d5cfcaed975c7475fd3f99d072bce2075fcedf43d1f82af775
F ext/fts5/test/fts5detail.test 31b240dbf6d44ac3507e2f8b65f29fdc12465ffd531212378c7ce1066766f54e
@@ -233,31 +234,31 @@ F ext/fts5/tool/mkfts5c.tcl d1c2a9ab8e0ec690a52316f33dd9b1d379942f45
F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
F ext/icu/README.txt 1c48ffaf7f255bd73d00a35f68f6de357c2a6594f16cb00506a151be23694706
F ext/icu/icu.c 91c021c7e3e8bbba286960810fa303295c622e323567b2e6def4ce58e4466e60
-F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
+F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8
F ext/lsm1/Makefile a553b728bba6c11201b795188c5708915cc4290f02b7df6ba7e8c4c943fd5cd9
F ext/lsm1/Makefile.msc f8c878b467232226de288da320e1ac71c131f5ec91e08b21f502303347260013
F ext/lsm1/lsm-test/README 87ea529d2abe615e856d4714bfe8bb185e6c2771b8612aa6298588b7b43e6f86
F ext/lsm1/lsm-test/lsmtest.h cf58528ffe0cfe535e91b44584e2ec5fb1caacdabecef0d8dcf83bf83168bf28
-F ext/lsm1/lsm-test/lsmtest1.c ae6ba48a0851b39be69a7d0eb220bfb9521a526e926223d5014bd385df10abb3
+F ext/lsm1/lsm-test/lsmtest1.c 54374fe88cee888c52c31160013c26184288f47a45b23d4d85390aa539733aab
F ext/lsm1/lsm-test/lsmtest2.c 188b09aec776516aeedcfd13b9c6faf85ba16b3671a0897a2c740ee00a5dc4f8
F ext/lsm1/lsm-test/lsmtest3.c 9ab87528a36dbf4a61d7c8ad954f5ee368c0878c127b84b942b2e2abe522de26
F ext/lsm1/lsm-test/lsmtest4.c d258d6a245db5d8eaede096e2368d23f859c5e92c80ab9122463f708514fe10c
F ext/lsm1/lsm-test/lsmtest5.c 8d5242a0f870d65eeada191c8945781fed9cb8ece3886573790ebd373b62dac5
F ext/lsm1/lsm-test/lsmtest6.c 869cb4a172cd07d1a75b3aeaecd61d0a477787b3b8668bad0d3ff0f43b642b7c
F ext/lsm1/lsm-test/lsmtest7.c 7a917455a0f956a8ed3f44f5c9387ec0ea6627714874464cc3fa5c5a9cabb2f2
-F ext/lsm1/lsm-test/lsmtest8.c 589b68c44531a0f04d5e879bb1e211be5f7100f48eed7e8631e07ed5cbd68f94
-F ext/lsm1/lsm-test/lsmtest9.c dd1a0ebf41134933a744d1e00e60429a2a21fc50d587ae7dd6bdb6e96d805bdc
-F ext/lsm1/lsm-test/lsmtest_bt.c d70d9a9be5eef9360af1251dd083948d74fd30137a08f61bef995f7ac04e037f
+F ext/lsm1/lsm-test/lsmtest8.c 773f226163d0f0d62701e3764d0c35fd4365faca74098bd63648bc57d6f14402
+F ext/lsm1/lsm-test/lsmtest9.c 0a168757b757b106191acf43143dbbb5b2d76e57a3c8fd3018cecbaee1080aba
+F ext/lsm1/lsm-test/lsmtest_bt.c 79b24bfd37e05fd626c35ec23bc5bb62d8a403afd66c710335384884dc1366d7
F ext/lsm1/lsm-test/lsmtest_datasource.c 5d770be191d0ca51315926723009b2c25c0b4b8136840494ef710ac324aa916c
F ext/lsm1/lsm-test/lsmtest_func.c 159aa401bc8032bfa3d8cf2977bd687abebab880255895a5eb45770d626fa38d
F ext/lsm1/lsm-test/lsmtest_io.c cf11b27b129c6bd5818fa1d440176502dc27229f0db892b4479118d61993ea20
F ext/lsm1/lsm-test/lsmtest_main.c a9bc647738c0dcaebf205d6d194b3ce4a6ef3925801cd2d919f0a4ea33a15aeb
F ext/lsm1/lsm-test/lsmtest_mem.c 4e63c764345ab1df59d4f13a77980c6f3643798210b10d6cdbd785b4b888fda5
-F ext/lsm1/lsm-test/lsmtest_tdb.c 618a8619183fda4f5540fcde15f9068293c5e3180e1a246e34409b0c148758b3
+F ext/lsm1/lsm-test/lsmtest_tdb.c 754b1ca8e1cfa7b29cbe2e4ab500f7eee0059033741b8d83267afe6f495a536d
F ext/lsm1/lsm-test/lsmtest_tdb.h 8733eee249b12956a9df8322994b43d19bd8c02ad2e8b0bb5164db4d6ccc1735
-F ext/lsm1/lsm-test/lsmtest_tdb2.cc 99ea7f2dd9c7536c8fb9bdd329e4cfeb76899f3ddf6f48bdd3926e016922b715
+F ext/lsm1/lsm-test/lsmtest_tdb2.cc aebe50f2cb7a759214241938046fe5f00da66e4217637f946f436ca209776af9
F ext/lsm1/lsm-test/lsmtest_tdb3.c 7a7ccae189f5bb25bcd1ec3bbd740529706eded7f6729a5a0a9eeaeb57785320
-F ext/lsm1/lsm-test/lsmtest_tdb4.c 47e8bb5eba266472d690fb8264f1855ebdba0ae5a0e541e35fcda61ebf1d277f
+F ext/lsm1/lsm-test/lsmtest_tdb4.c cbe230727b9413d244062943371af1421ace472ccb023b75af6540e0fa52b1bb
F ext/lsm1/lsm-test/lsmtest_util.c 241622db5a332a09c8e6e7606b617d288a37b557f7d3bce0bb97809f67cc2806
F ext/lsm1/lsm-test/lsmtest_win32.c 0e0a224674c4d3170631c41b026b56c7e1672b151f5261e1b4cc19068641da2d
F ext/lsm1/lsm.h 0f6f64ff071471cb87bf98beb8386566f30ea001
@@ -272,7 +273,7 @@ F ext/lsm1/lsm_shared.c 76adfc1ed9ffebaf92746dde4b370ccc48143ca8b05b563816eadd2a
F ext/lsm1/lsm_sorted.c 6f7d8cf7a7d3d3f1ab5d9ba6347e8f39f3d73c00ec48afcd0c4bcbefd806f9b8
F ext/lsm1/lsm_str.c 65e361b488c87b10bf3e5c0070b14ffc602cf84f094880bece77bbf6678bca82
F ext/lsm1/lsm_tree.c 682679d7ef2b8b6f2fe77aeb532c8d29695bca671c220b0abac77069de5fb9fb
-F ext/lsm1/lsm_unix.c 57361bcf5b1a1a028f5d66571ee490e9064d2cfb145a2cc9e5ddade467bb551b
+F ext/lsm1/lsm_unix.c 11e0a5c19d754a4e1d93dfad06de8cc201f10f886b8e61a4c599ed34e334fc24
F ext/lsm1/lsm_varint.c 43f954af668a66c7928b81597c14d6ad4be9fedbc276bbd80f52fa28a02fdb62
F ext/lsm1/lsm_vtab.c 169bfe7ef8e6c9de9c77e17c4c50c9ae55fb0167d80be3d1be82c991184b6f35
F ext/lsm1/lsm_win32.c 0a4acbd7e8d136dd3a5753f0a9e7a9802263a9d96cef3278cf120bcaa724db7c
@@ -282,37 +283,38 @@ F ext/lsm1/tool/mklsm1c.tcl f31561bbee5349f0a554d1ad7236ac1991fc09176626f529f607
F ext/misc/README.md d6dd0fe1d8af77040216798a6a2b0c46c73054d2f0ea544fbbcdccf6f238c240
F ext/misc/amatch.c e3ad5532799cee9a97647f483f67f43b38796b84b5a8c60594fe782a4338f358
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
-F ext/misc/appendvfs.c 3777f22ec1057dc4e5fd89f2fbddcc7a29fbeef1ad038c736c54411bb1967af7
+F ext/misc/appendvfs.c 55121d311d408ba9c62c3cfa367408887638f02f9522dd9859891d0ee69a7eba
F ext/misc/blobio.c a867c4c4617f6ec223a307ebfe0eabb45e0992f74dd47722b96f3e631c0edb2a
-F ext/misc/btreeinfo.c 26004b7a6be320ec08fc20ca8d0f01fccb00a98cbe0f3197446794ff2a506aa3
+F ext/misc/btreeinfo.c d28ce349b40054eaa9473e835837bad7a71deec33ba13e39f963d50933bfa0f9
F ext/misc/carray.c 91e9a7f512fda934894bed30464552fffa7d3073b5be04189ae0bd0c59f26bfd
-F ext/misc/cksumvfs.c b0d07f2e1bb08f8b6f311f4e454360b6a7f0021912c326428d74900020f29c31
+F ext/misc/cksumvfs.c 0f022867786b615d7f68fb3ab3a16627fe6a730442abf804735e18a73f835a83
F ext/misc/closure.c dbfd8543b2a017ae6b1a5843986b22ddf99ff126ec9634a2f4047cd14c85c243
-F ext/misc/completion.c a0efe03edfdc4f717c61e6c9b0bfe2708ff7878010dae3174980a68fdf76aabc
+F ext/misc/completion.c 6dafd7f4348eecc7be9e920d4b419d1fb2af75d938cd9c59a20cfe8beb2f22b9
F ext/misc/compress.c 3354c77a7c8e86e07d849916000cdac451ed96500bfb5bd83b20eb61eee012c9
F ext/misc/csv.c 3ed979c1eb35e35a98b30ef545a2facf62994594217681d9138b4b75faf6b0d7
F ext/misc/dbdata.c e316fba936571584e55abd5b974a32a191727a6b746053a0c9d439bd2cf93940
-F ext/misc/dbdump.c baf6e37447c9d6968417b1cd34cbedb0b0ab3f91b5329501d8a8d5be3287c336
+F ext/misc/dbdump.c b8592f6f2da292c62991a13864a60d6c573c47a9cc58362131b9e6a64f823e01
+F ext/misc/decimal.c 3ddbf8162015be4d5ec2395dee4538f1e638bb517174bb148274b132df6e1d08
F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1
-F ext/misc/explain.c d5c12962d79913ef774b297006872af1fccda388f61a11d37758f9179a09551f
+F ext/misc/explain.c 0086fab288d4352ea638cf40ac382aad3b0dc5e845a1ea829a694c015fd970fe
F ext/misc/fileio.c 9b69e25da3b51d4a1d905a464ccb96709792ad627a742ba09215bc0d1447e7bd
F ext/misc/fossildelta.c 1240b2d3e52eab1d50c160c7fe1902a9bd210e052dc209200a750bbf885402d5
F ext/misc/fuzzer.c eae560134f66333e9e1ca4c8ffea75df42056e2ce8456734565dbe1c2a92bf3d
-F ext/misc/ieee754.c eaffd9b364d7c8371727e9c43fc8bec38cdacc4d11fc26beffaa3ca05a0ea9d6
-F ext/misc/json1.c 3a42e3231d716516a8ae33b0a052d3ed5f52943e3d627b68744a427a6e552ae3
+F ext/misc/ieee754.c 5c7ca326361c7368f95f5743972eade3b8b24f60359ed7cba4706668a5682896
+F ext/misc/json1.c f31e89171f932d1821c91f10d2cb4979fc0447030030a8bce70420cd43d074c0
F ext/misc/memstat.c 3017a0832c645c0f8c773435620d663855f04690172316bd127270d1a7523d4d
F ext/misc/memtrace.c 7c0d115d2ef716ad0ba632c91e05bd119cb16c1aedf3bec9f06196ead2d5537b
F ext/misc/memvfs.c ab36f49e02ebcdf85a1e08dc4d8599ea8f343e073ac9e0bca18a98b7e1ec9567
-F ext/misc/mmapwarm.c 8c5fe90d807a23e44a8b93e96e8b812b19b300d5fd8c1d40a4fd1d8224e33f46
+F ext/misc/mmapwarm.c 347caa99915fb254e8949ec131667b7fae99e2a9ce91bd468efb6dc372d9b7a9
F ext/misc/nextchar.c 7877914c2a80c2f181dd04c3dbef550dfb54c93495dc03da2403b5dd58f34edd
F ext/misc/noop.c 81efe4cad9ec740e64388b14281cb983e6e2c223fed43eb77ab3e34946e0c1ab
-F ext/misc/normalize.c b4290464f542bae7a97b43f15bd197949b833ffd668b7c313631bd5d4610212c
+F ext/misc/normalize.c bd84355c118e297522aba74de34a4fd286fc775524e0499b14473918d09ea61f
F ext/misc/percentile.c b9086e223d583bdaf8cb73c98a6539d501a2fc4282654adbfea576453d82e691
F ext/misc/prefixes.c 0f4f8cff5aebc00a7e3ac4021fd59cfe1a8e17c800ceaf592859ecb9cbc38196
F ext/misc/regexp.c 246244c714267f303df76acf73dcf110cf2eaf076896aaaba8db6d6d21a129db
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
-F ext/misc/scrub.c db9fff56fed322ca587d73727c6021b11ae79ce3f31b389e1d82891d144f22ad
+F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946
F ext/misc/series.c 4057dda3579b38ff88b2d3b13b4dd92dbd9d6f90dac2b55c19b0a8ed87ee4959
F ext/misc/sha1.c c8f2253c8792ffab9517695ea7d88c079f0395a5505eefef5c8198fe184ed5ac
F ext/misc/shathree.c 135b7c145db4a09b1650c3e7aff9cb538763a9a361e834c015dd1aaf8d5c9a00
@@ -373,12 +375,12 @@ F ext/rbu/rbuvacuum.test 55e101e90168c2b31df6c9638fe73dc7f7cc666b6142266d1563697
F ext/rbu/rbuvacuum2.test b8e5b51dc8b2c0153373d024c0936be3f66f9234acbd6d0baab0869d56b14e6b
F ext/rbu/rbuvacuum3.test 8addd82e4b83b4c93fa47428eae4fd0dbf410f8512c186f38e348feb49ba03dc
F ext/rbu/rbuvacuum4.test a78898e438a44803eb2bc897ba3323373c9f277418e2d6d76e90f2f1dbccfd10
-F ext/rbu/sqlite3rbu.c 77a47f3231f5f363b2c584dba3e310a7efdaf073ad8c18728ab846b38de2879c
+F ext/rbu/sqlite3rbu.c 05c457c27e9340c944f34e850871a915a6b5ee1d823f7a0bb2b482ac6b1e1464
F ext/rbu/sqlite3rbu.h 1dc88ab7bd32d0f15890ea08d23476c4198d3da3056985403991f8c9cd389812
F ext/rbu/test_rbu.c 03f6f177096a5f822d68d8e4069ad8907fe572c62ff2d19b141f59742821828a
F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15
F ext/repair/checkfreelist.c 0dbae18c1b552f58d64f8969e4fb1e7f11930c60a8c2a9a8d50b7f15bdfd54bd
-F ext/repair/checkindex.c 7d28c01a2e012ac64257d230fc452b2cafb78311a91a343633d01d95220f66f3
+F ext/repair/checkindex.c 4383e4469c21e5b9ae321d0d63cec53e981af9d7a6564be6374f0eeb93dfc890
F ext/repair/sqlite3_checker.c.in 4a5a3af3f450fe503e5a2985e98516dc2a6b9ad247449e284c1cf140fc91720f
F ext/repair/sqlite3_checker.tcl a9a2caa9660567257c177a91124d8c0dccdfa341e25c51e6da7f1fd9e601eafa
F ext/repair/test/README.md 34b2f542cf5be7bffe479242b33ee3492cea30711e447cc4a1a86cb5915f419e
@@ -386,8 +388,8 @@ F ext/repair/test/checkfreelist01.test 3e8aa6aeb4007680c94a8d07b41c339aa635cc782
F ext/repair/test/checkindex01.test b530f141413b587c9eb78ff734de6bb79bc3515c335096108c12c01bddbadcec
F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
-F ext/rtree/geopoly.c cac70b5502742bd0ba8877a1329a74e86a379c78567546a2a18cf5f9c3787f73
-F ext/rtree/rtree.c 0ee39cc787b95aa03a012e09e6090b0fa452154fa812af9a379898560fd6c00f
+F ext/rtree/geopoly.c f15cc6845d64a629035627d863cbe3eadc9cb30f9ca77bd823b0ca8a5a3f8b00
+F ext/rtree/rtree.c f87ffcc91f49272862119cfdd256b02514351893786a710d88f85933790608d4
F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412
F ext/rtree/rtree1.test 00792b030a4e188ff1b22e8530e8aa0452bb5dd81c2b18cb004afc7dc63e040e
F ext/rtree/rtree2.test 9d9deddbb16fd0c30c36e6b4fdc3ee3132d765567f0f9432ee71e1303d32603d
@@ -437,17 +439,17 @@ F ext/session/sessionE.test b2010949c9d7415306f64e3c2072ddabc4b8250c98478d3c0c4d
F ext/session/sessionF.test d37ed800881e742c208df443537bf29aa49fd56eac520d0f0c6df3e6320f3401
F ext/session/sessionG.test 3828b944cd1285f4379340fd36f8b64c464fc84df6ff3ccbc95578fd87140b9c
F ext/session/sessionH.test b17afdbd3b8f17e9bab91e235acf167cf35485db2ab2df0ea8893fbb914741a4
-F ext/session/session_common.tcl 29ec9910aca1e996ca1c8531b8cecabf96eb576aa53de65a8ff03d848b9a2a8b
+F ext/session/session_common.tcl f613174665456b2d916ae8df3e5735092a1c1712f36f46840172e9a01e8cc53e
F ext/session/session_speed_test.c dcf0ef58d76b70c8fbd9eab3be77cf9deb8bc1638fed8be518b62d6cbdef88b3
F ext/session/sessionat.test efe88965e74ff1bc2af9c310b28358c02d420c1fb2705cc7a28f0c1cc142c3ec
F ext/session/sessiondiff.test ad13dd65664bae26744e1f18eb3cbd5588349b7e9118851d8f9364248d67bcec
F ext/session/sessionfault.test da273f2712b6411e85e71465a1733b8501dbf6f7
F ext/session/sessionfault2.test dd593f80b6b4786f7adfe83c5939620bc505559770cc181332da26f29cddd7bb
-F ext/session/sessioninvert.test ae1a003a9ab1f8d64227dbb5c3a4c97e65b561b01e7b2953cf48683fb2724169
+F ext/session/sessioninvert.test 04075517a9497a80d39c495ba6b44f3982c7371129b89e2c52219819bc105a25
F ext/session/sessionrebase.test ccfa716b23bd1d3b03217ee58cfd90c78d4b99f53e6a9a2f05e82363b9142810
F ext/session/sessionstat1.test 218d351cf9fcd6648f125a26b607b140310160184723c2666091b54450a68fb5
F ext/session/sessionwor.test 67b5ab91d4f93ce65ff1f58240ac5ddf73f8670facc1ffa49cef56293d52818d
-F ext/session/sqlite3session.c e25b345896fa3646ff8b6c4058b3d9e365dc7eab4afe80b110808681098551c8
+F ext/session/sqlite3session.c fc8c6c13dc0456943ff24abf574ced10418eec66a548c97d3eafbebe9fc5e908
F ext/session/sqlite3session.h a2db5b72b938d12c727b4b4ec632254ca493670a9c0de597af3271a7f774fc57
F ext/session/test_session.c 98797aba475a799376c9a42214f2d1debf2d0c3cb657d9c8bbf4f70bf3fb4aec
F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
@@ -456,7 +458,7 @@ F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
-F main.mk 13814e3d9720918964eb7de6273accf601f53ff98d3ee05f37784f69b6d4b66a
+F main.mk 7d384a56be992954cf3ae0eb8bdd910d48727554ff3ca4904253a125ac7e615a
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
@@ -468,90 +470,90 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
-F src/alter.c e1198116d98c2dd7ca252a54dd6df33d32dd2c74af825b44c40c732fd58c3ffb
-F src/analyze.c b2b878f8467d7c545db8d838d00ae8ac2069cc535fd025b74077d8a439f5c14a
-F src/attach.c 22ddf11d73e1eecf547304e4babd44a322bc1db79c7b0aeb9e53f58a4ae7f8a7
+F src/alter.c 485b411347f8566792f8023f83117da300ddaf263cb61027bd69ada015d2e300
+F src/analyze.c 5eab9cfb85d1280fa35fd4cf5c497f77ad884bf3658610e7321c3994e703c2e6
+F src/attach.c f5e649fb70e856e2bc388d2f158cd4b4e43b85f43ad4c397fee192b35bd0dd57
F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06
F src/backup.c b1c90cd4110248c8e1273ff4578d3a84c0c34725e1b96dacd4a6294a908702de
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
-F src/btree.c f14e415fcfd0b52b4e4ebd193ba5fadac5e8252c30f023389af682813af44025
-F src/btree.h 989ef3c33413549e3e148f3dcb46c030f317dac130dc86809ba6b9aa4b16c72a
-F src/btreeInt.h 5c8b8749805787313ecf49eb5be3ced1e94bbf8ef54bb01470ce6bd0d5185c67
-F src/build.c 838e367617c20403fc21546fb1d9d9f8ba45d74427dbbc987df46af9f01704a7
+F src/btree.c 1439fd9b45d4d1883c53752daef42af489adaa1a1508fa39dedbc9c80ea21a2f
+F src/btree.h 7af72bbb4863c331c8f6753277ab40ee67d2a2125a63256d5c25489722ec162b
+F src/btreeInt.h 83166f6daeb91062b6ae9ee6247b3ad07e40eba58f3c05ba9e8dedad4ab1ea38
+F src/build.c 3b360c8171b401401fe6aae4c80759ab8c1a42fa5f45bb2ea73073bcd446bef8
F src/callback.c d8cdf5d697a31cf54a2b64bce9001fe24f3522a566f44c9fe1eb3a0c7e291c56
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c f5eaef0a5985fab6fc21e8b00aeaea1ca862a09c1ea5e505b0ad1da157eec247
-F src/date.c b29b349d277e3d579dcc295b24c0a2caed83fd8f090a9f7cbe6070c0fd662384
+F src/date.c dace306a10d9b02ee553d454c8e1cf8d3c9b932e137738a6b15b90253a9bfc10
F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a
-F src/dbstat.c 793deaf88a0904f88285d93d6713c636d55ede0ffd9f08d10f4ea825531d367f
-F src/delete.c 88047c8e59878c920fce14582bc1dde4d81157d1ca5ffdf36c2907e6d41996c4
-F src/expr.c b46669d9fc9e0361dba6cc289901a013789e0b1dc629c4c1bc88ec9403633b38
+F src/dbstat.c 3aa79fc3aed7ce906e4ea6c10e85d657299e304f6049861fe300053ac57de36c
+F src/delete.c 410c771c25afc113c273d9efad6ab6881bda28c75a1838b9d2c52ba20d1dc704
+F src/expr.c 58c06940d964c2cf455b979cf66a648499d294a5ee6dadcaeaed447257c1dc75
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
-F src/fkey.c 784662bc65fd0770221bc91c58c45a785849b49ecb39fdb163fb5c65d067d377
+F src/fkey.c 6cf1e15c986e5a393399ce337e4c085bf872117b8b095b04c79ae39d1f6a069a
F src/func.c 2333eb4277f55a5efdc12ef754e7d7ec9105d257b2fd00301d23ce1e8fa67dc0
-F src/global.c 79a988b56b06ce2d08ebefe1d35da9aa25b3851faa47ea5233361c4827185a64
+F src/global.c 943256ac44f333039d35a9830c18d075a81fa6b6bf2af05771494a9acfb9a40b
F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38
F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
-F src/insert.c 92b07a7f7e682114948ce59fd6511ffec7672b508cc343a804ef6afee21b6c11
+F src/insert.c 957254a2d0542597455d0d4c640e4e3f3eea8c6d78f04582df03dfc626f07925
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
-F src/loadext.c 421310045bd78afefb772294a99e50f37d87ae578786a6169074e6291e30d969
-F src/main.c 3e88148106fead4d8edfec84a8c3604bd84fb6af4eceb4d20020387c52405d77
-F src/malloc.c d0400b0366e1a3a2414ca4534b4a7406df34732835f37a15cb4642eb7df1a363
+F src/loadext.c 436af4968c6954d304fce9efa12719367bd8f37b19b93b71d6ad607e85adbb47
+F src/main.c 58a3980c13b994a90b70a9148bec4e103c17f3ac885791a789f776d37a958561
+F src/malloc.c 22d5bdd9fe88ae4fad1b91a1b9735104b82853ffef868f1f05517d60dc1875f5
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
-F src/mem2.c f1940d9e91948dd6a908fbb9ce3835c36b5d83c3
-F src/mem3.c 8768ac94694f31ffaf8b4d0ea5dc08af7010a35a
+F src/mem2.c b93b8762ab999a29ae7751532dadf0a1ac78040308a5fb1d17fcc365171d67eb
+F src/mem3.c 30301196cace2a085cbedee1326a49f4b26deff0af68774ca82c1f7c06fda4f6
F src/mem5.c 9bf955937b07f8c32541c8a9991f33ce3173d944
-F src/memdb.c 252137ca122acb8f54a99b48cf9f96a31d5130f19d174381a53294446d8b64a3
-F src/memjournal.c 7561c01c90958f3ba9bc6cb2d857123d932bdfa5539ea34427a0957b2e35154d
+F src/memdb.c d58e398e315e88f95f8d07d17e80ab11259ebd6d1a10397434329eeabd1985e3
+F src/memjournal.c 90b2ca7e2f465d57c16b69d15a9f3e3294af61088eb4938f2f7664d5ac50f813
F src/msvc.h 3a15918220367a8876be3fa4f2abe423a861491e84b864fb2b7426bf022a28f8
F src/mutex.c 5e3409715552348732e97b9194abe92fdfcd934cfb681df4ba0ab87ac6c18d25
F src/mutex.h a7b2293c48db5f27007c3bdb21d438873637d12658f5a0bf8ad025bb96803c4a
F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4
-F src/mutex_unix.c aaf9ebc3f89df28483c52208497a99a02cc3650011422fc9d4c57e4392f7fe58
-F src/mutex_w32.c 7670d770c94bbfe8289bec9d7f1394c5a00a57c37f892aab6b6612d085255235
-F src/notify.c 9711a7575036f0d3040ba61bc6e217f13a9888e7
-F src/os.c 669cc3839cc35d20f81faf0be1ab6d4581cea35e9d8f3a9d48a98d6571f7c285
+F src/mutex_unix.c dd2b3f1cc1863079bc1349ac0fec395a500090c4fe4e11ab775310a49f2f956d
+F src/mutex_w32.c caa50e1c0258ac4443f52e00fe8aaea73b6d0728bd8856bedfff822cae418541
+F src/notify.c 89a97dc854c3aa62ad5f384ef50c5a4a11d70fcc69f86de3e991573421130ed6
+F src/os.c 80e4cf3e5da06be03ca641661e331ce60eeeeabf0d7354dbb1c0e166d0eedbbe
F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
-F src/os_unix.c 13f983da988b6460ef3c4c22099c67ab0938291e543644ac4d99eccc8ba604f1
-F src/os_win.c e832e21e830c1f9409c9c54053939b6dcb14c1e92128b756204ce1e3e331d678
+F src/os_unix.c 9b1b860163fd2d4d7679b5260d384d1a9f88ef917a90f28963eca8acd472d8c8
+F src/os_win.c a2149ff0a85c1c3f9cc102a46c673ce87e992396ba3411bfb53db66813b32f1d
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
-F src/pager.c 96436cb1920074d4ade120a1a8a9d0ae3f52df06651e21b7eccc5eae2f02b111
-F src/pager.h 8d1dc9a2c3fc5eb6eeed75f48a076f425e77706f8935f05817fa05a308f587b5
-F src/parse.y c8eff38606f443d5ba245263fa7abc05e4116d95656e050c4b78e9bfbf931add
+F src/pager.c 3700a1c55427a3d4168ad1f1b8a8b0cb9ace1d107e4506e30a8f1e66d8a1195e
+F src/pager.h 4bf9b3213a4b2bebbced5eaa8b219cf25d4a82f385d093cd64b7e93e5285f66f
+F src/parse.y 5bdb760a29c0b25caf7e80e82210b81cd2ea3066d5199ca29e6eac40b34bc184
F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
F src/pcache1.c 6596e10baf3d8f84cc1585d226cf1ab26564a5f5caf85a15757a281ff977d51a
-F src/pragma.c 4937f87d57292a80b61d7a858d8d26eb9a33e8cbd43389a62530cb34dd0adac8
-F src/pragma.h 29c562664ae96b51e5687f66af3c6e7f3481ff42f7c0fe1d05708da69cd50789
-F src/prepare.c 45824c5f6dbacb9cb2c966a1d6eebdd94170da9b8700a265abd6a5e49cbd73dd
-F src/printf.c 94b5419ad0a17269f76a9e968ca19cf9fa37617abed2e246fc48844e511b6bc6
+F src/pragma.c b4e8df9a29c6fbe7e6576217e79a50cef34742d13ad49af20dd3c75434112e71
+F src/pragma.h ce2b135cde481eeb198af0dfc4781d58528ce80b17580a2b747b8fd4bc969e44
+F src/prepare.c dfc6eba4bd2583c72735f3a3240441a68a5fb9a9d6e1e490de06b7735106a05e
+F src/printf.c 9efcd4e984f22bcccb1ded37a1178cac98f6e3a0534e1e0629f64899971f8838
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
-F src/resolve.c c2008519a0654f1e7490e9281ed0397d0f14bb840d81f0b96946248afcbdb25d
+F src/resolve.c d74715aceed2a8f493ba244d535646fa93132042a4400a29dfd26ec841514048
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
-F src/select.c e2a59548681bf1c407132863ae87bf2444aca5543867c21d9d09aa07f44aef5d
-F src/shell.c.in a1be0ab48832b0863a92969bbf3575eb04efd1c644719d713507ae4367ea6f9d
-F src/sqlite.h.in b88058cf1d02cbb51ab7d15ac89461896a6cb638b6180dee4b4f20311cfbbd03
+F src/select.c 510fdf819f218be3dac2683d3eaaf64e5080f548061a4dd12205590beda976bb
+F src/shell.c.in 0598d0e6d5489ddbfa8d6d54662bb43f0ac92679fe8d8ddf31fae6ffbc421f8b
+F src/sqlite.h.in 7c1b9b3e42c6ed1670ef7dfd2df5ae95aaa966508c14ae5d060a9d14be9d99ae
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 2d1af80082edffd71c6f96f70ad1ce6a4fb46615ad10291fc77fe0dea9ff0197
-F src/sqliteInt.h 087cb10287c2938acf68e89f14537520fc849ee80237d3d802db966f9475d9d1
+F src/sqliteInt.h 827cf0bf109871f5c6d343bf6ce160890fa60b639cc9b6dd1d0c06037f692d01
F src/sqliteLimit.h 95cb8479ca459496d9c1c6a9f76b38aee12203a56ce1092fe13e50ae2454c032
-F src/status.c f6e2b6c37873620ce2cb597f5606a1c9adca4c0db1ff3a08a37231e920d21985
+F src/status.c d0956e57c71160155f620a3efeb1e5c05a3f8b9a897dd09c5263268e5d237579
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
F src/tclsqlite.c f4dd32d001c2be33371dca87e30117352f02dad59a2e5428c97f08703360a169
-F src/test1.c 5e8b8cc54e8c88906ea8a084387aa79bad245e539f4cee73149e5c0527e1db16
+F src/test1.c 77d0bf0140d92e5e8234dd3e158a985fc905e5bd9d94254370d4e9421f7c2224
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
-F src/test4.c 405834f6a93ec395cc4c9bb8ecebf7c3d8079e7ca16ae65e82d01afd229694bb
+F src/test4.c 7c4420e01c577b5c4add2cb03119743b1a357543d347773b9e717195ea967159
F src/test5.c 328aae2c010c57a9829d255dc099d6899311672d
F src/test6.c e8d839fbc552ce044bec8234561a2d5b8819b48e29548ad0ba400471697946a8
F src/test7.c 5612e9aecf934d6df7bba6ce861fdf5ba5456010
-F src/test8.c 3f7d0cc4e12e06832ba3db4455cb16867ccadafa602eb6ff5fcf097bffce56ed
+F src/test8.c 7fb971777c2c79c734bb52757191d68d4af659b8de9b4a071be3f527a9d19a02
F src/test9.c 12e5ba554d2d1cbe0158f6ab3f7ffcd7a86ee4e5
F src/test_async.c 195ab49da082053fdb0f949c114b806a49ca770a
F src/test_autoext.c 915d245e736652a219a907909bb6710f0d587871
@@ -571,21 +573,21 @@ F src/test_intarray.c 39b4181662a0f33a427748d87218e7578d913e683dc27eab7098bb4161
F src/test_intarray.h d57ae92f420cda25e22790dac474d60961bd0c500cbaa3338a05152d4a669ef7
F src/test_journal.c a0b9709b2f12b1ec819eea8a1176f283bca6d688a6d4a502bd6fd79786f4e287
F src/test_loadext.c 337056bae59f80b9eb00ba82088b39d0f4fe6dfd
-F src/test_malloc.c dec0aa821b230773aeb3dd11d652c1193f7cedb18a20b25659bc672288115242
+F src/test_malloc.c 21121ea85b49ec0bdb69995847cef9036ef9beca3ce63bbb776e4ea2ecc44b97
F src/test_md5.c 7268e1e8c399d4a5e181b64ac20e1e6f3bc4dd9fc87abac02db145a3d951fa8c
-F src/test_multiplex.c 46e278397bef99b10530c1a695b4f6f23823fde6d6589b182f14e9bd43440b57
+F src/test_multiplex.c 2ccf35551c094e353af20b0cdfac053a37bf3e96e10e7cf9f4abd1d279890a78
F src/test_multiplex.h 5436d03f2d0501d04f3ed50a75819e190495b635
-F src/test_mutex.c 7f4337ba23ee6b1d2ec81c189653608cb069926a
+F src/test_mutex.c abf486e91bd65e2448027d4bb505e7cce6ba110e1afb9bd348d1996961cadf0d
F src/test_onefile.c f31e52e891c5fef6709b9fcef54ce660648a34172423a9cbdf4cbce3ba0049f4
-F src/test_osinst.c 98ef31ff03d55497829ca0f6c74a9f4e1aa48690
+F src/test_osinst.c d341f9d7613e007c8c3f7eba6cd307230047506aa8f97858c1fd21f5069616bd
F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00
F src/test_quota.c 6cb9297115b551f433a9ad1741817a9831abed99
F src/test_quota.h 2a8ad1952d1d2ca9af0ce0465e56e6c023b5e15d
F src/test_rtree.c 671f3fae50ff116ef2e32a3bf1fe21b5615b4b7b
-F src/test_schema.c f575932cb6274d12147a77e13ea4b49d52408513
+F src/test_schema.c f5d6067dfc2f2845c4dd56df63e66ee826fb23877855c785f75cc2ca83fd0c1b
F src/test_schemapool.c ae21a79f9bc7e9099ae78dbd46d5c28ee75330e62e3256a9fde25564ff9df492
F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe
-F src/test_sqllog.c 11e6ce7575f489155c604ac4b439f2ac1d3d5aef
+F src/test_sqllog.c 540feaea7280cd5f926168aee9deb1065ae136d0bbbe7361e2ef3541783e187a
F src/test_superlock.c 4839644b9201da822f181c5bc406c0b2385f672e
F src/test_syscall.c 1073306ba2e9bfc886771871a13d3de281ed3939
F src/test_tclsh.c 6cbaaf30c4fed76c7b35baa42c521fd225c49563ff580f736d77def9e216b31b
@@ -599,39 +601,39 @@ F src/test_windirent.h 90dfbe95442c9762357fe128dc7ae3dc199d006de93eb33ba3972e0a9
F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394ba3f
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
-F src/tokenize.c 194677eb6d46dff9a4d6d615af3e43405ab893c340f3807ba6da326d50948a1b
-F src/treeview.c 9df54af6e5830fd527496e62ae0148e1ba33197205d8e232c2826537d42d4063
-F src/trigger.c fe34ac585410bf1cd449db2eebea6b343601c7af590b8e666b320a102ced2f12
-F src/update.c 3199098455830fc2d8c8fc4ae3ec2ea513eef64339ae9a7048db62b21169bc7a
+F src/tokenize.c cc9b7b311ea93b70aff96fe9aeb37b034588453115c3a09a728a0675594953d4
+F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda
+F src/trigger.c 595153f55f10058605e84aa6e41718e92ebd6fa896528bcc3a97708f0bb27ac4
+F src/update.c fb15bec5b54fd098f4b84f6abc83c7103b45ba8484011fff8edf5ae31656eab6
F src/upsert.c 2920de71b20f04fe25eb00b655d086f0ba60ea133c59d7fa3325c49838818e78
-F src/utf.c d7a61c1dfdac3eb091d43341a674032dca5a34e122f78ef0b5bd2d5a31967dde
-F src/util.c 3b6cedf7a0c69bd6e1acce832873952d416212d6293b18d03064e07d7a9b5118
-F src/vacuum.c 593bdeaa1381b9f3030691ef5a5143d738d509311bca54e1201998ca2b51f633
-F src/vdbe.c 56860bb96bdf2162642e54ca4fc4147369c4a439018858759c3d336659ad1c1b
-F src/vdbe.h 1c7eaf26b674d9c1a8030b5ad27531e4b99df472a1fba78de43bcd0e812fb763
-F src/vdbeInt.h 571413068b5ac07e2ed8ca7a02fa529622fd5455ae6981498376e5e492d2e5ef
-F src/vdbeapi.c e467b75a710ea099f8d2d022abf601d2ccd05e28f63b44b12d93000b6a75f4a8
-F src/vdbeaux.c 79846956661ec4b4b36e41c9d072f1294c0865ab429be48aa1e5f079ae5ee754
+F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
+F src/util.c c8bf30c4356b091bcc3b624d0e24b2b4d11b8be4d6c90d8e0705971e15cc819b
+F src/vacuum.c 55537753cfc6b860b844bf9a3e47b855ba5a8094e165074a7a908304dd1960ad
+F src/vdbe.c 9ae5113faf176c3305db3b8cb06a3e129293cc66af15e42142dbab13ce10bac5
+F src/vdbe.h 9e947bd4a40e3b65159b699571c8246c209f6bda6e13979a1ab623faa2f0d23f
+F src/vdbeInt.h 762abffb7709f19c2cb74af1bba73a900f762e64f80d69c31c9ae89ed1066b60
+F src/vdbeapi.c c5e7cb2ab89a24d7f723e87b508f21bfb1359a04db5277d8a99fd1e015c12eb9
+F src/vdbeaux.c 1aa53cee66d6fd880d47891a0d6f0beaf3f8530335c7e8824e0491516bf81397
F src/vdbeblob.c 40028e015fe557a945c99edb6cbf844ea96d853c3e8ac4eb5c1e49bff59f154e
-F src/vdbemem.c 39b942ecca179f4f30a32b54579a85d74ccaefa5af2a0ad2700abe5ef0768b22
+F src/vdbemem.c 947f2a65910edb4014dc981d33e414a68c51f169f9df8c4c493a0ba840b6eb1f
F src/vdbesort.c 2be76d26998ce2b3324cdcc9f6443728e54b6c7677c553ad909c7d7cfab587df
F src/vdbetrace.c fa3bf238002f0bbbdfb66cc8afb0cea284ff9f148d6439bc1f6f2b4c3b7143f0
-F src/vdbevtab.c ee5b4c902fdda2230f9503ac7b84c6d614c91e8f6f4dc1633e2e8dfef8ffb144
-F src/vtab.c df7634fbdf42f8dc53f0a95eebf913b11a34bbdb7ae6cd08b8e55119a0ce227d
+F src/vdbevtab.c f99b275366c5fc5e2d99f734729880994ab9500bdafde7fae3b02d562b9d323c
+F src/vtab.c 54b6ab9f5ab772f56e9f3a95543207943e775ec699b7cbbfd3a99c264cad377f
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
-F src/wal.c 04c3d2a673192016a671eb051a1900945a8c7331f4378636a8bfb70e8e596c84
+F src/wal.c 7a05a519a02ffb7f2a458838a25853c7300c9e6d9ef546ee48469378ac0404f9
F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
F src/walker.c 3df26a33dc4f54e8771600fb7fdebe1ece0896c2ad68c30ab40b017aa4395049
-F src/where.c 9546c82056e8cdb27291f98cf1adca5d271240b399bb97b32f77fc2bea6146c9
+F src/where.c 2ea911238674e9baaeddf105dddabed92692a01996073c4d4983f9a7efe481f9
F src/whereInt.h 6b874aa15f94e43a2cec1080be64d955b04deeafeac90ffb5d6975c0d511be3c
-F src/wherecode.c 7b939de85d65cc4b4bfa197513136b9e0ae03167e3b82842ca5a0ba1055ba65d
+F src/wherecode.c 8064fe5c042824853a9b1fda670054a51a49033a6c79059988c97751ccf8088e
F src/whereexpr.c 264d58971eaf8256eb5b0917bcd7fc7a1f1109fdda183a8382308a1b18a2dce7
-F src/window.c 66c5fd1e48af7581cf90b97700268294f4da4037f120f367715f912e1148d3f9
+F src/window.c edd6f5e25a1e8f2b6f5305b7f5f7da7bb35f07f0d432b255b1d4c2fcab4205aa
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
-F test/aggnested.test 12106f0748e8e9bfc1a8e6840e203e051eae06a26ed13fc9fd5db108a8d6db54
+F test/aggnested.test 2f65ec8132e0ca896de550b9908094d49ad65a99116a9d79deeb6017604ad4f6
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
F test/all.test 2ecb8bbd52416642e41c9081182a8df05d42c75637afd4488aace78cc4b69e13
F test/alter.test 25e109787dc5e631e117eb6e1c57f96a572bb51228db3b4f8b5f41d665e2ccaa
@@ -644,9 +646,9 @@ F test/altercol.test 1d6a6fe698b81e626baea4881f5717f9bc53d7d07f1cd23ee7ad1b931f1
F test/alterlegacy.test 82022721ce0de29cedc9a7af63bc9fcc078b0ee000f8283b4b6ea9c3eab2f44b
F test/altermalloc.test 167a47de41b5c638f5f5c6efb59784002b196fff70f98d9b4ed3cd74a3fb80c9
F test/altermalloc2.test fa7b1c1139ea39b8dec407cf1feb032ca8e0076bd429574969b619175ad0174b
-F test/altertab.test 523ba6368e0da19f462f7c05563c569675736d946724cac1c4ae848f76783434
+F test/altertab.test b8b2104212e8ea87c75c3cbe3cb78ed7236a6c828ee2e59ed09d3dbe9812d002
F test/altertab2.test b0d62f323ca5dab42b0bc028c52e310ebdd13e655e8fac070fe622bad7852c2b
-F test/altertab3.test 155b8dc225ce484454a7fb4c8ba745680b6fa0fc3e08919cbbc19f9309d128ff
+F test/altertab3.test d0d51e652aaa11e37de1f1215181d88334fefcb185f3b9bd91e06e98260c4694
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
F test/analyze.test 547bb700f903107b38611b014ca645d6b5bb819f5210d7bf39c40802aafeb7d7
F test/analyze3.test 01f0b122e3e54ad2544f14f7cc7dcb4c2cb8753cad5e88c6b8d49615b3fd6a2b
@@ -670,7 +672,7 @@ F test/async5.test 383ab533fdb9f7ad228cc99ee66e1acb34cc0dc0
F test/atof1.test 1ccfc96a6888566597b83d882c81b3c04258dc39317e8c1cec89ba481eaa2fba
F test/atomic.test 065a453dde33c77ff586d91ccaa6ed419829d492dbb1a5694b8a09f3f9d7d061
F test/atomic2.test b6863b4aa552543874f80b42fb3063f1c8c2e3d8e56b6562f00a3cc347b5c1da
-F test/atrc.c ec92d56d8fbed9eb3e11aaf1ab98cf7dd59e69dae31f128013f1d97e54e7dfed
+F test/atrc.c c388fac43dbba05c804432a7135ae688b32e8f25818e9994ffba4b64cf60c27c
F test/attach.test d42862c72fef3d54367d962d41dcfb5363442a4a1bd898c22ae950cea1aa0dd3
F test/attach2.test 256bd240da1835fb8408dd59fb7ef71f8358c7a756c46662434d11d07ba3a0ce
F test/attach3.test c59d92791070c59272e00183b7353eeb94915976
@@ -728,6 +730,7 @@ F test/btree01.test e08b3613540145b353f20c81cb18ead54ff12e0f
F test/btree02.test 7555a5440453d900410160a52554fe6478af4faf53098f7235f1f443d5a1d6cc
F test/btreefault.test c2bcb542685eea44621275cfedbd8a13f65201e3
F test/busy.test 510dc6daaad18bcbbc085bcc6217d6dc418def5e73f72ce1475eea0cb7834727
+F test/busy2.test 2499cb62c9e58e18335892602c158cb35639c411803adca6423401b31e46c503
F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de
F test/cacheflush.test af25bb1509df04c1da10e38d8f322d66eceedf61
F test/cachespill.test 895997f84a25b323b166aecb69baab2d6380ea98f9e0bcc688c4493c535cfab9
@@ -764,7 +767,7 @@ F test/conflict3.test 81865d9599609aca394fb3b9cd5f561d4729ea5b176bece3644f6ecb54
F test/contrib01.test 2a1cbc0f2f48955d7d073f725765da6fbceda6b4
F test/corrupt.test d7cb0300e4a297147b6a05e92a1684bc8973635c3bcaa3d66e983c9cbdbf47a3
F test/corrupt2.test bb50042cf9a1f1023d73af325d47eb02a6bb11e3c52f8812644b220c5d4bca35
-F test/corrupt3.test f95d7bf78109e0b84eb285a787ce91a3fd6a2dd7d0cb55882abff3bdc081a57e
+F test/corrupt3.test 2520432b1fbf99994841e69804a3c59fb828183f4d09b85a1631bc7adca17e31
F test/corrupt4.test 8d1d86b850fcc43e417450454f2044e52d55778a
F test/corrupt5.test 387be3250795e2a86e6234745558b80efb248a357d0cd8e53bce75c7463f545d
F test/corrupt6.test fc6a891716139665dae0073b6945e3670bf92568
@@ -782,9 +785,9 @@ F test/corruptH.test 79801d97ec5c2f9f3c87739aa1ec2eb786f96454
F test/corruptI.test a17bbf54fdde78d43cf3cc34b0057719fd4a173a3d824285b67dc5257c064c7b
F test/corruptJ.test 4d5ccc4bf959464229a836d60142831ef76a5aa4
F test/corruptK.test 5b4212fe346699831c5ad559a62c54e11c0611bdde1ea8423a091f9c01aa32af
-F test/corruptL.test 13ef74a93223af25015d223add0df4c2d375f0b958b546a2a72033f2fdab7a70
+F test/corruptL.test e1a85214e2448ed0baa1810af86ff94d6c359d2677e4867780786d0c61546484
F test/corruptM.test 7d574320e08c1b36caa3e47262061f186367d593a7e305d35f15289cc2c3e067
-F test/cost.test 51f4fcaae6e78ad5a57096831259ed6c760e2ac6876836e91c00030fad385b34
+F test/cost.test 1d156ce9858780a966c062694687afe0343a0ed12d081d071fb57027e726bafc
F test/count.test e0699a15712bc2a4679d60e408921c2cce7f6365a30340e790c98e0f334a9c77
F test/countofview.test e17d6e6688cf74f22783c9ec6e788c0790ee4fbbaee713affd00b1ac0bb39b86
F test/coveridxscan.test 5ec98719a2e2914e8908dc75f7247d9b54a26df04625f846ac7900d5483f7296
@@ -809,12 +812,13 @@ F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373
F test/date2.test 5ef8265c71460cda6b1698bf18f4bb0ffb40ac08c5092f6afe84d398c2feb5be
F test/dbdata.test 042f49acff3438f940eeba5868d3af080ae64ddf26ae78f80c92bec3ca7d8603
F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
-F test/dbfuzz001.test 42aad1dcef6219fbee86a9b7d08832c9bbb2e41508f6f128ae91745927276292
+F test/dbfuzz001.test 55e1a3504f8dea84155e09912fe3b1c3ad77e0b1a938ec42ca03b8e51b321e30
F test/dbfuzz2-seed1.db e6225c6f3d7b63f9c5b6867146a5f329d997ab105bee64644dc2b3a2f2aebaee
-F test/dbfuzz2.c c2c9cb40082a77b7e95ffb8b2da1e93322efadfb1c8c1e0001c95a0af1e156c2
+F test/dbfuzz2.c 40cc4600947f30600f0ab365a2714ec76a899c9adb2c0ccd63ba583b2f71390e
F test/dbpage.test 650234ba683b9d82b899c6c51439819787e7609f17a0cc40e0080a7b6443bc38
F test/dbstatus.test 4a4221a883025ffd39696b3d1b3910b928fb097d77e671351acb35f3aed42759
F test/dbstatus2.test f5fe0afed3fa45e57cfa70d1147606c20d2ba23feac78e9a172f2fe8ab5b78ef
+F test/decimal.test fcf403fd5585f47342234e153c4a4338cd737b8e0884ac66fc484df47dbcf1a7
F test/default.test 9687cfb16717e4b8238c191697c98be88c0b16e568dd5368cd9284154097ef50
F test/delete.test 31832b0c45ecb51a54348c68db173be462985901e6ed7f403d6d7a8f70ab4ef0
F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa
@@ -835,10 +839,10 @@ F test/e_blobwrite.test f87ff598b67af5b3ec002a8d83e804dc8d23808e88cf0080c176612f
F test/e_changes.test fd66105385153dbf21fdb35eb8ef6c3e1eade579
F test/e_createtable.test ea27082d6f84df61e1d9e383f3fd79220418856a4a8afc41af75d458b8e7ac33
F test/e_delete.test ab39084f26ae1f033c940b70ebdbbd523dc4962e
-F test/e_droptrigger.test 3cd080807622c13e5bbb61fc9a57bd7754da2412
+F test/e_droptrigger.test 235c610f8bf8ec44513e222b9085c7e49fad65ad0c1975ac2577109dd06fd8fa
F test/e_dropview.test 74e405df7fa0f762e0c9445b166fe03955856532e2bb234c372f7c51228d75e7
F test/e_expr.test 62000e6675d5bcf4b09276fe011a27779629ff8f6678ba5937fb6f1b78d645ff
-F test/e_fkey.test b497feb7c436693e16a36cdaba8d81ffe12f23659d139ee71dfa57c0c52d1e5b
+F test/e_fkey.test 0b458b85f192cdb9e9933d5891848bb19bcc44d3f49faf111a375f2844a164d3
F test/e_fts3.test 17ba7c373aba4d4f5696ba147ee23fd1a1ef70782af050e03e262ca187c5ee07
F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e
F test/e_reindex.test 2b0e29344497d9a8a999453a003cb476b6b1d2eef2d6c120f83c2d3a429f3164
@@ -872,7 +876,7 @@ F test/extraquick.test cb254400bd42bfb777ff675356aabf3287978f79
F test/fallocate.test 37a62e396a68eeede8f8d2ecf23573a80faceb630788d314d0a073d862616717
F test/filectrl.test 6e871c2d35dead1d9a88e176e8d2ca094fec6bb3
F test/filefmt.test f393e80c4b8d493b7a7f8f3809a8425bbf4292af1f5140f01cb1427798a2bbd4
-F test/filter1.test 8a6f047a000ef391db2ca17b6beecc0006f4e0f9ca8bbe272b2443c7316e66b1
+F test/filter1.test 6c483ecf7886c8843a8612c021aa23f33c581f584151f251842b3a3592c95ac8
F test/filter2.tcl 44e525497ce07382915f01bd29ffd0fa49dab3adb87253b5e5103ba8f93393e8
F test/filter2.test 485cf95d1f6d6ceee5632201ca52a71868599836f430cdee42e5f7f14666e30a
F test/filterfault.test c08fb491d698e8df6c122c98f7db1c65ffcfcad2c1ab0e07fa8a5be1b34eaa8b
@@ -880,7 +884,7 @@ F test/fkey1.test d11dbb8a93ead9b5c46ae5d02da016d61245d47662fb2d844c99214f6163f7
F test/fkey2.test b1b6a8c5556dc0ccf31291b1fed8aa57e404b38f3236110e19ab4dc6aa93edf2
F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
-F test/fkey5.test 24dd28eb3d9f1b5a174f47e9899ace5facb08373a4223593c8c631e6cf9f7d5a
+F test/fkey5.test 6727452e163a427147e84e739da18713da553d79f9783559b04fdcd36d5c7421
F test/fkey6.test d078a1e323a740062bed38df32b8a736fd320dc0
F test/fkey7.test 64fb28da03da5dfe3cdef5967aa7e832c2507bf7fb8f0780cacbca1f2338d031
F test/fkey8.test 48ef829d63f5f7b37aabd4df9363ac05f65539d1da8c4a44251631769d920579
@@ -948,10 +952,11 @@ F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958
F test/fts3comp1.test a0f5b16a2df44dd0b15751787130af2183167c0c
F test/fts3conf.test c84bbaec81281c1788aa545ac6e78a6bd6cde2bdbbce2da261690e3659f5a76b
F test/fts3corrupt.test 79a32ffdcd5254e2f7fa121d9656e61949ad049c3c6554229911b7ceac37c9c6
-F test/fts3corrupt2.test bf55c3fa0b0dc8ea1c0fe5543623bd27714585da6a129038fd6999fe3b0d25f3
+F test/fts3corrupt2.test e318f0676e5e78d5a4b702637e2bb25265954c08a1b1e4aaf93c7880bb0c67d0
F test/fts3corrupt3.test 0d5b69a0998b4adf868cc301fc78f3d0707745f1d984ce044c205cdb764b491f
-F test/fts3corrupt4.test fde292a4712753c7ef235a199273c5d196e18a56bd2c4d2db7ccaf59b7027a0a
+F test/fts3corrupt4.test e4662d37f02248301d8b58778eac380663e09a17a38dd5d6bb5ea4c927b9a575
F test/fts3corrupt5.test 0549f85ec4bd22e992f645f13c59b99d652f2f5e643dac75568bfd23a6db7ed5
+F test/fts3corrupt6.test b6c55218b704b0cef224b284c756f9c55d0afd0b3c3837618bffeaa8c31e0d8e
F test/fts3cov.test 7eacdbefd756cfa4dc2241974e3db2834e9b372ca215880e00032222f32194cf
F test/fts3d.test 2bd8c97bcb9975f2334147173b4872505b6a41359a4f9068960a36afe07a679f
F test/fts3defer.test f4c20e4c7153d20a98ee49ee5f3faef624fefc9a067f8d8d629db380c4d9f1de
@@ -1009,6 +1014,7 @@ F test/fts4record.test a48508f69a84c9287c8019d3a1ae712f5730d8335ffaf8e2101e691d0
F test/fts4rename.test 15fd9985c2bce6dea20da2245b22029ec89bd4710ed317c4c53abbe3cfd0c880
F test/fts4umlaut.test fcaca4471de7e78c9d1f7e8976e3e8704d7d8ad979d57a739d00f3f757380429
F test/fts4unicode.test ceca76422abc251818cb25dabe33d3c3970da5f7c90e1540f190824e6b3a7c95
+F test/fts4upfrom.test 8df5acb6e10ad73f393d1add082b042ab1db72567888847d098152121e507b34
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
F test/func.test f673822636fb8ed618dd2b80230d16e495d19c8f2e2e7d6c22e93e2b3de097ad
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
@@ -1031,20 +1037,20 @@ F test/fuzzdata4.db b502c7d5498261715812dd8b3c2005bad08b3a26e6489414bd13926cd3e4
F test/fuzzdata5.db e35f64af17ec48926481cfaf3b3855e436bd40d1cfe2d59a9474cb4b748a52a5
F test/fuzzdata6.db 92a80e4afc172c24f662a10a612d188fb272de4a9bd19e017927c95f737de6d7
F test/fuzzdata7.db 0166b56fd7a6b9636a1d60ef0a060f86ddaecf99400a666bb6e5bbd7199ad1f2
-F test/fuzzdata8.db 209623791b0ad72ab39110c867af2080a79004e493c4da14ad661e790b5d1ed8
+F test/fuzzdata8.db 99f99201280962430f3287e879e050ba88fe458d05cbf28e37ecab369ffe2e86
F test/fuzzer1.test 3d4c4b7e547aba5e5511a2991e3e3d07166cfbb8
F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536
F test/gcfault.test dd28c228a38976d6336a3fc42d7e5f1ad060cb8c
-F test/gencol1.test e89eafdf03245e2609ddf6e9b0add37a17ce229095836c409131764c3a5282a5
+F test/gencol1.test b05e6c5edb9b10d48efb634ed07342441bddc89d225043e17095c36e567521a0
F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
F test/having.test e4098a4b8962f9596035c3b87a8928a10648acc509f1bb8d6f96413bbf79a1b3
F test/hexlit.test 4a6a5f46e3c65c4bf1fa06f5dd5a9507a5627751
F test/hidden.test 23c1393a79e846d68fd902d72c85d5e5dcf98711
-F test/hook.test 1604b3b2f5931430087540404555c1b6be3618600b81558657c66b533ed70b13
+F test/hook.test e97382e68e4379838e888756d653afd159f5f14780315ff97b70360d3d8485bc
F test/hook2.test b9ff3b8c6519fb67f33192f1afe86e7782ee4ac8
F test/icu.test 716a6b89fbabe5cc63e0cd4c260befb08fd7b9d761f04d43669233292f0753b1
-F test/ieee754.test 806fc0ce7f305f57e3331eaceeddcfec9339e607
+F test/ieee754.test b0945d12be7d255f3dfa18e2511b17ca37e0edd2b803231c52d05b86c04ab26e
F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8
F test/in.test ae4ba0fe3232fdd84ef1090a68c5cd6ccd93f1f8774d5c967dd0c1b301492eed
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
@@ -1069,10 +1075,10 @@ F test/index3.test 51685f39345462b84fcf77eb8537af847fdf438cc96b05c45d6aaca4e473a
F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6
F test/index5.test 8621491915800ec274609e42e02a97d67e9b13e7
F test/index6.test f172653b35b20233e59200e8b92a76db61bf7285437bf777b93b306ba26a47e7
-F test/index7.test 1d764c0cca45f5a76150b08e127ccc8d52492cfa788b5fafed4be784a351b020
+F test/index7.test b8a0ba2110fd517bb48c4e76d26d60f1ab2ed9e257b18d71f820d7e71e9f8570
F test/index8.test bc2e3db70e8e62459aaa1bd7e4a9b39664f8f9d7
F test/index9.test 0aa3e509dddf81f93380396e40e9bb386904c1054924ba8fa9bcdfe85a8e7721
-F test/indexedby.test a52c8c6abfae4fbfb51d99440de4ca1840dbacc606b05e29328a2a8ba7cd914e
+F test/indexedby.test f54aac21c06948872010a956fd02de5178c362c7785a9887cf0b8616be17883b
F test/indexexpr1.test 284e119999d132cc8bf37735a928c9859b28e8e295d02b7a6a4f93977c7f9ba5
F test/indexexpr2.test dba11dbb0a58fcba4cd694f46b4004976123b81b0501f525d43c9be59f0207b1
F test/indexfault.test 98d78a8ff1f5335628b62f886a1cb7c7dac1ef6d48fa39c51ec871c87dce9811
@@ -1097,7 +1103,7 @@ F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd
F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4
F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b
-F test/istrue.test 75327829744e65cc8700e69340b8e6c192e10e39dfae7ccb0e970d3c4f49090a
+F test/istrue.test 06f92ea38750fa74df7dbbe6920205251c2310861fbbe23a3adfa918a2e2ba74
F test/join.test bca044589e94bb466e4c1e91fb6fecdc3f3326ca6b3f590f555f1958156eb321
F test/join2.test 7d24d095ab88d3910228d53a3b548b7baf2e0e7d8aac6731a273e300e1b34b61
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
@@ -1116,7 +1122,7 @@ F test/json103.test aff6b7a4c17d5a20b487a7bc1a274bfdc63b829413bdfb83bedac42ec7f6
F test/json104.test 317f4ec4b2d87afbba4d2460cf5be297aea76f2285eb618d276dbcd40a50950f
F test/json105.test 45f7d6a9a54c85f8a9589b68d3e7a1f42d02f2359911a8cdbad1f9988f571173
F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff
-F test/kvtest.c 94da54bb66aae7a54e47cf7e4ea4acecc0f217560f79ad3abfcc0361d6d557ba
+F test/kvtest.c feb4358fb022da8ebd098c45811f2f6507688bb6c43aa72b3e840df19026317b
F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63
F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
F test/lemon-test01.y 58b764610fd934e189ffbb0bbfa33d171b9cb06019b55bdc04d090d6767e11d7
@@ -1179,7 +1185,7 @@ F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d
F test/misc4.test 10cd6addb2fa9093df4751a1b92b50440175dd5468a6ec84d0386e78f087db0e
F test/misc5.test c4aeaa0fa28faa08f2485309c38db4719e6cd1364215d5687a5b96d340a3fa58
F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
-F test/misc7.test 4f21954012e4eb0a923c54a311f38c81bf6798ccdd7b51584db46d4007f63daa
+F test/misc7.test 7b4c88c1d5ea8c8b9d537d212c08a0343d345fdd5c789598692c1c0e60fbda69
F test/misc8.test 8782708f4c8a459591c3e8fe1215bd2048bffb4024b3df249e9b9ed407dc61ed
F test/misuse.test 9e7f78402005e833af71dcab32d048003869eca5abcaccc985d4f8dc1d86bcc7
F test/mjournal.test 28a08d5cb5fb5b5702a46e19176e45e964e0800d1f894677169e79f34030e152
@@ -1193,7 +1199,7 @@ F test/multiplex.test dc0d67b66f84b484a83cb8bbdf3f0a7f49562ccd
F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a
F test/multiplex3.test d228f59eac91839a977eac19f21d053f03e4d101
F test/multiplex4.test e8ae4c4bd70606a5727743241f13b5701990abe4
-F test/mutex1.test ea2cc74d97f077b9e74c84cbd024f14d79a8126f
+F test/mutex1.test 177db2e4edb530f2ff21edc52ac79a412dbe63e4c47c3ae9504d3fb4f1ce81fa
F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
F test/nan.test 437d40e6d0778b050d7750726c0cbd2c9936b81962926e8f8c48ca698f00f4d1
F test/nockpt.test 8c43b25af63b0bd620cf1b003529e37b6f1dc53bd22690e96a1bd73f78dde53a
@@ -1209,7 +1215,7 @@ F test/numcast.test 5d126f7f581432e86a90d1e35cac625164aec4a1
F test/numindex1.test 20a5450d4b056e48cd5db30e659f13347a099823
F test/offset1.test f06b83657bcf26f9ce805e67450e189e282143b2
F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394
-F test/optfuzz-db01.c a0c256905c8ac79f9a5de2f374a3d9f757bef0dca2a238dc7c10cc8a38031834
+F test/optfuzz-db01.c 9f2fa80b8f84ebbf1f2e8b13421a4e0477fe300f6686fbd76cac1d2db66e0fdc
F test/optfuzz-db01.txt 21f6bdeadc701cf11528276e2a55c70bfcb846ba42df327f979bd9e7b6ce7041
F test/optfuzz.c 50e330304eb1992e15ddd11f3daaad9bcc0d9aaad09cb2bcc77f9515df2e88b1
F test/orderby1.test 6bf0ce45cbfb1cf4779dd418ac5e8cf66abfa04de2c1d2edf1e0e85f1520d8f3
@@ -1226,7 +1232,7 @@ F test/oserror.test 1fc9746b83d778e70d115049747ba19c7fba154afce7cc165b09feb6ca6a
F test/ossfuzz.c 9636dad2092a05a32110df0ca06713038dd0c43dd89a77dabe4b8b0d71096715
F test/ossshell.c f125c5bd16e537a2549aa579b328dd1c59905e7ab1338dfc210e755bb7b69f17
F test/ovfl.test 199c482696defceacee8c8e0e0ef36da62726b2f
-F test/pager1.test 1e9ee778bdeaf4f7f09997d029cdaca6a42dfc2092edafe4f5e590acbf1eab13
+F test/pager1.test 4fba160bf450cea19f6bf1d6483ef467545bac6405570e176c83c2c4b5d6d0d5
F test/pager2.test 67b8f40ae98112bcdba1f2b2d03ea83266418c71
F test/pager3.test 4e9a83d6ca0838d7c602c9eb93d1357562d9059c1e02ffb138a8271020838370
F test/pager4.test a122e9e6925d5b23b31e3dfef8c6a44bbf19590e
@@ -1239,16 +1245,16 @@ F test/parser1.test 6ccdf5e459a5dc4673d3273dc311a7e9742ca952dd0551a6a6320d27035c
F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b
F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
-F test/permutations.test c83339862d72b6272f957905205f874e6eefdbad2823380452c4f0128fd3d906
-F test/pg_common.tcl 222a1bad1c41c308fa366313cd7b51b3be7e9b21c8736a421b974ac941693b54
-F test/pragma.test 59becdfd720b80d463ab750f69f7118fde10dfd556aa5d554f3bf6b7e5ea7533
+F test/permutations.test 4d174cfc92e31aff96a383dac767a94d649566b73857875afb7511e3e430d5f5
+F test/pg_common.tcl 3b27542224db1e713ae387459b5d117c836a5f6e328846922993b6d2b7640d9f
+F test/pragma.test 50b91bedea9324d3ab48e793f908ee7d2c7dcf84bfa2281e792838be59641ec8
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
F test/pragma3.test 92a46bbea12322dd94a404f49edcfbfc913a2c98115f0d030a7459bb4712ef31
-F test/pragma4.test 10c624e45a83c0096a82a7579a5ff658542391d3b77355192da6572c8c17c00b
+F test/pragma4.test ca5e4dfc46adfe490f75d73734f70349d95a199e6510973899e502eef2c8b1f8
F test/pragma5.test 7b33fc43e2e41abf17f35fb73f71b49671a380ea92a6c94b6ce530a25f8d9102
F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8
F test/prefixes.test b524a1c44bffec225b9aec98bd728480352aa8532ac4c15771fb85e8beef65d9
-F test/printf.test 1e0e469f5f8a09afa8a182f34647e3d9b8c01978cbbe2313a194ccc3a8471506
+F test/printf.test 390d0d7fcffc3c4ea3c1bb4cbb267444e32b33b048ae21895f23a291844fe1da
F test/printf2.test 30b5dd0b4b992dc5626496846ecce17ff592cacbcb11c3e589f3ac4d7e129dae
F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
@@ -1317,14 +1323,14 @@ F test/securedel.test 2f70b2449186a1921bd01ec9da407fbfa98c3a7a5521854c300c194b2f
F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5
F test/select1.test 009a6d8eacd9684d046302b8d13b50846a87e39d6f08e92178aa13e95ea29a2d
F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56
-F test/select3.test ddd1bc6d0c8dece136321c11bd26d0d8ad17f2b27c72935fdd6574d8cb99d1d4
+F test/select3.test c49fbb758903f3718e2de5aa4655eda4838131cbea24a86db908f8b6889aa68c
F test/select4.test e8a2502e3623f3058871030599a48abb35789d2244d5b380ecf3696873fdd4a4
F test/select5.test df9ec0d218cedceb4fe7b63262025b547b50a55e59148c6f40b60ca25f1d4546
F test/select6.test 319d45e414cdd321bf17cfacedaf19e3935ad64dac357c53f1492338c6e9b801
F test/select7.test f659f231489349e8c5734e610803d7654207318f
F test/select8.test 8c8f5ae43894c891efc5755ed905467d1d67ad5d
F test/select9.test aebc2bb0c3bc44606125033cbcaac2c8d1f33a95
-F test/selectA.test b8a590f6493cad5b0bb4dfe1709bf7dcda0b6c40bb4caf32d1e36a89eebc8fc5
+F test/selectA.test 68de52409e45a3313d00b8461b48bef4fb729faf36ade9067a994eae55cc86f4
F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25
F test/selectC.test e25243f8ca503e06f252eb0218976d07cfeceac3
F test/selectD.test fc20452847a01775710090383cfb4423275d2f745fed61f34fbf37573ac0d214
@@ -1334,7 +1340,7 @@ F test/selectG.test 089f7d3d7e6db91566f00b036cb353107a2cca6220eb1cb264085a836dae
F test/server1.test c2b00864514a68a0e6fd518659dc95d0050307a357a08969872bef027d785dc4
F test/session.test 78fa2365e93d3663a6e933f86e7afc395adf18be
F test/sessionfuzz-data1.db 1f8d5def831f19b1c74571037f0d53a588ea49a6c4ca2a028fc0c27ef896dbcb
-F test/sessionfuzz.c be9c4d4afd359ce80024d8b541b9b8a880510aef5cf263df56fc0e9b947727f1
+F test/sessionfuzz.c f74c4e806bab5a093fb9c11b6123d17a6e0cf73fb7a0f49b12f5a75bf0b7b1a8
F test/shared.test 1826673eb5eb745fb91a3bdac99a7737057742ae38dcb0fe076a384d6727578b
F test/shared2.test 03eb4a8d372e290107d34b6ce1809919a698e879
F test/shared3.test ab693f9b6e156b8bfb2a0ad94f29fe69602a5d38
@@ -1347,7 +1353,7 @@ F test/sharedA.test 49d87ec54ab640fbbc3786ee3c01de94aaa482a3a9f834ad3fe92770eb69
F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
-F test/shell1.test 5bd10014ec494744f5e966a1521334e9d612119a0afcfa5251684a4e1f2ffc66
+F test/shell1.test a1cf47c5e110560ff25a714570bfd53bfaceeb61db5cad3072a4064f17ebd10e
F test/shell2.test e242a9912f44f4c23c3d1d802a83e934e84c853b
F test/shell3.test ac8c2b744014c3e9a0e26bfd829ab65f00923dc1a91ffd044863e9423cc91494
F test/shell4.test 1c6aef11daaa2d6830acaba3ac9cbec93fbc1c3d5530743a637f39b3987d08ce
@@ -1388,7 +1394,7 @@ F test/speed3.test 694affeb9100526007436334cf7d08f3d74b85ef
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
F test/speed4p.test 377a0c48e5a92e0b11c1c5ebb1bc9d83a7312c922bc0cb05970ef5d6a96d1f0c
-F test/speedtest1.c d564e7689a731f691adfe2cf3f3f735d3e11f100eebb065e2a0a267fdc39fb26
+F test/speedtest1.c ac0e6ebadb97b54b7ac45288d1beea633a219d5fb98aa3395cb8364c31c985cb
F test/spellfix.test 951a6405d49d1a23d6b78027d3877b4a33eeb8221dcab5704b499755bb4f552e
F test/spellfix2.test dfc8f519a3fc204cb2dfa8b4f29821ae90f6f8c3
F test/spellfix3.test 0f9efaaa502a0e0a09848028518a6fb096c8ad33
@@ -1396,7 +1402,7 @@ F test/spellfix4.test 51c7c26514ade169855c66bcf130bd5acfb4d7fd090cc624645ab275ae
F test/sqldiff1.test 28cd737cf1b0078b1ec1bbf425e674c47785835e
F test/sqllimits1.test 264f4b0f941800ba139d25e33ee919c5d95fea06dfbe8ac291d6811a30984ca5
F test/sqllog.test 6af6cb0b09f4e44e1917e06ce85be7670302517a
-F test/stat.test 423257dc36e5865fb9dd1d9051ac985763b6fba1daec134932f37772d5ed1e64
+F test/stat.test 15a3106eddedfc882f64bc09f237b4169be4b92dd57c93031b8ff8b13af3e7c5
F test/statfault.test f525a7bf633e50afd027700e9a486090684b1ac1
F test/stmt.test 54ed2cc0764bf3e48a058331813c3dbd19fc1d0827c3d8369914a5d8f564ec75
F test/stmtvtab1.test 6873dfb24f8e79cbb5b799b95c2e4349060eb7a3b811982749a84b359468e2d5
@@ -1429,7 +1435,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
F test/temptable2.test d2940417496e2b9548e01d09990763fbe88c316504033256d51493e1f1a5ce6a
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
-F test/tester.tcl fd9d134a7cc4e31b307ad028a195f51cdcf556fc620d74b680515562f0137f25
+F test/tester.tcl 6417cbb60c4169804e2e1b36ce1a840c9f33d0b0d97956e058f3cc49ed3904f0
F test/thread001.test b61a29dd87cf669f5f6ac96124a7c97d71b0c80d9012746072055877055cf9ef
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
@@ -1611,12 +1617,13 @@ F test/triggerD.test 8e7f3921a92a5797d472732108109e44575fa650
F test/triggerE.test ede2e4bce4ba802337bd69d39447fa04a938e06d84a8bfc53c76850fc36ed86d
F test/triggerF.test 5d76f0a8c428ff87a4d5ed52da06f6096a2c787a1e21b846111dfac4123de3ad
F test/triggerG.test 2b816093c91ba73c733cfa8aedcc210ad819d72a98b1da30768a3c56505233e9
+F test/triggerupfrom.test d25961fa70a99b6736193da7b49a36d8c1d28d56188f0be6406d4366315cd6e4
F test/trustschema1.test 4e970aef0bfe0cee139703cc7209d0e0f07725d999b180ba50770f49edef1494
F test/tt3_checkpoint.c 9a7fe00e07700af027769d83ef67ab727927ae6c865ecdc71fe8011194200c53
F test/tt3_index.c 95592839426dc85ce5a7a57b41be2cbf3c2ec3457b9cd841a06ed5877f712c7c
F test/tt3_lookaside1.c 2ddd99bfffeef288f0786827ef68f912f6f47ce3d3184e62f05808d8e13b920e
F test/tt3_reuseschema.c 4d52e141f89f009028d8ab0bd1f0697d0edffa94bafc1fff0f7ad4d9d9baa549
-F test/tt3_stress.c bbd430f23fa64f466ea8f212756f5f7135a2f8ff5accad85550c0ba73be76b16
+F test/tt3_stress.c 077e817ac1168443b075fedb44e92db84bb4dc5bd3b6fe1aba25c94ac280b231
F test/tt3_vacuum.c ca42adcf8a671abbe34338b828464269e21758a6b4857b889dabfd39a3206d98
F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
F test/types2.test 1aeb81976841a91eef292723649b5c4fe3bc3cac
@@ -1629,6 +1636,11 @@ F test/unixexcl.test d936ba2b06794018e136418addd59a2354eeae97
F test/unordered.test ffeea7747d5ba962a8009a20b7e53d68cbae05b063604c68702c5998eb50c981
F test/update.test e906ca7cb1dc6f52af1ea243e08f727edfa79f924c2691f2f9e72481f847310d
F test/update2.test 67455bc61fcbcf96923c45b3bc4f87bc72be7d67575ad35f134906148c7b06d3
+F test/upfrom1.tcl 8859d9d437f03b44174c4524a7a734a391fd4526fcff65be08285dafc9dc9041
+F test/upfrom1.test d18f69f7c691bc791e7f31bf0e354eeff04cf2f44edc32d6b1928bad71697073
+F test/upfrom2.test 6ebd3be8c3fac984e89a177d823686f04605b512fc167392bce6d8ba2ba63325
+F test/upfrom3.test 7dab379d128e8dd7beb2055b295fb113c7ba93e8c2038f5ddb7a4a10f0ebb348
+F test/upfromfault.test 70ecf8eb85559727a487283f69374e3ae39879e994d8a2437c49d7c05ecb70c9
F test/upsert1.test 88f9e258c6a0eeeb85937b08831e8daad440ba41f125af48439e9d33f266fb18
F test/upsert2.test 9c3cdbb1a890227f6504ce4b0e3de68f4cdfa16bb21d8641208a9239896c5a09
F test/upsert3.test 88d7d590a1948a9cb6eac1b54b0642f67a9f35a1fc0f19b200e97d5d39e3179c
@@ -1671,7 +1683,7 @@ F test/vtab_err.test dcc8b7b9cb67522b3fe7a272c73856829dae4ab7fdb30399aea1b6981bd
F test/vtab_shared.test 5253bff2355a9a3f014c15337da7e177ab0ef8ad
F test/vtabdrop.test 65d4cf6722972e5499bdaf0c0d70ee3b8133944a4e4bc31862563f32a7edca12
F test/wal.test 16180bc4becda176428ad02eaea437b4b8f5ae099314de443a4e12b2dcc007a2
-F test/wal2.test 537f59e5c5932e3b45bf3591ae3e48a2601360c2e52821b633e222fe6ebd5b09
+F test/wal2.test 31f6e2c404b9f2cdf9ca19b105a1742fdc19653c2c936da39e3658c617524046
F test/wal3.test 2a93004bc0fb2b5c29888964024695bade278ab2
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
F test/wal5.test 9c11da7aeccd83a46d79a556ad11a18d3cb15aa9
@@ -1696,7 +1708,7 @@ F test/walmode.test cd6e7cff618eaaa5910ce57c3657aa50110397f86213886a2400afb9bfec
F test/walnoshm.test 84ca10c544632a756467336b7c3b864d493ee496
F test/waloverwrite.test dad2f26567f1b45174e54fbf9a8dc1cb876a7f03
F test/walpersist.test 8c6b7e3ec1ba91b5e4dc4e0921d6d3f87cd356a6
-F test/walprotocol.test a112aba0b79e3adeaa485fed09484b32c654e97df58e454aa8489ac2cd57bf84
+F test/walprotocol.test 1b3f922125e341703f6e946d77fdc564d38fb3e07a9385cfdc6c99cac1ecf878
F test/walprotocol2.test 7d3b6b4bf0b12f8007121b1e6ef714bc99101fb3b48e46371df1db868eebc131
F test/walro.test cb438d05ba0d191f10b688e39c4f0cd5b71569a1d1f4440e5bdf3c6880e08c20
F test/walro2.test 0e79dd15cbdb4f482c01ea248373669c732414a726b357d04846a816afafb768
@@ -1705,10 +1717,10 @@ F test/walsetlk.test 11f7fe792fdce54cf09874dab824e0627f2eedecfb9f7983e325606ec51
F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417
F test/walslow.test c05c68d4dc2700a982f89133ce103a1a84cc285f
F test/walthread.test 14b20fcfa6ae152f5d8e12f5dc8a8a724b7ef189f5d8ef1e2ceab79f2af51747
-F test/walvfs.test ca81c9f427e0e5434076dfa948fd1d8e6d5ddd192b2fb6991635d81da5f3f5d4
+F test/walvfs.test a2913001a83b19c1d20220e556cee14d87d47ecb6949b5e0a2e9e2590abecf1e
F test/wapp.tcl b440cd8cf57953d3a49e7ee81e6a18f18efdaf113b69f7d8482b0710a64566ec
F test/wapptest.tcl 3cca775aede0591756a1fc0da55bbb3715d8c363873fd2cfdd4d555b0a4af57d x
-F test/where.test 19c709c9f0f6ed12c23f909f6592aa55fba34269d5a2898537aa27a22b9ce650
+F test/where.test f5e62453537e5b335b69f3b09f8a02ce3328289fad5d866e25371284b837d78d
F test/where2.test 478d2170637b9211f593120648858593bf2445a1
F test/where3.test 2341a294e17193a6b1699ea7f192124a5286ca6acfcc3f4b06d16c931fbcda2c
F test/where4.test 4a371bfcc607f41d233701bdec33ac2972908ba8
@@ -1716,14 +1728,14 @@ F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
F test/where7.test 75722434c486ac9e74718caa6cce234f45ba34c0b6c0f9555b29eb8bb5f6ade1
F test/where8.test 461ca40265ed996a6305da99bb024b0e41602bb586acf544c08f95922358e49f
-F test/where9.test 2c554b97bbdb2fdf26c57099f60db8a52bfcf7c147f2c256f9798fa0e267ca85
+F test/where9.test 8e3e0ff42cc17156f52361a1c012281550d0d632912fec92d1d6df74db7a8e6d
F test/whereA.test 6c6a420ca7d313242f9b1bd471dc80e4d0f8323700ba9c78df0bb843d4daa3b4
F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
F test/whereC.test cae295158703cb3fc23bf1a108a9ab730efff0f6
F test/whereD.test c1c335e914e28b122e000e9310f02d2be83e1c9dbca2e29f46bd732703944d1b
F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f
F test/whereF.test 3d9412b1199d3e2bed34fcb76b4c48d0bf4df95d27e3f8dd27b6f8b4716d0d89
-F test/whereG.test c9378b285828754377ef47fbece7264018c0a3743e7eb686e89917bb9df10885
+F test/whereG.test 9363b2a97d914cb1b81aff5069ef0cf2a071a67e2b604eac6fe9c0114017d9aa
F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
F test/whereI.test a2874062140ed4aba9ffae76e6190a3df6fc73d1373fdfa8fd632945082a5364
F test/whereJ.test 88287550f6ee604422403b053455b1ad894eeaa5c35d348532dfa1439286cb9a
@@ -1732,12 +1744,12 @@ F test/whereL.test e05cedc9389c6f09ad55bd5999a3fddccebec90672fb989433c145dcdaf26
F test/wherefault.test 1374c3aa198388925246475f84ad4cd5f9528864
F test/wherelfault.test 9012e4ef5259058b771606616bd007af5d154e64cc25fa9fd4170f6411db44e3
F test/wherelimit.test 592081800806d297dd7449b1030c863d2883d6d42901837ccd2e5a9bd962edb0
-F test/wherelimit2.test 9bf0aa56cca40ea0e4c5e2915341355a2bbc0859ec4ce1589197fe2a9d94635f
+F test/wherelimit2.test 657a3f24aadee62d058c5091ea682dc4af4b95ffe32f137155be49799a58e721
F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2aeee74
F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972
F test/win32longpath.test 4baffc3acb2e5188a5e3a895b2b543ed09e62f7c72d713c1feebf76222fe9976
F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
-F test/window1.test 502a3e72fce895aaaa633bbe709f6de3c24eed3ecb8098ab9fb8b47584b4452c
+F test/window1.test e52b81fff0c3cb122a1240f336688eb81bea2967a99c4ddb78969adec7aadc2a
F test/window2.tcl 492c125fa550cda1dd3555768a2303b3effbeceee215293adf8871efc25f1476
F test/window2.test e466a88bd626d66edc3d352d7d7e1d5531e0079b549ba44efb029d1fbff9fd3c
F test/window3.tcl acea6e86a4324a210fd608d06741010ca83ded9fde438341cb978c49928faf03
@@ -1750,7 +1762,7 @@ F test/window7.tcl 6a1210f05d40ec89c22960213a22cd3f98d4e2f2eb20646c83c8c30d4d761
F test/window7.test 1d31276961ae7801edc72173edaf7593e3cbc79c06d1f1f09e20d8418af403cd
F test/window8.tcl f2711aa3571e4e6b0dad98db8d95fd6cb8d9db0c92bbdf535f153b07606a1ce2
F test/window8.test c4331b27a6f66d69fa8f8bab10cc731db1a81d293ae108a68f7c3487fa94e65b
-F test/window9.test c22c25377c820613e1842fe7ad4af7c03df625f6a7caee99e6fdb4fcd52e0a8b
+F test/window9.test 4d8c875b73febdbac9b8f2b52ec132b98f48261cdafd6b08db62bc6d8ff913fc
F test/windowA.test 6d63dc1260daa17141a55007600581778523a8b420629f1282d2acfc36af23be
F test/windowB.test 7a983ea1cc1cf72be7f378e4b32f6cb2d73014c5cd8b25aaee825164cd4269e5
F test/windowerr.tcl f5acd6fbc210d7b5546c0e879d157888455cd4a17a1d3f28f07c1c8a387019e0
@@ -1763,7 +1775,7 @@ F test/with4.test 257be66c0c67fee1defbbac0f685c3465e2cad037f21ce65f23f86084f1982
F test/withM.test 693b61765f2b387b5e3e24a4536e2e82de15ff64
F test/without_rowid1.test 9cfb83705c506e3849fa7efc88a3c9a15f9a50bf9b1516b41757a7cef9bba8c3
F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
-F test/without_rowid3.test f8e6b9f7cb32a3570bab743dd4f28d2000e2107808d57585e776f5c3eb076241
+F test/without_rowid3.test 96426a6c9a2a5cf62bbe55ea1ad038eaaf4bf743f40a1ad517233b8e5a3d4339
F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a
F test/without_rowid5.test 89b1c587bd92a0590e440da33e7666bf4891572a
F test/without_rowid6.test 8463b20098e9f75a501a9f17dfb42fffc79068eac0b2775fe56ef2281d2df45e
@@ -1782,26 +1794,27 @@ F tool/build-all-msvc.bat c12328d06c45fec8baada5949e3d5af54bf8c887 x
F tool/build-shell.sh 950f47c6174f1eea171319438b93ba67ff5bf367
F tool/cg_anno.tcl c1f875f5a4c9caca3d59937b16aff716f8b1883935f1b4c9ae23124705bc8099 x
F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2
-F tool/dbhash.c 19560c9a2aa2b269b6a5108259b93d26d12f8f0877c31fe9f8f61dfbd219ba63
+F tool/dbhash.c 5da0c61032d23d74f2ab84ffc5740f0e8abec94f2c45c0b4306be7eb3ae96df0
F tool/dbtotxt.c b2221864a20fb391c46bd31bc1fbdc4a96f5c8a89bef58f421eb9b9c36b1702c
F tool/dbtotxt.md c9a57af8739957ef36d2cfad5c4b1443ff3688ed33e4901ee200c8b651f43f3c
+F tool/enlargedb.c 3e8b2612b985cfa7e3e8800031ee191b43ae80de96abb5abbd5eada62651ee21
F tool/extract-sqlite3h.tcl 069ceab0cee26cba99952bfa08c0b23e35941c837acabe143f0c355d96c9e2eb x
F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2
-F tool/fast_vacuum.c 5ba0d6f5963a0a63bdc42840f678bad75b2ebce1
+F tool/fast_vacuum.c c129ae2924a48310c7b766810391da9e8fda532b9f6bd3f9a9e3a799a1b42af9
F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439
F tool/fuzzershell.c e1d90a03ca790d7c331c2aae08ca46ff435f1ae1faa6cb9cc48f4687c18fdc6e
F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4
F tool/genfkey.test b6afd7b825d797a1e1274f519ab5695373552ecad5cd373530c63533638a5a4f
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
-F tool/index_usage.c 9ec344d29cbeb03fdc0fce668eedfb7495792170de933adf95cf8d6904a166ad
+F tool/index_usage.c f62a0c701b2c7ff2f3e21d206f093c123f222dbf07136a10ffd1ca15a5c706c5
F tool/kvtest-speed.sh 4761a9c4b3530907562314d7757995787f7aef8f
-F tool/lemon.c a361b85fa230560b783006ac002a6a8bad214c3b9d7fa48980aecc2b691ddcad
+F tool/lemon.c 600a58b9d1b8ec5419373982428e927ca208826edacb91ca42ab94514d006039
F tool/lempar.c e8899b28488f060d0ff931539ea6311b16b22dce068c086c788a06d5e8d01ab7
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
F tool/logest.c 11346aa019e2e77a00902aa7d0cabd27bd2e8cca
F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439
-F tool/mkautoconfamal.sh 422fc365358a2e92876ffc62971a0ff28ed472fc8bcf9de0df921c736fdeca5e
+F tool/mkautoconfamal.sh f62353eb6c06ab264da027fd4507d09914433dbdcab9cb011cdc18016f1ab3b8
F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x
F tool/mkctimec.tcl dd183b73ae1c28249669741c250525f0407e579a70482371668fd5f130d9feb3
F tool/mkkeywordhash.c 11a3f3af8e787d0c5ca459ed66fe80fd09e661876506e7b978ec08c19477bdc2
@@ -1809,16 +1822,16 @@ F tool/mkmsvcmin.tcl 6ecab9fe22c2c8de4d82d4c46797bda3d2deac8e763885f5a38d0c44a89
F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
F tool/mkopcodeh.tcl 352a4319c0ad869eb26442bf7c3b015aa15594c21f1cce5a6420dbe999367c21
F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa
-F tool/mkpragmatab.tcl 44bcfb4aaff0a9a4f44b3ae71e2b3b2bb0cfb41f918d63f57a302da00aadb128
+F tool/mkpragmatab.tcl 37381569b5a5cd3269e3fdbc08829eb1a5f7c2a8e59ee7be8995127e5ef99e0d
F tool/mkshellc.tcl 70a9978e363b0f3280ca9ce1c46d72563ff479c1930a12a7375e3881b7325712
F tool/mksourceid.c 36aa8020014aed0836fd13c51d6dc9219b0df1761d6b5f58ff5b616211b079b9
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
F tool/mksqlite3c-noext.tcl 4f7cfef5152b0c91920355cbfc1d608a4ad242cb819f1aea07f6d0274f584a7f
-F tool/mksqlite3c.tcl 3ab95bcf7b765f9d6d99cbeb8c4f150b38b0bb1f001ffac688f2ad02ebce2123
-F tool/mksqlite3h.tcl 080873e3856eceb9d289a08a00c4b30f875ea3feadcbece796bd509b1532792c
+F tool/mksqlite3c.tcl f4ef476510eca4124c874a72029f1e01bc54a896b1724e8f9eef0d8bfae0e84c
+F tool/mksqlite3h.tcl 1f5e4a1dbbbc43c83cc6e74fe32c6c620502240b66c7c0f33a51378e78fc4edf
F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b
F tool/mkvsix.tcl b9e0777a213c23156b6542842c238479e496ebf5
-F tool/offsets.c fe4262fdfa378e8f5499a42136d17bf3b98f6091
+F tool/offsets.c 8ed2b344d33f06e71366a9b93ccedaa38c096cc1dbd4c3c26ad08c6115285845
F tool/omittest.tcl 6616fbf384f0f630113eab27d41d4530435dd94e2883307759988b45f0604a3b
F tool/opcodesum.tcl 740ed206ba8c5040018988129abbf3089a0ccf4a
F tool/pagesig.c ff0ca355fd3c2398e933da5e22439bbff89b803b
@@ -1826,22 +1839,22 @@ 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 9b2dbb4b7a00afaf8fc1719f0d775775effa5b135ac1a2c23f1c3f5d670c4e15
+F tool/showdb.c 49e810f5c414c792b5bf38cd5557ca9639713ebfef32aaff32faf7cb7ccce513
F tool/showjournal.c 5bad7ae8784a43d2b270d953060423b8bd480818
-F tool/showlocks.c 9920bcc64f58378ff1118caead34147201f48c68
+F tool/showlocks.c 9cc5e66d4ebbf2d194f39db2527ece92077e86ae627ddd233ee48e16e8142564
F tool/showshm.c a0ab6ec32dd1f11218ca2a4018f8fb875b59414801ab8ceed8b2e69b7b45a809
F tool/showstat4.c 0682ebea7abf4d3657f53c4a243f2e7eab48eab344ed36a94bb75dcd19a5c2a1
F tool/showwal.c ad9d768f96ca6199ad3a8c9562d679680bd032dd01204ea3e5ea6fb931d81847
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
-F tool/spaceanal.tcl c161d838825d0242317c7cc13b1eb2126f8cec031950ef31114d42732cb2674e
-F tool/speed-check.sh 2b042d703a9472f08c3b13be27afac658426f8e4fc87cd2d575953fda86f08d1
+F tool/spaceanal.tcl a95036b36622e25cffd65a55b22d6af53dfbbff0de02d45dd0059bb3c9978609
+F tool/speed-check.sh 8ba7c7c0dba37e664679974f5954f2282275271a5b92f890756e282df0bfc458
F tool/speedtest.tcl 06c76698485ccf597b9e7dbb1ac70706eb873355
F tool/speedtest16.c ecb6542862151c3e6509bbc00509b234562ae81e
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 7ce07da76b5e745783e703a834417d725b7d45fd
F tool/split-sqlite3c.tcl 3efcd4240b738f6bb2b5af0aea7e1e0ef9bc1c61654f645076cec883030b710c
-F tool/sqldiff.c 7b9b7238284f02131dbb8f21a4e862409bff728045c5473139d28c67ac87580e
+F tool/sqldiff.c 5046b8e227213ad016b336eb5a933e252e1f0fd1e07060c5755e259a30891287
F tool/sqlite3_analyzer.c.in 7eeaae8b0d7577662acaabbb11107af0659d1b41bc1dfdd4d91422de27127968
F tool/sqltclsh.c.in 1bcc2e9da58fadf17b0bf6a50e68c1159e602ce057210b655d50bad5aaaef898
F tool/sqltclsh.tcl 862f4cf1418df5e1315b5db3b5ebe88969e2a784525af5fbf9596592f14ed848
@@ -1856,7 +1869,7 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
F tool/warnings.sh 09311479bdc290e20ec8e35a3d1b14b096bbd96222277cfd6274c3a99b3d012f
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
F vsixtest/App.xaml b76d3b48860e7454775c47ea38ffea9c4abe3e85
-F vsixtest/App.xaml.cpp c465147f50871165c60ca16955219f6c5812d6d8
+F vsixtest/App.xaml.cpp 41158ee43269820136fa3bba00c0bd91b26cc38b650ee392aec2a8d823e54318
F vsixtest/App.xaml.h 4a9768e2983d05600ad1e1c2f1b00a132967da9f
F vsixtest/Assets/LockScreenLogo.scale-200.png e820c9a3deb909197081b0bf3216c06e13905f0a
F vsixtest/Assets/SplashScreen.scale-200.png cab70988ca71bebec7bfeb3b6dbafe17b9ab0b4a
@@ -1876,7 +1889,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 31706878c3ab3ad8f84035553f0c4de25af1e371577e7caccba191fe172905ee 0c1fcf4711a2e66c813aed38cf41cd3e2123ee8eb6db98118086764c4ba83350
-R d8d39cfa3774b2a9cbf6c727274564e0
+P ecf8dece0362b79d248bae1847d2224d18af395c336a604bbcf2b29ffab645d5 5bbd4bddd3b9fa64d134ed62bce3eb4a09456bf24dec2474b5d764a3a3775964
+R ee0b968df0e1e1dcb574e297557a3e7d
U drh
-Z 509c77359a6d084a1c09cb315377f14c
+Z a71810780ea07fa9ef6e981886e896da
diff --git a/manifest.uuid b/manifest.uuid
index 9a3f53cbff..b44e3c4028 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-ecf8dece0362b79d248bae1847d2224d18af395c336a604bbcf2b29ffab645d5
\ No newline at end of file
+b1a77b7eade14d58b3ccd50b98c2ffb6362d093f2cde2bd178ea62cef2cb8d9f
\ No newline at end of file
diff --git a/src/alter.c b/src/alter.c
index 2f4bbb60e7..c712bfa842 100644
--- a/src/alter.c
+++ b/src/alter.c
@@ -52,22 +52,22 @@ static int isAlterableTable(Parse *pParse, Table *pTab){
static void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){
sqlite3NestedParse(pParse,
"SELECT 1 "
- "FROM \"%w\".%s "
+ "FROM \"%w\"." DFLT_SCHEMA_TABLE " "
"WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'"
" AND sql NOT LIKE 'create virtual%%'"
" AND sqlite_rename_test(%Q, sql, type, name, %d)=NULL ",
- zDb, MASTER_NAME,
+ zDb,
zDb, bTemp
);
if( bTemp==0 ){
sqlite3NestedParse(pParse,
"SELECT 1 "
- "FROM temp.%s "
+ "FROM temp." DFLT_SCHEMA_TABLE " "
"WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'"
" AND sql NOT LIKE 'create virtual%%'"
" AND sqlite_rename_test(%Q, sql, type, name, 1)=NULL ",
- MASTER_NAME, zDb
+ zDb
);
}
}
@@ -185,17 +185,17 @@ void sqlite3AlterRenameTable(
/* Rewrite all CREATE TABLE, INDEX, TRIGGER or VIEW statements in
** the schema to use the new table name. */
sqlite3NestedParse(pParse,
- "UPDATE \"%w\".%s SET "
+ "UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET "
"sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, %d) "
"WHERE (type!='index' OR tbl_name=%Q COLLATE nocase)"
"AND name NOT LIKE 'sqliteX_%%' ESCAPE 'X'"
- , zDb, MASTER_NAME, zDb, zTabName, zName, (iDb==1), zTabName
+ , zDb, zDb, zTabName, zName, (iDb==1), zTabName
);
- /* Update the tbl_name and name columns of the sqlite_master table
+ /* Update the tbl_name and name columns of the sqlite_schema table
** as required. */
sqlite3NestedParse(pParse,
- "UPDATE %Q.%s SET "
+ "UPDATE %Q." DFLT_SCHEMA_TABLE " SET "
"tbl_name = %Q, "
"name = CASE "
"WHEN type='table' THEN %Q "
@@ -205,7 +205,7 @@ void sqlite3AlterRenameTable(
"ELSE name END "
"WHERE tbl_name=%Q COLLATE nocase AND "
"(type='table' OR type='index' OR type='trigger');",
- zDb, MASTER_NAME,
+ zDb,
zName, zName, zName,
nTabName, zTabName
);
@@ -226,7 +226,7 @@ void sqlite3AlterRenameTable(
** as required. */
if( iDb!=1 ){
sqlite3NestedParse(pParse,
- "UPDATE sqlite_temp_master SET "
+ "UPDATE sqlite_temp_schema SET "
"sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, 1), "
"tbl_name = "
"CASE WHEN tbl_name=%Q COLLATE nocase AND "
@@ -382,10 +382,10 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
}
db->mDbFlags |= DBFLAG_PreferBuiltin;
sqlite3NestedParse(pParse,
- "UPDATE \"%w\".%s SET "
+ "UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET "
"sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) "
"WHERE type = 'table' AND name = %Q",
- zDb, MASTER_NAME, pNew->addColOffset, zCol, pNew->addColOffset+1,
+ zDb, pNew->addColOffset, zCol, pNew->addColOffset+1,
zTab
);
sqlite3DbFree(db, zCol);
@@ -587,7 +587,7 @@ void sqlite3AlterRenameColumn(
/* Do the rename operation using a recursive UPDATE statement that
** uses the sqlite_rename_column() SQL function to compute the new
- ** CREATE statement text for the sqlite_master table.
+ ** CREATE statement text for the sqlite_schema table.
*/
sqlite3MayAbort(pParse);
zNew = sqlite3NameFromToken(db, pNew);
@@ -595,21 +595,20 @@ void sqlite3AlterRenameColumn(
assert( pNew->n>0 );
bQuote = sqlite3Isquote(pNew->z[0]);
sqlite3NestedParse(pParse,
- "UPDATE \"%w\".%s SET "
+ "UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET "
"sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, %d) "
"WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X' "
" AND (type != 'index' OR tbl_name = %Q)"
" AND sql NOT LIKE 'create virtual%%'",
- zDb, MASTER_NAME,
+ zDb,
zDb, pTab->zName, iCol, zNew, bQuote, iSchema==1,
pTab->zName
);
sqlite3NestedParse(pParse,
- "UPDATE temp.%s SET "
+ "UPDATE temp." DFLT_SCHEMA_TABLE " SET "
"sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, 1) "
"WHERE type IN ('trigger', 'view')",
- MASTER_NAME,
zDb, pTab->zName, iCol, zNew, bQuote
);
@@ -1161,7 +1160,7 @@ static int renameEditSql(
** successful. Otherwise, return an SQLite error code and leave an error
** message in the Parse object.
*/
-static int renameResolveTrigger(Parse *pParse, const char *zDb){
+static int renameResolveTrigger(Parse *pParse){
sqlite3 *db = pParse->db;
Trigger *pNew = pParse->pNewTrigger;
TriggerStep *pStep;
@@ -1192,17 +1191,22 @@ static int renameResolveTrigger(Parse *pParse, const char *zDb){
if( pParse->nErr ) rc = pParse->rc;
}
if( rc==SQLITE_OK && pStep->zTarget ){
- Table *pTarget = sqlite3LocateTable(pParse, 0, pStep->zTarget, zDb);
- if( pTarget==0 ){
- rc = SQLITE_ERROR;
- }else if( SQLITE_OK==(rc = sqlite3ViewGetColumnNames(pParse, pTarget)) ){
- SrcList sSrc;
- memset(&sSrc, 0, sizeof(sSrc));
- sSrc.nSrc = 1;
- sSrc.a[0].zName = pStep->zTarget;
- sSrc.a[0].pTab = pTarget;
- sNC.pSrcList = &sSrc;
- if( pStep->pWhere ){
+ SrcList *pSrc = sqlite3TriggerStepSrc(pParse, pStep);
+ if( pSrc ){
+ int i;
+ for(i=0; inSrc; i++){
+ struct SrcList_item *p = &pSrc->a[i];
+ p->pTab = sqlite3LocateTableItem(pParse, 0, p);
+ p->iCursor = pParse->nTab++;
+ if( p->pTab==0 ){
+ rc = SQLITE_ERROR;
+ }else{
+ p->pTab->nTabRef++;
+ rc = sqlite3ViewGetColumnNames(pParse, p->pTab);
+ }
+ }
+ sNC.pSrcList = pSrc;
+ if( rc==SQLITE_OK && pStep->pWhere ){
rc = sqlite3ResolveExprNames(&sNC, pStep->pWhere);
}
if( rc==SQLITE_OK ){
@@ -1212,7 +1216,7 @@ static int renameResolveTrigger(Parse *pParse, const char *zDb){
if( pStep->pUpsert ){
Upsert *pUpsert = pStep->pUpsert;
assert( rc==SQLITE_OK );
- pUpsert->pUpsertSrc = &sSrc;
+ pUpsert->pUpsertSrc = pSrc;
sNC.uNC.pUpsert = pUpsert;
sNC.ncFlags = NC_UUpsert;
rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);
@@ -1229,6 +1233,9 @@ static int renameResolveTrigger(Parse *pParse, const char *zDb){
sNC.ncFlags = 0;
}
sNC.pSrcList = 0;
+ sqlite3SrcListDelete(db, pSrc);
+ }else{
+ rc = SQLITE_NOMEM;
}
}
}
@@ -1415,7 +1422,7 @@ static void renameColumnFunc(
}else{
/* A trigger */
TriggerStep *pStep;
- rc = renameResolveTrigger(&sParse, (bTemp ? 0 : zDb));
+ rc = renameResolveTrigger(&sParse);
if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
for(pStep=sParse.pNewTrigger->step_list; pStep; pStep=pStep->pNext){
@@ -1618,7 +1625,7 @@ static void renameTableFunc(
}
if( isLegacy==0 ){
- rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb);
+ rc = renameResolveTrigger(&sParse);
if( rc==SQLITE_OK ){
renameWalkTrigger(&sWalker, pTrigger);
for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){
@@ -1705,7 +1712,7 @@ static void renameTableTest(
else if( sParse.pNewTrigger ){
if( isLegacy==0 ){
- rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb);
+ rc = renameResolveTrigger(&sParse);
}
if( rc==SQLITE_OK ){
int i1 = sqlite3SchemaToIndex(db, sParse.pNewTrigger->pTabSchema);
diff --git a/src/analyze.c b/src/analyze.c
index 1231f06b75..39812e4aca 100644
--- a/src/analyze.c
+++ b/src/analyze.c
@@ -186,7 +186,7 @@ static void openStatTable(
sqlite3 *db = pParse->db;
Db *pDb;
Vdbe *v = sqlite3GetVdbe(pParse);
- int aRoot[ArraySize(aTable)];
+ u32 aRoot[ArraySize(aTable)];
u8 aCreateTbl[ArraySize(aTable)];
#ifdef SQLITE_ENABLE_STAT4
const int nToOpen = OptimizationEnabled(db,SQLITE_Stat4) ? 2 : 1;
@@ -216,7 +216,7 @@ static void openStatTable(
sqlite3NestedParse(pParse,
"CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols
);
- aRoot[i] = pParse->regRoot;
+ aRoot[i] = (u32)pParse->regRoot;
aCreateTbl[i] = OPFLAG_P2ISREG;
}
}else{
@@ -236,7 +236,7 @@ static void openStatTable(
#endif
}else{
/* The sqlite_stat[134] table already exists. Delete all rows. */
- sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb);
+ sqlite3VdbeAddOp2(v, OP_Clear, (int)aRoot[i], iDb);
}
}
}
@@ -244,7 +244,7 @@ static void openStatTable(
/* Open the sqlite_stat[134] tables for writing. */
for(i=0; i=0 && knColumn );
+ i = pIdx->aiColumn[k];
+ if( NEVER(i==XN_ROWID) ){
+ VdbeComment((v,"%s.rowid",pIdx->zName));
+ }else if( i==XN_EXPR ){
+ VdbeComment((v,"%s.expr(%d)",pIdx->zName, k));
+ }else{
+ VdbeComment((v,"%s.%s", pIdx->zName, pIdx->pTable->aCol[i].zName));
+ }
+}
+#else
+# define analyzeVdbeCommentIndexWithColumnName(a,b,c)
+#endif /* SQLITE_DEBUG */
+
/*
** Generate code to do an analysis of all indices associated with
** a single table.
@@ -1168,7 +1192,7 @@ static void analyzeOneTable(
char *pColl = (char*)sqlite3LocateCollSeq(pParse, pIdx->azColl[i]);
sqlite3VdbeAddOp2(v, OP_Integer, i, regChng);
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regTemp);
- VdbeComment((v, "%s.column(%d)", pIdx->zName, i));
+ analyzeVdbeCommentIndexWithColumnName(v,pIdx,i);
aGotoChng[i] =
sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, regPrev+i, pColl, P4_COLLSEQ);
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
@@ -1189,7 +1213,7 @@ static void analyzeOneTable(
for(i=0; izName, i));
+ analyzeVdbeCommentIndexWithColumnName(v,pIdx,i);
}
sqlite3VdbeResolveLabel(v, endDistinctTest);
sqlite3DbFree(db, aGotoChng);
@@ -1215,7 +1239,7 @@ static void analyzeOneTable(
k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]);
assert( k>=0 && knColumn );
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
- VdbeComment((v, "%s.column(%d)", pIdx->zName, i));
+ analyzeVdbeCommentIndexWithColumnName(v,pIdx,k);
}
sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid);
sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol);
diff --git a/src/attach.c b/src/attach.c
index 9bb1e63a85..66569a5d54 100644
--- a/src/attach.c
+++ b/src/attach.c
@@ -600,6 +600,9 @@ int sqlite3FixTriggerStep(
if( sqlite3FixExprList(pFix, pStep->pExprList) ){
return 1;
}
+ if( pStep->pFrom && sqlite3FixSrcList(pFix, pStep->pFrom) ){
+ return 1;
+ }
#ifndef SQLITE_OMIT_UPSERT
if( pStep->pUpsert ){
Upsert *pUp = pStep->pUpsert;
diff --git a/src/btree.c b/src/btree.c
index f269b3deee..919d3b87cd 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -69,7 +69,7 @@ int sqlite3BtreeTrace=1; /* True to enable tracing */
** but the test harness needs to access it so we make it global for
** test builds.
**
-** Access to this variable is protected by SQLITE_MUTEX_STATIC_MASTER.
+** Access to this variable is protected by SQLITE_MUTEX_STATIC_MAIN.
*/
#ifdef SQLITE_TEST
BtShared *SQLITE_WSD sqlite3SharedCacheList = 0;
@@ -200,16 +200,18 @@ static int hasSharedCacheTableLock(
** table. */
if( isIndex ){
HashElem *p;
+ int bSeen = 0;
for(p=sqliteHashFirst(&pSchema->idxHash); p; p=sqliteHashNext(p)){
Index *pIdx = (Index *)sqliteHashData(p);
if( pIdx->tnum==(int)iRoot ){
- if( iTab ){
+ if( bSeen ){
/* Two or more indexes share the same root page. There must
** be imposter tables. So just return true. The assert is not
** useful in that case. */
return 1;
}
iTab = pIdx->pTable->tnum;
+ bSeen = 1;
}
}
}else{
@@ -355,7 +357,7 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
/* A connection with the read-uncommitted flag set will never try to
** obtain a read-lock using this function. The only read-lock obtained
- ** by a connection in read-uncommitted mode is on the sqlite_master
+ ** by a connection in read-uncommitted mode is on the sqlite_schema
** table, and that lock is obtained in BtreeBeginTrans(). */
assert( 0==(p->db->flags&SQLITE_ReadUncommit) || eLock==WRITE_LOCK );
@@ -991,7 +993,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){
if( *pRC ) return;
assert( sqlite3_mutex_held(pBt->mutex) );
- /* The master-journal page number must never be used as a pointer map page */
+ /* The super-journal page number must never be used as a pointer map page */
assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) );
assert( pBt->autoVacuum );
@@ -1751,7 +1753,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
nFrag = iFreeBlk - iEnd;
if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage);
iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]);
- if( NEVER(iEnd > pPage->pBt->usableSize) ){
+ if( iEnd > pPage->pBt->usableSize ){
return SQLITE_CORRUPT_PAGE(pPage);
}
iSize = iEnd - iStart;
@@ -2137,12 +2139,11 @@ static MemPage *btreePageLookup(BtShared *pBt, Pgno pgno){
** error, return ((unsigned int)-1).
*/
static Pgno btreePagecount(BtShared *pBt){
- assert( (pBt->nPage & 0x80000000)==0 || CORRUPT_DB );
return pBt->nPage;
}
-u32 sqlite3BtreeLastPage(Btree *p){
+Pgno sqlite3BtreeLastPage(Btree *p){
assert( sqlite3BtreeHoldsMutex(p) );
- return btreePagecount(p->pBt) & 0x7fffffff;
+ return btreePagecount(p->pBt);
}
/*
@@ -2420,7 +2421,7 @@ int sqlite3BtreeOpen(
#if SQLITE_THREADSAFE
mutexOpen = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_OPEN);
sqlite3_mutex_enter(mutexOpen);
- mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+ mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
sqlite3_mutex_enter(mutexShared);
#endif
for(pBt=GLOBAL(BtShared*,sqlite3SharedCacheList); pBt; pBt=pBt->pNext){
@@ -2539,7 +2540,7 @@ int sqlite3BtreeOpen(
pBt->nRef = 1;
if( p->sharable ){
MUTEX_LOGIC( sqlite3_mutex *mutexShared; )
- MUTEX_LOGIC( mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);)
+ MUTEX_LOGIC( mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);)
if( SQLITE_THREADSAFE && sqlite3GlobalConfig.bCoreMutex ){
pBt->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_FAST);
if( pBt->mutex==0 ){
@@ -2628,13 +2629,13 @@ btree_open_out:
*/
static int removeFromSharingList(BtShared *pBt){
#ifndef SQLITE_OMIT_SHARED_CACHE
- MUTEX_LOGIC( sqlite3_mutex *pMaster; )
+ MUTEX_LOGIC( sqlite3_mutex *pMainMtx; )
BtShared *pList;
int removed = 0;
assert( sqlite3_mutex_notheld(pBt->mutex) );
- MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
- sqlite3_mutex_enter(pMaster);
+ MUTEX_LOGIC( pMainMtx = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); )
+ sqlite3_mutex_enter(pMainMtx);
pBt->nRef--;
if( pBt->nRef<=0 ){
if( GLOBAL(BtShared*,sqlite3SharedCacheList)==pBt ){
@@ -2653,7 +2654,7 @@ static int removeFromSharingList(BtShared *pBt){
}
removed = 1;
}
- sqlite3_mutex_leave(pMaster);
+ sqlite3_mutex_leave(pMainMtx);
return removed;
#else
return 1;
@@ -2930,8 +2931,8 @@ int sqlite3BtreeGetRequestedReserve(Btree *p){
** No changes are made if mxPage is 0 or negative.
** Regardless of the value of mxPage, return the maximum page count.
*/
-int sqlite3BtreeMaxPageCount(Btree *p, int mxPage){
- int n;
+Pgno sqlite3BtreeMaxPageCount(Btree *p, Pgno mxPage){
+ Pgno n;
sqlite3BtreeEnter(p);
n = sqlite3PagerMaxPageCount(p->pBt->pPager, mxPage);
sqlite3BtreeLeave(p);
@@ -3429,7 +3430,7 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
/* Any read-only or read-write transaction implies a read-lock on
** page 1. So if some other shared-cache client already has a write-lock
** on page 1, the transaction cannot be opened. */
- rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK);
+ rc = querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK);
if( SQLITE_OK!=rc ) goto trans_begun;
pBt->btsFlags &= ~BTS_INITIALLY_EMPTY;
@@ -3884,7 +3885,7 @@ int sqlite3BtreeIncrVacuum(Btree *p){
Pgno nFree = get4byte(&pBt->pPage1->aData[36]);
Pgno nFin = finalDbSize(pBt, nOrig, nFree);
- if( nOrig=nOrig ){
rc = SQLITE_CORRUPT_BKPT;
}else if( nFree>0 ){
rc = saveAllCursors(pBt, 0, 0);
@@ -3981,18 +3982,18 @@ static int autoVacuumCommit(BtShared *pBt){
**
** This call is a no-op if no write-transaction is currently active on pBt.
**
-** Otherwise, sync the database file for the btree pBt. zMaster points to
-** the name of a master journal file that should be written into the
-** individual journal file, or is NULL, indicating no master journal file
+** Otherwise, sync the database file for the btree pBt. zSuperJrnl points to
+** the name of a super-journal file that should be written into the
+** individual journal file, or is NULL, indicating no super-journal file
** (single database transaction).
**
-** When this is called, the master journal should already have been
+** When this is called, the super-journal should already have been
** created, populated with this journal pointer and synced to disk.
**
** Once this is routine has returned, the only thing required to commit
** the write-transaction for this database file is to delete the journal.
*/
-int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){
+int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zSuperJrnl){
int rc = SQLITE_OK;
if( p->inTrans==TRANS_WRITE ){
BtShared *pBt = p->pBt;
@@ -4009,7 +4010,7 @@ int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){
sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage);
}
#endif
- rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, 0);
+ rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zSuperJrnl, 0);
sqlite3BtreeLeave(p);
}
return rc;
@@ -4072,7 +4073,7 @@ static void btreeEndTransaction(Btree *p){
** the upper layer will attempt a rollback. However, if the second argument
** is non-zero then this b-tree transaction is part of a multi-file
** transaction. In this case, the transaction has already been committed
-** (by deleting a master journal file) and the caller will ignore this
+** (by deleting a super-journal file) and the caller will ignore this
** functions return code. So, even if an error occurs in the pager layer,
** reset the b-tree objects internal state to indicate that the write
** transaction has been closed. This is quite safe, as the pager will have
@@ -4370,7 +4371,7 @@ int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
*/
static int btreeCursor(
Btree *p, /* The btree */
- int iTable, /* Root page of table to open */
+ Pgno iTable, /* Root page of table to open */
int wrFlag, /* 1 to write. 0 read-only */
struct KeyInfo *pKeyInfo, /* First arg to comparison function */
BtCursor *pCur /* Space for new cursor */
@@ -4413,7 +4414,7 @@ static int btreeCursor(
/* Now that no other errors can occur, finish filling in the BtCursor
** variables and link the cursor into the BtShared list. */
- pCur->pgnoRoot = (Pgno)iTable;
+ pCur->pgnoRoot = iTable;
pCur->iPage = -1;
pCur->pKeyInfo = pKeyInfo;
pCur->pBtree = p;
@@ -4423,7 +4424,7 @@ static int btreeCursor(
/* If there are two or more cursors on the same btree, then all such
** cursors *must* have the BTCF_Multiple flag set. */
for(pX=pBt->pCursor; pX; pX=pX->pNext){
- if( pX->pgnoRoot==(Pgno)iTable ){
+ if( pX->pgnoRoot==iTable ){
pX->curFlags |= BTCF_Multiple;
pCur->curFlags |= BTCF_Multiple;
}
@@ -4435,7 +4436,7 @@ static int btreeCursor(
}
static int btreeCursorWithLock(
Btree *p, /* The btree */
- int iTable, /* Root page of table to open */
+ Pgno iTable, /* Root page of table to open */
int wrFlag, /* 1 to write. 0 read-only */
struct KeyInfo *pKeyInfo, /* First arg to comparison function */
BtCursor *pCur /* Space for new cursor */
@@ -4448,7 +4449,7 @@ static int btreeCursorWithLock(
}
int sqlite3BtreeCursor(
Btree *p, /* The btree */
- int iTable, /* Root page of table to open */
+ Pgno iTable, /* Root page of table to open */
int wrFlag, /* 1 to write. 0 read-only */
struct KeyInfo *pKeyInfo, /* First arg to xCompare() */
BtCursor *pCur /* Write new cursor here */
@@ -4834,7 +4835,7 @@ static int accessPayload(
Pgno nextPage;
nextPage = get4byte(&aPayload[pCur->info.nLocal]);
-
+
/* If the BtCursor.aOverflow[] has not been allocated, allocate it now.
**
** The aOverflow[] array is sized at one entry for each overflow page
@@ -4873,6 +4874,7 @@ static int accessPayload(
assert( rc==SQLITE_OK && amt>0 );
while( nextPage ){
/* If required, populate the overflow page-list cache. */
+ if( nextPage > pBt->nPage ) return SQLITE_CORRUPT_BKPT;
assert( pCur->aOverflow[iIdx]==0
|| pCur->aOverflow[iIdx]==nextPage
|| CORRUPT_DB );
@@ -6288,6 +6290,10 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
u32 nLeaf; /* Initial number of leaf cells on trunk page */
iTrunk = get4byte(&pPage1->aData[32]);
+ if( iTrunk>btreePagecount(pBt) ){
+ rc = SQLITE_CORRUPT_BKPT;
+ goto freepage_out;
+ }
rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0);
if( rc!=SQLITE_OK ){
goto freepage_out;
@@ -8770,7 +8776,11 @@ int sqlite3BtreeInsert(
assert( pPage->intKey || pX->nKey>=0 );
assert( pPage->leaf || !pPage->intKey );
if( pPage->nFree<0 ){
- rc = btreeComputeFreeSpace(pPage);
+ if( pCur->eState>CURSOR_INVALID ){
+ rc = SQLITE_CORRUPT_BKPT;
+ }else{
+ rc = btreeComputeFreeSpace(pPage);
+ }
if( rc ) return rc;
}
@@ -9088,7 +9098,7 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys
** BTREE_ZERODATA Used for SQL indices
*/
-static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
+static int btreeCreateTable(Btree *p, Pgno *piTable, int createTabFlags){
BtShared *pBt = p->pBt;
MemPage *pRoot;
Pgno pgnoRoot;
@@ -9121,6 +9131,9 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
** created so far, so the new root-page is (meta[3]+1).
*/
sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &pgnoRoot);
+ if( pgnoRoot>btreePagecount(pBt) ){
+ return SQLITE_CORRUPT_BKPT;
+ }
pgnoRoot++;
/* The new root-page may not be allocated on a pointer-map page, or the
@@ -9130,8 +9143,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
pgnoRoot==PENDING_BYTE_PAGE(pBt) ){
pgnoRoot++;
}
- assert( pgnoRoot>=3 || CORRUPT_DB );
- testcase( pgnoRoot<3 );
+ assert( pgnoRoot>=3 );
/* Allocate a page. The page that currently resides at pgnoRoot will
** be moved to the allocated page (unless the allocated page happens
@@ -9228,10 +9240,10 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
zeroPage(pRoot, ptfFlags);
sqlite3PagerUnref(pRoot->pDbPage);
assert( (pBt->openFlags & BTREE_SINGLE)==0 || pgnoRoot==2 );
- *piTable = (int)pgnoRoot;
+ *piTable = pgnoRoot;
return SQLITE_OK;
}
-int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){
+int sqlite3BtreeCreateTable(Btree *p, Pgno *piTable, int flags){
int rc;
sqlite3BtreeEnter(p);
rc = btreeCreateTable(p, piTable, flags);
@@ -9477,7 +9489,7 @@ void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){
sqlite3BtreeEnter(p);
assert( p->inTrans>TRANS_NONE );
- assert( SQLITE_OK==querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK) );
+ assert( SQLITE_OK==querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK) );
assert( pBt->pPage1 );
assert( idx>=0 && idx<=15 );
@@ -9630,7 +9642,7 @@ static void checkAppendMsg(
sqlite3_str_vappendf(&pCheck->errMsg, zFormat, ap);
va_end(ap);
if( pCheck->errMsg.accError==SQLITE_NOMEM ){
- pCheck->mallocFailed = 1;
+ pCheck->bOomFault = 1;
}
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@@ -9695,7 +9707,7 @@ static void checkPtrmap(
rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent);
if( rc!=SQLITE_OK ){
- if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) pCheck->mallocFailed = 1;
+ if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) pCheck->bOomFault = 1;
checkAppendMsg(pCheck, "Failed to read ptrmap key=%d", iChild);
return;
}
@@ -9715,7 +9727,7 @@ static void checkPtrmap(
static void checkList(
IntegrityCk *pCheck, /* Integrity checking context */
int isFreeList, /* True for a freelist. False for overflow page list */
- int iPage, /* Page number for first page in the list */
+ Pgno iPage, /* Page number for first page in the list */
u32 N /* Expected number of pages in the list */
){
int i;
@@ -9847,7 +9859,7 @@ static int btreeHeapPull(u32 *aHeap, u32 *pOut){
*/
static int checkTreePage(
IntegrityCk *pCheck, /* Context for the sanity check */
- int iPage, /* Page number of the page to check */
+ Pgno iPage, /* Page number of the page to check */
i64 *piMinKey, /* Write minimum integer primary key here */
i64 maxKey /* Error if integer primary key greater than this */
){
@@ -9883,9 +9895,9 @@ static int checkTreePage(
usableSize = pBt->usableSize;
if( iPage==0 ) return 0;
if( checkRef(pCheck, iPage) ) return 0;
- pCheck->zPfx = "Page %d: ";
+ pCheck->zPfx = "Page %u: ";
pCheck->v1 = iPage;
- if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){
+ if( (rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0 ){
checkAppendMsg(pCheck,
"unable to get the page. error code=%d", rc);
goto end_of_check;
@@ -9910,7 +9922,7 @@ static int checkTreePage(
hdr = pPage->hdrOffset;
/* Set up for cell analysis */
- pCheck->zPfx = "On tree page %d cell %d: ";
+ pCheck->zPfx = "On tree page %u cell %d: ";
contentOffset = get2byteNotZero(&data[hdr+5]);
assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
@@ -9930,7 +9942,7 @@ static int checkTreePage(
pgno = get4byte(&data[hdr+8]);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
- pCheck->zPfx = "On page %d at right child: ";
+ pCheck->zPfx = "On page %u at right child: ";
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage);
}
#endif
@@ -10071,7 +10083,7 @@ static int checkTreePage(
while( btreeHeapPull(heap,&x) ){
if( (prev&0xffff)>=(x>>16) ){
checkAppendMsg(pCheck,
- "Multiple uses for byte %u of page %d", x>>16, iPage);
+ "Multiple uses for byte %u of page %u", x>>16, iPage);
break;
}else{
nFrag += (x>>16) - (prev&0xffff) - 1;
@@ -10086,7 +10098,7 @@ static int checkTreePage(
*/
if( heap[0]==0 && nFrag!=data[hdr+7] ){
checkAppendMsg(pCheck,
- "Fragmentation of %d bytes reported as %d on page %d",
+ "Fragmentation of %d bytes reported as %d on page %u",
nFrag, data[hdr+7], iPage);
}
}
@@ -10114,11 +10126,20 @@ end_of_check:
** allocation errors, an error message held in memory obtained from
** malloc is returned if *pnErr is non-zero. If *pnErr==0 then NULL is
** returned. If a memory allocation error occurs, NULL is returned.
+**
+** If the first entry in aRoot[] is 0, that indicates that the list of
+** root pages is incomplete. This is a "partial integrity-check". This
+** happens when performing an integrity check on a single table. The
+** zero is skipped, of course. But in addition, the freelist checks
+** and the checks to make sure every page is referenced are also skipped,
+** since obviously it is not possible to know which pages are covered by
+** the unverified btrees. Except, if aRoot[1] is 1, then the freelist
+** checks are still performed.
*/
char *sqlite3BtreeIntegrityCheck(
sqlite3 *db, /* Database connection that is running the check */
Btree *p, /* The btree to be checked */
- int *aRoot, /* An array of root pages numbers for individual trees */
+ Pgno *aRoot, /* An array of root pages numbers for individual trees */
int nRoot, /* Number of entries in aRoot[] */
int mxErr, /* Stop reporting errors after this many */
int *pnErr /* Write number of errors seen to this variable */
@@ -10128,7 +10149,17 @@ char *sqlite3BtreeIntegrityCheck(
BtShared *pBt = p->pBt;
u64 savedDbFlags = pBt->db->flags;
char zErr[100];
+ int bPartial = 0; /* True if not checking all btrees */
+ int bCkFreelist = 1; /* True to scan the freelist */
VVA_ONLY( int nRef );
+ assert( nRoot>0 );
+
+ /* aRoot[0]==0 means this is a partial check */
+ if( aRoot[0]==0 ){
+ assert( nRoot>1 );
+ bPartial = 1;
+ if( aRoot[1]!=1 ) bCkFreelist = 0;
+ }
sqlite3BtreeEnter(p);
assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE );
@@ -10140,7 +10171,7 @@ char *sqlite3BtreeIntegrityCheck(
sCheck.nPage = btreePagecount(sCheck.pBt);
sCheck.mxErr = mxErr;
sCheck.nErr = 0;
- sCheck.mallocFailed = 0;
+ sCheck.bOomFault = 0;
sCheck.zPfx = 0;
sCheck.v1 = 0;
sCheck.v2 = 0;
@@ -10154,12 +10185,12 @@ char *sqlite3BtreeIntegrityCheck(
sCheck.aPgRef = sqlite3MallocZero((sCheck.nPage / 8)+ 1);
if( !sCheck.aPgRef ){
- sCheck.mallocFailed = 1;
+ sCheck.bOomFault = 1;
goto integrity_ck_cleanup;
}
sCheck.heap = (u32*)sqlite3PageMalloc( pBt->pageSize );
if( sCheck.heap==0 ){
- sCheck.mallocFailed = 1;
+ sCheck.bOomFault = 1;
goto integrity_ck_cleanup;
}
@@ -10168,29 +10199,33 @@ char *sqlite3BtreeIntegrityCheck(
/* Check the integrity of the freelist
*/
- sCheck.zPfx = "Main freelist: ";
- checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]),
- get4byte(&pBt->pPage1->aData[36]));
- sCheck.zPfx = 0;
+ if( bCkFreelist ){
+ sCheck.zPfx = "Main freelist: ";
+ checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]),
+ get4byte(&pBt->pPage1->aData[36]));
+ sCheck.zPfx = 0;
+ }
/* Check all the tables.
*/
#ifndef SQLITE_OMIT_AUTOVACUUM
- if( pBt->autoVacuum ){
- int mx = 0;
- int mxInHdr;
- for(i=0; (int)ipPage1->aData[52]);
- if( mx!=mxInHdr ){
+ if( !bPartial ){
+ if( pBt->autoVacuum ){
+ Pgno mx = 0;
+ Pgno mxInHdr;
+ for(i=0; (int)ipPage1->aData[52]);
+ if( mx!=mxInHdr ){
+ checkAppendMsg(&sCheck,
+ "max rootpage (%d) disagrees with header (%d)",
+ mx, mxInHdr
+ );
+ }
+ }else if( get4byte(&pBt->pPage1->aData[64])!=0 ){
checkAppendMsg(&sCheck,
- "max rootpage (%d) disagrees with header (%d)",
- mx, mxInHdr
+ "incremental_vacuum enabled with a max rootpage of zero"
);
}
- }else if( get4byte(&pBt->pPage1->aData[64])!=0 ){
- checkAppendMsg(&sCheck,
- "incremental_vacuum enabled with a max rootpage of zero"
- );
}
#endif
testcase( pBt->db->flags & SQLITE_CellSizeCk );
@@ -10199,7 +10234,7 @@ char *sqlite3BtreeIntegrityCheck(
i64 notUsed;
if( aRoot[i]==0 ) continue;
#ifndef SQLITE_OMIT_AUTOVACUUM
- if( pBt->autoVacuum && aRoot[i]>1 ){
+ if( pBt->autoVacuum && aRoot[i]>1 && !bPartial ){
checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0);
}
#endif
@@ -10209,24 +10244,26 @@ char *sqlite3BtreeIntegrityCheck(
/* Make sure every page in the file is referenced
*/
- for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
+ if( !bPartial ){
+ for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
#ifdef SQLITE_OMIT_AUTOVACUUM
- if( getPageReferenced(&sCheck, i)==0 ){
- checkAppendMsg(&sCheck, "Page %d is never used", i);
- }
+ if( getPageReferenced(&sCheck, i)==0 ){
+ checkAppendMsg(&sCheck, "Page %d is never used", i);
+ }
#else
- /* If the database supports auto-vacuum, make sure no tables contain
- ** references to pointer-map pages.
- */
- if( getPageReferenced(&sCheck, i)==0 &&
- (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
- checkAppendMsg(&sCheck, "Page %d is never used", i);
- }
- if( getPageReferenced(&sCheck, i)!=0 &&
- (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
- checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i);
- }
+ /* If the database supports auto-vacuum, make sure no tables contain
+ ** references to pointer-map pages.
+ */
+ if( getPageReferenced(&sCheck, i)==0 &&
+ (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
+ checkAppendMsg(&sCheck, "Page %d is never used", i);
+ }
+ if( getPageReferenced(&sCheck, i)!=0 &&
+ (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
+ checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i);
+ }
#endif
+ }
}
/* Clean up and report errors.
@@ -10234,7 +10271,7 @@ char *sqlite3BtreeIntegrityCheck(
integrity_ck_cleanup:
sqlite3PageFree(sCheck.heap);
sqlite3_free(sCheck.aPgRef);
- if( sCheck.mallocFailed ){
+ if( sCheck.bOomFault ){
sqlite3_str_reset(&sCheck.errMsg);
sCheck.nErr++;
}
@@ -10354,13 +10391,13 @@ void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){
/*
** Return SQLITE_LOCKED_SHAREDCACHE if another user of the same shared
** btree as the argument handle holds an exclusive lock on the
-** sqlite_master table. Otherwise SQLITE_OK.
+** sqlite_schema table. Otherwise SQLITE_OK.
*/
int sqlite3BtreeSchemaLocked(Btree *p){
int rc;
assert( sqlite3_mutex_held(p->db->mutex) );
sqlite3BtreeEnter(p);
- rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK);
+ rc = querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK);
assert( rc==SQLITE_OK || rc==SQLITE_LOCKED_SHAREDCACHE );
sqlite3BtreeLeave(p);
return rc;
diff --git a/src/btree.h b/src/btree.h
index c152b63cb2..5dd5287d18 100644
--- a/src/btree.h
+++ b/src/btree.h
@@ -71,20 +71,20 @@ int sqlite3BtreeSetSpillSize(Btree*,int);
int sqlite3BtreeSetPagerFlags(Btree*,unsigned);
int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
int sqlite3BtreeGetPageSize(Btree*);
-int sqlite3BtreeMaxPageCount(Btree*,int);
-u32 sqlite3BtreeLastPage(Btree*);
+Pgno sqlite3BtreeMaxPageCount(Btree*,Pgno);
+Pgno sqlite3BtreeLastPage(Btree*);
int sqlite3BtreeSecureDelete(Btree*,int);
int sqlite3BtreeGetRequestedReserve(Btree*);
int sqlite3BtreeGetReserveNoMutex(Btree *p);
int sqlite3BtreeSetAutoVacuum(Btree *, int);
int sqlite3BtreeGetAutoVacuum(Btree *);
int sqlite3BtreeBeginTrans(Btree*,int,int*);
-int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
+int sqlite3BtreeCommitPhaseOne(Btree*, const char*);
int sqlite3BtreeCommitPhaseTwo(Btree*, int);
int sqlite3BtreeCommit(Btree*);
int sqlite3BtreeRollback(Btree*,int,int);
int sqlite3BtreeBeginStmt(Btree*,int);
-int sqlite3BtreeCreateTable(Btree*, int*, int flags);
+int sqlite3BtreeCreateTable(Btree*, Pgno*, int flags);
int sqlite3BtreeIsInTrans(Btree*);
int sqlite3BtreeIsInReadTrans(Btree*);
int sqlite3BtreeIsInBackup(Btree*);
@@ -225,7 +225,7 @@ int sqlite3BtreeNewDb(Btree *p);
int sqlite3BtreeCursor(
Btree*, /* BTree containing table to open */
- int iTable, /* Index of root page */
+ Pgno iTable, /* Index of root page */
int wrFlag, /* 1 for writing. 0 for read-only */
struct KeyInfo*, /* First argument to compare function */
BtCursor *pCursor /* Space to write cursor structure */
@@ -316,7 +316,7 @@ const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
u32 sqlite3BtreePayloadSize(BtCursor*);
sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor*);
-char *sqlite3BtreeIntegrityCheck(sqlite3*,Btree*,int*aRoot,int nRoot,int,int*);
+char *sqlite3BtreeIntegrityCheck(sqlite3*,Btree*,Pgno*aRoot,int nRoot,int,int*);
struct Pager *sqlite3BtreePager(Btree*);
i64 sqlite3BtreeRowCountEst(BtCursor*);
diff --git a/src/btreeInt.h b/src/btreeInt.h
index ec25b54662..c6dfa27ef5 100644
--- a/src/btreeInt.h
+++ b/src/btreeInt.h
@@ -381,7 +381,7 @@ struct Btree {
**
** Fields in this structure are accessed under the BtShared.mutex
** mutex, except for nRef and pNext which are accessed under the
-** global SQLITE_MUTEX_STATIC_MASTER mutex. The pPager field
+** global SQLITE_MUTEX_STATIC_MAIN mutex. The pPager field
** may not be modified once it is initially set as long as nRef>0.
** The pSchema field may be set once under BtShared.mutex and
** thereafter is unchanged as long as nRef>0.
@@ -679,9 +679,10 @@ struct IntegrityCk {
Pgno nPage; /* Number of pages in the database */
int mxErr; /* Stop accumulating errors when this reaches zero */
int nErr; /* Number of messages written to zErrMsg so far */
- int mallocFailed; /* A memory allocation error has occurred */
+ int bOomFault; /* A memory allocation error has occurred */
const char *zPfx; /* Error message prefix */
- int v1, v2; /* Values for up to two %d fields in zPfx */
+ Pgno v1; /* Value for first %u substitution in zPfx */
+ int v2; /* Value for second %d substitution in zPfx */
StrAccum errMsg; /* Accumulate the error message text here */
u32 *heap; /* Min-heap used for analyzing cell coverage */
sqlite3 *db; /* Database connection running the check */
diff --git a/src/build.c b/src/build.c
index 3bae2304c5..46f84fc1fe 100644
--- a/src/build.c
+++ b/src/build.c
@@ -31,7 +31,7 @@
*/
struct TableLock {
int iDb; /* The database containing the table to be locked */
- int iTab; /* The root page of the table to be locked */
+ Pgno iTab; /* The root page of the table to be locked */
u8 isWriteLock; /* True for write lock. False for a read lock */
const char *zLockName; /* Name of the table */
};
@@ -49,7 +49,7 @@ struct TableLock {
void sqlite3TableLock(
Parse *pParse, /* Parsing context */
int iDb, /* Index of the database containing the table to lock */
- int iTab, /* Root page number of the table to be locked */
+ Pgno iTab, /* Root page number of the table to be locked */
u8 isWriteLock, /* True for a write lock */
const char *zName /* Name of the table to be locked */
){
@@ -207,12 +207,21 @@ void sqlite3FinishCoding(Parse *pParse){
*/
sqlite3AutoincrementBegin(pParse);
- /* Code constant expressions that where factored out of inner loops */
+ /* Code constant expressions that where factored out of inner loops.
+ **
+ ** The pConstExpr list might also contain expressions that we simply
+ ** want to keep around until the Parse object is deleted. Such
+ ** expressions have iConstExprReg==0. Do not generate code for
+ ** those expressions, of course.
+ */
if( pParse->pConstExpr ){
ExprList *pEL = pParse->pConstExpr;
pParse->okConstFactor = 0;
for(i=0; inExpr; i++){
- sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg);
+ int iReg = pEL->a[i].u.iConstExprReg;
+ if( iReg>0 ){
+ sqlite3ExprCode(pParse, pEL->a[i].pExpr, iReg);
+ }
}
}
@@ -244,7 +253,7 @@ void sqlite3FinishCoding(Parse *pParse){
** outermost parser.
**
** Not everything is nestable. This facility is designed to permit
-** INSERT, UPDATE, and DELETE operations against SQLITE_MASTER. Use
+** INSERT, UPDATE, and DELETE operations against the schema table. Use
** care if you decide to try to use this routine for some other purposes.
*/
void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
@@ -367,9 +376,17 @@ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
}
/* Not found. If the name we were looking for was temp.sqlite_master
** then change the name to sqlite_temp_master and try again. */
- if( sqlite3StrICmp(zName, MASTER_NAME)!=0 ) break;
+ if( sqlite3StrICmp(zName, ALT_SCHEMA_TABLE)==0 ){
+ zName = DFLT_SCHEMA_TABLE;
+ continue;
+ }
+ if( sqlite3StrICmp(zName, ALT_TEMP_SCHEMA_TABLE)==0 ){
+ zName = DFLT_TEMP_SCHEMA_TABLE;
+ continue;
+ }
+ if( sqlite3StrICmp(zName, DFLT_SCHEMA_TABLE)!=0 ) break;
if( sqlite3_stricmp(zDatabase, db->aDb[1].zDbSName)!=0 ) break;
- zName = TEMP_MASTER_NAME;
+ zName = DFLT_TEMP_SCHEMA_TABLE;
}
return 0;
}
@@ -772,13 +789,13 @@ char *sqlite3NameFromToken(sqlite3 *db, Token *pName){
}
/*
-** Open the sqlite_master table stored in database number iDb for
+** Open the sqlite_schema table stored in database number iDb for
** writing. The table is opened using cursor 0.
*/
-void sqlite3OpenMasterTable(Parse *p, int iDb){
+void sqlite3OpenSchemaTable(Parse *p, int iDb){
Vdbe *v = sqlite3GetVdbe(p);
- sqlite3TableLock(p, iDb, MASTER_ROOT, 1, MASTER_NAME);
- sqlite3VdbeAddOp4Int(v, OP_OpenWrite, 0, MASTER_ROOT, iDb, 5);
+ sqlite3TableLock(p, iDb, SCHEMA_ROOT, 1, DFLT_SCHEMA_TABLE);
+ sqlite3VdbeAddOp4Int(v, OP_OpenWrite, 0, SCHEMA_ROOT, iDb, 5);
if( p->nTab==0 ){
p->nTab = 1;
}
@@ -886,7 +903,7 @@ int sqlite3WritableSchema(sqlite3 *db){
** "sqlite_" (in upper, lower or mixed case). This portion of the namespace
** is reserved for internal use.
**
-** When parsing the sqlite_master table, this routine also checks to
+** When parsing the sqlite_schema table, this routine also checks to
** make sure the "type", "name", and "tbl_name" columns are consistent
** with the SQL.
*/
@@ -897,7 +914,10 @@ int sqlite3CheckObjectName(
const char *zTblName /* Parent table name for triggers and indexes */
){
sqlite3 *db = pParse->db;
- if( sqlite3WritableSchema(db) || db->init.imposterTable ){
+ if( sqlite3WritableSchema(db)
+ || db->init.imposterTable
+ || !sqlite3Config.bExtraSchemaChecks
+ ){
/* Skip these error checks for writable_schema=ON */
return SQLITE_OK;
}
@@ -906,10 +926,8 @@ int sqlite3CheckObjectName(
|| sqlite3_stricmp(zName, db->init.azInit[1])
|| sqlite3_stricmp(zTblName, db->init.azInit[2])
){
- if( sqlite3Config.bExtraSchemaChecks ){
- sqlite3ErrorMsg(pParse, ""); /* corruptSchema() will supply the error */
- return SQLITE_ERROR;
- }
+ sqlite3ErrorMsg(pParse, ""); /* corruptSchema() will supply the error */
+ return SQLITE_ERROR;
}
}else{
if( (pParse->nested==0 && 0==sqlite3StrNICmp(zName, "sqlite_", 7))
@@ -1058,7 +1076,7 @@ void sqlite3StartTable(
Token *pName; /* Unqualified name of the table to create */
if( db->init.busy && db->init.newTnum==1 ){
- /* Special case: Parsing the sqlite_master or sqlite_temp_master schema */
+ /* Special case: Parsing the sqlite_schema or sqlite_temp_schema schema */
iDb = db->init.iDb;
zName = sqlite3DbStrDup(db, SCHEMA_TABLE(iDb));
pName = pName1;
@@ -1164,7 +1182,7 @@ void sqlite3StartTable(
#endif
/* Begin generating the code that will insert the table record into
- ** the SQLITE_MASTER table. Note in particular that we must go ahead
+ ** the schema table. Note in particular that we must go ahead
** and allocate the record number for the table entry now. Before any
** PRIMARY KEY or UNIQUE keywords are parsed. Those keywords will cause
** indices to be created and the table record must come before the
@@ -1200,7 +1218,7 @@ void sqlite3StartTable(
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, ENC(db));
sqlite3VdbeJumpHere(v, addr1);
- /* This just creates a place-holder record in the sqlite_master table.
+ /* This just creates a place-holder record in the sqlite_schema table.
** The record created does not contain anything yet. It will be replaced
** by the real entry in code generated at sqlite3EndTable().
**
@@ -1218,7 +1236,7 @@ void sqlite3StartTable(
pParse->addrCrTab =
sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, reg2, BTREE_INTKEY);
}
- sqlite3OpenMasterTable(pParse, iDb);
+ sqlite3OpenSchemaTable(pParse, iDb);
sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1);
sqlite3VdbeAddOp4(v, OP_Blob, 6, reg3, 0, nullRow, P4_STATIC);
sqlite3VdbeAddOp3(v, OP_Insert, 0, reg3, reg1);
@@ -2028,9 +2046,9 @@ static void recomputeColumnsNotIndexed(Index *pIdx){
** (1) Set all columns of the PRIMARY KEY schema object to be NOT NULL.
** (2) Convert P3 parameter of the OP_CreateBtree from BTREE_INTKEY
** into BTREE_BLOBKEY.
-** (3) Bypass the creation of the sqlite_master table entry
+** (3) Bypass the creation of the sqlite_schema table entry
** for the PRIMARY KEY as the primary key index is now
-** identified by the sqlite_master table entry of the table itself.
+** identified by the sqlite_schema table entry of the table itself.
** (4) Set the Index.tnum of the PRIMARY KEY Index object in the
** schema to the rootpage from the main table.
** (5) Add all table columns to the PRIMARY KEY Index object
@@ -2117,13 +2135,13 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
if( !db->init.imposterTable ) pPk->uniqNotNull = 1;
nPk = pPk->nColumn = pPk->nKeyCol;
- /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master
+ /* Bypass the creation of the PRIMARY KEY btree and the sqlite_schema
** table entry. This is only required if currently generating VDBE
** code for a CREATE TABLE (not when parsing one as part of reading
** a database schema). */
if( v && pPk->tnum>0 ){
assert( db->init.busy==0 );
- sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto);
+ sqlite3VdbeChangeOpcode(v, (int)pPk->tnum, OP_Goto);
}
/* The root page of the PRIMARY KEY is the table root page */
@@ -2265,12 +2283,12 @@ static void markExprListImmutable(ExprList *pList){
** is added to the internal hash tables, assuming no errors have
** occurred.
**
-** An entry for the table is made in the master table on disk, unless
+** An entry for the table is made in the schema table on disk, unless
** this is a temporary table or db->init.busy==1. When db->init.busy==1
-** it means we are reading the sqlite_master table because we just
-** connected to the database or because the sqlite_master table has
+** it means we are reading the sqlite_schema table because we just
+** connected to the database or because the sqlite_schema table has
** recently changed, so the entry for this table already exists in
-** the sqlite_master table. We do not want to create it again.
+** the sqlite_schema table. We do not want to create it again.
**
** If the pSelect argument is not NULL, it means that this routine
** was called to create a table generated from a
@@ -2301,12 +2319,12 @@ void sqlite3EndTable(
}
/* If the db->init.busy is 1 it means we are reading the SQL off the
- ** "sqlite_master" or "sqlite_temp_master" table on the disk.
+ ** "sqlite_schema" or "sqlite_temp_schema" table on the disk.
** So do not write to the disk again. Extract the root page number
** for the table from the db->init.newTnum field. (The page number
** should have been put there by the sqliteOpenCb routine.)
**
- ** If the root page number is 1, that means this is the sqlite_master
+ ** If the root page number is 1, that means this is the sqlite_schema
** table itself. So mark it read-only.
*/
if( db->init.busy ){
@@ -2393,7 +2411,7 @@ void sqlite3EndTable(
}
/* If not initializing, then create a record for the new table
- ** in the SQLITE_MASTER table of the database.
+ ** in the schema table of the database.
**
** If this is a TEMPORARY table, write the entry into the auxiliary
** file instead of into the main database file.
@@ -2495,14 +2513,14 @@ void sqlite3EndTable(
}
/* A slot for the record has already been allocated in the
- ** SQLITE_MASTER table. We just need to update that slot with all
+ ** schema table. We just need to update that slot with all
** the information we've collected.
*/
sqlite3NestedParse(pParse,
- "UPDATE %Q.%s "
- "SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q "
- "WHERE rowid=#%d",
- db->aDb[iDb].zDbSName, MASTER_NAME,
+ "UPDATE %Q." DFLT_SCHEMA_TABLE
+ " SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q"
+ " WHERE rowid=#%d",
+ db->aDb[iDb].zDbSName,
zType,
p->zName,
p->zName,
@@ -2630,7 +2648,7 @@ void sqlite3CreateView(
sEnd.z = &z[n-1];
sEnd.n = 1;
- /* Use sqlite3EndTable() to add the view to the SQLITE_MASTER table */
+ /* Use sqlite3EndTable() to add the view to the schema table */
sqlite3EndTable(pParse, 0, &sEnd, 0, 0);
create_view_fail:
@@ -2711,10 +2729,8 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
assert( pTable->pSelect );
pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
if( pSel ){
-#ifndef SQLITE_OMIT_ALTERTABLE
u8 eParseMode = pParse->eParseMode;
pParse->eParseMode = PARSE_MODE_NORMAL;
-#endif
n = pParse->nTab;
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
pTable->nCol = -1;
@@ -2762,9 +2778,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
sqlite3DeleteTable(db, pSelTab);
sqlite3SelectDelete(db, pSel);
EnableLookaside;
-#ifndef SQLITE_OMIT_ALTERTABLE
pParse->eParseMode = eParseMode;
-#endif
} else {
nErr++;
}
@@ -2819,7 +2833,7 @@ static void sqliteViewResetAll(sqlite3 *db, int idx){
** in order to be certain that we got the right one.
*/
#ifndef SQLITE_OMIT_AUTOVACUUM
-void sqlite3RootPageMoved(sqlite3 *db, int iDb, int iFrom, int iTo){
+void sqlite3RootPageMoved(sqlite3 *db, int iDb, Pgno iFrom, Pgno iTo){
HashElem *pElem;
Hash *pHash;
Db *pDb;
@@ -2845,7 +2859,7 @@ void sqlite3RootPageMoved(sqlite3 *db, int iDb, int iFrom, int iTo){
/*
** Write code to erase the table with root-page iTable from database iDb.
-** Also write code to modify the sqlite_master table and internal schema
+** Also write code to modify the sqlite_schema table and internal schema
** if a root-page of another table is moved by the btree-layer whilst
** erasing iTable (this can happen with an auto-vacuum database).
*/
@@ -2858,7 +2872,7 @@ static void destroyRootPage(Parse *pParse, int iTable, int iDb){
#ifndef SQLITE_OMIT_AUTOVACUUM
/* OP_Destroy stores an in integer r1. If this integer
** is non-zero, then it is the root page number of a table moved to
- ** location iTable. The following code modifies the sqlite_master table to
+ ** location iTable. The following code modifies the sqlite_schema table to
** reflect this.
**
** The "#NNN" in the SQL is a special constant that means whatever value
@@ -2866,15 +2880,16 @@ static void destroyRootPage(Parse *pParse, int iTable, int iDb){
** token for additional information.
*/
sqlite3NestedParse(pParse,
- "UPDATE %Q.%s SET rootpage=%d WHERE #%d AND rootpage=#%d",
- pParse->db->aDb[iDb].zDbSName, MASTER_NAME, iTable, r1, r1);
+ "UPDATE %Q." DFLT_SCHEMA_TABLE
+ " SET rootpage=%d WHERE #%d AND rootpage=#%d",
+ pParse->db->aDb[iDb].zDbSName, iTable, r1, r1);
#endif
sqlite3ReleaseTempReg(pParse, r1);
}
/*
** Write VDBE code to erase table pTab and all associated indices on disk.
-** Code to update the sqlite_master tables and internal schema definitions
+** Code to update the sqlite_schema tables and internal schema definitions
** in case a root-page belonging to another table is moved by the btree layer
** is also added (this can happen with an auto-vacuum database).
*/
@@ -2895,18 +2910,18 @@ static void destroyTable(Parse *pParse, Table *pTab){
** "OP_Destroy 4 0" opcode. The subsequent "OP_Destroy 5 0" would hit
** a free-list page.
*/
- int iTab = pTab->tnum;
- int iDestroyed = 0;
+ Pgno iTab = pTab->tnum;
+ Pgno iDestroyed = 0;
while( 1 ){
Index *pIdx;
- int iLargest = 0;
+ Pgno iLargest = 0;
if( iDestroyed==0 || iTabpIndex; pIdx; pIdx=pIdx->pNext){
- int iIdx = pIdx->tnum;
+ Pgno iIdx = pIdx->tnum;
assert( pIdx->pSchema==pTab->pSchema );
if( (iDestroyed==0 || (iIdxiLargest ){
iLargest = iIdx;
@@ -2967,8 +2982,8 @@ void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){
#endif
/* Drop all triggers associated with the table being dropped. Code
- ** is generated to remove entries from sqlite_master and/or
- ** sqlite_temp_master if required.
+ ** is generated to remove entries from sqlite_schema and/or
+ ** sqlite_temp_schema if required.
*/
pTrigger = sqlite3TriggerList(pParse, pTab);
while( pTrigger ){
@@ -2992,16 +3007,17 @@ void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){
}
#endif
- /* Drop all SQLITE_MASTER table and index entries that refer to the
- ** table. The program name loops through the master table and deletes
+ /* Drop all entries in the schema table that refer to the
+ ** table. The program name loops through the schema table and deletes
** every row that refers to a table of the same name as the one being
** dropped. Triggers are handled separately because a trigger can be
** created in the temp database that refers to a table in another
** database.
*/
sqlite3NestedParse(pParse,
- "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'",
- pDb->zDbSName, MASTER_NAME, pTab->zName);
+ "DELETE FROM %Q." DFLT_SCHEMA_TABLE
+ " WHERE tbl_name=%Q and type!='trigger'",
+ pDb->zDbSName, pTab->zName);
if( !isView && !IsVirtual(pTab) ){
destroyTable(pParse, pTab);
}
@@ -3138,7 +3154,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
}
#endif
- /* Generate code to remove the table from the master table
+ /* Generate code to remove the table from the schema table
** on disk.
*/
v = sqlite3GetVdbe(pParse);
@@ -3329,7 +3345,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
int iSorter; /* Cursor opened by OpenSorter (if in use) */
int addr1; /* Address of top of loop */
int addr2; /* Address to jump to for next iteration */
- int tnum; /* Root page of index */
+ Pgno tnum; /* Root page of index */
int iPartIdxLabel; /* Jump to this label to skip a row */
Vdbe *v; /* Generate code into this virtual machine */
KeyInfo *pKey; /* KeyInfo for index */
@@ -3350,7 +3366,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
v = sqlite3GetVdbe(pParse);
if( v==0 ) return;
if( memRootPage>=0 ){
- tnum = memRootPage;
+ tnum = (Pgno)memRootPage;
}else{
tnum = pIndex->tnum;
}
@@ -3375,7 +3391,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, addr1);
if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb);
- sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb,
+ sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, (int)tnum, iDb,
(char *)pKey, P4_KEYINFO);
sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0));
@@ -3592,10 +3608,7 @@ void sqlite3CreateIndex(
#if SQLITE_USER_AUTHENTICATION
&& sqlite3UserAuthTable(pTab->zName)==0
#endif
-#ifdef SQLITE_ALLOW_SQLITE_MASTER_INDEX
- && sqlite3StrICmp(&pTab->zName[7],"master")!=0
-#endif
- ){
+ ){
sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
goto exit_create_index;
}
@@ -3617,7 +3630,7 @@ void sqlite3CreateIndex(
** index or table with the same name.
**
** Exception: If we are reading the names of permanent indices from the
- ** sqlite_master table (because some other process changed the schema) and
+ ** sqlite_schema table (because some other process changed the schema) and
** one of the index names collides with the name of a temporary table or
** index, then we will continue to process this index.
**
@@ -3961,8 +3974,8 @@ void sqlite3CreateIndex(
/* If this is the initial CREATE INDEX statement (or CREATE TABLE if the
** index is an implied index for a UNIQUE or PRIMARY KEY constraint) then
** emit code to allocate the index rootpage on disk and make an entry for
- ** the index in the sqlite_master table and populate the index with
- ** content. But, do not do this if we are simply reading the sqlite_master
+ ** the index in the sqlite_schema table and populate the index with
+ ** content. But, do not do this if we are simply reading the sqlite_schema
** table to parse the schema, or if this index is the PRIMARY KEY index
** of a WITHOUT ROWID table.
**
@@ -3987,7 +4000,7 @@ void sqlite3CreateIndex(
** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In
** that case the convertToWithoutRowidTable() routine will replace
** the Noop with a Goto to jump over the VDBE code generated below. */
- pIndex->tnum = sqlite3VdbeAddOp0(v, OP_Noop);
+ pIndex->tnum = (Pgno)sqlite3VdbeAddOp0(v, OP_Noop);
sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY);
/* Gather the complete text of the CREATE INDEX statement into
@@ -4006,11 +4019,11 @@ void sqlite3CreateIndex(
zStmt = 0;
}
- /* Add an entry in sqlite_master for this index
+ /* Add an entry in sqlite_schema for this index
*/
sqlite3NestedParse(pParse,
- "INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);",
- db->aDb[iDb].zDbSName, MASTER_NAME,
+ "INSERT INTO %Q." DFLT_SCHEMA_TABLE " VALUES('index',%Q,%Q,#%d,%Q);",
+ db->aDb[iDb].zDbSName,
pIndex->zName,
pTab->zName,
iMem,
@@ -4029,7 +4042,7 @@ void sqlite3CreateIndex(
sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
}
- sqlite3VdbeJumpHere(v, pIndex->tnum);
+ sqlite3VdbeJumpHere(v, (int)pIndex->tnum);
}
}
if( db->init.busy || pTblName==0 ){
@@ -4086,9 +4099,10 @@ exit_create_index:
** are based on typical values found in actual indices.
*/
void sqlite3DefaultRowEst(Index *pIdx){
- /* 10, 9, 8, 7, 6 */
- LogEst aVal[] = { 33, 32, 30, 28, 26 };
+ /* 10, 9, 8, 7, 6 */
+ static const LogEst aVal[] = { 33, 32, 30, 28, 26 };
LogEst *a = pIdx->aiRowLogEst;
+ LogEst x;
int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol);
int i;
@@ -4097,10 +4111,21 @@ void sqlite3DefaultRowEst(Index *pIdx){
/* 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. */
- a[0] = pIdx->pTable->nRowLogEst;
- if( pIdx->pPartIdxWhere!=0 ) a[0] -= 10; assert( 10==sqlite3LogEst(2) );
- if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) );
+ ** for a partial index.
+ **
+ ** 2020-05-27: If some of the stat data is coming from the sqlite_stat1
+ ** table but other parts we are having to guess at, then do not let the
+ ** estimated number of rows in the table be less than 1000 (LogEst 99).
+ ** Failure to do this can cause the indexes for which we do not have
+ ** stat1 data to be ignored by the query planner. tag-20200527-1
+ */
+ x = pIdx->pTable->nRowLogEst;
+ assert( 99==sqlite3LogEst(1000) );
+ if( x<99 ){
+ pIdx->pTable->nRowLogEst = x = 99;
+ }
+ if( pIdx->pPartIdxWhere!=0 ) x -= 10; assert( 10==sqlite3LogEst(2) );
+ a[0] = x;
/* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is
** 6 and each subsequent value (if any) is 5. */
@@ -4164,13 +4189,13 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
}
#endif
- /* Generate code to remove the index and from the master table */
+ /* Generate code to remove the index and from the schema table */
v = sqlite3GetVdbe(pParse);
if( v ){
sqlite3BeginWriteOperation(pParse, 1, iDb);
sqlite3NestedParse(pParse,
- "DELETE FROM %Q.%s WHERE name=%Q AND type='index'",
- db->aDb[iDb].zDbSName, MASTER_NAME, pIndex->zName
+ "DELETE FROM %Q." DFLT_SCHEMA_TABLE " WHERE name=%Q AND type='index'",
+ db->aDb[iDb].zDbSName, pIndex->zName
);
sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName);
sqlite3ChangeCookie(pParse, iDb);
@@ -4569,6 +4594,26 @@ void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){
}
}
+/*
+** Append the contents of SrcList p2 to SrcList p1 and return the resulting
+** SrcList. Or, if an error occurs, return NULL. In all cases, p1 and p2
+** are deleted by this function.
+*/
+SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2){
+ assert( p1 && p1->nSrc==1 );
+ if( p2 ){
+ SrcList *pNew = sqlite3SrcListEnlarge(pParse, p1, p2->nSrc, 1);
+ if( pNew==0 ){
+ sqlite3SrcListDelete(pParse->db, p2);
+ }else{
+ p1 = pNew;
+ memcpy(&p1->a[1], p2->a, p2->nSrc*sizeof(struct SrcList_item));
+ sqlite3DbFree(pParse->db, p2);
+ }
+ }
+ return p1;
+}
+
/*
** Add the list of function arguments to the SrcList entry for a
** table-valued-function.
diff --git a/src/date.c b/src/date.c
index fff062fb5a..1db26b1c69 100644
--- a/src/date.c
+++ b/src/date.c
@@ -515,7 +515,7 @@ static int osLocaltime(time_t *t, struct tm *pTm){
#if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S
struct tm *pX;
#if SQLITE_THREADSAFE>0
- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
#endif
sqlite3_mutex_enter(mutex);
pX = localtime(t);
@@ -1112,8 +1112,8 @@ static void strftimeFunc(
case 'm': sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break;
case 'M': sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break;
case 's': {
- sqlite3_snprintf(30,&z[j],"%lld",
- (i64)(x.iJD/1000 - 21086676*(i64)10000));
+ i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000);
+ sqlite3Int64ToText(iS, &z[j]);
j += sqlite3Strlen30(&z[j]);
break;
}
@@ -1211,10 +1211,10 @@ static void currentTimeFunc(
#if HAVE_GMTIME_R
pTm = gmtime_r(&t, &sNow);
#else
- sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN));
pTm = gmtime(&t);
if( pTm ) memcpy(&sNow, pTm, sizeof(sNow));
- sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN));
#endif
if( pTm ){
strftime(zBuf, 20, zFormat, &sNow);
diff --git a/src/dbstat.c b/src/dbstat.c
index bddde79ced..78173c3976 100644
--- a/src/dbstat.c
+++ b/src/dbstat.c
@@ -724,10 +724,10 @@ static int statFilter(
pSql = sqlite3_str_new(pTab->db);
sqlite3_str_appendf(pSql,
"SELECT * FROM ("
- "SELECT 'sqlite_master' AS name,1 AS rootpage,'table' AS type"
+ "SELECT 'sqlite_schema' AS name,1 AS rootpage,'table' AS type"
" UNION ALL "
"SELECT name,rootpage,type"
- " FROM \"%w\".sqlite_master WHERE rootpage!=0)",
+ " FROM \"%w\".sqlite_schema WHERE rootpage!=0)",
pTab->db->aDb[pCsr->iDb].zDbSName);
if( zName ){
sqlite3_str_appendf(pSql, "WHERE name=%Q", zName);
diff --git a/src/delete.c b/src/delete.c
index 141efa5940..ae2f85b3a9 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -31,7 +31,7 @@
Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
struct SrcList_item *pItem = pSrc->a;
Table *pTab;
- assert( pItem && pSrc->nSrc==1 );
+ assert( pItem && pSrc->nSrc>=1 );
pTab = sqlite3LocateTableItem(pParse, 0, pItem);
sqlite3DeleteTable(pParse->db, pItem->pTab);
pItem->pTab = pTab;
@@ -51,7 +51,7 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
** 1) It is a virtual table and no implementation of the xUpdate method
** has been provided
**
-** 2) It is a system table (i.e. sqlite_master), this call is not
+** 2) It is a system table (i.e. sqlite_schema), this call is not
** part of a nested parse and writable_schema pragma has not
** been specified
**
diff --git a/src/expr.c b/src/expr.c
index c5b6783871..b64ea28bf5 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -52,6 +52,9 @@ char sqlite3ExprAffinity(const Expr *pExpr){
op = pExpr->op;
if( op==TK_SELECT ){
assert( pExpr->flags&EP_xIsSelect );
+ assert( pExpr->x.pSelect!=0 );
+ assert( pExpr->x.pSelect->pEList!=0 );
+ assert( pExpr->x.pSelect->pEList->a[0].pExpr!=0 );
return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
}
if( op==TK_REGISTER ) op = pExpr->op2;
@@ -195,7 +198,7 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){
&& ALWAYS(!ExprHasProperty(p, EP_xIsSelect))
){
int i;
- for(i=0; ix.pList->nExpr; i++){
+ for(i=0; ALWAYS(ix.pList->nExpr); i++){
if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){
pNext = p->x.pList->a[i].pExpr;
break;
@@ -1988,10 +1991,10 @@ Expr *sqlite3ExprSimplifiedAndOr(Expr *pExpr){
**
** The sqlite3ExprIsConstantOrFunction() is used for evaluating DEFAULT
** expressions in a CREATE TABLE statement. The Walker.eCode value is 5
-** when parsing an existing schema out of the sqlite_master table and 4
+** when parsing an existing schema out of the sqlite_schema table and 4
** when processing a new CREATE TABLE statement. A bound parameter raises
** an error for new statements, but is silently converted
-** to NULL for existing schemas. This allows sqlite_master tables that
+** to NULL for existing schemas. This allows sqlite_schema tables that
** contain a bound parameter because they were generated by older versions
** of SQLite to be parsed by newer versions of SQLite without raising a
** malformed schema error.
@@ -2026,7 +2029,7 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
if( sqlite3ExprIdToTrueFalse(pExpr) ){
return WRC_Prune;
}
- /* Fall thru */
+ /* no break */ deliberate_fall_through
case TK_COLUMN:
case TK_AGG_FUNCTION:
case TK_AGG_COLUMN:
@@ -2040,18 +2043,20 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){
return WRC_Continue;
}
- /* Fall through */
+ /* no break */ deliberate_fall_through
case TK_IF_NULL_ROW:
case TK_REGISTER:
+ case TK_DOT:
testcase( pExpr->op==TK_REGISTER );
testcase( pExpr->op==TK_IF_NULL_ROW );
+ testcase( pExpr->op==TK_DOT );
pWalker->eCode = 0;
return WRC_Abort;
case TK_VARIABLE:
if( pWalker->eCode==5 ){
/* Silently convert bound parameters that appear inside of CREATE
** statements into a NULL when parsing the CREATE statement text out
- ** of the sqlite_master table */
+ ** of the sqlite_schema table */
pExpr->op = TK_NULL;
}else if( pWalker->eCode==4 ){
/* A bound parameter in a CREATE statement that originates from
@@ -2059,7 +2064,7 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
pWalker->eCode = 0;
return WRC_Abort;
}
- /* Fall through */
+ /* no break */ deliberate_fall_through
default:
testcase( pExpr->op==TK_SELECT ); /* sqlite3SelectWalkFail() disallows */
testcase( pExpr->op==TK_EXISTS ); /* sqlite3SelectWalkFail() disallows */
@@ -2184,12 +2189,12 @@ int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprList *pGroupBy){
** the expression is constant or a function call with constant arguments.
** Return and 0 if there are any variables.
**
-** isInit is true when parsing from sqlite_master. isInit is false when
+** isInit is true when parsing from sqlite_schema. isInit is false when
** processing a new CREATE TABLE statement. When isInit is true, parameters
** (such as ? or $abc) in the expression are converted into NULL. When
** isInit is false, parameters raise an error. Parameters should not be
** allowed in a CREATE TABLE statement, but some legacy versions of SQLite
-** allowed it, so we need to support it when reading sqlite_master for
+** allowed it, so we need to support it when reading sqlite_schema for
** backwards compatibility.
**
** If isInit is true, set EP_FromDDL on every TK_FUNCTION node.
@@ -2552,7 +2557,7 @@ int sqlite3FindInIndex(
if( pParse->nErr==0 && (p = isCandidateForInOpt(pX))!=0 ){
sqlite3 *db = pParse->db; /* Database connection */
Table *pTab; /* Table . */
- i16 iDb; /* Database idx for pTab */
+ int iDb; /* Database idx for pTab */
ExprList *pEList = p->pEList;
int nExpr = pEList->nExpr;
@@ -2563,6 +2568,7 @@ int sqlite3FindInIndex(
/* Code an OP_Transaction and OP_TableLock for . */
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+ assert( iDb>=0 && iDbtnum, 0, pTab->zName);
@@ -3796,10 +3802,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
int p5 = 0;
assert( target>0 && target<=pParse->nMem );
- if( v==0 ){
- assert( pParse->db->mallocFailed );
- return 0;
- }
+ assert( v!=0 );
expr_code_doover:
if( pExpr==0 ){
@@ -3833,6 +3836,7 @@ expr_code_doover:
return target;
}
/* Otherwise, fall thru into the TK_COLUMN case */
+ /* no break */ deliberate_fall_through
}
case TK_COLUMN: {
int iTab = pExpr->iTable;
@@ -4265,7 +4269,9 @@ expr_code_doover:
int nCol;
testcase( op==TK_EXISTS );
testcase( op==TK_SELECT );
- if( op==TK_SELECT && (nCol = pExpr->x.pSelect->pEList->nExpr)!=1 ){
+ if( pParse->db->mallocFailed ){
+ return 0;
+ }else if( op==TK_SELECT && (nCol = pExpr->x.pSelect->pEList->nExpr)!=1 ){
sqlite3SubselectError(pParse, nCol, 1);
}else{
return sqlite3CodeSubselect(pParse, pExpr);
@@ -4629,9 +4635,10 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
assert( pExpr==0 || !ExprHasVVAProperty(pExpr,EP_Immutable) );
assert( target>0 && target<=pParse->nMem );
- inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
assert( pParse->pVdbe!=0 || pParse->db->mallocFailed );
- if( inReg!=target && pParse->pVdbe ){
+ if( pParse->pVdbe==0 ) return;
+ inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
+ if( inReg!=target ){
u8 op;
if( ExprHasProperty(pExpr,EP_Subquery) ){
op = OP_Copy;
@@ -4895,7 +4902,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
testcase( op==TK_ISNOT );
op = (op==TK_IS) ? TK_EQ : TK_NE;
jumpIfNull = SQLITE_NULLEQ;
- /* Fall thru */
+ /* no break */ deliberate_fall_through
case TK_LT:
case TK_LE:
case TK_GT:
@@ -5071,7 +5078,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
testcase( pExpr->op==TK_ISNOT );
op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
jumpIfNull = SQLITE_NULLEQ;
- /* Fall thru */
+ /* no break */ deliberate_fall_through
case TK_LT:
case TK_LE:
case TK_GT:
@@ -5383,13 +5390,13 @@ static int exprImpliesNotNull(
case TK_RSHIFT:
case TK_CONCAT:
seenNot = 1;
- /* Fall thru */
+ /* no break */ deliberate_fall_through
case TK_STAR:
case TK_REM:
case TK_BITAND:
case TK_SLASH: {
if( exprImpliesNotNull(pParse, p->pRight, pNN, iTab, seenNot) ) return 1;
- /* Fall thru into the next case */
+ /* no break */ deliberate_fall_through
}
case TK_SPAN:
case TK_COLLATE:
@@ -5538,6 +5545,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
){
return WRC_Prune;
}
+ /* no break */ deliberate_fall_through
}
default:
return WRC_Continue;
@@ -5650,10 +5658,25 @@ int sqlite3ExprCoveredByIndex(
*/
struct SrcCount {
SrcList *pSrc; /* One particular FROM clause in a nested query */
+ int iSrcInner; /* Smallest cursor number in this context */
int nThis; /* Number of references to columns in pSrcList */
int nOther; /* Number of references to columns in other FROM clauses */
};
+/*
+** xSelect callback for sqlite3FunctionUsesThisSrc(). If this is the first
+** SELECT with a FROM clause encountered during this iteration, set
+** SrcCount.iSrcInner to the cursor number of the leftmost object in
+** the FROM cause.
+*/
+static int selectSrcCount(Walker *pWalker, Select *pSel){
+ struct SrcCount *p = pWalker->u.pSrcCount;
+ if( p->iSrcInner==0x7FFFFFFF && ALWAYS(pSel->pSrc) && pSel->pSrc->nSrc ){
+ pWalker->u.pSrcCount->iSrcInner = pSel->pSrc->a[0].iCursor;
+ }
+ return WRC_Continue;
+}
+
/*
** Count the number of references to columns.
*/
@@ -5674,7 +5697,7 @@ static int exprSrcCount(Walker *pWalker, Expr *pExpr){
}
if( inThis++;
- }else if( nSrc==0 || pExpr->iTablea[0].iCursor ){
+ }else if( pExpr->iTableiSrcInner ){
/* In a well-formed parse tree (no name resolution errors),
** TK_COLUMN nodes with smaller Expr.iTable values are in an
** outer context. Those are the only ones to count as "other" */
@@ -5696,9 +5719,10 @@ int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){
assert( pExpr->op==TK_AGG_FUNCTION );
memset(&w, 0, sizeof(w));
w.xExprCallback = exprSrcCount;
- w.xSelectCallback = sqlite3SelectWalkNoop;
+ w.xSelectCallback = selectSrcCount;
w.u.pSrcCount = &cnt;
cnt.pSrc = pSrcList;
+ cnt.iSrcInner = (pSrcList&&pSrcList->nSrc)?pSrcList->a[0].iCursor:0x7FFFFFFF;
cnt.nThis = 0;
cnt.nOther = 0;
sqlite3WalkExprList(&w, pExpr->x.pList);
@@ -5710,6 +5734,64 @@ int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){
return cnt.nThis>0 || cnt.nOther==0;
}
+/*
+** This is a Walker expression node callback.
+**
+** For Expr nodes that contain pAggInfo pointers, make sure the AggInfo
+** object that is referenced does not refer directly to the Expr. If
+** it does, make a copy. This is done because the pExpr argument is
+** subject to change.
+**
+** The copy is stored on pParse->pConstExpr with a register number of 0.
+** This will cause the expression to be deleted automatically when the
+** Parse object is destroyed, but the zero register number means that it
+** will not generate any code in the preamble.
+*/
+static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
+ if( ALWAYS(!ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced))
+ && pExpr->pAggInfo!=0
+ ){
+ AggInfo *pAggInfo = pExpr->pAggInfo;
+ int iAgg = pExpr->iAgg;
+ Parse *pParse = pWalker->pParse;
+ sqlite3 *db = pParse->db;
+ assert( pExpr->op==TK_AGG_COLUMN || pExpr->op==TK_AGG_FUNCTION );
+ if( pExpr->op==TK_AGG_COLUMN ){
+ assert( iAgg>=0 && iAggnColumn );
+ if( pAggInfo->aCol[iAgg].pCExpr==pExpr ){
+ pExpr = sqlite3ExprDup(db, pExpr, 0);
+ if( pExpr ){
+ pAggInfo->aCol[iAgg].pCExpr = pExpr;
+ pParse->pConstExpr =
+ sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr);
+ }
+ }
+ }else{
+ assert( iAgg>=0 && iAggnFunc );
+ if( pAggInfo->aFunc[iAgg].pFExpr==pExpr ){
+ pExpr = sqlite3ExprDup(db, pExpr, 0);
+ if( pExpr ){
+ pAggInfo->aFunc[iAgg].pFExpr = pExpr;
+ pParse->pConstExpr =
+ sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr);
+ }
+ }
+ }
+ }
+ return WRC_Continue;
+}
+
+/*
+** Initialize a Walker object so that will persist AggInfo entries referenced
+** by the tree that is walked.
+*/
+void sqlite3AggInfoPersistWalkerInit(Walker *pWalker, Parse *pParse){
+ memset(pWalker, 0, sizeof(*pWalker));
+ pWalker->pParse = pParse;
+ pWalker->xExprCallback = agginfoPersistExprCb;
+ pWalker->xSelectCallback = sqlite3SelectWalkNoop;
+}
+
/*
** Add a new element to the pAggInfo->aCol[] array. Return the index of
** the new element. Return a negative number if malloc fails.
@@ -5740,7 +5822,7 @@ static int addAggInfoFunc(sqlite3 *db, AggInfo *pInfo){
&i
);
return i;
-}
+}
/*
** This is the xExprCallback for a tree walker. It is used to
@@ -5791,7 +5873,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
pCol->iColumn = pExpr->iColumn;
pCol->iMem = ++pParse->nMem;
pCol->iSorterColumn = -1;
- pCol->pExpr = pExpr;
+ pCol->pCExpr = pExpr;
if( pAggInfo->pGroupBy ){
int j, n;
ExprList *pGB = pAggInfo->pGroupBy;
@@ -5834,7 +5916,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
*/
struct AggInfo_func *pItem = pAggInfo->aFunc;
for(i=0; inFunc; i++, pItem++){
- if( sqlite3ExprCompare(0, pItem->pExpr, pExpr, -1)==0 ){
+ if( sqlite3ExprCompare(0, pItem->pFExpr, pExpr, -1)==0 ){
break;
}
}
@@ -5846,7 +5928,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
if( i>=0 ){
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
pItem = &pAggInfo->aFunc[i];
- pItem->pExpr = pExpr;
+ pItem->pFExpr = pExpr;
pItem->iMem = ++pParse->nMem;
assert( !ExprHasProperty(pExpr, EP_IntValue) );
pItem->pFunc = sqlite3FindFunction(pParse->db,
diff --git a/src/fkey.c b/src/fkey.c
index d4ace40a2a..e9bfbbfcfd 100644
--- a/src/fkey.c
+++ b/src/fkey.c
@@ -1359,6 +1359,7 @@ static Trigger *fkActionTrigger(
pStep->op = TK_DELETE;
break;
}
+ /* no break */ deliberate_fall_through
default:
pStep->op = TK_UPDATE;
}
diff --git a/src/global.c b/src/global.c
index aeddada6f2..8ef5a8b2d0 100644
--- a/src/global.c
+++ b/src/global.c
@@ -300,6 +300,11 @@ sqlite3_uint64 sqlite3NProfileCnt = 0;
int sqlite3PendingByte = 0x40000000;
#endif
+/*
+** Flags for select tracing and the ".selecttrace" macro of the CLI
+*/
+u32 sqlite3_unsupported_selecttrace = 0;
+
#include "opcodes.h"
/*
** Properties of opcodes. The OPFLG_INITIALIZER macro is
diff --git a/src/insert.c b/src/insert.c
index 287caeb0ff..789b3b6634 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -180,7 +180,7 @@ static int readsTable(Parse *p, int iDb, Table *pTab){
assert( pOp!=0 );
if( pOp->opcode==OP_OpenRead && pOp->p3==iDb ){
Index *pIndex;
- int tnum = pOp->p2;
+ Pgno tnum = pOp->p2;
if( tnum==pTab->tnum ){
return 1;
}
@@ -1612,7 +1612,7 @@ void sqlite3GenerateConstraintChecks(
}
case OE_Abort:
sqlite3MayAbort(pParse);
- /* Fall through */
+ /* no break */ deliberate_fall_through
case OE_Rollback:
case OE_Fail: {
char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName,
@@ -1840,7 +1840,7 @@ void sqlite3GenerateConstraintChecks(
switch( onError ){
default: {
onError = OE_Abort;
- /* Fall thru into the next case */
+ /* no break */ deliberate_fall_through
}
case OE_Rollback:
case OE_Abort:
@@ -1901,7 +1901,7 @@ void sqlite3GenerateConstraintChecks(
#ifndef SQLITE_OMIT_UPSERT
case OE_Update: {
sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, 0, iDataCur);
- /* Fall through */
+ /* no break */ deliberate_fall_through
}
#endif
case OE_Ignore: {
@@ -2122,7 +2122,7 @@ void sqlite3GenerateConstraintChecks(
#ifndef SQLITE_OMIT_UPSERT
case OE_Update: {
sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, pIdx, iIdxCur+ix);
- /* Fall through */
+ /* no break */ deliberate_fall_through
}
#endif
case OE_Ignore: {
@@ -2610,7 +2610,7 @@ static int xferOptimization(
return 0; /* FROM clause does not contain a real table */
}
if( pSrc->tnum==pDest->tnum && pSrc->pSchema==pDest->pSchema ){
- testcase( pSrc!=pDest ); /* Possible due to bad sqlite_master.rootpage */
+ testcase( pSrc!=pDest ); /* Possible due to bad sqlite_schema.rootpage */
return 0; /* tab1 and tab2 may not be the same table */
}
if( HasRowid(pDest)!=HasRowid(pSrc) ){
diff --git a/src/loadext.c b/src/loadext.c
index 067c47c17f..7007e3137d 100644
--- a/src/loadext.c
+++ b/src/loadext.c
@@ -689,7 +689,7 @@ int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
** The following object holds the list of automatically loaded
** extensions.
**
-** This list is shared across threads. The SQLITE_MUTEX_STATIC_MASTER
+** This list is shared across threads. The SQLITE_MUTEX_STATIC_MAIN
** mutex must be held while accessing this list.
*/
typedef struct sqlite3AutoExtList sqlite3AutoExtList;
@@ -731,7 +731,7 @@ int sqlite3_auto_extension(
{
u32 i;
#if SQLITE_THREADSAFE
- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
#endif
wsdAutoextInit;
sqlite3_mutex_enter(mutex);
@@ -769,7 +769,7 @@ int sqlite3_cancel_auto_extension(
void (*xInit)(void)
){
#if SQLITE_THREADSAFE
- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
#endif
int i;
int n = 0;
@@ -796,7 +796,7 @@ void sqlite3_reset_auto_extension(void){
#endif
{
#if SQLITE_THREADSAFE
- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
#endif
wsdAutoextInit;
sqlite3_mutex_enter(mutex);
@@ -826,7 +826,7 @@ void sqlite3AutoLoadExtensions(sqlite3 *db){
for(i=0; go; i++){
char *zErrmsg;
#if SQLITE_THREADSAFE
- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
#endif
#ifdef SQLITE_OMIT_LOAD_EXTENSION
const sqlite3_api_routines *pThunk = 0;
diff --git a/src/main.c b/src/main.c
index ae708dac7f..0679c7046e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -100,7 +100,7 @@ static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = {
#ifndef SQLITE_AMALGAMATION
/* IMPLEMENTATION-OF: R-46656-45156 The sqlite3_version[] string constant
-** contains the text of SQLITE_VERSION macro.
+** contains the text of SQLITE_VERSION macro.
*/
const char sqlite3_version[] = SQLITE_VERSION;
#endif
@@ -201,7 +201,7 @@ char *sqlite3_data_directory = 0;
** without blocking.
*/
int sqlite3_initialize(void){
- MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
+ MUTEX_LOGIC( sqlite3_mutex *pMainMtx; ) /* The main static mutex */
int rc; /* Result code */
#ifdef SQLITE_EXTRA_INIT
int bRunExtraInit = 0; /* Extra initialization needed */
@@ -241,13 +241,13 @@ int sqlite3_initialize(void){
if( rc ) return rc;
/* Initialize the malloc() system and the recursive pInitMutex mutex.
- ** This operation is protected by the STATIC_MASTER mutex. Note that
+ ** This operation is protected by the STATIC_MAIN mutex. Note that
** MutexAlloc() is called for a static mutex prior to initializing the
** malloc subsystem - this implies that the allocation of a static
** mutex must not require support from the malloc subsystem.
*/
- MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
- sqlite3_mutex_enter(pMaster);
+ MUTEX_LOGIC( pMainMtx = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); )
+ sqlite3_mutex_enter(pMainMtx);
sqlite3GlobalConfig.isMutexInit = 1;
if( !sqlite3GlobalConfig.isMallocInit ){
rc = sqlite3MallocInit();
@@ -265,7 +265,7 @@ int sqlite3_initialize(void){
if( rc==SQLITE_OK ){
sqlite3GlobalConfig.nRefInitMutex++;
}
- sqlite3_mutex_leave(pMaster);
+ sqlite3_mutex_leave(pMainMtx);
/* If rc is not SQLITE_OK at this point, then either the malloc
** subsystem could not be initialized or the system failed to allocate
@@ -326,14 +326,14 @@ int sqlite3_initialize(void){
/* Go back under the static mutex and clean up the recursive
** mutex to prevent a resource leak.
*/
- sqlite3_mutex_enter(pMaster);
+ sqlite3_mutex_enter(pMainMtx);
sqlite3GlobalConfig.nRefInitMutex--;
if( sqlite3GlobalConfig.nRefInitMutex<=0 ){
assert( sqlite3GlobalConfig.nRefInitMutex==0 );
sqlite3_mutex_free(sqlite3GlobalConfig.pInitMutex);
sqlite3GlobalConfig.pInitMutex = 0;
}
- sqlite3_mutex_leave(pMaster);
+ sqlite3_mutex_leave(pMainMtx);
/* The following is just a sanity check to make sure SQLite has
** been compiled correctly. It is important to run this code, but
@@ -1213,7 +1213,7 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
}
sqlite3_mutex_enter(db->mutex);
if( db->mTrace & SQLITE_TRACE_CLOSE ){
- db->xTrace(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0);
+ db->trace.xV2(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0);
}
/* Force xDisconnect calls on all virtual tables */
@@ -2103,7 +2103,7 @@ void *sqlite3_trace(sqlite3 *db, void(*xTrace)(void*,const char*), void *pArg){
sqlite3_mutex_enter(db->mutex);
pOld = db->pTraceArg;
db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0;
- db->xTrace = (int(*)(u32,void*,void*,void*))xTrace;
+ db->trace.xLegacy = xTrace;
db->pTraceArg = pArg;
sqlite3_mutex_leave(db->mutex);
return pOld;
@@ -2127,7 +2127,7 @@ int sqlite3_trace_v2(
if( mTrace==0 ) xTrace = 0;
if( xTrace==0 ) mTrace = 0;
db->mTrace = mTrace;
- db->xTrace = xTrace;
+ db->trace.xV2 = xTrace;
db->pTraceArg = pArg;
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
@@ -3124,7 +3124,7 @@ static int openDatabase(
SQLITE_OPEN_MAIN_JOURNAL |
SQLITE_OPEN_TEMP_JOURNAL |
SQLITE_OPEN_SUBJOURNAL |
- SQLITE_OPEN_MASTER_JOURNAL |
+ SQLITE_OPEN_SUPER_JOURNAL |
SQLITE_OPEN_NOMUTEX |
SQLITE_OPEN_FULLMUTEX |
SQLITE_OPEN_WAL
@@ -4117,8 +4117,14 @@ int sqlite3_test_control(int op, ...){
/* sqlite3_test_control(SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS, int);
**
** Set or clear a flag that causes SQLite to verify that type, name,
- ** and tbl_name fields of the sqlite_master table. This is normally
+ ** and tbl_name fields of the sqlite_schema table. This is normally
** on, but it is sometimes useful to turn it off for testing.
+ **
+ ** 2020-07-22: Disabling EXTRA_SCHEMA_CHECKS also disables the
+ ** verification of rootpage numbers when parsing the schema. This
+ ** is useful to make it easier to reach strange internal error states
+ ** during testing. The EXTRA_SCHEMA_CHECKS settting is always enabled
+ ** in production.
*/
case SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS: {
sqlite3GlobalConfig.bExtraSchemaChecks = va_arg(ap, int);
diff --git a/src/malloc.c b/src/malloc.c
index 577836ef9a..70e6ff94e5 100644
--- a/src/malloc.c
+++ b/src/malloc.c
@@ -719,11 +719,9 @@ char *sqlite3DbStrDup(sqlite3 *db, const char *z){
char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){
char *zNew;
assert( db!=0 );
- if( z==0 ){
- return 0;
- }
+ assert( z!=0 || n==0 );
assert( (n&0x7fffffff)==n );
- zNew = sqlite3DbMallocRawNN(db, n+1);
+ zNew = z ? sqlite3DbMallocRawNN(db, n+1) : 0;
if( zNew ){
memcpy(zNew, z, (size_t)n);
zNew[n] = 0;
diff --git a/src/mem2.c b/src/mem2.c
index 51ea297c6a..ac031508c2 100644
--- a/src/mem2.c
+++ b/src/mem2.c
@@ -379,7 +379,7 @@ void sqlite3MemSetDefault(void){
** Set the "type" of an allocation.
*/
void sqlite3MemdebugSetType(void *p, u8 eType){
- if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
+ if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){
struct MemBlockHdr *pHdr;
pHdr = sqlite3MemsysGetHeader(p);
assert( pHdr->iForeGuard==FOREGUARD );
@@ -398,7 +398,7 @@ void sqlite3MemdebugSetType(void *p, u8 eType){
*/
int sqlite3MemdebugHasType(void *p, u8 eType){
int rc = 1;
- if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
+ if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){
struct MemBlockHdr *pHdr;
pHdr = sqlite3MemsysGetHeader(p);
assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */
@@ -420,7 +420,7 @@ int sqlite3MemdebugHasType(void *p, u8 eType){
*/
int sqlite3MemdebugNoType(void *p, u8 eType){
int rc = 1;
- if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
+ if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){
struct MemBlockHdr *pHdr;
pHdr = sqlite3MemsysGetHeader(p);
assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */
diff --git a/src/mem3.c b/src/mem3.c
index 2de028daa9..16463d6a5c 100644
--- a/src/mem3.c
+++ b/src/mem3.c
@@ -118,16 +118,16 @@ static SQLITE_WSD struct Mem3Global {
/*
** The minimum amount of free space that we have seen.
*/
- u32 mnMaster;
+ u32 mnKeyBlk;
/*
- ** iMaster is the index of the master chunk. Most new allocations
- ** occur off of this chunk. szMaster is the size (in Mem3Blocks)
- ** of the current master. iMaster is 0 if there is not master chunk.
- ** The master chunk is not in either the aiHash[] or aiSmall[].
+ ** iKeyBlk is the index of the key chunk. Most new allocations
+ ** occur off of this chunk. szKeyBlk is the size (in Mem3Blocks)
+ ** of the current key chunk. iKeyBlk is 0 if there is no key chunk.
+ ** The key chunk is not in either the aiHash[] or aiSmall[].
*/
- u32 iMaster;
- u32 szMaster;
+ u32 iKeyBlk;
+ u32 szKeyBlk;
/*
** Array of lists of free blocks according to the block size
@@ -263,34 +263,34 @@ static void *memsys3Checkout(u32 i, u32 nBlock){
}
/*
-** Carve a piece off of the end of the mem3.iMaster free chunk.
-** Return a pointer to the new allocation. Or, if the master chunk
+** Carve a piece off of the end of the mem3.iKeyBlk free chunk.
+** Return a pointer to the new allocation. Or, if the key chunk
** is not large enough, return 0.
*/
-static void *memsys3FromMaster(u32 nBlock){
+static void *memsys3FromKeyBlk(u32 nBlock){
assert( sqlite3_mutex_held(mem3.mutex) );
- assert( mem3.szMaster>=nBlock );
- if( nBlock>=mem3.szMaster-1 ){
- /* Use the entire master */
- void *p = memsys3Checkout(mem3.iMaster, mem3.szMaster);
- mem3.iMaster = 0;
- mem3.szMaster = 0;
- mem3.mnMaster = 0;
+ assert( mem3.szKeyBlk>=nBlock );
+ if( nBlock>=mem3.szKeyBlk-1 ){
+ /* Use the entire key chunk */
+ void *p = memsys3Checkout(mem3.iKeyBlk, mem3.szKeyBlk);
+ mem3.iKeyBlk = 0;
+ mem3.szKeyBlk = 0;
+ mem3.mnKeyBlk = 0;
return p;
}else{
- /* Split the master block. Return the tail. */
+ /* Split the key block. Return the tail. */
u32 newi, x;
- newi = mem3.iMaster + mem3.szMaster - nBlock;
- assert( newi > mem3.iMaster+1 );
- mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = nBlock;
- mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x |= 2;
+ newi = mem3.iKeyBlk + mem3.szKeyBlk - nBlock;
+ assert( newi > mem3.iKeyBlk+1 );
+ mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = nBlock;
+ mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x |= 2;
mem3.aPool[newi-1].u.hdr.size4x = nBlock*4 + 1;
- mem3.szMaster -= nBlock;
- mem3.aPool[newi-1].u.hdr.prevSize = mem3.szMaster;
- x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2;
- mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x;
- if( mem3.szMaster < mem3.mnMaster ){
- mem3.mnMaster = mem3.szMaster;
+ mem3.szKeyBlk -= nBlock;
+ mem3.aPool[newi-1].u.hdr.prevSize = mem3.szKeyBlk;
+ x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2;
+ mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x;
+ if( mem3.szKeyBlk < mem3.mnKeyBlk ){
+ mem3.mnKeyBlk = mem3.szKeyBlk;
}
return (void*)&mem3.aPool[newi];
}
@@ -304,13 +304,13 @@ static void *memsys3FromMaster(u32 nBlock){
** This routine examines all entries on the given list and tries
** to coalesce each entries with adjacent free chunks.
**
-** If it sees a chunk that is larger than mem3.iMaster, it replaces
-** the current mem3.iMaster with the new larger chunk. In order for
-** this mem3.iMaster replacement to work, the master chunk must be
+** If it sees a chunk that is larger than mem3.iKeyBlk, it replaces
+** the current mem3.iKeyBlk with the new larger chunk. In order for
+** this mem3.iKeyBlk replacement to work, the key chunk must be
** linked into the hash tables. That is not the normal state of
-** affairs, of course. The calling routine must link the master
+** affairs, of course. The calling routine must link the key
** chunk before invoking this routine, then must unlink the (possibly
-** changed) master chunk once this routine has finished.
+** changed) key chunk once this routine has finished.
*/
static void memsys3Merge(u32 *pRoot){
u32 iNext, prev, size, i, x;
@@ -337,9 +337,9 @@ static void memsys3Merge(u32 *pRoot){
}else{
size /= 4;
}
- if( size>mem3.szMaster ){
- mem3.iMaster = i;
- mem3.szMaster = size;
+ if( size>mem3.szKeyBlk ){
+ mem3.iKeyBlk = i;
+ mem3.szKeyBlk = size;
}
}
}
@@ -388,26 +388,26 @@ static void *memsys3MallocUnsafe(int nByte){
/* STEP 2:
** Try to satisfy the allocation by carving a piece off of the end
- ** of the master chunk. This step usually works if step 1 fails.
+ ** of the key chunk. This step usually works if step 1 fails.
*/
- if( mem3.szMaster>=nBlock ){
- return memsys3FromMaster(nBlock);
+ if( mem3.szKeyBlk>=nBlock ){
+ return memsys3FromKeyBlk(nBlock);
}
/* STEP 3:
** Loop through the entire memory pool. Coalesce adjacent free
- ** chunks. Recompute the master chunk as the largest free chunk.
+ ** chunks. Recompute the key chunk as the largest free chunk.
** Then try again to satisfy the allocation by carving a piece off
- ** of the end of the master chunk. This step happens very
+ ** of the end of the key chunk. This step happens very
** rarely (we hope!)
*/
for(toFree=nBlock*16; toFree<(mem3.nPool*16); toFree *= 2){
memsys3OutOfMemory(toFree);
- if( mem3.iMaster ){
- memsys3Link(mem3.iMaster);
- mem3.iMaster = 0;
- mem3.szMaster = 0;
+ if( mem3.iKeyBlk ){
+ memsys3Link(mem3.iKeyBlk);
+ mem3.iKeyBlk = 0;
+ mem3.szKeyBlk = 0;
}
for(i=0; i=nBlock ){
- return memsys3FromMaster(nBlock);
+ if( mem3.szKeyBlk ){
+ memsys3Unlink(mem3.iKeyBlk);
+ if( mem3.szKeyBlk>=nBlock ){
+ return memsys3FromKeyBlk(nBlock);
}
}
}
@@ -448,23 +448,23 @@ static void memsys3FreeUnsafe(void *pOld){
mem3.aPool[i+size-1].u.hdr.size4x &= ~2;
memsys3Link(i);
- /* Try to expand the master using the newly freed chunk */
- if( mem3.iMaster ){
- while( (mem3.aPool[mem3.iMaster-1].u.hdr.size4x&2)==0 ){
- size = mem3.aPool[mem3.iMaster-1].u.hdr.prevSize;
- mem3.iMaster -= size;
- mem3.szMaster += size;
- memsys3Unlink(mem3.iMaster);
- x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2;
- mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x;
- mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster;
+ /* Try to expand the key using the newly freed chunk */
+ if( mem3.iKeyBlk ){
+ while( (mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x&2)==0 ){
+ size = mem3.aPool[mem3.iKeyBlk-1].u.hdr.prevSize;
+ mem3.iKeyBlk -= size;
+ mem3.szKeyBlk += size;
+ memsys3Unlink(mem3.iKeyBlk);
+ x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2;
+ mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x;
+ mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = mem3.szKeyBlk;
}
- x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2;
- while( (mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x&1)==0 ){
- memsys3Unlink(mem3.iMaster+mem3.szMaster);
- mem3.szMaster += mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x/4;
- mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x;
- mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster;
+ x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2;
+ while( (mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x&1)==0 ){
+ memsys3Unlink(mem3.iKeyBlk+mem3.szKeyBlk);
+ mem3.szKeyBlk += mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x/4;
+ mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x;
+ mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = mem3.szKeyBlk;
}
}
}
@@ -560,11 +560,11 @@ static int memsys3Init(void *NotUsed){
mem3.aPool = (Mem3Block *)sqlite3GlobalConfig.pHeap;
mem3.nPool = (sqlite3GlobalConfig.nHeap / sizeof(Mem3Block)) - 2;
- /* Initialize the master block. */
- mem3.szMaster = mem3.nPool;
- mem3.mnMaster = mem3.szMaster;
- mem3.iMaster = 1;
- mem3.aPool[0].u.hdr.size4x = (mem3.szMaster<<2) + 2;
+ /* Initialize the key block. */
+ mem3.szKeyBlk = mem3.nPool;
+ mem3.mnKeyBlk = mem3.szKeyBlk;
+ mem3.iKeyBlk = 1;
+ mem3.aPool[0].u.hdr.size4x = (mem3.szKeyBlk<<2) + 2;
mem3.aPool[mem3.nPool].u.hdr.prevSize = mem3.nPool;
mem3.aPool[mem3.nPool].u.hdr.size4x = 1;
@@ -624,7 +624,7 @@ void sqlite3Memsys3Dump(const char *zFilename){
fprintf(out, "%p %6d bytes checked out\n", &mem3.aPool[i], (size/4)*8-8);
}else{
fprintf(out, "%p %6d bytes free%s\n", &mem3.aPool[i], (size/4)*8-8,
- i==mem3.iMaster ? " **master**" : "");
+ i==mem3.iKeyBlk ? " **key**" : "");
}
}
for(i=0; imFlags = SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE;
assert( pOutFlags!=0 ); /* True because flags==SQLITE_OPEN_MAIN_DB */
*pOutFlags = flags | SQLITE_OPEN_MEMORY;
- p->base.pMethods = &memdb_io_methods;
+ pFile->pMethods = &memdb_io_methods;
p->szMax = sqlite3GlobalConfig.mxMemdbSize;
return SQLITE_OK;
}
-#if 0 /* Only used to delete rollback journals, master journals, and WAL
+#if 0 /* Only used to delete rollback journals, super-journals, and WAL
** files, none of which exist in memdb. So this routine is never used */
/*
** Delete the file located at zPath. If the dirSync argument is true,
diff --git a/src/memjournal.c b/src/memjournal.c
index 0a14e847a2..4811f2d8d4 100644
--- a/src/memjournal.c
+++ b/src/memjournal.c
@@ -366,7 +366,7 @@ int sqlite3JournalOpen(
assert( MEMJOURNAL_DFLT_FILECHUNKSIZE==fileChunkSize(p->nChunkSize) );
}
- p->pMethod = (const sqlite3_io_methods*)&MemJournalMethods;
+ pJfd->pMethods = (const sqlite3_io_methods*)&MemJournalMethods;
p->nSpill = nSpill;
p->flags = flags;
p->zJournal = zName;
@@ -392,7 +392,7 @@ void sqlite3MemJournalOpen(sqlite3_file *pJfd){
int sqlite3JournalCreate(sqlite3_file *pJfd){
int rc = SQLITE_OK;
MemJournal *p = (MemJournal*)pJfd;
- if( p->pMethod==&MemJournalMethods && (
+ if( pJfd->pMethods==&MemJournalMethods && (
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
p->nSpill>0
#else
diff --git a/src/mutex_unix.c b/src/mutex_unix.c
index 9282d28016..2afaddec69 100644
--- a/src/mutex_unix.c
+++ b/src/mutex_unix.c
@@ -112,7 +112,7 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; }
**
** - SQLITE_MUTEX_FAST
**
- SQLITE_MUTEX_RECURSIVE
-**
- SQLITE_MUTEX_STATIC_MASTER
+**
- SQLITE_MUTEX_STATIC_MAIN
**
- SQLITE_MUTEX_STATIC_MEM
**
- SQLITE_MUTEX_STATIC_OPEN
**
- SQLITE_MUTEX_STATIC_PRNG
diff --git a/src/mutex_w32.c b/src/mutex_w32.c
index 8a8ae289ba..09deda4091 100644
--- a/src/mutex_w32.c
+++ b/src/mutex_w32.c
@@ -171,7 +171,7 @@ static int winMutexEnd(void){
**
** - SQLITE_MUTEX_FAST
**
- SQLITE_MUTEX_RECURSIVE
-**
- SQLITE_MUTEX_STATIC_MASTER
+**
- SQLITE_MUTEX_STATIC_MAIN
**
- SQLITE_MUTEX_STATIC_MEM
**
- SQLITE_MUTEX_STATIC_OPEN
**
- SQLITE_MUTEX_STATIC_PRNG
diff --git a/src/notify.c b/src/notify.c
index 8137226f35..4960ab76b1 100644
--- a/src/notify.c
+++ b/src/notify.c
@@ -29,12 +29,12 @@
*/
#define assertMutexHeld() \
- assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)) )
+ assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN)) )
/*
** Head of a linked list of all sqlite3 objects created by this process
** for which either sqlite3.pBlockingConnection or sqlite3.pUnlockConnection
-** is not NULL. This variable may only accessed while the STATIC_MASTER
+** is not NULL. This variable may only accessed while the STATIC_MAIN
** mutex is held.
*/
static sqlite3 *SQLITE_WSD sqlite3BlockedList = 0;
@@ -108,20 +108,20 @@ static void addToBlockedList(sqlite3 *db){
}
/*
-** Obtain the STATIC_MASTER mutex.
+** Obtain the STATIC_MAIN mutex.
*/
static void enterMutex(void){
- sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN));
checkListProperties(0);
}
/*
-** Release the STATIC_MASTER mutex.
+** Release the STATIC_MAIN mutex.
*/
static void leaveMutex(void){
assertMutexHeld();
checkListProperties(0);
- sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN));
}
/*
@@ -232,7 +232,7 @@ void sqlite3ConnectionUnlocked(sqlite3 *db){
void *aStatic[16]; /* Starter space for aArg[]. No malloc required */
aArg = aStatic;
- enterMutex(); /* Enter STATIC_MASTER mutex */
+ enterMutex(); /* Enter STATIC_MAIN mutex */
/* This loop runs once for each entry in the blocked-connections list. */
for(pp=&sqlite3BlockedList; *pp; /* no-op */ ){
@@ -315,7 +315,7 @@ void sqlite3ConnectionUnlocked(sqlite3 *db){
xUnlockNotify(aArg, nArg);
}
sqlite3_free(aDyn);
- leaveMutex(); /* Leave STATIC_MASTER mutex */
+ leaveMutex(); /* Leave STATIC_MAIN mutex */
}
/*
diff --git a/src/os.c b/src/os.c
index b729e95e65..a1a276f433 100644
--- a/src/os.c
+++ b/src/os.c
@@ -353,7 +353,7 @@ sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){
if( rc ) return 0;
#endif
#if SQLITE_THREADSAFE
- mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+ mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
#endif
sqlite3_mutex_enter(mutex);
for(pVfs = vfsList; pVfs; pVfs=pVfs->pNext){
@@ -368,7 +368,7 @@ sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){
** Unlink a VFS from the linked list
*/
static void vfsUnlink(sqlite3_vfs *pVfs){
- assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)) );
+ assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN)) );
if( pVfs==0 ){
/* No-op */
}else if( vfsList==pVfs ){
@@ -399,7 +399,7 @@ int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
if( pVfs==0 ) return SQLITE_MISUSE_BKPT;
#endif
- MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
+ MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); )
sqlite3_mutex_enter(mutex);
vfsUnlink(pVfs);
if( makeDflt || vfsList==0 ){
@@ -423,7 +423,7 @@ int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
int rc = sqlite3_initialize();
if( rc ) return rc;
#endif
- MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
+ MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); )
sqlite3_mutex_enter(mutex);
vfsUnlink(pVfs);
sqlite3_mutex_leave(mutex);
diff --git a/src/os_unix.c b/src/os_unix.c
index d510711087..fc54153333 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -3340,7 +3340,7 @@ static int unixRead(
assert( offset>=0 );
assert( amt>0 );
- /* If this is a database file (not a journal, master-journal or temp
+ /* If this is a database file (not a journal, super-journal or temp
** file), the bytes in the locking range should never be read or written. */
#if 0
assert( pFile->pPreallocatedUnused==0
@@ -3453,7 +3453,7 @@ static int unixWrite(
assert( id );
assert( amt>0 );
- /* If this is a database file (not a journal, master-journal or temp
+ /* If this is a database file (not a journal, super-journal or temp
** file), the bytes in the locking range should never be read or written. */
#if 0
assert( pFile->pPreallocatedUnused==0
@@ -4836,7 +4836,10 @@ static int unixShmLock(
**
** In other words, if this is a blocking lock, none of the locks that
** occur later in the above list than the lock being obtained may be
- ** held. */
+ ** held.
+ **
+ ** It is not permitted to block on the RECOVER lock.
+ */
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
(ofst!=2) /* not RECOVER */
@@ -5689,7 +5692,7 @@ static int fillInUnixFile(
if( rc!=SQLITE_OK ){
if( h>=0 ) robust_close(pNew, h, __LINE__);
}else{
- pNew->pMethod = pLockingStyle;
+ pId->pMethods = pLockingStyle;
OpenCounter(+1);
verifyDbFile(pNew);
}
@@ -5770,7 +5773,7 @@ static int proxyTransformUnixFile(unixFile*, const char*);
/*
** Search for an unused file descriptor that was opened on the database
-** file (not a journal or master-journal file) identified by pathname
+** file (not a journal or super-journal file) identified by pathname
** zPath with SQLITE_OPEN_XXX flags matching those passed as the second
** argument to this function.
**
@@ -5904,7 +5907,7 @@ static int findCreateFileMode(
while( zPath[nDb]!='-' ){
/* In normal operation, the journal file name will always contain
** a '-' character. However in 8+3 filename mode, or if a corrupt
- ** rollback journal specifies a master journal with a goofy name, then
+ ** rollback journal specifies a super-journal with a goofy name, then
** the '-' might be missing. */
if( nDb==0 || zPath[nDb]=='.' ) return SQLITE_OK;
nDb--;
@@ -5977,12 +5980,12 @@ static int unixOpen(
struct statfs fsInfo;
#endif
- /* If creating a master or main-file journal, this function will open
+ /* If creating a super- or main-file journal, this function will open
** a file-descriptor on the directory too. The first time unixSync()
** is called the directory file descriptor will be fsync()ed and close()d.
*/
int isNewJrnl = (isCreate && (
- eType==SQLITE_OPEN_MASTER_JOURNAL
+ eType==SQLITE_OPEN_SUPER_JOURNAL
|| eType==SQLITE_OPEN_MAIN_JOURNAL
|| eType==SQLITE_OPEN_WAL
));
@@ -6005,17 +6008,17 @@ static int unixOpen(
assert(isExclusive==0 || isCreate);
assert(isDelete==0 || isCreate);
- /* The main DB, main journal, WAL file and master journal are never
+ /* The main DB, main journal, WAL file and super-journal are never
** automatically deleted. Nor are they ever temporary files. */
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
- assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_SUPER_JOURNAL );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
/* Assert that the upper layer has set one of the "file-type" flags. */
assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
|| eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
- || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
+ || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_SUPER_JOURNAL
|| eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
);
@@ -6208,7 +6211,7 @@ static int unixOpen(
#endif
assert( zPath==0 || zPath[0]=='/'
- || eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL
+ || eType==SQLITE_OPEN_SUPER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL
);
rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
diff --git a/src/os_win.c b/src/os_win.c
index 0adfd7fbf2..1f22fd992a 100644
--- a/src/os_win.c
+++ b/src/os_win.c
@@ -1290,17 +1290,17 @@ int sqlite3_win32_compact_heap(LPUINT pnLargest){
*/
int sqlite3_win32_reset_heap(){
int rc;
- MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
+ MUTEX_LOGIC( sqlite3_mutex *pMainMtx; ) /* The main static mutex */
MUTEX_LOGIC( sqlite3_mutex *pMem; ) /* The memsys static mutex */
- MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
+ MUTEX_LOGIC( pMainMtx = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); )
MUTEX_LOGIC( pMem = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); )
- sqlite3_mutex_enter(pMaster);
+ sqlite3_mutex_enter(pMainMtx);
sqlite3_mutex_enter(pMem);
winMemAssertMagic();
if( winMemGetHeap()!=NULL && winMemGetOwned() && sqlite3_memory_used()==0 ){
/*
** At this point, there should be no outstanding memory allocations on
- ** the heap. Also, since both the master and memsys locks are currently
+ ** the heap. Also, since both the main and memsys locks are currently
** being held by us, no other function (i.e. from another thread) should
** be able to even access the heap. Attempt to destroy and recreate our
** isolated Win32 native heap now.
@@ -1323,7 +1323,7 @@ int sqlite3_win32_reset_heap(){
rc = SQLITE_BUSY;
}
sqlite3_mutex_leave(pMem);
- sqlite3_mutex_leave(pMaster);
+ sqlite3_mutex_leave(pMainMtx);
return rc;
}
#endif /* SQLITE_WIN32_MALLOC */
@@ -5023,7 +5023,7 @@ static int winOpen(
#ifndef NDEBUG
int isOpenJournal = (isCreate && (
- eType==SQLITE_OPEN_MASTER_JOURNAL
+ eType==SQLITE_OPEN_SUPER_JOURNAL
|| eType==SQLITE_OPEN_MAIN_JOURNAL
|| eType==SQLITE_OPEN_WAL
));
@@ -5044,17 +5044,17 @@ static int winOpen(
assert(isExclusive==0 || isCreate);
assert(isDelete==0 || isCreate);
- /* The main DB, main journal, WAL file and master journal are never
+ /* The main DB, main journal, WAL file and super-journal are never
** automatically deleted. Nor are they ever temporary files. */
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
- assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_SUPER_JOURNAL );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
/* Assert that the upper layer has set one of the "file-type" flags. */
assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
|| eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
- || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
+ || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_SUPER_JOURNAL
|| eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
);
@@ -5266,7 +5266,7 @@ static int winOpen(
}
sqlite3_free(zTmpname);
- pFile->pMethod = pAppData ? pAppData->pMethod : &winIoMethod;
+ id->pMethods = pAppData ? pAppData->pMethod : &winIoMethod;
pFile->pVfs = pVfs;
pFile->h = h;
if( isReadonly ){
diff --git a/src/pager.c b/src/pager.c
index a826f256bf..005d678f94 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -70,8 +70,8 @@
** (5) All writes to the database file are synced prior to the rollback journal
** being deleted, truncated, or zeroed.
**
-** (6) If a master journal file is used, then all writes to the database file
-** are synced prior to the master journal being deleted.
+** (6) If a super-journal file is used, then all writes to the database file
+** are synced prior to the super-journal being deleted.
**
** Definition: Two databases (or the same database at two points it time)
** are said to be "logically equivalent" if they give the same answer to
@@ -488,29 +488,29 @@ struct PagerSavepoint {
** need only update the change-counter once, for the first transaction
** committed.
**
-** setMaster
+** setSuper
**
** When PagerCommitPhaseOne() is called to commit a transaction, it may
-** (or may not) specify a master-journal name to be written into the
+** (or may not) specify a super-journal name to be written into the
** journal file before it is synced to disk.
**
-** Whether or not a journal file contains a master-journal pointer affects
+** Whether or not a journal file contains a super-journal pointer affects
** the way in which the journal file is finalized after the transaction is
** committed or rolled back when running in "journal_mode=PERSIST" mode.
-** If a journal file does not contain a master-journal pointer, it is
+** If a journal file does not contain a super-journal pointer, it is
** finalized by overwriting the first journal header with zeroes. If
-** it does contain a master-journal pointer the journal file is finalized
+** it does contain a super-journal pointer the journal file is finalized
** by truncating it to zero bytes, just as if the connection were
** running in "journal_mode=truncate" mode.
**
-** Journal files that contain master journal pointers cannot be finalized
+** Journal files that contain super-journal pointers cannot be finalized
** simply by overwriting the first journal-header with zeroes, as the
-** master journal pointer could interfere with hot-journal rollback of any
+** super-journal pointer could interfere with hot-journal rollback of any
** subsequently interrupted transaction that reuses the journal file.
**
** The flag is cleared as soon as the journal file is finalized (either
** by PagerCommitPhaseTwo or PagerRollback). If an IO error prevents the
-** journal file from being successfully finalized, the setMaster flag
+** journal file from being successfully finalized, the setSuper flag
** is cleared anyway (and the pager will move to ERROR state).
**
** doNotSpill
@@ -642,7 +642,7 @@ struct Pager {
u8 eState; /* Pager state (OPEN, READER, WRITER_LOCKED..) */
u8 eLock; /* Current lock held on database file */
u8 changeCountDone; /* Set after incrementing the change-counter */
- u8 setMaster; /* True if a m-j name has been written to jrnl */
+ u8 setSuper; /* Super-jrnl name is written into jrnl */
u8 doNotSpill; /* Do not spill the cache when non-zero */
u8 subjInMemory; /* True to use in-memory sub-journals */
u8 bUseFetch; /* True to use xFetch() */
@@ -786,11 +786,6 @@ static const unsigned char aJournalMagic[] = {
# define USEFETCH(x) 0
#endif
-/*
-** The maximum legal page number is (2^31 - 1).
-*/
-#define PAGER_MAX_PGNO 2147483647
-
/*
** The argument to this macro is a file descriptor (type sqlite3_file*).
** Return 0 if it is not open, or non-zero (but not 1) if it is.
@@ -920,7 +915,7 @@ static int assert_pager_state(Pager *p){
assert( pPager->dbSize==pPager->dbOrigSize );
assert( pPager->dbOrigSize==pPager->dbFileSize );
assert( pPager->dbOrigSize==pPager->dbHintSize );
- assert( pPager->setMaster==0 );
+ assert( pPager->setSuper==0 );
break;
case PAGER_WRITER_CACHEMOD:
@@ -1274,66 +1269,66 @@ static void checkPage(PgHdr *pPg){
/*
** When this is called the journal file for pager pPager must be open.
-** This function attempts to read a master journal file name from the
+** This function attempts to read a super-journal file name from the
** end of the file and, if successful, copies it into memory supplied
-** by the caller. See comments above writeMasterJournal() for the format
-** used to store a master journal file name at the end of a journal file.
+** by the caller. See comments above writeSuperJournal() for the format
+** used to store a super-journal file name at the end of a journal file.
**
-** zMaster must point to a buffer of at least nMaster bytes allocated by
+** zSuper must point to a buffer of at least nSuper bytes allocated by
** the caller. This should be sqlite3_vfs.mxPathname+1 (to ensure there is
-** enough space to write the master journal name). If the master journal
-** name in the journal is longer than nMaster bytes (including a
-** nul-terminator), then this is handled as if no master journal name
+** enough space to write the super-journal name). If the super-journal
+** name in the journal is longer than nSuper bytes (including a
+** nul-terminator), then this is handled as if no super-journal name
** were present in the journal.
**
-** If a master journal file name is present at the end of the journal
-** file, then it is copied into the buffer pointed to by zMaster. A
-** nul-terminator byte is appended to the buffer following the master
-** journal file name.
+** If a super-journal file name is present at the end of the journal
+** file, then it is copied into the buffer pointed to by zSuper. A
+** nul-terminator byte is appended to the buffer following the
+** super-journal file name.
**
-** If it is determined that no master journal file name is present
-** zMaster[0] is set to 0 and SQLITE_OK returned.
+** If it is determined that no super-journal file name is present
+** zSuper[0] is set to 0 and SQLITE_OK returned.
**
** If an error occurs while reading from the journal file, an SQLite
** error code is returned.
*/
-static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){
+static int readSuperJournal(sqlite3_file *pJrnl, char *zSuper, u32 nSuper){
int rc; /* Return code */
- u32 len; /* Length in bytes of master journal name */
+ u32 len; /* Length in bytes of super-journal name */
i64 szJ; /* Total size in bytes of journal file pJrnl */
u32 cksum; /* MJ checksum value read from journal */
u32 u; /* Unsigned loop counter */
unsigned char aMagic[8]; /* A buffer to hold the magic header */
- zMaster[0] = '\0';
+ zSuper[0] = '\0';
if( SQLITE_OK!=(rc = sqlite3OsFileSize(pJrnl, &szJ))
|| szJ<16
|| SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len))
- || len>=nMaster
+ || len>=nSuper
|| len>szJ-16
|| len==0
|| SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum))
|| SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8))
|| memcmp(aMagic, aJournalMagic, 8)
- || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, zMaster, len, szJ-16-len))
+ || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, zSuper, len, szJ-16-len))
){
return rc;
}
- /* See if the checksum matches the master journal name */
+ /* See if the checksum matches the super-journal name */
for(u=0; usetMaster==0 );
+ assert( pPager->setSuper==0 );
assert( !pagerUseWal(pPager) );
- if( !zMaster
+ if( !zSuper
|| pPager->journalMode==PAGER_JOURNALMODE_MEMORY
|| !isOpen(pPager->jfd)
){
return SQLITE_OK;
}
- pPager->setMaster = 1;
+ pPager->setSuper = 1;
assert( pPager->journalHdr <= pPager->journalOff );
- /* Calculate the length in bytes and the checksum of zMaster */
- for(nMaster=0; zMaster[nMaster]; nMaster++){
- cksum += zMaster[nMaster];
+ /* Calculate the length in bytes and the checksum of zSuper */
+ for(nSuper=0; zSuper[nSuper]; nSuper++){
+ cksum += zSuper[nSuper];
}
/* If in full-sync mode, advance to the next disk sector before writing
- ** the master journal name. This is in case the previous page written to
+ ** the super-journal name. This is in case the previous page written to
** the journal has already been synced.
*/
if( pPager->fullSync ){
@@ -1712,25 +1707,25 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
}
iHdrOff = pPager->journalOff;
- /* Write the master journal data to the end of the journal file. If
+ /* Write the super-journal data to the end of the journal file. If
** an error occurs, return the error code to the caller.
*/
if( (0 != (rc = write32bits(pPager->jfd, iHdrOff, PAGER_MJ_PGNO(pPager))))
- || (0 != (rc = sqlite3OsWrite(pPager->jfd, zMaster, nMaster, iHdrOff+4)))
- || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster, nMaster)))
- || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster+4, cksum)))
+ || (0 != (rc = sqlite3OsWrite(pPager->jfd, zSuper, nSuper, iHdrOff+4)))
+ || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nSuper, nSuper)))
+ || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nSuper+4, cksum)))
|| (0 != (rc = sqlite3OsWrite(pPager->jfd, aJournalMagic, 8,
- iHdrOff+4+nMaster+8)))
+ iHdrOff+4+nSuper+8)))
){
return rc;
}
- pPager->journalOff += (nMaster+20);
+ pPager->journalOff += (nSuper+20);
/* If the pager is in peristent-journal mode, then the physical
- ** journal-file may extend past the end of the master-journal name
+ ** journal-file may extend past the end of the super-journal name
** and 8 bytes of magic data just written to the file. This is
** dangerous because the code to rollback a hot-journal file
- ** will not be able to find the master-journal name to determine
+ ** will not be able to find the super-journal name to determine
** whether or not the journal is hot.
**
** Easiest thing to do in this scenario is to truncate the journal
@@ -1891,7 +1886,7 @@ static void pager_unlock(Pager *pPager){
pPager->journalOff = 0;
pPager->journalHdr = 0;
- pPager->setMaster = 0;
+ pPager->setSuper = 0;
}
/*
@@ -2007,7 +2002,7 @@ static int pagerFlushOnCommit(Pager *pPager, int bCommit){
** to the first error encountered (the journal finalization one) is
** returned.
*/
-static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
+static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){
int rc = SQLITE_OK; /* Error code from journal finalization operation */
int rc2 = SQLITE_OK; /* Error code from db file unlock operation */
@@ -2059,7 +2054,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
}else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST
|| (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL)
){
- rc = zeroJournalHdr(pPager, hasMaster||pPager->tempFile);
+ rc = zeroJournalHdr(pPager, hasSuper||pPager->tempFile);
pPager->journalOff = 0;
}else{
/* This branch may be executed with Pager.journalMode==MEMORY if
@@ -2132,7 +2127,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
rc2 = pagerUnlockDb(pPager, SHARED_LOCK);
}
pPager->eState = PAGER_READER;
- pPager->setMaster = 0;
+ pPager->setSuper = 0;
return (rc==SQLITE_OK?rc2:rc);
}
@@ -2440,36 +2435,36 @@ static int pager_playback_one_page(
}
/*
-** Parameter zMaster is the name of a master journal file. A single journal
-** file that referred to the master journal file has just been rolled back.
-** This routine checks if it is possible to delete the master journal file,
+** Parameter zSuper is the name of a super-journal file. A single journal
+** file that referred to the super-journal file has just been rolled back.
+** This routine checks if it is possible to delete the super-journal file,
** and does so if it is.
**
-** Argument zMaster may point to Pager.pTmpSpace. So that buffer is not
+** Argument zSuper may point to Pager.pTmpSpace. So that buffer is not
** available for use within this function.
**
-** When a master journal file is created, it is populated with the names
+** When a super-journal file is created, it is populated with the names
** of all of its child journals, one after another, formatted as utf-8
** encoded text. The end of each child journal file is marked with a
-** nul-terminator byte (0x00). i.e. the entire contents of a master journal
+** nul-terminator byte (0x00). i.e. the entire contents of a super-journal
** file for a transaction involving two databases might be:
**
** "/home/bill/a.db-journal\x00/home/bill/b.db-journal\x00"
**
-** A master journal file may only be deleted once all of its child
+** A super-journal file may only be deleted once all of its child
** journals have been rolled back.
**
-** This function reads the contents of the master-journal file into
+** This function reads the contents of the super-journal file into
** memory and loops through each of the child journal names. For
** each child journal, it checks if:
**
** * if the child journal exists, and if so
-** * if the child journal contains a reference to master journal
-** file zMaster
+** * if the child journal contains a reference to super-journal
+** file zSuper
**
** If a child journal can be found that matches both of the criteria
** above, this function returns without doing anything. Otherwise, if
-** no such child journal can be found, file zMaster is deleted from
+** no such child journal can be found, file zSuper is deleted from
** the file-system using sqlite3OsDelete().
**
** If an IO error within this function, an error code is returned. This
@@ -2478,99 +2473,100 @@ static int pager_playback_one_page(
** occur, SQLITE_OK is returned.
**
** TODO: This function allocates a single block of memory to load
-** the entire contents of the master journal file. This could be
+** the entire contents of the super-journal file. This could be
** a couple of kilobytes or so - potentially larger than the page
** size.
*/
-static int pager_delmaster(Pager *pPager, const char *zMaster){
+static int pager_delsuper(Pager *pPager, const char *zSuper){
sqlite3_vfs *pVfs = pPager->pVfs;
int rc; /* Return code */
- sqlite3_file *pMaster; /* Malloc'd master-journal file descriptor */
+ sqlite3_file *pSuper; /* Malloc'd super-journal file descriptor */
sqlite3_file *pJournal; /* Malloc'd child-journal file descriptor */
- char *zMasterJournal = 0; /* Contents of master journal file */
- i64 nMasterJournal; /* Size of master journal file */
+ char *zSuperJournal = 0; /* Contents of super-journal file */
+ i64 nSuperJournal; /* Size of super-journal file */
char *zJournal; /* Pointer to one journal within MJ file */
- char *zMasterPtr; /* Space to hold MJ filename from a journal file */
- int nMasterPtr; /* Amount of space allocated to zMasterPtr[] */
+ char *zSuperPtr; /* Space to hold super-journal filename */
+ int nSuperPtr; /* Amount of space allocated to zSuperPtr[] */
- /* Allocate space for both the pJournal and pMaster file descriptors.
- ** If successful, open the master journal file for reading.
+ /* Allocate space for both the pJournal and pSuper file descriptors.
+ ** If successful, open the super-journal file for reading.
*/
- pMaster = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
- pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile);
- if( !pMaster ){
+ pSuper = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
+ if( !pSuper ){
rc = SQLITE_NOMEM_BKPT;
+ pJournal = 0;
}else{
- const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL);
- rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0);
+ const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_SUPER_JOURNAL);
+ rc = sqlite3OsOpen(pVfs, zSuper, pSuper, flags, 0);
+ pJournal = (sqlite3_file *)(((u8 *)pSuper) + pVfs->szOsFile);
}
- if( rc!=SQLITE_OK ) goto delmaster_out;
+ if( rc!=SQLITE_OK ) goto delsuper_out;
- /* Load the entire master journal file into space obtained from
- ** sqlite3_malloc() and pointed to by zMasterJournal. Also obtain
- ** sufficient space (in zMasterPtr) to hold the names of master
- ** journal files extracted from regular rollback-journals.
+ /* Load the entire super-journal file into space obtained from
+ ** sqlite3_malloc() and pointed to by zSuperJournal. Also obtain
+ ** sufficient space (in zSuperPtr) to hold the names of super-journal
+ ** files extracted from regular rollback-journals.
*/
- rc = sqlite3OsFileSize(pMaster, &nMasterJournal);
- if( rc!=SQLITE_OK ) goto delmaster_out;
- nMasterPtr = pVfs->mxPathname+1;
- zMasterJournal = sqlite3Malloc(nMasterJournal + nMasterPtr + 2);
- if( !zMasterJournal ){
+ rc = sqlite3OsFileSize(pSuper, &nSuperJournal);
+ if( rc!=SQLITE_OK ) goto delsuper_out;
+ nSuperPtr = pVfs->mxPathname+1;
+ zSuperJournal = sqlite3Malloc(nSuperJournal + nSuperPtr + 2);
+ if( !zSuperJournal ){
rc = SQLITE_NOMEM_BKPT;
- goto delmaster_out;
+ goto delsuper_out;
}
- zMasterPtr = &zMasterJournal[nMasterJournal+2];
- rc = sqlite3OsRead(pMaster, zMasterJournal, (int)nMasterJournal, 0);
- if( rc!=SQLITE_OK ) goto delmaster_out;
- zMasterJournal[nMasterJournal] = 0;
- zMasterJournal[nMasterJournal+1] = 0;
+ zSuperPtr = &zSuperJournal[nSuperJournal+2];
+ rc = sqlite3OsRead(pSuper, zSuperJournal, (int)nSuperJournal, 0);
+ if( rc!=SQLITE_OK ) goto delsuper_out;
+ zSuperJournal[nSuperJournal] = 0;
+ zSuperJournal[nSuperJournal+1] = 0;
- zJournal = zMasterJournal;
- while( (zJournal-zMasterJournal)pageSize;
@@ -2761,8 +2757,8 @@ static int pager_playback(Pager *pPager, int isHot){
goto end_playback;
}
- /* Read the master journal name from the journal, if it is present.
- ** If a master journal file name is specified, but the file is not
+ /* Read the super-journal name from the journal, if it is present.
+ ** If a super-journal file name is specified, but the file is not
** present on disk, then the journal is not hot and does not need to be
** played back.
**
@@ -2772,12 +2768,12 @@ static int pager_playback(Pager *pPager, int isHot){
** mxPathname is 512, which is the same as the minimum allowable value
** for pageSize.
*/
- zMaster = pPager->pTmpSpace;
- rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1);
- if( rc==SQLITE_OK && zMaster[0] ){
- rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res);
+ zSuper = pPager->pTmpSpace;
+ rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1);
+ if( rc==SQLITE_OK && zSuper[0] ){
+ rc = sqlite3OsAccess(pVfs, zSuper, SQLITE_ACCESS_EXISTS, &res);
}
- zMaster = 0;
+ zSuper = 0;
if( rc!=SQLITE_OK || !res ){
goto end_playback;
}
@@ -2904,8 +2900,8 @@ end_playback:
pPager->changeCountDone = pPager->tempFile;
if( rc==SQLITE_OK ){
- zMaster = pPager->pTmpSpace;
- rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1);
+ zSuper = pPager->pTmpSpace;
+ rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1);
testcase( rc!=SQLITE_OK );
}
if( rc==SQLITE_OK
@@ -2914,14 +2910,14 @@ end_playback:
rc = sqlite3PagerSync(pPager, 0);
}
if( rc==SQLITE_OK ){
- rc = pager_end_transaction(pPager, zMaster[0]!='\0', 0);
+ rc = pager_end_transaction(pPager, zSuper[0]!='\0', 0);
testcase( rc!=SQLITE_OK );
}
- if( rc==SQLITE_OK && zMaster[0] && res ){
- /* If there was a master journal and this routine will return success,
- ** see if it is possible to delete the master journal.
+ if( rc==SQLITE_OK && zSuper[0] && res ){
+ /* If there was a super-journal and this routine will return success,
+ ** see if it is possible to delete the super-journal.
*/
- rc = pager_delmaster(pPager, zMaster);
+ rc = pager_delsuper(pPager, zSuper);
testcase( rc!=SQLITE_OK );
}
if( isHot && nPlayback ){
@@ -3300,7 +3296,7 @@ static int pagerOpenWalIfPresent(Pager *pPager){
/*
** Playback savepoint pSavepoint. Or, if pSavepoint==NULL, then playback
-** the entire master journal file. The case pSavepoint==NULL occurs when
+** the entire super-journal file. The case pSavepoint==NULL occurs when
** a ROLLBACK TO command is invoked on a SAVEPOINT that is a transaction
** savepoint.
**
@@ -3763,7 +3759,7 @@ void *sqlite3PagerTempSpace(Pager *pPager){
**
** Regardless of mxPage, return the current maximum page count.
*/
-int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){
+Pgno sqlite3PagerMaxPageCount(Pager *pPager, Pgno mxPage){
if( mxPage>0 ){
pPager->mxPgno = mxPage;
}
@@ -5040,8 +5036,8 @@ sqlite3_file *sqlite3_database_file_object(const char *zName){
** just deleted using OsDelete, *pExists is set to 0 and SQLITE_OK
** is returned.
**
-** This routine does not check if there is a master journal filename
-** at the end of the file. If there is, and that master journal file
+** This routine does not check if there is a super-journal filename
+** at the end of the file. If there is, and that super-journal file
** does not exist, then the journal file is not really hot. In this
** case this routine will return a false-positive. The pager_playback()
** routine will discover that the journal file is not really hot and
@@ -5490,7 +5486,7 @@ static int getPageNormal(
if( pPg->pPager && !noContent ){
/* In this case the pcache already contains an initialized copy of
** the page. Return without further ado. */
- assert( pgno<=PAGER_MAX_PGNO && pgno!=PAGER_MJ_PGNO(pPager) );
+ assert( pgno!=PAGER_MJ_PGNO(pPager) );
pPager->aStat[PAGER_STAT_HIT]++;
return SQLITE_OK;
@@ -5498,10 +5494,10 @@ static int getPageNormal(
/* The pager cache has created a new page. Its content needs to
** be initialized. But first some error checks:
**
- ** (1) The maximum page number is 2^31
+ ** (*) obsolete. Was: maximum page number is 2^31
** (2) Never try to fetch the locking page
*/
- if( pgno>PAGER_MAX_PGNO || pgno==PAGER_MJ_PGNO(pPager) ){
+ if( pgno==PAGER_MJ_PGNO(pPager) ){
rc = SQLITE_CORRUPT_BKPT;
goto pager_acquire_err;
}
@@ -5786,7 +5782,7 @@ static int pager_open_journal(Pager *pPager){
/* TODO: Check if all of these are really required. */
pPager->nRec = 0;
pPager->journalOff = 0;
- pPager->setMaster = 0;
+ pPager->setSuper = 0;
pPager->journalHdr = 0;
rc = writeJournalHdr(pPager);
}
@@ -6298,9 +6294,9 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
** If successful, or if called on a pager for which it is a no-op, this
** function returns SQLITE_OK. Otherwise, an IO error code is returned.
*/
-int sqlite3PagerSync(Pager *pPager, const char *zMaster){
+int sqlite3PagerSync(Pager *pPager, const char *zSuper){
int rc = SQLITE_OK;
- void *pArg = (void*)zMaster;
+ void *pArg = (void*)zSuper;
rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC, pArg);
if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
if( rc==SQLITE_OK && !pPager->noSync ){
@@ -6338,10 +6334,10 @@ int sqlite3PagerExclusiveLock(Pager *pPager){
}
/*
-** Sync the database file for the pager pPager. zMaster points to the name
-** of a master journal file that should be written into the individual
-** journal file. zMaster may be NULL, which is interpreted as no master
-** journal (a single database transaction).
+** Sync the database file for the pager pPager. zSuper points to the name
+** of a super-journal file that should be written into the individual
+** journal file. zSuper may be NULL, which is interpreted as no
+** super-journal (a single database transaction).
**
** This routine ensures that:
**
@@ -6353,9 +6349,9 @@ int sqlite3PagerExclusiveLock(Pager *pPager){
**
** The only thing that remains to commit the transaction is to finalize
** (delete, truncate or zero the first part of) the journal file (or
-** delete the master journal file if specified).
+** delete the super-journal file if specified).
**
-** Note that if zMaster==NULL, this does not overwrite a previous value
+** Note that if zSuper==NULL, this does not overwrite a previous value
** passed to an sqlite3PagerCommitPhaseOne() call.
**
** If the final parameter - noSync - is true, then the database file itself
@@ -6365,7 +6361,7 @@ int sqlite3PagerExclusiveLock(Pager *pPager){
*/
int sqlite3PagerCommitPhaseOne(
Pager *pPager, /* Pager object */
- const char *zMaster, /* If not NULL, the master journal name */
+ const char *zSuper, /* If not NULL, the super-journal name */
int noSync /* True to omit the xSync on the db file */
){
int rc = SQLITE_OK; /* Return code */
@@ -6383,8 +6379,8 @@ int sqlite3PagerCommitPhaseOne(
/* Provide the ability to easily simulate an I/O error during testing */
if( sqlite3FaultSim(400) ) return SQLITE_IOERR;
- PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n",
- pPager->zFilename, zMaster, pPager->dbSize));
+ PAGERTRACE(("DATABASE SYNC: File=%s zSuper=%s nSize=%d\n",
+ pPager->zFilename, zSuper, pPager->dbSize));
/* If no database changes have been made, return early. */
if( pPager->eStatefd;
- int bBatch = zMaster==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */
+ int bBatch = zSuper==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */
&& (sqlite3OsDeviceCharacteristics(fd) & SQLITE_IOCAP_BATCH_ATOMIC)
&& !pPager->noSync
&& sqlite3JournalIsInMemory(pPager->jfd);
@@ -6461,7 +6457,7 @@ int sqlite3PagerCommitPhaseOne(
|| pPager->journalMode==PAGER_JOURNALMODE_OFF
|| pPager->journalMode==PAGER_JOURNALMODE_WAL
);
- if( !zMaster && isOpen(pPager->jfd)
+ if( !zSuper && isOpen(pPager->jfd)
&& pPager->journalOff==jrnlBufferSize(pPager)
&& pPager->dbSize>=pPager->dbOrigSize
&& (!(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
@@ -6482,7 +6478,7 @@ int sqlite3PagerCommitPhaseOne(
}
#else /* SQLITE_ENABLE_ATOMIC_WRITE */
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
- if( zMaster ){
+ if( zSuper ){
rc = sqlite3JournalCreate(pPager->jfd);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
assert( bBatch==0 );
@@ -6492,11 +6488,11 @@ int sqlite3PagerCommitPhaseOne(
#endif /* !SQLITE_ENABLE_ATOMIC_WRITE */
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
- /* Write the master journal name into the journal file. If a master
- ** journal file name has already been written to the journal file,
- ** or if zMaster is NULL (no master journal), then this call is a no-op.
+ /* Write the super-journal name into the journal file. If a
+ ** super-journal file name has already been written to the journal file,
+ ** or if zSuper is NULL (no super-journal), then this call is a no-op.
*/
- rc = writeMasterJournal(pPager, zMaster);
+ rc = writeSuperJournal(pPager, zSuper);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
/* Sync the journal file and write all dirty pages to the database.
@@ -6564,7 +6560,7 @@ int sqlite3PagerCommitPhaseOne(
/* Finally, sync the database file. */
if( !noSync ){
- rc = sqlite3PagerSync(pPager, zMaster);
+ rc = sqlite3PagerSync(pPager, zSuper);
}
IOTRACE(("DBSYNC %p\n", pPager))
}
@@ -6629,7 +6625,7 @@ int sqlite3PagerCommitPhaseTwo(Pager *pPager){
}
PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
- rc = pager_end_transaction(pPager, pPager->setMaster, 1);
+ rc = pager_end_transaction(pPager, pPager->setSuper, 1);
return pager_error(pPager, rc);
}
@@ -6674,7 +6670,7 @@ int sqlite3PagerRollback(Pager *pPager){
if( pagerUseWal(pPager) ){
int rc2;
rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1);
- rc2 = pager_end_transaction(pPager, pPager->setMaster, 0);
+ rc2 = pager_end_transaction(pPager, pPager->setSuper, 0);
if( rc==SQLITE_OK ) rc = rc2;
}else if( !isOpen(pPager->jfd) || pPager->eState==PAGER_WRITER_LOCKED ){
int eState = pPager->eState;
diff --git a/src/pager.h b/src/pager.h
index 62a371ef89..8d899bd1a6 100644
--- a/src/pager.h
+++ b/src/pager.h
@@ -46,8 +46,8 @@ typedef struct PgHdr DbPage;
** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is
** reserved for working around a windows/posix incompatibility). It is
** used in the journal to signify that the remainder of the journal file
-** is devoted to storing a master journal name - there are no more pages to
-** roll back. See comments for function writeMasterJournal() in pager.c
+** is devoted to storing a super-journal name - there are no more pages to
+** roll back. See comments for function writeSuperJournal() in pager.c
** for details.
*/
#define PAGER_MJ_PGNO(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1))
@@ -128,7 +128,7 @@ int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
/* Functions used to configure a Pager object. */
void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *);
int sqlite3PagerSetPagesize(Pager*, u32*, int);
-int sqlite3PagerMaxPageCount(Pager*, int);
+Pgno sqlite3PagerMaxPageCount(Pager*, Pgno);
void sqlite3PagerSetCachesize(Pager*, int);
int sqlite3PagerSetSpillsize(Pager*, int);
void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
@@ -161,9 +161,9 @@ void *sqlite3PagerGetExtra(DbPage *);
/* Functions used to manage pager transactions and savepoints. */
void sqlite3PagerPagecount(Pager*, int*);
int sqlite3PagerBegin(Pager*, int exFlag, int);
-int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, int);
+int sqlite3PagerCommitPhaseOne(Pager*,const char *zSuper, int);
int sqlite3PagerExclusiveLock(Pager*);
-int sqlite3PagerSync(Pager *pPager, const char *zMaster);
+int sqlite3PagerSync(Pager *pPager, const char *zSuper);
int sqlite3PagerCommitPhaseTwo(Pager*);
int sqlite3PagerRollback(Pager*);
int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
diff --git a/src/parse.y b/src/parse.y
index 09731eb99c..44e0b4f343 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -111,6 +111,27 @@ static void disableLookaside(Parse *pParse){
DisableLookaside;
}
+#if !defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) \
+ && defined(SQLITE_UDL_CAPABLE_PARSER)
+/*
+** Issue an error message if an ORDER BY or LIMIT clause occurs on an
+** UPDATE or DELETE statement.
+*/
+static void updateDeleteLimitError(
+ Parse *pParse,
+ ExprList *pOrderBy,
+ Expr *pLimit
+){
+ if( pOrderBy ){
+ sqlite3ErrorMsg(pParse, "syntax error near \"ORDER BY\"");
+ }else{
+ sqlite3ErrorMsg(pParse, "syntax error near \"LIMIT\"");
+ }
+ sqlite3ExprListDelete(pParse->db, pOrderBy);
+ sqlite3ExprDelete(pParse->db, pLimit);
+}
+#endif /* SQLITE_ENABLE_UPDATE_DELETE_LIMIT */
+
} // end %include
// Input is a single SQL command
@@ -448,7 +469,7 @@ cmd ::= DROP VIEW ifexists(E) fullname(X). {
//////////////////////// The SELECT statement /////////////////////////////////
//
cmd ::= select(X). {
- SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0};
+ SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0, 0};
sqlite3Select(pParse, X, &dest);
sqlite3SelectDelete(pParse->db, X);
}
@@ -637,7 +658,7 @@ as(X) ::= . {X.n = 0; X.z = 0;}
// A complete FROM clause.
//
-from(A) ::= . {A = sqlite3DbMallocZero(pParse->db, sizeof(*A));}
+from(A) ::= . {A = 0;}
from(A) ::= FROM seltablist(X). {
A = X;
sqlite3SrcListShiftJoinType(A);
@@ -840,18 +861,20 @@ limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y).
/////////////////////////// The DELETE statement /////////////////////////////
//
-%ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+%if SQLITE_ENABLE_UPDATE_DELETE_LIMIT || SQLITE_UDL_CAPABLE_PARSER
cmd ::= with DELETE FROM xfullname(X) indexed_opt(I) where_opt(W)
orderby_opt(O) limit_opt(L). {
sqlite3SrcListIndexedBy(pParse, X, &I);
#ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
- sqlite3ExprListDelete(pParse->db, O); O = 0;
- sqlite3ExprDelete(pParse->db, L); L = 0;
+ if( O || L ){
+ updateDeleteLimitError(pParse,O,L);
+ O = 0;
+ L = 0;
+ }
#endif
sqlite3DeleteFrom(pParse,X,W,O,L);
}
-%endif
-%ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+%else
cmd ::= with DELETE FROM xfullname(X) indexed_opt(I) where_opt(W). {
sqlite3SrcListIndexedBy(pParse, X, &I);
sqlite3DeleteFrom(pParse,X,W,0,0);
@@ -866,23 +889,33 @@ where_opt(A) ::= WHERE expr(X). {A = X;}
////////////////////////// The UPDATE command ////////////////////////////////
//
-%ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
-cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y)
+%if SQLITE_ENABLE_UPDATE_DELETE_LIMIT || SQLITE_UDL_CAPABLE_PARSER
+cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F)
where_opt(W) orderby_opt(O) limit_opt(L). {
sqlite3SrcListIndexedBy(pParse, X, &I);
+ X = sqlite3SrcListAppendList(pParse, X, F);
sqlite3ExprListCheckLength(pParse,Y,"set list");
+#ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+ if( O || L ){
+ updateDeleteLimitError(pParse,O,L);
+ O = 0;
+ L = 0;
+ }
+#endif
sqlite3Update(pParse,X,Y,W,R,O,L,0);
}
-%endif
-%ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
-cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y)
- where_opt(W). {
+%else
+cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F)
+ where_opt(W). {
sqlite3SrcListIndexedBy(pParse, X, &I);
sqlite3ExprListCheckLength(pParse,Y,"set list");
+ X = sqlite3SrcListAppendList(pParse, X, F);
sqlite3Update(pParse,X,Y,W,R,0,0,0);
}
%endif
+
+
%type setlist {ExprList*}
%destructor setlist {sqlite3ExprListDelete(pParse->db, $$);}
@@ -1315,7 +1348,7 @@ uniqueflag(A) ::= . {A = OE_None;}
//
// IMPORTANT COMPATIBILITY NOTE: Some prior versions of SQLite accepted
// COLLATE clauses and ASC or DESC keywords on ID lists in inappropriate
-// places - places that might have been stored in the sqlite_master schema.
+// places - places that might have been stored in the sqlite_schema table.
// Those extra features were ignored. But because they might be in some
// (busted) old databases, we need to continue parsing them when loading
// historical schemas.
@@ -1370,16 +1403,14 @@ cmd ::= DROP INDEX ifexists(E) fullname(X). {sqlite3DropIndex(pParse, X, E);}
///////////////////////////// The VACUUM command /////////////////////////////
//
-%ifndef SQLITE_OMIT_VACUUM
-%ifndef SQLITE_OMIT_ATTACH
+%if !SQLITE_OMIT_VACUUM && !SQLITE_OMIT_ATTACH
%type vinto {Expr*}
%destructor vinto {sqlite3ExprDelete(pParse->db, $$);}
cmd ::= VACUUM vinto(Y). {sqlite3Vacuum(pParse,0,Y);}
cmd ::= VACUUM nm(X) vinto(Y). {sqlite3Vacuum(pParse,&X,Y);}
vinto(A) ::= INTO expr(X). {A = X;}
vinto(A) ::= . {A = 0;}
-%endif SQLITE_OMIT_ATTACH
-%endif SQLITE_OMIT_VACUUM
+%endif
///////////////////////////// The PRAGMA command /////////////////////////////
//
@@ -1486,8 +1517,8 @@ tridxby ::= NOT INDEXED. {
%destructor trigger_cmd {sqlite3DeleteTriggerStep(pParse->db, $$);}
// UPDATE
trigger_cmd(A) ::=
- UPDATE(B) orconf(R) trnm(X) tridxby SET setlist(Y) where_opt(Z) scanpt(E).
- {A = sqlite3TriggerUpdateStep(pParse, &X, Y, Z, R, B.z, E);}
+ UPDATE(B) orconf(R) trnm(X) tridxby SET setlist(Y) from(F) where_opt(Z) scanpt(E).
+ {A = sqlite3TriggerUpdateStep(pParse, &X, F, Y, Z, R, B.z, E);}
// INSERT
trigger_cmd(A) ::= scanpt(B) insert_cmd(R) INTO
diff --git a/src/pragma.c b/src/pragma.c
index ba28f8a930..69d6a0a531 100644
--- a/src/pragma.c
+++ b/src/pragma.c
@@ -617,13 +617,19 @@ void sqlite3Pragma(
*/
case PragTyp_PAGE_COUNT: {
int iReg;
+ i64 x = 0;
sqlite3CodeVerifySchema(pParse, iDb);
iReg = ++pParse->nMem;
if( sqlite3Tolower(zLeft[0])=='p' ){
sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg);
}else{
- sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg,
- sqlite3AbsInt32(sqlite3Atoi(zRight)));
+ if( zRight && sqlite3DecOrHexToI64(zRight,&x)==0 ){
+ if( x<0 ) x = 0;
+ else if( x>0xfffffffe ) x = 0xfffffffe;
+ }else{
+ x = 0;
+ }
+ sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg, (int)x);
}
sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1);
break;
@@ -1144,15 +1150,14 @@ void sqlite3Pragma(
*/
case PragTyp_TABLE_INFO: if( zRight ){
Table *pTab;
+ sqlite3CodeVerifyNamedSchema(pParse, zDb);
pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb);
if( pTab ){
- int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
int i, k;
int nHidden = 0;
Column *pCol;
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
pParse->nMem = 7;
- sqlite3CodeVerifySchema(pParse, iTabDb);
sqlite3ViewGetColumnNames(pParse, pTab);
for(i=0, pCol=pTab->aCol; inCol; i++, pCol++){
int isHidden = 0;
@@ -1409,7 +1414,6 @@ void sqlite3Pragma(
regRow = ++pParse->nMem;
k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash);
while( k ){
- int iTabDb;
if( zRight ){
pTab = sqlite3LocateTable(pParse, 0, zRight, zDb);
k = 0;
@@ -1418,23 +1422,24 @@ void sqlite3Pragma(
k = sqliteHashNext(k);
}
if( pTab==0 || pTab->pFKey==0 ) continue;
- iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
- sqlite3CodeVerifySchema(pParse, iTabDb);
- sqlite3TableLock(pParse, iTabDb, pTab->tnum, 0, pTab->zName);
+ iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+ zDb = db->aDb[iDb].zDbSName;
+ sqlite3CodeVerifySchema(pParse, iDb);
+ sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow;
- sqlite3OpenTable(pParse, 0, iTabDb, pTab, OP_OpenRead);
+ sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead);
sqlite3VdbeLoadString(v, regResult, pTab->zName);
for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){
pParent = sqlite3FindTable(db, pFK->zTo, zDb);
if( pParent==0 ) continue;
pIdx = 0;
- sqlite3TableLock(pParse, iTabDb, pParent->tnum, 0, pParent->zName);
+ sqlite3TableLock(pParse, iDb, pParent->tnum, 0, pParent->zName);
x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, 0);
if( x==0 ){
if( pIdx==0 ){
- sqlite3OpenTable(pParse, i, iTabDb, pParent, OP_OpenRead);
+ sqlite3OpenTable(pParse, i, iDb, pParent, OP_OpenRead);
}else{
- sqlite3VdbeAddOp3(v, OP_OpenRead, i, pIdx->tnum, iTabDb);
+ sqlite3VdbeAddOp3(v, OP_OpenRead, i, pIdx->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
}
}else{
@@ -1527,9 +1532,22 @@ void sqlite3Pragma(
** integrity_check designed to detect most database corruption
** without the overhead of cross-checking indexes. Quick_check
** is linear time wherease integrity_check is O(NlogN).
+ **
+ ** The maximum nubmer of errors is 100 by default. A different default
+ ** can be specified using a numeric parameter N.
+ **
+ ** Or, the parameter N can be the name of a table. In that case, only
+ ** the one table named is verified. The freelist is only verified if
+ ** the named table is "sqlite_schema" (or one of its aliases).
+ **
+ ** All schemas are checked by default. To check just a single
+ ** schema, use the form:
+ **
+ ** PRAGMA schema.integrity_check;
*/
case PragTyp_INTEGRITY_CHECK: {
int i, j, addr, mxErr;
+ Table *pObjTab = 0; /* Check only this one table, if not NULL */
int isQuick = (sqlite3Tolower(zLeft[0])=='q');
@@ -1552,9 +1570,13 @@ void sqlite3Pragma(
/* Set the maximum error count */
mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
if( zRight ){
- sqlite3GetInt32(zRight, &mxErr);
- if( mxErr<=0 ){
- mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
+ if( sqlite3GetInt32(zRight, &mxErr) ){
+ if( mxErr<=0 ){
+ mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
+ }
+ }else{
+ pObjTab = sqlite3LocateTable(pParse, 0, zRight,
+ iDb>=0 ? db->aDb[iDb].zDbSName : 0);
}
}
sqlite3VdbeAddOp2(v, OP_Integer, mxErr-1, 1); /* reg[1] holds errors left */
@@ -1583,15 +1605,21 @@ void sqlite3Pragma(
Table *pTab = sqliteHashData(x); /* Current table */
Index *pIdx; /* An index on pTab */
int nIdx; /* Number of indexes on pTab */
+ if( pObjTab && pObjTab!=pTab ) continue;
if( HasRowid(pTab) ) cnt++;
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; }
if( nIdx>mxIdx ) mxIdx = nIdx;
}
+ if( cnt==0 ) continue;
+ if( pObjTab ) cnt++;
aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1));
if( aRoot==0 ) break;
- for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
+ cnt = 0;
+ if( pObjTab ) aRoot[++cnt] = 0;
+ for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx;
+ if( pObjTab && pObjTab!=pTab ) continue;
if( HasRowid(pTab) ) aRoot[++cnt] = pTab->tnum;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
aRoot[++cnt] = pIdx->tnum;
@@ -1625,6 +1653,7 @@ void sqlite3Pragma(
int r1 = -1;
if( pTab->tnum<1 ) continue; /* Skip VIEWs or VIRTUAL TABLEs */
+ if( pObjTab && pObjTab!=pTab ) continue;
pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
1, 0, &iDataCur, &iIdxCur);
@@ -1897,6 +1926,7 @@ void sqlite3Pragma(
aOp[1].p1 = iDb;
aOp[1].p2 = iCookie;
aOp[1].p3 = sqlite3Atoi(zRight);
+ aOp[1].p5 = 1;
}else{
/* Read the specified cookie value */
static const VdbeOpList readCookie[] = {
diff --git a/src/pragma.h b/src/pragma.h
index 06683e120b..c9a5aa9c92 100644
--- a/src/pragma.h
+++ b/src/pragma.h
@@ -288,7 +288,7 @@ static const PragmaName aPragmaName[] = {
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
{/* zName: */ "foreign_key_check",
/* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK,
- /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_OneSchema,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt,
/* ColNames: */ 37, 4,
/* iArg: */ 0 },
#endif
diff --git a/src/prepare.c b/src/prepare.c
index 9b0e7f88f7..ea2468df54 100644
--- a/src/prepare.c
+++ b/src/prepare.c
@@ -151,7 +151,13 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
assert( db->init.busy );
db->init.iDb = iDb;
- db->init.newTnum = sqlite3Atoi(argv[3]);
+ if( sqlite3GetUInt32(argv[3], &db->init.newTnum)==0
+ || (db->init.newTnum>pData->mxPage && pData->mxPage>0)
+ ){
+ if( sqlite3Config.bExtraSchemaChecks ){
+ corruptSchema(pData, argv[1], "invalid rootpage");
+ }
+ }
db->init.orphanTrigger = 0;
db->init.azInit = argv;
pStmt = 0;
@@ -193,12 +199,17 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
*/
Index *pIndex;
pIndex = sqlite3FindIndex(db, argv[1], db->aDb[iDb].zDbSName);
- if( pIndex==0
- || sqlite3GetInt32(argv[3],&pIndex->tnum)==0
+ if( pIndex==0 ){
+ corruptSchema(pData, argv[1], "orphan index");
+ }else
+ if( sqlite3GetUInt32(argv[3],&pIndex->tnum)==0
|| pIndex->tnum<2
+ || pIndex->tnum>pData->mxPage
|| sqlite3IndexHasDuplicateRootPage(pIndex)
){
- corruptSchema(pData, argv[1], pIndex?"invalid rootpage":"orphan index");
+ if( sqlite3Config.bExtraSchemaChecks ){
+ corruptSchema(pData, argv[1], "invalid rootpage");
+ }
}
}
@@ -228,7 +239,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
char const *azArg[6];
int meta[5];
InitData initData;
- const char *zMasterName;
+ const char *zSchemaTabName;
int openedTransaction = 0;
int mask = ((db->mDbFlags & DBFLAG_EncodingFixed) | ~DBFLAG_EncodingFixed);
@@ -258,13 +269,13 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
db->init.busy = 1;
- /* Construct the in-memory representation schema tables (sqlite_master or
- ** sqlite_temp_master) by invoking the parser directly. The appropriate
+ /* Construct the in-memory representation schema tables (sqlite_schema or
+ ** sqlite_temp_schema) by invoking the parser directly. The appropriate
** table name will be inserted automatically by the parser so we can just
** use the abbreviation "x" here. The parser will also automatically tag
** the schema table as read-only. */
azArg[0] = "table";
- azArg[1] = zMasterName = SCHEMA_TABLE(iDb);
+ azArg[1] = zSchemaTabName = SCHEMA_TABLE(iDb);
azArg[2] = azArg[1];
azArg[3] = "1";
azArg[4] = "CREATE TABLE x(type text,name text,tbl_name text,"
@@ -277,6 +288,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
initData.mInitFlags = mFlags;
initData.nInitRow = 0;
initData.cksum = 0;
+ initData.mxPage = 0;
sqlite3InitCallback(&initData, 5, (char **)azArg, 0);
db->mDbFlags &= mask;
if( initData.rc ){
@@ -398,11 +410,12 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
/* Read the schema information out of the schema tables
*/
assert( db->init.busy );
+ initData.mxPage = sqlite3BtreeLastPage(pDb->pBt);
{
char *zSql;
zSql = sqlite3MPrintf(db,
"SELECT*FROM\"%w\".%s ORDER BY rowid",
- db->aDb[iDb].zDbSName, zMasterName);
+ db->aDb[iDb].zDbSName, zSchemaTabName);
#ifndef SQLITE_OMIT_AUTHORIZATION
{
sqlite3_xauth xAuth;
@@ -432,7 +445,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
** current sqlite3_prepare() operation will fail, but the following one
** will attempt to compile the supplied statement against whatever subset
** of the schema was loaded before the error occurred. The primary
- ** purpose of this is to allow access to the sqlite_master table
+ ** purpose of this is to allow access to the sqlite_schema table
** even when its contents have been corrupted.
*/
DbSetProperty(db, iDb, DB_SchemaLoaded);
@@ -614,17 +627,18 @@ static void schemaIsValid(Parse *pParse){
** attached database is returned.
*/
int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
- int i = -1000000;
+ int i = -32768;
- /* If pSchema is NULL, then return -1000000. This happens when code in
+ /* If pSchema is NULL, then return -32768. This happens when code in
** expr.c is trying to resolve a reference to a transient table (i.e. one
** created by a sub-select). In this case the return value of this
** function should never be used.
**
- ** We return -1000000 instead of the more usual -1 simply because using
- ** -1000000 as the incorrect index into db->aDb[] is much
+ ** We return -32768 instead of the more usual -1 simply because using
+ ** -32768 as the incorrect index into db->aDb[] is much
** more likely to cause a segfault than -1 (of course there are assert()
- ** statements too, but it never hurts to play the odds).
+ ** statements too, but it never hurts to play the odds) and
+ ** -32768 will still fit into a 16-bit signed integer.
*/
assert( sqlite3_mutex_held(db->mutex) );
if( pSchema ){
@@ -639,11 +653,26 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
return i;
}
+/*
+** Deallocate a single AggInfo object
+*/
+static void agginfoFree(sqlite3 *db, AggInfo *p){
+ sqlite3DbFree(db, p->aCol);
+ sqlite3DbFree(db, p->aFunc);
+ sqlite3DbFree(db, p);
+}
+
/*
** Free all memory allocations in the pParse object
*/
void sqlite3ParserReset(Parse *pParse){
sqlite3 *db = pParse->db;
+ AggInfo *pThis = pParse->pAggList;
+ while( pThis ){
+ AggInfo *pNext = pThis->pNext;
+ agginfoFree(db, pThis);
+ pThis = pNext;
+ }
sqlite3DbFree(db, pParse->aLabel);
sqlite3ExprListDelete(db, pParse->pConstExpr);
if( db ){
@@ -843,7 +872,7 @@ static int sqlite3LockAndPrepare(
**
** If the statement is successfully recompiled, return SQLITE_OK. Otherwise,
** if the statement cannot be recompiled because another connection has
-** locked the sqlite3_master table, return SQLITE_LOCKED. If any other error
+** locked the sqlite3_schema table, return SQLITE_LOCKED. If any other error
** occurs, return SQLITE_SCHEMA.
*/
int sqlite3Reprepare(Vdbe *p){
diff --git a/src/printf.c b/src/printf.c
index ae957022a1..2f99208bf3 100644
--- a/src/printf.c
+++ b/src/printf.c
@@ -407,11 +407,11 @@ void sqlite3_str_vappendf(
case etPOINTER:
flag_long = sizeof(char*)==sizeof(i64) ? 2 :
sizeof(char*)==sizeof(long int) ? 1 : 0;
- /* Fall through into the next case */
+ /* no break */ deliberate_fall_through
case etORDINAL:
case etRADIX:
cThousand = 0;
- /* Fall through into the next case */
+ /* no break */ deliberate_fall_through
case etDECIMAL:
if( infop->flags & FLAG_SIGNED ){
i64 v;
diff --git a/src/resolve.c b/src/resolve.c
index aff6dbeadb..fcb6f15224 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -16,6 +16,11 @@
*/
#include "sqliteInt.h"
+/*
+** Magic table number to mean the EXCLUDED table in an UPSERT statement.
+*/
+#define EXCLUDED_TABLE_NUMBER 2
+
/*
** Walk the expression tree pExpr and increase the aggregate function
** depth (the Expr.op2 field) by N on every TK_AGG_FUNCTION node.
@@ -386,7 +391,7 @@ static int lookupName(
Upsert *pUpsert = pNC->uNC.pUpsert;
if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){
pTab = pUpsert->pUpsertSrc->a[0].pTab;
- pExpr->iTable = 2;
+ pExpr->iTable = EXCLUDED_TABLE_NUMBER;
}
}
#endif /* SQLITE_OMIT_UPSERT */
@@ -411,14 +416,15 @@ static int lookupName(
if( iColnCol ){
cnt++;
#ifndef SQLITE_OMIT_UPSERT
- if( pExpr->iTable==2 ){
+ if( pExpr->iTable==EXCLUDED_TABLE_NUMBER ){
testcase( iCol==(-1) );
if( IN_RENAME_OBJECT ){
pExpr->iColumn = iCol;
pExpr->y.pTab = pTab;
eNewExprOp = TK_COLUMN;
}else{
- pExpr->iTable = pNC->uNC.pUpsert->regData + iCol;
+ pExpr->iTable = pNC->uNC.pUpsert->regData +
+ sqlite3TableColumnToStorage(pTab, iCol);
eNewExprOp = TK_REGISTER;
ExprSetProperty(pExpr, EP_Alias);
}
@@ -750,26 +756,23 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
#endif
switch( pExpr->op ){
-#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
/* The special operator TK_ROW means use the rowid for the first
** column in the FROM clause. This is used by the LIMIT and ORDER BY
- ** clause processing on UPDATE and DELETE statements.
+ ** clause processing on UPDATE and DELETE statements, and by
+ ** UPDATE ... FROM statement processing.
*/
case TK_ROW: {
SrcList *pSrcList = pNC->pSrcList;
struct SrcList_item *pItem;
- assert( pSrcList && pSrcList->nSrc==1 );
+ assert( pSrcList && pSrcList->nSrc>=1 );
pItem = pSrcList->a;
- assert( HasRowid(pItem->pTab) && pItem->pTab->pSelect==0 );
pExpr->op = TK_COLUMN;
pExpr->y.pTab = pItem->pTab;
pExpr->iTable = pItem->iCursor;
- pExpr->iColumn = -1;
+ pExpr->iColumn--;
pExpr->affExpr = SQLITE_AFF_INTEGER;
break;
}
-#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT)
- && !defined(SQLITE_OMIT_SUBQUERY) */
/* A column name: ID
** Or table name and column name: ID.ID
@@ -1081,7 +1084,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
return WRC_Continue;
}
}
- /* Fall thru */
+ /* no break */ deliberate_fall_through
}
case TK_BETWEEN:
case TK_EQ:
diff --git a/src/select.c b/src/select.c
index 534dfbc01b..8b1fae75a5 100644
--- a/src/select.c
+++ b/src/select.c
@@ -14,20 +14,6 @@
*/
#include "sqliteInt.h"
-/*
-** Trace output macros
-*/
-#if SELECTTRACE_ENABLED
-/***/ int sqlite3SelectTrace = 0;
-# define SELECTTRACE(K,P,S,X) \
- if(sqlite3SelectTrace&(K)) \
- sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\
- sqlite3DebugPrintf X
-#else
-# define SELECTTRACE(K,P,S,X)
-#endif
-
-
/*
** An instance of the following object is used to record information about
** how to process the DISTINCT keyword, to simplify passing that information
@@ -117,6 +103,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){
pDest->eDest = (u8)eDest;
pDest->iSDParm = iParm;
+ pDest->iSDParm2 = 0;
pDest->zAffSdst = 0;
pDest->iSdst = 0;
pDest->nSdst = 0;
@@ -138,9 +125,9 @@ Select *sqlite3SelectNew(
u32 selFlags, /* Flag parameters, such as SF_Distinct */
Expr *pLimit /* LIMIT value. NULL means not used */
){
- Select *pNew;
+ Select *pNew, *pAllocated;
Select standin;
- pNew = sqlite3DbMallocRawNN(pParse->db, sizeof(*pNew) );
+ pAllocated = pNew = sqlite3DbMallocRawNN(pParse->db, sizeof(*pNew) );
if( pNew==0 ){
assert( pParse->db->mallocFailed );
pNew = &standin;
@@ -174,12 +161,11 @@ Select *sqlite3SelectNew(
#endif
if( pParse->db->mallocFailed ) {
clearSelect(pParse->db, pNew, pNew!=&standin);
- pNew = 0;
+ pAllocated = 0;
}else{
assert( pNew->pSrc!=0 || pParse->nErr>0 );
}
- assert( pNew!=&standin );
- return pNew;
+ return pAllocated;
}
@@ -190,21 +176,6 @@ void sqlite3SelectDelete(sqlite3 *db, Select *p){
if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1);
}
-/*
-** Delete all the substructure for p, but keep p allocated. Redefine
-** p to be a single SELECT where every column of the result set has a
-** value of NULL.
-*/
-void sqlite3SelectReset(Parse *pParse, Select *p){
- if( ALWAYS(p) ){
- clearSelect(pParse->db, p, 0);
- memset(&p->iLimit, 0, sizeof(Select) - offsetof(Select,iLimit));
- p->pEList = sqlite3ExprListAppend(pParse, 0,
- sqlite3ExprAlloc(pParse->db,TK_NULL,0,0));
- p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(SrcList));
- }
-}
-
/*
** Return a pointer to the right-most SELECT statement in a compound.
*/
@@ -293,8 +264,10 @@ int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){
*/
static int columnIndex(Table *pTab, const char *zCol){
int i;
- for(i=0; inCol; i++){
- if( sqlite3StrICmp(pTab->aCol[i].zName, zCol)==0 ) return i;
+ u8 h = sqlite3StrIHash(zCol);
+ Column *pCol;
+ for(pCol=pTab->aCol, i=0; inCol; pCol++, i++){
+ if( pCol->hName==h && sqlite3StrICmp(pCol->zName, zCol)==0 ) return i;
}
return -1;
}
@@ -1005,7 +978,8 @@ static void selectInnerLoop(
testcase( eDest==SRT_Coroutine );
testcase( eDest==SRT_Output );
assert( eDest==SRT_Set || eDest==SRT_Mem
- || eDest==SRT_Coroutine || eDest==SRT_Output );
+ || eDest==SRT_Coroutine || eDest==SRT_Output
+ || eDest==SRT_Upfrom );
}
sRowLoadInfo.regResult = regResult;
sRowLoadInfo.ecelFlags = ecelFlags;
@@ -1154,6 +1128,30 @@ static void selectInnerLoop(
break;
}
+ case SRT_Upfrom: {
+ if( pSort ){
+ pushOntoSorter(
+ pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
+ }else{
+ int i2 = pDest->iSDParm2;
+ int r1 = sqlite3GetTempReg(pParse);
+
+ /* If the UPDATE FROM join is an aggregate that matches no rows, it
+ ** might still be trying to return one row, because that is what
+ ** aggregates do. Don't record that empty row in the output table. */
+ sqlite3VdbeAddOp2(v, OP_IsNull, regResult, iBreak); VdbeCoverage(v);
+
+ sqlite3VdbeAddOp3(v, OP_MakeRecord,
+ regResult+(i2<0), nResultCol-(i2<0), r1);
+ if( i2<0 ){
+ sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, regResult);
+ }else{
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, i2);
+ }
+ }
+ break;
+ }
+
#ifndef SQLITE_OMIT_SUBQUERY
/* If we are creating a set for an "expr IN (SELECT ...)" construct,
** then there should be a single item on the stack. Write this
@@ -1178,6 +1176,7 @@ static void selectInnerLoop(
break;
}
+
/* If any row exist in the result set, record that fact and abort.
*/
case SRT_Exists: {
@@ -1585,6 +1584,17 @@ static void generateSortTail(
break;
}
#endif
+ case SRT_Upfrom: {
+ int i2 = pDest->iSDParm2;
+ int r1 = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord,regRow+(i2<0),nColumn-(i2<0),r1);
+ if( i2<0 ){
+ sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, regRow);
+ }else{
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regRow, i2);
+ }
+ break;
+ }
default: {
assert( eDest==SRT_Output || eDest==SRT_Coroutine );
testcase( eDest==SRT_Output );
@@ -2717,9 +2727,7 @@ static int multiSelect(
selectOpName(p->op)));
rc = sqlite3Select(pParse, p, &uniondest);
testcase( rc!=SQLITE_OK );
- /* Query flattening in sqlite3Select() might refill p->pOrderBy.
- ** Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */
- sqlite3ExprListDelete(db, p->pOrderBy);
+ assert( p->pOrderBy==0 );
pDelete = p->pPrior;
p->pPrior = pPrior;
p->pOrderBy = 0;
@@ -3173,7 +3181,7 @@ static int multiSelectOrderBy(
sqlite3 *db; /* Database connection */
ExprList *pOrderBy; /* The ORDER BY clause */
int nOrderBy; /* Number of terms in the ORDER BY clause */
- int *aPermute; /* Mapping from ORDER BY terms to result set columns */
+ u32 *aPermute; /* Mapping from ORDER BY terms to result set columns */
assert( p->pOrderBy!=0 );
assert( pKeyDup==0 ); /* "Managed" code needs this. Ticket #3382. */
@@ -3222,7 +3230,7 @@ static int multiSelectOrderBy(
** to the right and the left are evaluated, they use the correct
** collation.
*/
- aPermute = sqlite3DbMallocRawNN(db, sizeof(int)*(nOrderBy + 1));
+ aPermute = sqlite3DbMallocRawNN(db, sizeof(u32)*(nOrderBy + 1));
if( aPermute ){
struct ExprList_item *pItem;
aPermute[0] = nOrderBy;
@@ -3792,6 +3800,7 @@ static int flattenSubquery(
Expr *pWhere; /* The WHERE clause */
struct SrcList_item *pSubitem; /* The subquery */
sqlite3 *db = pParse->db;
+ Walker w; /* Walker to persist agginfo data */
/* Check to see if flattening is permitted. Return 0 if not.
*/
@@ -4105,7 +4114,7 @@ static int flattenSubquery(
** We look at every expression in the outer query and every place we see
** "a" we substitute "x*3" and every place we see "b" we substitute "y+10".
*/
- if( pSub->pOrderBy ){
+ if( pSub->pOrderBy && (pParent->selFlags & SF_NoopOrderBy)==0 ){
/* At this point, any non-zero iOrderByCol values indicate that the
** ORDER BY column expression is identical to the iOrderByCol'th
** expression returned by SELECT statement pSub. Since these values
@@ -4129,7 +4138,13 @@ static int flattenSubquery(
if( isLeftJoin>0 ){
sqlite3SetJoinExpr(pWhere, iNewParent);
}
- pParent->pWhere = sqlite3ExprAnd(pParse, pWhere, pParent->pWhere);
+ if( pWhere ){
+ if( pParent->pWhere ){
+ pParent->pWhere = sqlite3PExpr(pParse, TK_AND, pWhere, pParent->pWhere);
+ }else{
+ pParent->pWhere = pWhere;
+ }
+ }
if( db->mallocFailed==0 ){
SubstContext x;
x.pParse = pParse;
@@ -4166,10 +4181,12 @@ static int flattenSubquery(
/* Finially, delete what is left of the subquery and return
** success.
*/
+ sqlite3AggInfoPersistWalkerInit(&w, pParse);
+ sqlite3WalkSelect(&w,pSub1);
sqlite3SelectDelete(db, pSub1);
#if SELECTTRACE_ENABLED
- if( sqlite3SelectTrace & 0x100 ){
+ if( sqlite3_unsupported_selecttrace & 0x100 ){
SELECTTRACE(0x100,pParse,p,("After flattening:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
@@ -4426,11 +4443,14 @@ static int pushDownWhereTerms(
){
Expr *pNew;
int nChng = 0;
+ Select *pSel;
if( pWhere==0 ) return 0;
if( pSubq->selFlags & SF_Recursive ) return 0; /* restriction (2) */
#ifndef SQLITE_OMIT_WINDOWFUNC
- if( pSubq->pWin ) return 0; /* restriction (6) */
+ for(pSel=pSubq; pSel; pSel=pSel->pPrior){
+ if( pSel->pWin ) return 0; /* restriction (6) */
+ }
#endif
#ifdef SQLITE_DEBUG
@@ -4630,6 +4650,14 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
for(pX=p; pX && (pX->op==TK_ALL || pX->op==TK_SELECT); pX=pX->pPrior){}
if( pX==0 ) return WRC_Continue;
a = p->pOrderBy->a;
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ /* If iOrderByCol is already non-zero, then it has already been matched
+ ** to a result column of the SELECT statement. This occurs when the
+ ** SELECT is rewritten for window-functions processing and then passed
+ ** to sqlite3SelectPrep() and similar a second time. The rewriting done
+ ** by this function is not required in this case. */
+ if( a[0].u.x.iOrderByCol ) return WRC_Continue;
+#endif
for(i=p->pOrderBy->nExpr-1; i>=0; i--){
if( a[i].pExpr->flags & EP_Collate ) break;
}
@@ -4981,8 +5009,8 @@ static int selectExpander(Walker *pWalker, Select *p){
for(i=0, pFrom=pTabList->a; inSrc; i++, pFrom++){
Table *pTab;
assert( pFrom->fg.isRecursive==0 || pFrom->pTab!=0 );
- if( pFrom->fg.isRecursive ) continue;
- assert( pFrom->pTab==0 );
+ if( pFrom->pTab ) continue;
+ assert( pFrom->fg.isRecursive==0 );
#ifndef SQLITE_OMIT_CTE
if( withExpand(pWalker, pFrom) ) return WRC_Abort;
if( pFrom->pTab ) {} else
@@ -5370,7 +5398,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
struct AggInfo_func *pFunc;
int nReg = pAggInfo->nFunc + pAggInfo->nColumn;
if( nReg==0 ) return;
- if( pParse->nErr ) return;
+ if( pParse->nErr || pParse->db->mallocFailed ) return;
#ifdef SQLITE_DEBUG
/* Verify that all AggInfo registers are within the range specified by
** AggInfo.mnReg..AggInfo.mxReg */
@@ -5387,7 +5415,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
sqlite3VdbeAddOp3(v, OP_Null, 0, pAggInfo->mnReg, pAggInfo->mxReg);
for(pFunc=pAggInfo->aFunc, i=0; inFunc; i++, pFunc++){
if( pFunc->iDistinct>=0 ){
- Expr *pE = pFunc->pExpr;
+ Expr *pE = pFunc->pFExpr;
assert( !ExprHasProperty(pE, EP_xIsSelect) );
if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){
sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one "
@@ -5411,8 +5439,8 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
int i;
struct AggInfo_func *pF;
for(i=0, pF=pAggInfo->aFunc; inFunc; i++, pF++){
- ExprList *pList = pF->pExpr->x.pList;
- assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
+ ExprList *pList = pF->pFExpr->x.pList;
+ assert( !ExprHasProperty(pF->pFExpr, EP_xIsSelect) );
sqlite3VdbeAddOp2(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0);
sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
}
@@ -5441,22 +5469,26 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
int nArg;
int addrNext = 0;
int regAgg;
- ExprList *pList = pF->pExpr->x.pList;
- assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
- assert( !IsWindowFunc(pF->pExpr) );
- if( ExprHasProperty(pF->pExpr, EP_WinFunc) ){
- Expr *pFilter = pF->pExpr->y.pWin->pFilter;
+ ExprList *pList = pF->pFExpr->x.pList;
+ assert( !ExprHasProperty(pF->pFExpr, EP_xIsSelect) );
+ assert( !IsWindowFunc(pF->pFExpr) );
+ if( ExprHasProperty(pF->pFExpr, EP_WinFunc) ){
+ Expr *pFilter = pF->pFExpr->y.pWin->pFilter;
if( pAggInfo->nAccumulator
&& (pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
+ && regAcc
){
+ /* If regAcc==0, there there exists some min() or max() function
+ ** without a FILTER clause that will ensure the magnet registers
+ ** are populated. */
if( regHit==0 ) regHit = ++pParse->nMem;
- /* If this is the first row of the group (regAcc==0), clear the
+ /* If this is the first row of the group (regAcc contains 0), clear the
** "magnet" register regHit so that the accumulator registers
** are populated if the FILTER clause jumps over the the
** invocation of min() or max() altogether. Or, if this is not
- ** the first row (regAcc==1), set the magnet register so that the
- ** accumulators are not populated unless the min()/max() is invoked and
- ** indicates that they should be. */
+ ** the first row (regAcc contains 1), set the magnet register so that
+ ** the accumulators are not populated unless the min()/max() is invoked
+ ** and indicates that they should be. */
sqlite3VdbeAddOp2(v, OP_Copy, regAcc, regHit);
}
addrNext = sqlite3VdbeMakeLabel(pParse);
@@ -5507,7 +5539,7 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit); VdbeCoverage(v);
}
for(i=0, pC=pAggInfo->aCol; inAccumulator; i++, pC++){
- sqlite3ExprCode(pParse, pC->pExpr, pC->iMem);
+ sqlite3ExprCode(pParse, pC->pCExpr, pC->iMem);
}
pAggInfo->directMode = 0;
@@ -5592,7 +5624,7 @@ static void havingToWhere(Parse *pParse, Select *p){
sWalker.u.pSelect = p;
sqlite3WalkExpr(&sWalker, p->pHaving);
#if SELECTTRACE_ENABLED
- if( sWalker.eCode && (sqlite3SelectTrace & 0x100)!=0 ){
+ if( sWalker.eCode && (sqlite3_unsupported_selecttrace & 0x100)!=0 ){
SELECTTRACE(0x100,pParse,p,("Move HAVING terms into WHERE:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
@@ -5714,7 +5746,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
p->selFlags &= ~SF_Aggregate;
#if SELECTTRACE_ENABLED
- if( sqlite3SelectTrace & 0x400 ){
+ if( sqlite3_unsupported_selecttrace & 0x400 ){
SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
@@ -5750,10 +5782,10 @@ int sqlite3Select(
Expr *pWhere; /* The WHERE clause. May be NULL */
ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
Expr *pHaving; /* The HAVING clause. May be NULL */
+ AggInfo *pAggInfo = 0; /* Aggregate information */
int rc = 1; /* Value to return from this function */
DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */
SortCtx sSort; /* Info on how to code the ORDER BY clause */
- AggInfo sAggInfo; /* Information used by aggregate queries */
int iEnd; /* Address of the end of the query */
sqlite3 *db; /* The database connection */
ExprList *pMinMaxOrderBy = 0; /* Added ORDER BY for min/max queries */
@@ -5765,10 +5797,9 @@ int sqlite3Select(
return 1;
}
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
- memset(&sAggInfo, 0, sizeof(sAggInfo));
#if SELECTTRACE_ENABLED
SELECTTRACE(1,pParse,p, ("begin processing:\n", pParse->addrExplain));
- if( sqlite3SelectTrace & 0x100 ){
+ if( sqlite3_unsupported_selecttrace & 0x100 ){
sqlite3TreeViewSelect(0, p, 0);
}
#endif
@@ -5787,6 +5818,7 @@ int sqlite3Select(
sqlite3ExprListDelete(db, p->pOrderBy);
p->pOrderBy = 0;
p->selFlags &= ~SF_Distinct;
+ p->selFlags |= SF_NoopOrderBy;
}
sqlite3SelectPrep(pParse, p, 0);
if( pParse->nErr || db->mallocFailed ){
@@ -5794,12 +5826,30 @@ int sqlite3Select(
}
assert( p->pEList!=0 );
#if SELECTTRACE_ENABLED
- if( sqlite3SelectTrace & 0x104 ){
+ if( sqlite3_unsupported_selecttrace & 0x104 ){
SELECTTRACE(0x104,pParse,p, ("after name resolution:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
#endif
+ /* If the SF_UpdateFrom flag is set, then this function is being called
+ ** as part of populating the temp table for an UPDATE...FROM statement.
+ ** In this case, it is an error if the target object (pSrc->a[0]) name
+ ** or alias is duplicated within FROM clause (pSrc->a[1..n]). */
+ if( p->selFlags & SF_UpdateFrom ){
+ struct SrcList_item *p0 = &p->pSrc->a[0];
+ for(i=1; ipSrc->nSrc; i++){
+ struct SrcList_item *p1 = &p->pSrc->a[i];
+ if( p0->pTab==p1->pTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){
+ sqlite3ErrorMsg(pParse,
+ "target object/alias may not appear in FROM clause: %s",
+ p0->zAlias ? p0->zAlias : p0->pTab->zName
+ );
+ goto select_end;
+ }
+ }
+ }
+
if( pDest->eDest==SRT_Output ){
generateColumnNames(pParse, p);
}
@@ -5811,7 +5861,7 @@ int sqlite3Select(
goto select_end;
}
#if SELECTTRACE_ENABLED
- if( p->pWin && (sqlite3SelectTrace & 0x108)!=0 ){
+ if( p->pWin && (sqlite3_unsupported_selecttrace & 0x108)!=0 ){
SELECTTRACE(0x104,pParse,p, ("after window rewrite:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
@@ -5822,7 +5872,7 @@ int sqlite3Select(
memset(&sSort, 0, sizeof(sSort));
sSort.pOrderBy = p->pOrderBy;
- /* Try to various optimizations (flattening subqueries, and strength
+ /* Try to do various optimizations (flattening subqueries, and strength
** reduction of join operators) in the FROM clause up into the main query
*/
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
@@ -5831,6 +5881,11 @@ int sqlite3Select(
Select *pSub = pItem->pSelect;
Table *pTab = pItem->pTab;
+ /* The expander should have already created transient Table objects
+ ** even for FROM clause elements such as subqueries that do not correspond
+ ** to a real table */
+ assert( pTab!=0 );
+
/* Convert LEFT JOIN into JOIN if there are terms of the right table
** of the LEFT JOIN used in the WHERE clause.
*/
@@ -5913,7 +5968,7 @@ int sqlite3Select(
rc = multiSelect(pParse, p, pDest);
#if SELECTTRACE_ENABLED
SELECTTRACE(0x1,pParse,p,("end compound-select processing\n"));
- if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
+ if( (sqlite3_unsupported_selecttrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
sqlite3TreeViewSelect(0, p, 0);
}
#endif
@@ -5932,7 +5987,7 @@ int sqlite3Select(
&& propagateConstants(pParse, p)
){
#if SELECTTRACE_ENABLED
- if( sqlite3SelectTrace & 0x100 ){
+ if( sqlite3_unsupported_selecttrace & 0x100 ){
SELECTTRACE(0x100,pParse,p,("After constant propagation:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
@@ -6020,7 +6075,7 @@ int sqlite3Select(
(pItem->fg.jointype & JT_OUTER)!=0)
){
#if SELECTTRACE_ENABLED
- if( sqlite3SelectTrace & 0x100 ){
+ if( sqlite3_unsupported_selecttrace & 0x100 ){
SELECTTRACE(0x100,pParse,p,
("After WHERE-clause push-down into subquery %d:\n", pSub->selId));
sqlite3TreeViewSelect(0, p, 0);
@@ -6120,7 +6175,7 @@ int sqlite3Select(
sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0;
#if SELECTTRACE_ENABLED
- if( sqlite3SelectTrace & 0x400 ){
+ if( sqlite3_unsupported_selecttrace & 0x400 ){
SELECTTRACE(0x400,pParse,p,("After all FROM-clause analysis:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
@@ -6156,7 +6211,7 @@ int sqlite3Select(
assert( sDistinct.isTnct );
#if SELECTTRACE_ENABLED
- if( sqlite3SelectTrace & 0x400 ){
+ if( sqlite3_unsupported_selecttrace & 0x400 ){
SELECTTRACE(0x400,pParse,p,("Transform DISTINCT into GROUP BY:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
@@ -6222,7 +6277,7 @@ int sqlite3Select(
u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0)
| (p->selFlags & SF_FixedLimit);
#ifndef SQLITE_OMIT_WINDOWFUNC
- Window *pWin = p->pWin; /* Master window object (or NULL) */
+ Window *pWin = p->pWin; /* Main window object (or NULL) */
if( pWin ){
sqlite3WindowCodeInit(pParse, p);
}
@@ -6355,14 +6410,21 @@ int sqlite3Select(
** sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the
** SELECT statement.
*/
+ pAggInfo = sqlite3DbMallocZero(db, sizeof(*pAggInfo) );
+ if( pAggInfo==0 ){
+ goto select_end;
+ }
+ pAggInfo->pNext = pParse->pAggList;
+ pParse->pAggList = pAggInfo;
+ pAggInfo->selId = p->selId;
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
sNC.pSrcList = pTabList;
- sNC.uNC.pAggInfo = &sAggInfo;
+ sNC.uNC.pAggInfo = pAggInfo;
VVA_ONLY( sNC.ncFlags = NC_UAggInfo; )
- sAggInfo.mnReg = pParse->nMem+1;
- sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0;
- sAggInfo.pGroupBy = pGroupBy;
+ pAggInfo->mnReg = pParse->nMem+1;
+ pAggInfo->nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0;
+ pAggInfo->pGroupBy = pGroupBy;
sqlite3ExprAnalyzeAggList(&sNC, pEList);
sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy);
if( pHaving ){
@@ -6375,14 +6437,14 @@ int sqlite3Select(
}
sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
}
- sAggInfo.nAccumulator = sAggInfo.nColumn;
- if( p->pGroupBy==0 && p->pHaving==0 && sAggInfo.nFunc==1 ){
- minMaxFlag = minMaxQuery(db, sAggInfo.aFunc[0].pExpr, &pMinMaxOrderBy);
+ pAggInfo->nAccumulator = pAggInfo->nColumn;
+ if( p->pGroupBy==0 && p->pHaving==0 && pAggInfo->nFunc==1 ){
+ minMaxFlag = minMaxQuery(db, pAggInfo->aFunc[0].pFExpr, &pMinMaxOrderBy);
}else{
minMaxFlag = WHERE_ORDERBY_NORMAL;
}
- for(i=0; inFunc; i++){
+ Expr *pExpr = pAggInfo->aFunc[i].pFExpr;
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
sNC.ncFlags |= NC_InAggFunc;
sqlite3ExprAnalyzeAggList(&sNC, pExpr->x.pList);
@@ -6394,22 +6456,22 @@ int sqlite3Select(
#endif
sNC.ncFlags &= ~NC_InAggFunc;
}
- sAggInfo.mxReg = pParse->nMem;
+ pAggInfo->mxReg = pParse->nMem;
if( db->mallocFailed ) goto select_end;
#if SELECTTRACE_ENABLED
- if( sqlite3SelectTrace & 0x400 ){
+ if( sqlite3_unsupported_selecttrace & 0x400 ){
int ii;
- SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", &sAggInfo));
+ SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", pAggInfo));
sqlite3TreeViewSelect(0, p, 0);
- for(ii=0; iinColumn; ii++){
sqlite3DebugPrintf("agg-column[%d] iMem=%d\n",
- ii, sAggInfo.aCol[ii].iMem);
- sqlite3TreeViewExpr(0, sAggInfo.aCol[ii].pExpr, 0);
+ ii, pAggInfo->aCol[ii].iMem);
+ sqlite3TreeViewExpr(0, pAggInfo->aCol[ii].pCExpr, 0);
}
- for(ii=0; iinFunc; ii++){
sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n",
- ii, sAggInfo.aFunc[ii].iMem);
- sqlite3TreeViewExpr(0, sAggInfo.aFunc[ii].pExpr, 0);
+ ii, pAggInfo->aFunc[ii].iMem);
+ sqlite3TreeViewExpr(0, pAggInfo->aFunc[ii].pFExpr, 0);
}
}
#endif
@@ -6434,10 +6496,11 @@ int sqlite3Select(
** that we do not need it after all, the OP_SorterOpen instruction
** will be converted into a Noop.
*/
- sAggInfo.sortingIdx = pParse->nTab++;
- pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pGroupBy,0,sAggInfo.nColumn);
+ pAggInfo->sortingIdx = pParse->nTab++;
+ pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pGroupBy,
+ 0, pAggInfo->nColumn);
addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
- sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
+ pAggInfo->sortingIdx, pAggInfo->nSortingColumn,
0, (char*)pKeyInfo, P4_KEYINFO);
/* Initialize memory locations used by GROUP BY aggregate processing
@@ -6492,8 +6555,8 @@ int sqlite3Select(
nGroupBy = pGroupBy->nExpr;
nCol = nGroupBy;
j = nGroupBy;
- for(i=0; i=j ){
+ for(i=0; inColumn; i++){
+ if( pAggInfo->aCol[i].iSorterColumn>=j ){
nCol++;
j++;
}
@@ -6501,8 +6564,8 @@ int sqlite3Select(
regBase = sqlite3GetTempRange(pParse, nCol);
sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0);
j = nGroupBy;
- for(i=0; inColumn; i++){
+ struct AggInfo_col *pCol = &pAggInfo->aCol[i];
if( pCol->iSorterColumn>=j ){
int r1 = j + regBase;
sqlite3ExprCodeGetColumnOfTable(v,
@@ -6512,16 +6575,16 @@ int sqlite3Select(
}
regRecord = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord);
- sqlite3VdbeAddOp2(v, OP_SorterInsert, sAggInfo.sortingIdx, regRecord);
+ sqlite3VdbeAddOp2(v, OP_SorterInsert, pAggInfo->sortingIdx, regRecord);
sqlite3ReleaseTempReg(pParse, regRecord);
sqlite3ReleaseTempRange(pParse, regBase, nCol);
sqlite3WhereEnd(pWInfo);
- sAggInfo.sortingIdxPTab = sortPTab = pParse->nTab++;
+ pAggInfo->sortingIdxPTab = sortPTab = pParse->nTab++;
sortOut = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_OpenPseudo, sortPTab, sortOut, nCol);
- sqlite3VdbeAddOp2(v, OP_SorterSort, sAggInfo.sortingIdx, addrEnd);
+ sqlite3VdbeAddOp2(v, OP_SorterSort, pAggInfo->sortingIdx, addrEnd);
VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v);
- sAggInfo.useSortingIdx = 1;
+ pAggInfo->useSortingIdx = 1;
}
/* If the index or temporary table used by the GROUP BY sort
@@ -6545,14 +6608,14 @@ int sqlite3Select(
*/
addrTopOfLoop = sqlite3VdbeCurrentAddr(v);
if( groupBySort ){
- sqlite3VdbeAddOp3(v, OP_SorterData, sAggInfo.sortingIdx,
+ sqlite3VdbeAddOp3(v, OP_SorterData, pAggInfo->sortingIdx,
sortOut, sortPTab);
}
for(j=0; jnExpr; j++){
if( groupBySort ){
sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j);
}else{
- sAggInfo.directMode = 1;
+ pAggInfo->directMode = 1;
sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j);
}
}
@@ -6582,14 +6645,14 @@ int sqlite3Select(
** the current row
*/
sqlite3VdbeJumpHere(v, addr1);
- updateAccumulator(pParse, iUseFlag, &sAggInfo);
+ updateAccumulator(pParse, iUseFlag, pAggInfo);
sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag);
VdbeComment((v, "indicate data in accumulator"));
/* End of the loop
*/
if( groupBySort ){
- sqlite3VdbeAddOp2(v, OP_SorterNext, sAggInfo.sortingIdx, addrTopOfLoop);
+ sqlite3VdbeAddOp2(v, OP_SorterNext, pAggInfo->sortingIdx, addrTopOfLoop);
VdbeCoverage(v);
}else{
sqlite3WhereEnd(pWInfo);
@@ -6622,7 +6685,7 @@ int sqlite3Select(
VdbeCoverage(v);
VdbeComment((v, "Groupby result generator entry point"));
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
- finalizeAggFunctions(pParse, &sAggInfo);
+ finalizeAggFunctions(pParse, pAggInfo);
sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
selectInnerLoop(pParse, p, -1, &sSort,
&sDistinct, pDest,
@@ -6633,7 +6696,7 @@ int sqlite3Select(
/* Generate a subroutine that will reset the group-by accumulator
*/
sqlite3VdbeResolveLabel(v, addrReset);
- resetAccumulator(pParse, &sAggInfo);
+ resetAccumulator(pParse, pAggInfo);
sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag);
VdbeComment((v, "indicate accumulator empty"));
sqlite3VdbeAddOp1(v, OP_Return, regReset);
@@ -6641,7 +6704,7 @@ int sqlite3Select(
} /* endif pGroupBy. Begin aggregate queries without GROUP BY: */
else {
Table *pTab;
- if( (pTab = isSimpleCount(p, &sAggInfo))!=0 ){
+ if( (pTab = isSimpleCount(p, pAggInfo))!=0 ){
/* If isSimpleCount() returns a pointer to a Table structure, then
** the SQL statement is of the form:
**
@@ -6660,7 +6723,7 @@ int sqlite3Select(
Index *pIdx; /* Iterator variable */
KeyInfo *pKeyInfo = 0; /* Keyinfo for scanned index */
Index *pBest = 0; /* Best index found so far */
- int iRoot = pTab->tnum; /* Root page of scanned b-tree */
+ Pgno iRoot = pTab->tnum; /* Root page of scanned b-tree */
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
@@ -6692,15 +6755,16 @@ int sqlite3Select(
}
/* Open a read-only cursor, execute the OP_Count, close the cursor. */
- sqlite3VdbeAddOp4Int(v, OP_OpenRead, iCsr, iRoot, iDb, 1);
+ sqlite3VdbeAddOp4Int(v, OP_OpenRead, iCsr, (int)iRoot, iDb, 1);
if( pKeyInfo ){
sqlite3VdbeChangeP4(v, -1, (char *)pKeyInfo, P4_KEYINFO);
}
- sqlite3VdbeAddOp2(v, OP_Count, iCsr, sAggInfo.aFunc[0].iMem);
+ sqlite3VdbeAddOp2(v, OP_Count, iCsr, pAggInfo->aFunc[0].iMem);
sqlite3VdbeAddOp1(v, OP_Close, iCsr);
explainSimpleCount(pParse, pTab, pBest);
}else{
int regAcc = 0; /* "populate accumulators" flag */
+ int addrSkip;
/* If there are accumulator registers but no min() or max() functions
** without FILTER clauses, allocate register regAcc. Register regAcc
@@ -6711,12 +6775,16 @@ int sqlite3Select(
** first row visited by the aggregate, so that they are updated at
** least once even if the FILTER clause means the min() or max()
** function visits zero rows. */
- if( sAggInfo.nAccumulator ){
- for(i=0; ifuncFlags&SQLITE_FUNC_NEEDCOLL ) break;
+ if( pAggInfo->nAccumulator ){
+ for(i=0; inFunc; i++){
+ if( ExprHasProperty(pAggInfo->aFunc[i].pFExpr, EP_WinFunc) ){
+ continue;
+ }
+ if( pAggInfo->aFunc[i].pFunc->funcFlags&SQLITE_FUNC_NEEDCOLL ){
+ break;
+ }
}
- if( i==sAggInfo.nFunc ){
+ if( i==pAggInfo->nFunc ){
regAcc = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Integer, 0, regAcc);
}
@@ -6727,7 +6795,7 @@ int sqlite3Select(
** of output.
*/
assert( p->pGroupBy==0 );
- resetAccumulator(pParse, &sAggInfo);
+ resetAccumulator(pParse, pAggInfo);
/* If this query is a candidate for the min/max optimization, then
** minMaxFlag will have been previously set to either
@@ -6743,15 +6811,14 @@ int sqlite3Select(
if( pWInfo==0 ){
goto select_end;
}
- updateAccumulator(pParse, regAcc, &sAggInfo);
+ updateAccumulator(pParse, regAcc, pAggInfo);
if( regAcc ) sqlite3VdbeAddOp2(v, OP_Integer, 1, regAcc);
- if( sqlite3WhereIsOrdered(pWInfo)>0 ){
- sqlite3VdbeGoto(v, sqlite3WhereBreakLabel(pWInfo));
- VdbeComment((v, "%s() by index",
- (minMaxFlag==WHERE_ORDERBY_MIN?"min":"max")));
+ addrSkip = sqlite3WhereOrderByLimitOptLabel(pWInfo);
+ if( addrSkip!=sqlite3WhereContinueLabel(pWInfo) ){
+ sqlite3VdbeGoto(v, addrSkip);
}
sqlite3WhereEnd(pWInfo);
- finalizeAggFunctions(pParse, &sAggInfo);
+ finalizeAggFunctions(pParse, pAggInfo);
}
sSort.pOrderBy = 0;
@@ -6790,11 +6857,28 @@ int sqlite3Select(
*/
select_end:
sqlite3ExprListDelete(db, pMinMaxOrderBy);
- sqlite3DbFree(db, sAggInfo.aCol);
- sqlite3DbFree(db, sAggInfo.aFunc);
+#ifdef SQLITE_DEBUG
+ if( pAggInfo && !db->mallocFailed ){
+ for(i=0; inColumn; i++){
+ Expr *pExpr = pAggInfo->aCol[i].pCExpr;
+ assert( pExpr!=0 || db->mallocFailed );
+ if( pExpr==0 ) continue;
+ assert( pExpr->pAggInfo==pAggInfo );
+ assert( pExpr->iAgg==i );
+ }
+ for(i=0; inFunc; i++){
+ Expr *pExpr = pAggInfo->aFunc[i].pFExpr;
+ assert( pExpr!=0 || db->mallocFailed );
+ if( pExpr==0 ) continue;
+ assert( pExpr->pAggInfo==pAggInfo );
+ assert( pExpr->iAgg==i );
+ }
+ }
+#endif
+
#if SELECTTRACE_ENABLED
SELECTTRACE(0x1,pParse,p,("end processing\n"));
- if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
+ if( (sqlite3_unsupported_selecttrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
sqlite3TreeViewSelect(0, p, 0);
}
#endif
diff --git a/src/shell.c.in b/src/shell.c.in
index f422f820b7..23018c4fef 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -623,6 +623,21 @@ static int strlenChar(const char *z){
return n;
}
+/*
+** Return true if zFile does not exist or if it is not an ordinary file.
+*/
+#ifdef _WIN32
+# define notNormalFile(X) 0
+#else
+static int notNormalFile(const char *zFile){
+ struct stat x;
+ int rc;
+ memset(&x, 0, sizeof(x));
+ rc = stat(zFile, &x);
+ return rc || !S_ISREG(x.st_mode);
+}
+#endif
+
/*
** This routine reads a line of text from FILE in, stores
** the text in memory obtained from malloc() and returns a pointer
@@ -935,7 +950,7 @@ static void shellModuleSchema(
** CREATE VIRTUAL TABLE
**
** This UDF is used by the .schema command to insert the schema name of
-** attached databases into the middle of the sqlite_master.sql field.
+** attached databases into the middle of the sqlite_schema.sql field.
*/
static void shellAddSchemaName(
sqlite3_context *pCtx,
@@ -1011,6 +1026,8 @@ INCLUDE ../ext/misc/completion.c
INCLUDE ../ext/misc/appendvfs.c
INCLUDE ../ext/misc/memtrace.c
INCLUDE ../ext/misc/uint.c
+INCLUDE ../ext/misc/decimal.c
+INCLUDE ../ext/misc/ieee754.c
#ifdef SQLITE_HAVE_ZLIB
INCLUDE ../ext/misc/zipfile.c
INCLUDE ../ext/misc/sqlar.c
@@ -1035,18 +1052,6 @@ struct OpenSession {
};
#endif
-/*
-** Shell output mode information from before ".explain on",
-** saved so that it can be restored by ".explain off"
-*/
-typedef struct SavedModeInfo SavedModeInfo;
-struct SavedModeInfo {
- int valid; /* Is there legit data in here? */
- int mode; /* Mode prior to ".explain on" */
- int showHeader; /* The ".header" setting prior to ".explain on" */
- int colWidth[100]; /* Column widths prior to ".explain on" */
-};
-
typedef struct ExpertInfo ExpertInfo;
struct ExpertInfo {
sqlite3expert *pExpert;
@@ -1116,8 +1121,9 @@ struct ShellState {
char rowSeparator[20]; /* Row separator character for MODE_Ascii */
char colSepPrior[20]; /* Saved column separator */
char rowSepPrior[20]; /* Saved row separator */
- int colWidth[100]; /* Requested width of each column when in column mode*/
- int actualWidth[100]; /* Actual width of each column */
+ int *colWidth; /* Requested width of each column in columnar modes */
+ int *actualWidth; /* Actual width of each column */
+ int nWidth; /* Number of slots in colWidth[] and actualWidth[] */
char nullValue[20]; /* The text to print when a NULL comes back from
** the database */
char outfile[FILENAME_MAX]; /* Filename for *out */
@@ -1179,6 +1185,7 @@ struct ShellState {
#define SHFLG_Newlines 0x00000010 /* .dump --newline flag */
#define SHFLG_CountChanges 0x00000020 /* .changes setting */
#define SHFLG_Echo 0x00000040 /* .echo or --echo setting */
+#define SHFLG_HeaderSet 0x00000080 /* .header has been used */
/*
** Macros for testing and setting shellFlgs
@@ -1203,6 +1210,10 @@ struct ShellState {
#define MODE_Ascii 10 /* Use ASCII unit and record separators (0x1F/0x1E) */
#define MODE_Pretty 11 /* Pretty-print schemas */
#define MODE_EQP 12 /* Converts EXPLAIN QUERY PLAN output into a graph */
+#define MODE_Json 13 /* Output JSON */
+#define MODE_Markdown 14 /* Markdown formatting */
+#define MODE_Table 15 /* MySQL-style table formatting */
+#define MODE_Box 16 /* Unicode box-drawing characters */
static const char *modeDescr[] = {
"line",
@@ -1217,7 +1228,11 @@ static const char *modeDescr[] = {
"explain",
"ascii",
"prettyprint",
- "eqp"
+ "eqp",
+ "json",
+ "markdown",
+ "table",
+ "box"
};
/*
@@ -1585,6 +1600,40 @@ static void output_c_string(FILE *out, const char *z){
fputc('"', out);
}
+/*
+** Output the given string as a quoted according to JSON quoting rules.
+*/
+static void output_json_string(FILE *out, const char *z, int n){
+ unsigned int c;
+ if( n<0 ) n = (int)strlen(z);
+ fputc('"', out);
+ while( n-- ){
+ c = *(z++);
+ if( c=='\\' || c=='"' ){
+ fputc('\\', out);
+ fputc(c, out);
+ }else if( c<=0x1f ){
+ fputc('\\', out);
+ if( c=='\b' ){
+ fputc('b', out);
+ }else if( c=='\f' ){
+ fputc('f', out);
+ }else if( c=='\n' ){
+ fputc('n', out);
+ }else if( c=='\r' ){
+ fputc('r', out);
+ }else if( c=='\t' ){
+ fputc('t', out);
+ }else{
+ raw_printf(out, "u%04x",c);
+ }
+ }else{
+ fputc(c, out);
+ }
+ }
+ fputc('"', out);
+}
+
/*
** Output the given string with characters that are special to
** HTML escaped.
@@ -1894,6 +1943,40 @@ static int progress_handler(void *pClientData) {
}
#endif /* SQLITE_OMIT_PROGRESS_CALLBACK */
+/*
+** Print N dashes
+*/
+static void print_dashes(FILE *out, int N){
+ const char zDash[] = "--------------------------------------------------";
+ const int nDash = sizeof(zDash) - 1;
+ while( N>nDash ){
+ fputs(zDash, out);
+ N -= nDash;
+ }
+ raw_printf(out, "%.*s", N, zDash);
+}
+
+/*
+** Print a markdown or table-style row separator using ascii-art
+*/
+static void print_row_separator(
+ ShellState *p,
+ int nArg,
+ const char *zSep
+){
+ int i;
+ if( nArg>0 ){
+ fputs(zSep, p->out);
+ print_dashes(p->out, p->actualWidth[0]+2);
+ for(i=1; iout);
+ print_dashes(p->out, p->actualWidth[i]+2);
+ }
+ fputs(zSep, p->out);
+ }
+ fputs("\n", p->out);
+}
+
/*
** This is the callback routine that the shell
** invokes for each row of a query result.
@@ -1903,7 +1986,7 @@ static int shell_callback(
int nArg, /* Number of result columns */
char **azArg, /* Text of each result column */
char **azCol, /* Column names */
- int *aiType /* Column types */
+ int *aiType /* Column types. Might be NULL */
){
int i;
ShellState *p = (ShellState*)pArg;
@@ -1924,71 +2007,27 @@ static int shell_callback(
}
break;
}
- case MODE_Explain:
- case MODE_Column: {
- static const int aExplainWidths[] = {4, 13, 4, 4, 4, 13, 2, 13};
- const int *colWidth;
- int showHdr;
- char *rowSep;
- int nWidth;
- if( p->cMode==MODE_Column ){
- colWidth = p->colWidth;
- nWidth = ArraySize(p->colWidth);
- showHdr = p->showHeader;
- rowSep = p->rowSeparator;
- }else{
- colWidth = aExplainWidths;
- nWidth = ArraySize(aExplainWidths);
- showHdr = 1;
- rowSep = SEP_Row;
+ case MODE_Explain: {
+ static const int aExplainWidth[] = {4, 13, 4, 4, 4, 13, 2, 13};
+ if( nArg>ArraySize(aExplainWidth) ){
+ nArg = ArraySize(aExplainWidth);
}
if( p->cnt++==0 ){
for(i=0; inullValue);
- if( wactualWidth) ){
- p->actualWidth[i] = w;
- }
- if( showHdr ){
- utf8_width_print(p->out, w, azCol[i]);
- utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : " ");
- }
+ int w = aExplainWidth[i];
+ utf8_width_print(p->out, w, azCol[i]);
+ fputs(i==nArg-1 ? "\n" : " ", p->out);
}
- if( showHdr ){
- for(i=0; iactualWidth) ){
- w = p->actualWidth[i];
- if( w<0 ) w = -w;
- }else{
- w = 10;
- }
- utf8_printf(p->out,"%-*.*s%s",w,w,
- "----------------------------------------------------------"
- "----------------------------------------------------------",
- i==nArg-1 ? rowSep : " ");
- }
+ for(i=0; iout, w);
+ fputs(i==nArg-1 ? "\n" : " ", p->out);
}
}
if( azArg==0 ) break;
for(i=0; iactualWidth) ){
- w = p->actualWidth[i];
- }else{
- w = 10;
- }
- if( p->cMode==MODE_Explain && azArg[i] && strlenChar(azArg[i])>w ){
+ int w = aExplainWidth[i];
+ if( azArg[i] && strlenChar(azArg[i])>w ){
w = strlenChar(azArg[i]);
}
if( i==1 && p->aiIndent && p->pStmt ){
@@ -1998,7 +2037,7 @@ static int shell_callback(
p->iIndent++;
}
utf8_width_print(p->out, w, azArg[i] ? azArg[i] : p->nullValue);
- utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : " ");
+ fputs(i==nArg-1 ? "\n" : " ", p->out);
}
break;
}
@@ -2202,18 +2241,60 @@ static int shell_callback(
raw_printf(p->out,");\n");
break;
}
+ case MODE_Json: {
+ if( azArg==0 ) break;
+ if( p->cnt==0 ){
+ fputs("[{", p->out);
+ }else{
+ fputs(",\n{", p->out);
+ }
+ p->cnt++;
+ for(i=0; iout, azCol[i], -1);
+ putc(':', p->out);
+ if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
+ fputs("null",p->out);
+ }else if( aiType && aiType[i]==SQLITE_FLOAT ){
+ char z[50];
+ double r = sqlite3_column_double(p->pStmt, i);
+ sqlite3_uint64 ur;
+ memcpy(&ur,&r,sizeof(r));
+ if( ur==0x7ff0000000000000LL ){
+ raw_printf(p->out, "1e999");
+ }else if( ur==0xfff0000000000000LL ){
+ raw_printf(p->out, "-1e999");
+ }else{
+ sqlite3_snprintf(50,z,"%!.20g", r);
+ raw_printf(p->out, "%s", z);
+ }
+ }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
+ const void *pBlob = sqlite3_column_blob(p->pStmt, i);
+ int nBlob = sqlite3_column_bytes(p->pStmt, i);
+ output_json_string(p->out, pBlob, nBlob);
+ }else if( aiType && aiType[i]==SQLITE_TEXT ){
+ output_json_string(p->out, azArg[i], -1);
+ }else{
+ utf8_printf(p->out,"%s", azArg[i]);
+ }
+ if( iout);
+ }
+ }
+ putc('}', p->out);
+ break;
+ }
case MODE_Quote: {
if( azArg==0 ) break;
if( p->cnt==0 && p->showHeader ){
for(i=0; i0 ) raw_printf(p->out, ",");
+ if( i>0 ) fputs(p->colSeparator, p->out);
output_quoted_string(p->out, azCol[i]);
}
- raw_printf(p->out,"\n");
+ fputs(p->rowSeparator, p->out);
}
p->cnt++;
for(i=0; i0 ) raw_printf(p->out, ",");
+ if( i>0 ) fputs(p->colSeparator, p->out);
if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
utf8_printf(p->out,"NULL");
}else if( aiType && aiType[i]==SQLITE_TEXT ){
@@ -2235,7 +2316,7 @@ static int shell_callback(
output_quoted_string(p->out, azArg[i]);
}
}
- raw_printf(p->out,"\n");
+ fputs(p->rowSeparator, p->out);
break;
}
case MODE_Ascii: {
@@ -2308,16 +2389,16 @@ static void createSelftestTable(ShellState *p){
"INSERT INTO [_shell$self]\n"
" SELECT 'run',\n"
" 'SELECT hex(sha3_query(''SELECT type,name,tbl_name,sql "
- "FROM sqlite_master ORDER BY 2'',224))',\n"
+ "FROM sqlite_schema ORDER BY 2'',224))',\n"
" hex(sha3_query('SELECT type,name,tbl_name,sql "
- "FROM sqlite_master ORDER BY 2',224));\n"
+ "FROM sqlite_schema ORDER BY 2',224));\n"
"INSERT INTO [_shell$self]\n"
" SELECT 'run',"
" 'SELECT hex(sha3_query(''SELECT * FROM \"' ||"
" printf('%w',name) || '\" NOT INDEXED'',224))',\n"
" hex(sha3_query(printf('SELECT * FROM \"%w\" NOT INDEXED',name),224))\n"
" FROM (\n"
- " SELECT name FROM sqlite_master\n"
+ " SELECT name FROM sqlite_schema\n"
" WHERE type='table'\n"
" AND name<>'selftest'\n"
" AND coalesce(rootpage,0)>0\n"
@@ -2801,7 +2882,7 @@ static void explain_data_delete(ShellState *p){
** Disable and restore .wheretrace and .selecttrace settings.
*/
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
-extern int sqlite3SelectTrace;
+extern unsigned int sqlite3_unsupported_selecttrace;
static int savedSelectTrace;
#endif
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
@@ -2810,8 +2891,8 @@ static int savedWhereTrace;
#endif
static void disable_debug_trace_modes(void){
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
- savedSelectTrace = sqlite3SelectTrace;
- sqlite3SelectTrace = 0;
+ savedSelectTrace = sqlite3_unsupported_selecttrace;
+ sqlite3_unsupported_selecttrace = 0;
#endif
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
savedWhereTrace = sqlite3WhereTrace;
@@ -2820,7 +2901,7 @@ static void disable_debug_trace_modes(void){
}
static void restore_debug_trace_modes(void){
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
- sqlite3SelectTrace = savedSelectTrace;
+ sqlite3_unsupported_selecttrace = savedSelectTrace;
#endif
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
sqlite3WhereTrace = savedWhereTrace;
@@ -2891,6 +2972,232 @@ static void bind_prepared_stmt(ShellState *pArg, sqlite3_stmt *pStmt){
sqlite3_finalize(pQ);
}
+/*
+** UTF8 box-drawing characters. Imagine box lines like this:
+**
+** 1
+** |
+** 4 --+-- 2
+** |
+** 3
+**
+** Each box characters has between 2 and 4 of the lines leading from
+** the center. The characters are here identified by the numbers of
+** their corresponding lines.
+*/
+#define BOX_24 "\342\224\200" /* U+2500 --- */
+#define BOX_13 "\342\224\202" /* U+2502 | */
+#define BOX_23 "\342\224\214" /* U+250c ,- */
+#define BOX_34 "\342\224\220" /* U+2510 -, */
+#define BOX_12 "\342\224\224" /* U+2514 '- */
+#define BOX_14 "\342\224\230" /* U+2518 -' */
+#define BOX_123 "\342\224\234" /* U+251c |- */
+#define BOX_134 "\342\224\244" /* U+2524 -| */
+#define BOX_234 "\342\224\254" /* U+252c -,- */
+#define BOX_124 "\342\224\264" /* U+2534 -'- */
+#define BOX_1234 "\342\224\274" /* U+253c -|- */
+
+/* Draw horizontal line N characters long using unicode box
+** characters
+*/
+static void print_box_line(FILE *out, int N){
+ const char zDash[] =
+ BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24
+ BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24;
+ const int nDash = sizeof(zDash) - 1;
+ N *= 3;
+ while( N>nDash ){
+ utf8_printf(out, zDash);
+ N -= nDash;
+ }
+ utf8_printf(out, "%.*s", N, zDash);
+}
+
+/*
+** Draw a horizontal separator for a MODE_Box table.
+*/
+static void print_box_row_separator(
+ ShellState *p,
+ int nArg,
+ const char *zSep1,
+ const char *zSep2,
+ const char *zSep3
+){
+ int i;
+ if( nArg>0 ){
+ utf8_printf(p->out, "%s", zSep1);
+ print_box_line(p->out, p->actualWidth[0]+2);
+ for(i=1; iout, "%s", zSep2);
+ print_box_line(p->out, p->actualWidth[i]+2);
+ }
+ utf8_printf(p->out, "%s", zSep3);
+ }
+ fputs("\n", p->out);
+}
+
+
+
+/*
+** Run a prepared statement and output the result in one of the
+** table-oriented formats: MODE_Column, MODE_Markdown, MODE_Table,
+** or MODE_Box.
+**
+** This is different from ordinary exec_prepared_stmt() in that
+** it has to run the entire query and gather the results into memory
+** first, in order to determine column widths, before providing
+** any output.
+*/
+static void exec_prepared_stmt_columnar(
+ ShellState *p, /* Pointer to ShellState */
+ sqlite3_stmt *pStmt /* Statment to run */
+){
+ sqlite3_int64 nRow = 0;
+ int nColumn = 0;
+ char **azData = 0;
+ sqlite3_int64 nAlloc = 0;
+ const char *z;
+ int rc;
+ sqlite3_int64 i, nData;
+ int j, nTotal, w, n;
+ const char *colSep = 0;
+ const char *rowSep = 0;
+
+ rc = sqlite3_step(pStmt);
+ if( rc!=SQLITE_ROW ) return;
+ nColumn = sqlite3_column_count(pStmt);
+ nAlloc = nColumn*4;
+ azData = sqlite3_malloc64( nAlloc*sizeof(char*) );
+ if( azData==0 ) shell_out_of_memory();
+ for(i=0; i= nAlloc ){
+ nAlloc *= 2;
+ azData = sqlite3_realloc64(azData, nAlloc*sizeof(char*));
+ if( azData==0 ) shell_out_of_memory();
+ }
+ nRow++;
+ for(i=0; ip->nWidth ){
+ p->colWidth = realloc(p->colWidth, nColumn*2*sizeof(int));
+ if( p->colWidth==0 ) shell_out_of_memory();
+ for(i=p->nWidth; icolWidth[i] = 0;
+ p->nWidth = nColumn;
+ p->actualWidth = &p->colWidth[nColumn];
+ }
+ memset(p->actualWidth, 0, nColumn*sizeof(int));
+ for(i=0; icolWidth[i];
+ if( w<0 ) w = -w;
+ p->actualWidth[i] = w;
+ }
+ nTotal = nColumn*(nRow+1);
+ for(i=0; inullValue;
+ n = strlenChar(z);
+ j = i%nColumn;
+ if( n>p->actualWidth[j] ) p->actualWidth[j] = n;
+ }
+ if( seenInterrupt ) goto columnar_end;
+ switch( p->cMode ){
+ case MODE_Column: {
+ colSep = " ";
+ rowSep = "\n";
+ if( p->showHeader ){
+ for(i=0; iactualWidth[i];
+ if( p->colWidth[i]<0 ) w = -w;
+ utf8_width_print(p->out, w, azData[i]);
+ fputs(i==nColumn-1?"\n":" ", p->out);
+ }
+ for(i=0; iout, p->actualWidth[i]);
+ fputs(i==nColumn-1?"\n":" ", p->out);
+ }
+ }
+ break;
+ }
+ case MODE_Table: {
+ colSep = " | ";
+ rowSep = " |\n";
+ print_row_separator(p, nColumn, "+");
+ fputs("| ", p->out);
+ for(i=0; iactualWidth[i];
+ n = strlenChar(azData[i]);
+ utf8_printf(p->out, "%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, "");
+ fputs(i==nColumn-1?" |\n":" | ", p->out);
+ }
+ print_row_separator(p, nColumn, "+");
+ break;
+ }
+ case MODE_Markdown: {
+ colSep = " | ";
+ rowSep = " |\n";
+ fputs("| ", p->out);
+ for(i=0; iactualWidth[i];
+ n = strlenChar(azData[i]);
+ utf8_printf(p->out, "%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, "");
+ fputs(i==nColumn-1?" |\n":" | ", p->out);
+ }
+ print_row_separator(p, nColumn, "|");
+ break;
+ }
+ case MODE_Box: {
+ colSep = " " BOX_13 " ";
+ rowSep = " " BOX_13 "\n";
+ print_box_row_separator(p, nColumn, BOX_23, BOX_234, BOX_34);
+ utf8_printf(p->out, BOX_13 " ");
+ for(i=0; iactualWidth[i];
+ n = strlenChar(azData[i]);
+ utf8_printf(p->out, "%*s%s%*s%s",
+ (w-n)/2, "", azData[i], (w-n+1)/2, "",
+ i==nColumn-1?" "BOX_13"\n":" "BOX_13" ");
+ }
+ print_box_row_separator(p, nColumn, BOX_123, BOX_1234, BOX_134);
+ break;
+ }
+ }
+ for(i=nColumn, j=0; icMode!=MODE_Column ){
+ utf8_printf(p->out, "%s", p->cMode==MODE_Box?BOX_13" ":"| ");
+ }
+ z = azData[i];
+ if( z==0 ) z = p->nullValue;
+ w = p->actualWidth[j];
+ if( p->colWidth[j]<0 ) w = -w;
+ utf8_width_print(p->out, w, z);
+ if( j==nColumn-1 ){
+ utf8_printf(p->out, "%s", rowSep);
+ j = -1;
+ if( seenInterrupt ) goto columnar_end;
+ }else{
+ utf8_printf(p->out, "%s", colSep);
+ }
+ }
+ if( p->cMode==MODE_Table ){
+ print_row_separator(p, nColumn, "+");
+ }else if( p->cMode==MODE_Box ){
+ print_box_row_separator(p, nColumn, BOX_12, BOX_124, BOX_14);
+ }
+columnar_end:
+ if( seenInterrupt ){
+ utf8_printf(p->out, "Interrupt\n");
+ }
+ nData = (nRow+1)*nColumn;
+ for(i=0; icMode==MODE_Column
+ || pArg->cMode==MODE_Table
+ || pArg->cMode==MODE_Box
+ || pArg->cMode==MODE_Markdown
+ ){
+ exec_prepared_stmt_columnar(pArg, pStmt);
+ return;
+ }
+
/* perform the first step. this will tell us if we
** have a result set or not and how wide it is.
*/
@@ -2947,6 +3263,9 @@ static void exec_prepared_stmt(
}
} while( SQLITE_ROW == rc );
sqlite3_free(pData);
+ if( pArg->cMode==MODE_Json ){
+ fputs("]\n", pArg->out);
+ }
}
}
}
@@ -3397,7 +3716,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
if( strcmp(zTable, "sqlite_sequence")==0 ){
raw_printf(p->out, "DELETE FROM sqlite_sequence;\n");
}else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){
- raw_printf(p->out, "ANALYZE sqlite_master;\n");
+ raw_printf(p->out, "ANALYZE sqlite_schema;\n");
}else if( strncmp(zTable, "sqlite_", 7)==0 ){
return 0;
}else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
@@ -3407,7 +3726,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
p->writableSchema = 1;
}
zIns = sqlite3_mprintf(
- "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
+ "INSERT INTO sqlite_schema(type,name,tbl_name,rootpage,sql)"
"VALUES('table','%q','%q',0,'%q');",
zTable, zTable, zSql);
utf8_printf(p->out, "%s\n", zIns);
@@ -3627,16 +3946,20 @@ static const char *(azHelp[]) = {
".log FILE|off Turn logging on or off. FILE can be stderr/stdout",
".mode MODE ?TABLE? Set output mode",
" MODE is one of:",
- " ascii Columns/rows delimited by 0x1F and 0x1E",
- " csv Comma-separated values",
- " column Left-aligned columns. (See .width)",
- " html HTML
code",
- " insert SQL insert statements for TABLE",
- " line One value per line",
- " list Values delimited by \"|\"",
- " quote Escape answers as for SQL",
- " tabs Tab-separated values",
- " tcl TCL list elements",
+ " ascii Columns/rows delimited by 0x1F and 0x1E",
+ " box Tables using unicode box-drawing characters",
+ " csv Comma-separated values",
+ " column Output in columns. (See .width)",
+ " html HTML code",
+ " insert SQL insert statements for TABLE",
+ " json Results in a JSON array",
+ " line One value per line",
+ " list Values delimited by \"|\"",
+ " markdown Markdown table format",
+ " quote Escape answers as for SQL",
+ " table ASCII-art table",
+ " tabs Tab-separated values",
+ " tcl TCL list elements",
".nullvalue STRING Use STRING in place of NULL values",
".once ?OPTIONS? ?FILE? Output for the next SQL command only to FILE",
" If FILE begins with '|' then open as a pipe",
@@ -3644,7 +3967,7 @@ static const char *(azHelp[]) = {
" -e Send output to the system text editor",
" -x Send output as CSV to a spreadsheet (same as \".excel\")",
#ifdef SQLITE_DEBUG
- ".oom [--repeat M] [N] Simulate an OOM error on the N-th allocation",
+ ".oom ?--repeat M? ?N? Simulate an OOM error on the N-th allocation",
#endif
".open ?OPTIONS? ?FILE? Close existing database and reopen FILE",
" Options:",
@@ -3718,7 +4041,7 @@ static const char *(azHelp[]) = {
#endif
".sha3sum ... Compute a SHA3 hash of database content",
" Options:",
- " --schema Also hash the sqlite_master table",
+ " --schema Also hash the sqlite_schema table",
" --sha3-224 Use the sha3-224 algorithm",
" --sha3-256 Use the sha3-256 algorithm (default)",
" --sha3-384 Use the sha3-384 algorithm",
@@ -3767,7 +4090,7 @@ static const char *(azHelp[]) = {
".vfsinfo ?AUX? Information about the top-level VFS",
".vfslist List all available VFSes",
".vfsname ?AUX? Print the name of the VFS stack",
- ".width NUM1 NUM2 ... Set column widths for \"column\" mode",
+ ".width NUM1 NUM2 ... Set minimum column widths for columnar output",
" Negative values right-justify",
};
@@ -4277,6 +4600,8 @@ static void open_db(ShellState *p, int openFlags){
sqlite3_shathree_init(p->db, 0, 0);
sqlite3_completion_init(p->db, 0, 0);
sqlite3_uint_init(p->db, 0, 0);
+ sqlite3_decimal_init(p->db, 0, 0);
+ sqlite3_ieee_init(p->db, 0, 0);
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
sqlite3_dbdata_init(p->db, 0, 0);
#endif
@@ -4609,6 +4934,7 @@ typedef struct ImportCtx ImportCtx;
struct ImportCtx {
const char *zFile; /* Name of the input file */
FILE *in; /* Read the CSV text from this input stream */
+ int (SQLITE_CDECL *xCloser)(FILE*); /* Func to close in */
char *z; /* Accumulated text for a field */
int n; /* Number of bytes in z */
int nAlloc; /* Space allocated for z[] */
@@ -4621,6 +4947,16 @@ struct ImportCtx {
int cRowSep; /* The row separator character. (Usually "\n") */
};
+/* Clean up resourced used by an ImportCtx */
+static void import_cleanup(ImportCtx *p){
+ if( p->in!=0 && p->xCloser!=0 ){
+ p->xCloser(p->in);
+ p->in = 0;
+ }
+ sqlite3_free(p->z);
+ p->z = 0;
+}
+
/* Append a single byte to z[] */
static void import_append_char(ImportCtx *p, int c){
if( p->n+1>=p->nAlloc ){
@@ -4869,7 +5205,7 @@ end_data_xfer:
** Try to transfer all rows of the schema that match zWhere. For
** each row, invoke xForEach() on the object defined by that row.
** If an error is encountered while moving forward through the
-** sqlite_master table, try again moving backwards.
+** sqlite_schema table, try again moving backwards.
*/
static void tryToCloneSchema(
ShellState *p,
@@ -4884,7 +5220,7 @@ static void tryToCloneSchema(
const unsigned char *zSql;
char *zErrMsg = 0;
- zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
+ zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema"
" WHERE %s", zWhere);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
@@ -4911,7 +5247,7 @@ static void tryToCloneSchema(
if( rc!=SQLITE_DONE ){
sqlite3_finalize(pQuery);
sqlite3_free(zQuery);
- zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
+ zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema"
" WHERE %s ORDER BY rowid DESC", zWhere);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
@@ -5115,11 +5451,11 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
raw_printf(p->out, "\n");
}
if( zDb==0 ){
- zSchemaTab = sqlite3_mprintf("main.sqlite_master");
+ zSchemaTab = sqlite3_mprintf("main.sqlite_schema");
}else if( strcmp(zDb,"temp")==0 ){
- zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_master");
+ zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_schema");
}else{
- zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", zDb);
+ zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_schema", zDb);
}
for(i=0; iout, "%s;\n", zPrint);
@@ -7573,6 +7909,7 @@ static int do_meta_command(char *zLine, ShellState *p){
raw_printf(stderr, "The --preserve-rowids option is not compatible"
" with SQLITE_OMIT_VIRTUALTABLE\n");
rc = 1;
+ sqlite3_free(zLike);
goto meta_command_exit;
#else
ShellSetFlag(p, SHFLG_PreserveRowid);
@@ -7584,6 +7921,7 @@ static int do_meta_command(char *zLine, ShellState *p){
{
raw_printf(stderr, "Unknown option \"%s\" on \".dump\"\n", azArg[i]);
rc = 1;
+ sqlite3_free(zLike);
goto meta_command_exit;
}
}else if( zLike ){
@@ -7604,13 +7942,13 @@ static int do_meta_command(char *zLine, ShellState *p){
p->writableSchema = 0;
p->showHeader = 0;
/* Set writable_schema=ON since doing so forces SQLite to initialize
- ** as much of the schema as it can even if the sqlite_master table is
+ ** as much of the schema as it can even if the sqlite_schema table is
** corrupt. */
sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
p->nErr = 0;
if( zLike==0 ) zLike = sqlite3_mprintf("true");
zSql = sqlite3_mprintf(
- "SELECT name, type, sql FROM sqlite_master "
+ "SELECT name, type, sql FROM sqlite_schema "
"WHERE (%s) AND type=='table'"
" AND sql NOT NULL"
" ORDER BY tbl_name='sqlite_sequence', rowid",
@@ -7619,7 +7957,7 @@ static int do_meta_command(char *zLine, ShellState *p){
run_schema_dump_query(p,zSql);
sqlite3_free(zSql);
zSql = sqlite3_mprintf(
- "SELECT sql FROM sqlite_master "
+ "SELECT sql FROM sqlite_schema "
"WHERE (%s) AND sql NOT NULL"
" AND type IN ('index','trigger','view')",
zLike
@@ -7666,7 +8004,7 @@ static int do_meta_command(char *zLine, ShellState *p){
p->autoEQP = AUTOEQP_full;
p->autoEQPtrace = 1;
open_db(p, 0);
- sqlite3_exec(p->db, "SELECT name FROM sqlite_master LIMIT 1", 0, 0, 0);
+ sqlite3_exec(p->db, "SELECT name FROM sqlite_schema LIMIT 1", 0, 0, 0);
sqlite3_exec(p->db, "PRAGMA vdbe_trace=ON;", 0, 0, 0);
#endif
}else{
@@ -7879,8 +8217,8 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = sqlite3_exec(p->db,
"SELECT sql FROM"
" (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
- " FROM sqlite_master UNION ALL"
- " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
+ " FROM sqlite_schema UNION ALL"
+ " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_schema) "
"WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' "
"ORDER BY rowid",
callback, &data, &zErrMsg
@@ -7888,7 +8226,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( rc==SQLITE_OK ){
sqlite3_stmt *pStmt;
rc = sqlite3_prepare_v2(p->db,
- "SELECT rowid FROM sqlite_master"
+ "SELECT rowid FROM sqlite_schema"
" WHERE name GLOB 'sqlite_stat[134]'",
-1, &pStmt, 0);
doStats = sqlite3_step(pStmt)==SQLITE_ROW;
@@ -7897,21 +8235,22 @@ static int do_meta_command(char *zLine, ShellState *p){
if( doStats==0 ){
raw_printf(p->out, "/* No STAT tables available */\n");
}else{
- raw_printf(p->out, "ANALYZE sqlite_master;\n");
- sqlite3_exec(p->db, "SELECT 'ANALYZE sqlite_master'",
+ raw_printf(p->out, "ANALYZE sqlite_schema;\n");
+ sqlite3_exec(p->db, "SELECT 'ANALYZE sqlite_schema'",
callback, &data, &zErrMsg);
data.cMode = data.mode = MODE_Insert;
data.zDestTable = "sqlite_stat1";
shell_exec(&data, "SELECT * FROM sqlite_stat1", &zErrMsg);
data.zDestTable = "sqlite_stat4";
shell_exec(&data, "SELECT * FROM sqlite_stat4", &zErrMsg);
- raw_printf(p->out, "ANALYZE sqlite_master;\n");
+ raw_printf(p->out, "ANALYZE sqlite_schema;\n");
}
}else
if( c=='h' && strncmp(azArg[0], "headers", n)==0 ){
if( nArg==2 ){
p->showHeader = booleanValue(azArg[1]);
+ p->shellFlgs |= SHFLG_HeaderSet;
}else{
raw_printf(stderr, "Usage: .headers on|off\n");
rc = 1;
@@ -7941,7 +8280,6 @@ static int do_meta_command(char *zLine, ShellState *p){
char *zSql; /* An SQL statement */
ImportCtx sCtx; /* Reader context */
char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
- int (SQLITE_CDECL *xCloser)(FILE*); /* Func to close file */
int eVerbose = 0; /* Larger for more console output */
int nSkip = 0; /* Initial lines to skip */
int useOutputMode = 1; /* Use output mode to determine separators */
@@ -8047,11 +8385,11 @@ static int do_meta_command(char *zLine, ShellState *p){
#else
sCtx.in = popen(sCtx.zFile+1, "r");
sCtx.zFile = "";
- xCloser = pclose;
+ sCtx.xCloser = pclose;
#endif
}else{
sCtx.in = fopen(sCtx.zFile, "rb");
- xCloser = fclose;
+ sCtx.xCloser = fclose;
}
if( sCtx.in==0 ){
utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
@@ -8071,11 +8409,10 @@ static int do_meta_command(char *zLine, ShellState *p){
}
while( (nSkip--)>0 ){
while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
- sCtx.nLine++;
}
zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
if( zSql==0 ){
- xCloser(sCtx.in);
+ import_cleanup(&sCtx);
shell_out_of_memory();
}
nByte = strlen30(zSql);
@@ -8091,8 +8428,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
if( cSep=='(' ){
sqlite3_free(zCreate);
- sqlite3_free(sCtx.z);
- xCloser(sCtx.in);
+ import_cleanup(&sCtx);
utf8_printf(stderr,"%s: empty file\n", sCtx.zFile);
rc = 1;
goto meta_command_exit;
@@ -8106,8 +8442,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( rc ){
utf8_printf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
sqlite3_errmsg(p->db));
- sqlite3_free(sCtx.z);
- xCloser(sCtx.in);
+ import_cleanup(&sCtx);
rc = 1;
goto meta_command_exit;
}
@@ -8117,7 +8452,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( rc ){
if (pStmt) sqlite3_finalize(pStmt);
utf8_printf(stderr,"Error: %s\n", sqlite3_errmsg(p->db));
- xCloser(sCtx.in);
+ import_cleanup(&sCtx);
rc = 1;
goto meta_command_exit;
}
@@ -8127,7 +8462,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( nCol==0 ) return 0; /* no columns, no error */
zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 );
if( zSql==0 ){
- xCloser(sCtx.in);
+ import_cleanup(&sCtx);
shell_out_of_memory();
}
sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
@@ -8146,7 +8481,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( rc ){
utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
if (pStmt) sqlite3_finalize(pStmt);
- xCloser(sCtx.in);
+ import_cleanup(&sCtx);
rc = 1;
goto meta_command_exit;
}
@@ -8198,8 +8533,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}while( sCtx.cTerm!=EOF );
- xCloser(sCtx.in);
- sqlite3_free(sCtx.z);
+ import_cleanup(&sCtx);
sqlite3_finalize(pStmt);
if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
if( eVerbose>0 ){
@@ -8237,10 +8571,10 @@ static int do_meta_command(char *zLine, ShellState *p){
goto meta_command_exit;
}
zSql = sqlite3_mprintf(
- "SELECT rootpage, 0 FROM sqlite_master"
+ "SELECT rootpage, 0 FROM sqlite_schema"
" WHERE name='%q' AND type='index'"
"UNION ALL "
- "SELECT rootpage, 1 FROM sqlite_master"
+ "SELECT rootpage, 1 FROM sqlite_schema"
" WHERE name='%q' AND type='table'"
" AND sql LIKE '%%without%%rowid%%'",
azArg[1], azArg[1]
@@ -8438,6 +8772,9 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
}else if( c2=='c' && strncmp(azArg[1],"columns",n2)==0 ){
p->mode = MODE_Column;
+ if( (p->shellFlgs & SHFLG_HeaderSet)==0 ){
+ p->showHeader = 1;
+ }
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
}else if( c2=='l' && n2>2 && strncmp(azArg[1],"list",n2)==0 ){
p->mode = MODE_List;
@@ -8461,15 +8798,26 @@ static int do_meta_command(char *zLine, ShellState *p){
set_table_name(p, nArg>=3 ? azArg[2] : "table");
}else if( c2=='q' && strncmp(azArg[1],"quote",n2)==0 ){
p->mode = MODE_Quote;
+ sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
}else if( c2=='a' && strncmp(azArg[1],"ascii",n2)==0 ){
p->mode = MODE_Ascii;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit);
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record);
+ }else if( c2=='m' && strncmp(azArg[1],"markdown",n2)==0 ){
+ p->mode = MODE_Markdown;
+ }else if( c2=='t' && strncmp(azArg[1],"table",n2)==0 ){
+ p->mode = MODE_Table;
+ }else if( c2=='b' && strncmp(azArg[1],"box",n2)==0 ){
+ p->mode = MODE_Box;
+ }else if( c2=='j' && strncmp(azArg[1],"json",n2)==0 ){
+ p->mode = MODE_Json;
}else if( nArg==1 ){
raw_printf(p->out, "current output mode: %s\n", modeDescr[p->mode]);
}else{
raw_printf(stderr, "Error: mode should be one of: "
- "ascii column csv html insert line list quote tabs tcl\n");
+ "ascii box column csv html insert json line list markdown "
+ "quote table tabs tcl\n");
rc = 1;
}
p->cMode = p->mode;
@@ -8859,8 +9207,9 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = 1;
goto meta_command_exit;
}
- p->in = fopen(azArg[1], "rb");
- if( p->in==0 ){
+ if( notNormalFile(azArg[1])
+ || (p->in = fopen(azArg[1], "rb"))==0
+ ){
utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
rc = 1;
}else{
@@ -8963,8 +9312,11 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}
if( zName!=0 ){
- int isMaster = sqlite3_strlike(zName, "sqlite_master", '\\')==0;
- if( isMaster || sqlite3_strlike(zName,"sqlite_temp_master", '\\')==0 ){
+ int isSchema = sqlite3_strlike(zName, "sqlite_master", '\\')==0
+ || sqlite3_strlike(zName, "sqlite_schema", '\\')==0
+ || sqlite3_strlike(zName,"sqlite_temp_master", '\\')==0
+ || sqlite3_strlike(zName,"sqlite_temp_schema", '\\')==0;
+ if( isSchema ){
char *new_argv[2], *new_colv[2];
new_argv[0] = sqlite3_mprintf(
"CREATE TABLE %s (\n"
@@ -8973,7 +9325,7 @@ static int do_meta_command(char *zLine, ShellState *p){
" tbl_name text,\n"
" rootpage integer,\n"
" sql text\n"
- ")", isMaster ? "sqlite_master" : "sqlite_temp_master");
+ ")", zName);
new_argv[1] = 0;
new_colv[0] = "sql";
new_colv[1] = 0;
@@ -9011,7 +9363,7 @@ static int do_meta_command(char *zLine, ShellState *p){
appendText(&sSelect, zDb, '\'');
appendText(&sSelect, " AS sname FROM ", 0);
appendText(&sSelect, zDb, quoteChar(zDb));
- appendText(&sSelect, ".sqlite_master", 0);
+ appendText(&sSelect, ".sqlite_schema", 0);
}
sqlite3_finalize(pStmt);
#ifndef SQLITE_OMIT_INTROSPECTION_PRAGMAS
@@ -9063,7 +9415,7 @@ static int do_meta_command(char *zLine, ShellState *p){
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
- sqlite3SelectTrace = (int)integerValue(azArg[1]);
+ sqlite3_unsupported_selecttrace = nArg>=2 ? (int)integerValue(azArg[1]) : 0xffff;
}else
#endif
@@ -9455,12 +9807,12 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}
if( bSchema ){
- zSql = "SELECT lower(name) FROM sqlite_master"
+ zSql = "SELECT lower(name) FROM sqlite_schema"
" WHERE type='table' AND coalesce(rootpage,0)>1"
- " UNION ALL SELECT 'sqlite_master'"
+ " UNION ALL SELECT 'sqlite_schema'"
" ORDER BY 1 collate nocase";
}else{
- zSql = "SELECT lower(name) FROM sqlite_master"
+ zSql = "SELECT lower(name) FROM sqlite_schema"
" WHERE type='table' AND coalesce(rootpage,0)>1"
" AND name NOT LIKE 'sqlite_%'"
" ORDER BY 1 collate nocase";
@@ -9477,8 +9829,8 @@ static int do_meta_command(char *zLine, ShellState *p){
appendText(&sQuery,"SELECT * FROM ", 0);
appendText(&sQuery,zTab,'"');
appendText(&sQuery," NOT INDEXED;", 0);
- }else if( strcmp(zTab, "sqlite_master")==0 ){
- appendText(&sQuery,"SELECT type,name,tbl_name,sql FROM sqlite_master"
+ }else if( strcmp(zTab, "sqlite_schema")==0 ){
+ appendText(&sQuery,"SELECT type,name,tbl_name,sql FROM sqlite_schema"
" ORDER BY name;", 0);
}else if( strcmp(zTab, "sqlite_sequence")==0 ){
appendText(&sQuery,"SELECT name,seq FROM sqlite_sequence"
@@ -9579,7 +9931,7 @@ static int do_meta_command(char *zLine, ShellState *p){
raw_printf(p->out, "\n");
utf8_printf(p->out, "%12.12s: %s\n","stats", azBool[p->statsOn!=0]);
utf8_printf(p->out, "%12.12s: ", "width");
- for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
+ for (i=0;inWidth;i++) {
raw_printf(p->out, "%d ", p->colWidth[i]);
}
raw_printf(p->out, "\n");
@@ -9636,7 +9988,7 @@ static int do_meta_command(char *zLine, ShellState *p){
appendText(&s, "||'.'||name FROM ", 0);
}
appendText(&s, zDbName, '"');
- appendText(&s, ".sqlite_master ", 0);
+ appendText(&s, ".sqlite_schema ", 0);
if( c=='t' ){
appendText(&s," WHERE type IN ('table','view')"
" AND name NOT LIKE 'sqlite_%'"
@@ -10128,7 +10480,11 @@ static int do_meta_command(char *zLine, ShellState *p){
if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
int j;
assert( nArg<=ArraySize(azArg) );
- for(j=1; jcolWidth); j++){
+ p->nWidth = nArg-1;
+ p->colWidth = realloc(p->colWidth, p->nWidth*sizeof(int)*2);
+ if( p->colWidth==0 && p->nWidth>0 ) shell_out_of_memory();
+ if( p->nWidth ) p->actualWidth = &p->colWidth[p->nWidth];
+ for(j=1; jcolWidth[j-1] = (int)integerValue(azArg[j]);
}
}else
@@ -10473,6 +10829,7 @@ static const char zOptions[] =
" -ascii set output mode to 'ascii'\n"
" -bail stop after hitting an error\n"
" -batch force batch I/O\n"
+ " -box set output mode to 'box'\n"
" -column set output mode to 'column'\n"
" -cmd COMMAND run \"COMMAND\" before reading stdin\n"
" -csv set output mode to 'csv'\n"
@@ -10488,9 +10845,11 @@ static const char zOptions[] =
" -help show this message\n"
" -html set output mode to HTML\n"
" -interactive force interactive I/O\n"
+ " -json set output mode to 'json'\n"
" -line set output mode to 'line'\n"
" -list set output mode to 'list'\n"
" -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n"
+ " -markdown set output mode to 'markdown'\n"
#if defined(SQLITE_ENABLE_DESERIALIZE)
" -maxsize N maximum size for a --deserialize database\n"
#endif
@@ -10510,6 +10869,7 @@ static const char zOptions[] =
" -sorterref SIZE sorter references threshold size\n"
#endif
" -stats print memory stats before each finalize\n"
+ " -table set output mode to 'table'\n"
" -version show SQLite version\n"
" -vfs NAME use NAME as the default VFS\n"
#ifdef SQLITE_ENABLE_VFSTRACE
@@ -10913,6 +11273,14 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
data.mode = MODE_Line;
}else if( strcmp(z,"-column")==0 ){
data.mode = MODE_Column;
+ }else if( strcmp(z,"-json")==0 ){
+ data.mode = MODE_Json;
+ }else if( strcmp(z,"-markdown")==0 ){
+ data.mode = MODE_Markdown;
+ }else if( strcmp(z,"-table")==0 ){
+ data.mode = MODE_Table;
+ }else if( strcmp(z,"-box")==0 ){
+ data.mode = MODE_Box;
}else if( strcmp(z,"-csv")==0 ){
data.mode = MODE_Csv;
memcpy(data.colSeparator,",",2);
@@ -11132,6 +11500,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
for(i=0; i [SQLITE_OPEN_TEMP_JOURNAL]
** - [SQLITE_OPEN_TRANSIENT_DB]
**
- [SQLITE_OPEN_SUBJOURNAL]
-**
- [SQLITE_OPEN_MASTER_JOURNAL]
+**
- [SQLITE_OPEN_SUPER_JOURNAL]
**
- [SQLITE_OPEN_WAL]
** )^
**
@@ -1647,7 +1649,7 @@ int sqlite3_db_config(sqlite3*, int op, ...);
** by xInit. The pAppData pointer is used as the only parameter to
** xInit and xShutdown.
**
-** SQLite holds the [SQLITE_MUTEX_STATIC_MASTER] mutex when it invokes
+** SQLite holds the [SQLITE_MUTEX_STATIC_MAIN] mutex when it invokes
** the xInit method, so the xInit method need not be threadsafe. The
** xShutdown method is only called from [sqlite3_shutdown()] so it does
** not need to be threadsafe either. For all other methods, SQLite
@@ -2285,8 +2287,7 @@ struct sqlite3_mem_methods {
** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]]
**
- SQLITE_DBCONFIG_TRUSTED_SCHEMA
**
- The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to
-** assume that database schemas (the contents of the [sqlite_master] tables)
-** are untainted by malicious content.
+** assume that database schemas are untainted by malicious content.
** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite
** takes additional defensive steps to protect the application from harm
** including:
@@ -6276,7 +6277,7 @@ void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
** ^In the case of an update, this is the [rowid] after the update takes place.
**
** ^(The update hook is not invoked when internal system tables are
-** modified (i.e. sqlite_master and sqlite_sequence).)^
+** modified (i.e. sqlite_sequence).)^
** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified.
**
** ^In the current implementation, the update hook
@@ -7378,7 +7379,7 @@ int sqlite3_vfs_unregister(sqlite3_vfs*);
**
** - SQLITE_MUTEX_FAST
**
- SQLITE_MUTEX_RECURSIVE
-**
- SQLITE_MUTEX_STATIC_MASTER
+**
- SQLITE_MUTEX_STATIC_MAIN
**
- SQLITE_MUTEX_STATIC_MEM
**
- SQLITE_MUTEX_STATIC_OPEN
**
- SQLITE_MUTEX_STATIC_PRNG
@@ -7580,7 +7581,7 @@ int sqlite3_mutex_notheld(sqlite3_mutex*);
*/
#define SQLITE_MUTEX_FAST 0
#define SQLITE_MUTEX_RECURSIVE 1
-#define SQLITE_MUTEX_STATIC_MASTER 2
+#define SQLITE_MUTEX_STATIC_MAIN 2
#define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */
#define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */
#define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */
@@ -7595,6 +7596,10 @@ int sqlite3_mutex_notheld(sqlite3_mutex*);
#define SQLITE_MUTEX_STATIC_VFS2 12 /* For use by extension VFS */
#define SQLITE_MUTEX_STATIC_VFS3 13 /* For use by application VFS */
+/* Legacy compatibility: */
+#define SQLITE_MUTEX_STATIC_MASTER 2
+
+
/*
** CAPI3REF: Retrieve the mutex for a database connection
** METHOD: sqlite3
@@ -9390,7 +9395,7 @@ int sqlite3_db_cacheflush(sqlite3*);
**
** ^The preupdate hook only fires for changes to real database tables; the
** preupdate hook is not invoked for changes to [virtual tables] or to
-** system tables like sqlite_master or sqlite_stat1.
+** system tables like sqlite_sequence or sqlite_stat1.
**
** ^The second parameter to the preupdate callback is a pointer to
** the [database connection] that registered the preupdate hook.
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 5726ef4c49..74d0f599e2 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -128,6 +128,15 @@
# define _BSD_SOURCE
#endif
+/*
+** Macro to disable warnings about missing "break" at the end of a "case".
+*/
+#if GCC_VERSION>=7000000
+# define deliberate_fall_through __attribute__((fallthrough));
+#else
+# define deliberate_fall_through
+#endif
+
/*
** For MinGW, check to see if we can include the header file containing its
** version information, among other things. Normally, this internal MinGW
@@ -190,10 +199,10 @@
** WAL mode depends on atomic aligned 32-bit loads and stores in a few
** places. The following macros try to make this explicit.
*/
-#ifndef __has_feature
-# define __has_feature(x) 0 /* compatibility with non-clang compilers */
+#ifndef __has_extension
+# define __has_extension(x) 0 /* compatibility with non-clang compilers */
#endif
-#if GCC_VERSION>=4007000 || __has_feature(c_atomic)
+#if GCC_VERSION>=4007000 || __has_extension(c_atomic)
# define AtomicLoad(PTR) __atomic_load_n((PTR),__ATOMIC_RELAXED)
# define AtomicStore(PTR,VAL) __atomic_store_n((PTR),(VAL),__ATOMIC_RELAXED)
#else
@@ -902,6 +911,7 @@ typedef INT16_TYPE LogEst;
** compilers.
*/
#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
+#define LARGEST_UINT64 (0xffffffff|(((u64)0xffffffff)<<32))
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
/*
@@ -979,6 +989,16 @@ typedef INT16_TYPE LogEst;
#else
# define SELECTTRACE_ENABLED 0
#endif
+#if defined(SQLITE_ENABLE_SELECTTRACE)
+# define SELECTTRACE_ENABLED 1
+# define SELECTTRACE(K,P,S,X) \
+ if(sqlite3_unsupported_selecttrace&(K)) \
+ sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\
+ sqlite3DebugPrintf X
+#else
+# define SELECTTRACE(K,P,S,X)
+# define SELECTTRACE_ENABLED 0
+#endif
/*
** An instance of the following structure is used to store the busy-handler
@@ -997,22 +1017,24 @@ struct BusyHandler {
};
/*
-** Name of the master database table. The master database table
-** is a special table that holds the names and attributes of all
-** user tables and indices.
+** Name of table that holds the database schema.
*/
-#define MASTER_NAME "sqlite_master"
-#define TEMP_MASTER_NAME "sqlite_temp_master"
+#define DFLT_SCHEMA_TABLE "sqlite_master"
+#define DFLT_TEMP_SCHEMA_TABLE "sqlite_temp_master"
+#define ALT_SCHEMA_TABLE "sqlite_schema"
+#define ALT_TEMP_SCHEMA_TABLE "sqlite_temp_schema"
+
/*
-** The root-page of the master database table.
+** The root-page of the schema table.
*/
-#define MASTER_ROOT 1
+#define SCHEMA_ROOT 1
/*
-** The name of the schema table.
+** The name of the schema table. The name is different for TEMP.
*/
-#define SCHEMA_TABLE(x) ((!OMIT_TEMPDB)&&(x==1)?TEMP_MASTER_NAME:MASTER_NAME)
+#define SCHEMA_TABLE(x) \
+ ((!OMIT_TEMPDB)&&(x==1)?DFLT_TEMP_SCHEMA_TABLE:DFLT_SCHEMA_TABLE)
/*
** A convenience macro that returns the number of elements in
@@ -1033,7 +1055,7 @@ struct BusyHandler {
** pointer will work here as long as it is distinct from SQLITE_STATIC
** and SQLITE_TRANSIENT.
*/
-#define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3MallocSize)
+#define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3OomFault)
/*
** When SQLITE_OMIT_WSD is defined, it means that the target platform does
@@ -1174,9 +1196,9 @@ typedef int VList;
** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque
** pointer types (i.e. FuncDef) defined above.
*/
+#include "pager.h"
#include "btree.h"
#include "vdbe.h"
-#include "pager.h"
#include "pcache.h"
#include "os.h"
#include "mutex.h"
@@ -1477,7 +1499,7 @@ struct sqlite3 {
int aLimit[SQLITE_N_LIMIT]; /* Limits */
int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */
struct sqlite3InitInfo { /* Information used during initialization */
- int newTnum; /* Rootpage of table being initialized */
+ Pgno newTnum; /* Rootpage of table being initialized */
u8 iDb; /* Which db file is being initialized */
u8 busy; /* TRUE if currently initializing */
unsigned orphanTrigger : 1; /* Last statement is orphaned TEMP trigger */
@@ -1492,7 +1514,10 @@ struct sqlite3 {
int nVDestroy; /* Number of active OP_VDestroy operations */
int nExtension; /* Number of loaded extensions */
void **aExtension; /* Array of shared library handles */
- int (*xTrace)(u32,void*,void*,void*); /* Trace function */
+ union {
+ void (*xLegacy)(void*,const char*); /* Legacy trace function */
+ int (*xV2)(u32,void*,void*,void*); /* V2 Trace function */
+ } trace;
void *pTraceArg; /* Argument to the trace function */
#ifndef SQLITE_OMIT_DEPRECATED
void (*xProfile)(void*,const char*,u64); /* Profiling function */
@@ -1554,7 +1579,7 @@ struct sqlite3 {
i64 nDeferredImmCons; /* Net deferred immediate constraints */
int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
- /* The following variables are all protected by the STATIC_MASTER
+ /* The following variables are all protected by the STATIC_MAIN
** mutex, not by sqlite3.mutex. They are used by code in notify.c.
**
** When X.pUnlockConnection==Y, that means that X is waiting for Y to
@@ -1602,7 +1627,7 @@ struct sqlite3 {
** SQLITE_CkptFullFSync == PAGER_CKPT_FULLFSYNC
** SQLITE_CacheSpill == PAGER_CACHE_SPILL
*/
-#define SQLITE_WriteSchema 0x00000001 /* OK to update SQLITE_MASTER */
+#define SQLITE_WriteSchema 0x00000001 /* OK to update SQLITE_SCHEMA */
#define SQLITE_LegacyFileFmt 0x00000002 /* Create new databases in format 1 */
#define SQLITE_FullColNames 0x00000004 /* Show full column names on SELECT */
#define SQLITE_FullFSync 0x00000008 /* Use full fsync on the backend */
@@ -2128,7 +2153,7 @@ struct Table {
char *zColAff; /* String defining the affinity of each column */
ExprList *pCheck; /* All CHECK constraints */
/* ... also used as column name list in a VIEW */
- int tnum; /* Root BTree page for this table */
+ Pgno tnum; /* Root BTree page for this table */
u32 nTabRef; /* Number of pointers to this Table */
u32 tabFlags; /* Mask of TF_* values */
i16 iPKey; /* If not negative, use aCol[iPKey] as the rowid */
@@ -2402,7 +2427,7 @@ struct UnpackedRecord {
** element.
**
** While parsing a CREATE TABLE or CREATE INDEX statement in order to
-** generate VDBE code (as opposed to parsing one read from an sqlite_master
+** generate VDBE code (as opposed to parsing one read from an sqlite_schema
** table as part of parsing an existing database schema), transient instances
** of this structure may be created. In this case the Index.tnum variable is
** used to store the address of a VDBE instruction, not a database page
@@ -2421,7 +2446,7 @@ struct Index {
const char **azColl; /* Array of collation sequence names for index */
Expr *pPartIdxWhere; /* WHERE clause for partial indices */
ExprList *aColExpr; /* Column expressions */
- int tnum; /* DB Page containing root of this index */
+ Pgno tnum; /* DB Page containing root of this index */
LogEst szIdxRow; /* Estimated average row size in bytes */
u16 nKeyCol; /* Number of columns forming the key */
u16 nColumn; /* Number of columns stored in the index */
@@ -2526,25 +2551,32 @@ struct AggInfo {
ExprList *pGroupBy; /* The group by clause */
struct AggInfo_col { /* For each column used in source tables */
Table *pTab; /* Source table */
+ Expr *pCExpr; /* The original expression */
int iTable; /* Cursor number of the source table */
- int iColumn; /* Column number within the source table */
- int iSorterColumn; /* Column number in the sorting index */
int iMem; /* Memory location that acts as accumulator */
- Expr *pExpr; /* The original expression */
+ i16 iColumn; /* Column number within the source table */
+ i16 iSorterColumn; /* Column number in the sorting index */
} *aCol;
int nColumn; /* Number of used entries in aCol[] */
int nAccumulator; /* Number of columns that show through to the output.
** Additional columns are used only as parameters to
** aggregate functions */
struct AggInfo_func { /* For each aggregate function */
- Expr *pExpr; /* Expression encoding the function */
+ Expr *pFExpr; /* Expression encoding the function */
FuncDef *pFunc; /* The aggregate function implementation */
int iMem; /* Memory location that acts as accumulator */
int iDistinct; /* Ephemeral table used to enforce DISTINCT */
} *aFunc;
int nFunc; /* Number of entries in aFunc[] */
+ u32 selId; /* Select to which this AggInfo belongs */
+ AggInfo *pNext; /* Next in list of them all */
};
+/*
+** Value for AggInfo.iAggMagic when the structure is valid
+*/
+#define AggInfoMagic 0x2059e99e
+
/*
** The datatype ynVar is a signed integer, either 16-bit or 32-bit.
** Usually it is 16-bits. But if SQLITE_MAX_VARIABLE_NUMBER is greater
@@ -2721,7 +2753,7 @@ struct Expr {
#define EP_Static 0x8000000 /* Held in memory not obtained from malloc() */
#define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */
#define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */
-#define EP_FromDDL 0x40000000 /* Originates from sqlite_master */
+#define EP_FromDDL 0x40000000 /* Originates from sqlite_schema */
/* 0x80000000 // Available */
/*
@@ -2901,7 +2933,7 @@ struct SrcList {
unsigned isCorrelated :1; /* True if sub-query is correlated */
unsigned viaCoroutine :1; /* Implemented as a co-routine */
unsigned isRecursive :1; /* True for recursive reference in WITH */
- unsigned fromDDL :1; /* Comes from sqlite_master */
+ unsigned fromDDL :1; /* Comes from sqlite_schema */
} fg;
int iCursor; /* The VDBE cursor number used to access this table */
Expr *pOn; /* The ON clause of a join */
@@ -3022,7 +3054,7 @@ struct NameContext {
#define NC_HasWin 0x08000 /* One or more window functions seen */
#define NC_IsDDL 0x10000 /* Resolving names in a CREATE statement */
#define NC_InAggFunc 0x20000 /* True if analyzing arguments to an agg func */
-#define NC_FromDDL 0x40000 /* SQL text comes from sqlite_master */
+#define NC_FromDDL 0x40000 /* SQL text comes from sqlite_schema */
/*
** An instance of the following object describes a single ON CONFLICT
@@ -3125,6 +3157,8 @@ struct Select {
#define SF_WhereBegin 0x0080000 /* Really a WhereBegin() call. Debug Only */
#define SF_WinRewrite 0x0100000 /* Window function rewrite accomplished */
#define SF_View 0x0200000 /* SELECT statement is a view */
+#define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */
+#define SF_UpdateFrom 0x0800000 /* Statement is an UPDATE...FROM */
/*
** The results of a SELECT can be distributed in several ways, as defined
@@ -3189,6 +3223,14 @@ struct Select {
** SRT_DistQueue Store results in priority queue pDest->iSDParm only if
** the same record has never been stored before. The
** index at pDest->iSDParm+1 hold all prior stores.
+**
+** SRT_Upfrom Store results in the temporary table already opened by
+** pDest->iSDParm. If (pDest->iSDParm<0), then the temp
+** table is an intkey table - in this case the first
+** column returned by the SELECT is used as the integer
+** key. If (pDest->iSDParm>0), then the table is an index
+** table. (pDest->iSDParm) is the number of key columns in
+** each index record in this case.
*/
#define SRT_Union 1 /* Store result as keys in an index */
#define SRT_Except 2 /* Remove result from a UNION index */
@@ -3208,14 +3250,16 @@ struct Select {
#define SRT_EphemTab 12 /* Create transient tab and store like SRT_Table */
#define SRT_Coroutine 13 /* Generate a single row of result */
#define SRT_Table 14 /* Store result as data with an automatic rowid */
+#define SRT_Upfrom 15 /* Store result as data with rowid */
/*
** An instance of this object describes where to put of the results of
** a SELECT statement.
*/
struct SelectDest {
- u8 eDest; /* How to dispose of the results. On of SRT_* above. */
+ u8 eDest; /* How to dispose of the results. One of SRT_* above. */
int iSDParm; /* A parameter used by the eDest disposal method */
+ int iSDParm2; /* A second parameter for the eDest disposal method */
int iSdst; /* Base register where results are written */
int nSdst; /* Number of registers allocated */
char *zAffSdst; /* Affinity used when eDest==SRT_Set */
@@ -3340,6 +3384,7 @@ struct Parse {
AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */
Parse *pToplevel; /* Parse structure for main program (or NULL) */
Table *pTriggerTab; /* Table triggers are being coded for */
+ AggInfo *pAggList; /* List of all AggInfo objects */
int addrCrTab; /* Address of OP_CreateBtree opcode on CREATE TABLE */
u32 nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
u32 oldmask; /* Mask of old.* columns referenced */
@@ -3369,9 +3414,7 @@ struct Parse {
ynVar nVar; /* Number of '?' variables seen in the SQL so far */
u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */
u8 explain; /* True if the EXPLAIN flag is found on the query */
-#if !(defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_OMIT_ALTERTABLE))
u8 eParseMode; /* PARSE_MODE_XXX constant */
-#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
int nVtabLock; /* Number of virtual tables to lock */
#endif
@@ -3562,6 +3605,7 @@ struct TriggerStep {
Trigger *pTrig; /* The trigger that this step is a part of */
Select *pSelect; /* SELECT statement or RHS of INSERT INTO SELECT ... */
char *zTarget; /* Target table for DELETE, UPDATE, INSERT */
+ SrcList *pFrom; /* FROM clause for UPDATE statement (if any) */
Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */
ExprList *pExprList; /* SET clause for UPDATE */
IdList *pIdList; /* Column names for INSERT */
@@ -3618,6 +3662,7 @@ typedef struct {
u32 mInitFlags; /* Flags controlling error messages */
u32 nInitRow; /* Number of rows processed */
u64 cksum; /* Schema checksum for REUSE_SCHEMA mode */
+ Pgno mxPage; /* Maximum page number. 0 for no limit. */
} InitData;
/*
@@ -4148,7 +4193,7 @@ void sqlite3DeleteColumnNames(sqlite3*,Table*);
int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**);
void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*,char);
Table *sqlite3ResultSetOfSelect(Parse*,Select*,char);
-void sqlite3OpenMasterTable(Parse *, int);
+void sqlite3OpenSchemaTable(Parse *, int);
Index *sqlite3PrimaryKeyIndex(Table*);
i16 sqlite3TableColumnToIndex(Index*, i16);
#ifdef SQLITE_OMIT_GENERATED_COLUMNS
@@ -4231,6 +4276,7 @@ void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*);
IdList *sqlite3IdListAppend(Parse*, IdList*, Token*);
int sqlite3IdListIndex(IdList*,const char*);
SrcList *sqlite3SrcListEnlarge(Parse*, SrcList*, int, int);
+SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2);
SrcList *sqlite3SrcListAppend(Parse*, SrcList*, Token*, Token*);
SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*,
Token*, Select*, Expr*, IdList*);
@@ -4249,7 +4295,6 @@ int sqlite3Select(Parse*, Select*, SelectDest*);
Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
Expr*,ExprList*,u32,Expr*);
void sqlite3SelectDelete(sqlite3*, Select*);
-void sqlite3SelectReset(Parse*, Select*);
Table *sqlite3SrcListLookup(Parse*, SrcList*);
int sqlite3IsReadOnly(Parse*, Table*, int);
void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
@@ -4310,6 +4355,7 @@ int sqlite3ExprCompareSkip(Expr*, Expr*, int);
int sqlite3ExprListCompare(ExprList*, ExprList*, int);
int sqlite3ExprImpliesExpr(Parse*,Expr*, Expr*, int);
int sqlite3ExprImpliesNonNullRow(Expr*,int);
+void sqlite3AggInfoPersistWalkerInit(Walker*,Parse*);
void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx);
@@ -4400,13 +4446,14 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
TriggerStep *sqlite3TriggerInsertStep(Parse*,Token*, IdList*,
Select*,u8,Upsert*,
const char*,const char*);
- TriggerStep *sqlite3TriggerUpdateStep(Parse*,Token*,ExprList*, Expr*, u8,
- const char*,const char*);
+ TriggerStep *sqlite3TriggerUpdateStep(Parse*,Token*,SrcList*,ExprList*,
+ Expr*, u8, const char*,const char*);
TriggerStep *sqlite3TriggerDeleteStep(Parse*,Token*, Expr*,
const char*,const char*);
void sqlite3DeleteTrigger(sqlite3*, Trigger*);
void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Table*,int);
+ SrcList *sqlite3TriggerStepSrc(Parse*, TriggerStep*);
# define sqlite3ParseToplevel(p) ((p)->pToplevel ? (p)->pToplevel : (p))
# define sqlite3IsToplevel(p) ((p)->pToplevel==0)
#else
@@ -4420,6 +4467,7 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
# define sqlite3ParseToplevel(p) p
# define sqlite3IsToplevel(p) 1
# define sqlite3TriggerColmask(A,B,C,D,E,F,G) 0
+# define sqlite3TriggerStepSrc(A,B) 0
#endif
int sqlite3JoinType(Parse*, Token*, Token*, Token*);
@@ -4448,8 +4496,10 @@ int sqlite3FixExpr(DbFixer*, Expr*);
int sqlite3FixExprList(DbFixer*, ExprList*);
int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
int sqlite3RealSameAsInt(double,sqlite3_int64);
+void sqlite3Int64ToText(i64,char*);
int sqlite3AtoF(const char *z, double*, int, u8);
int sqlite3GetInt32(const char *, int*);
+int sqlite3GetUInt32(const char*, u32*);
int sqlite3Atoi(const char*);
#ifndef SQLITE_OMIT_UTF16
int sqlite3Utf16ByteLen(const void *pData, int nChar);
@@ -4569,14 +4619,15 @@ extern const unsigned char sqlite3UpperToLower[];
extern const unsigned char sqlite3CtypeMap[];
extern SQLITE_WSD struct Sqlite3Config sqlite3Config;
extern FuncDefHash sqlite3BuiltinFunctions;
+extern u32 sqlite3_unsupported_selecttrace;
#ifndef SQLITE_OMIT_WSD
extern int sqlite3PendingByte;
#endif
-#endif
+#endif /* SQLITE_AMALGAMATION */
#ifdef VDBE_PROFILE
extern sqlite3_uint64 sqlite3NProfileCnt;
#endif
-void sqlite3RootPageMoved(sqlite3*, int, int, int);
+void sqlite3RootPageMoved(sqlite3*, int, Pgno, Pgno);
void sqlite3Reindex(Parse*, Token*, Token*);
void sqlite3AlterFunctions(void);
void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
@@ -4713,7 +4764,7 @@ void sqlite3AutoLoadExtensions(sqlite3*);
#endif
#ifndef SQLITE_OMIT_SHARED_CACHE
- void sqlite3TableLock(Parse *, int, int, u8, const char *);
+ void sqlite3TableLock(Parse *, int, Pgno, u8, const char *);
#else
#define sqlite3TableLock(v,w,x,y,z)
#endif
diff --git a/src/status.c b/src/status.c
index 58860d9dc7..8e2980212d 100644
--- a/src/status.c
+++ b/src/status.c
@@ -372,7 +372,7 @@ int sqlite3_db_status(
*/
case SQLITE_DBSTATUS_CACHE_SPILL:
op = SQLITE_DBSTATUS_CACHE_WRITE+1;
- /* Fall through into the next case */
+ /* no break */ deliberate_fall_through
case SQLITE_DBSTATUS_CACHE_HIT:
case SQLITE_DBSTATUS_CACHE_MISS:
case SQLITE_DBSTATUS_CACHE_WRITE:{
diff --git a/src/test1.c b/src/test1.c
index 29207d51ac..e9a75d6368 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -4630,7 +4630,7 @@ static int SQLITE_TCLAPI test_open_v2(
{ "SQLITE_OPEN_MAIN_JOURNAL", SQLITE_OPEN_MAIN_JOURNAL },
{ "SQLITE_OPEN_TEMP_JOURNAL", SQLITE_OPEN_TEMP_JOURNAL },
{ "SQLITE_OPEN_SUBJOURNAL", SQLITE_OPEN_SUBJOURNAL },
- { "SQLITE_OPEN_MASTER_JOURNAL", SQLITE_OPEN_MASTER_JOURNAL },
+ { "SQLITE_OPEN_SUPER_JOURNAL", SQLITE_OPEN_SUPER_JOURNAL },
{ "SQLITE_OPEN_NOMUTEX", SQLITE_OPEN_NOMUTEX },
{ "SQLITE_OPEN_FULLMUTEX", SQLITE_OPEN_FULLMUTEX },
{ "SQLITE_OPEN_SHAREDCACHE", SQLITE_OPEN_SHAREDCACHE },
@@ -6437,6 +6437,30 @@ static int SQLITE_TCLAPI prng_seed(
return TCL_OK;
}
+/*
+** tclcmd: extra_schema_checks BOOLEAN
+**
+** Enable or disable schema checks when parsing the sqlite_schema file.
+** This is always enabled in production, but it is sometimes useful to
+** disable the checks in order to make some internal error states reachable
+** for testing.
+*/
+static int SQLITE_TCLAPI extra_schema_checks(
+ ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int objc, /* Number of arguments */
+ Tcl_Obj *CONST objv[] /* Command arguments */
+){
+ int i = 0;
+ if( objc!=2 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
+ return TCL_ERROR;
+ }
+ if( Tcl_GetBooleanFromObj(interp,objv[1],&i) ) return TCL_ERROR;
+ sqlite3_test_control(SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS, i);
+ return TCL_OK;
+}
+
/*
** tclcmd: database_may_be_corrupt
**
@@ -7257,6 +7281,7 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_explain_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*);
+ extern int sqlite3_decimal_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*);
@@ -7282,6 +7307,7 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
{ "carray", sqlite3_carray_init },
{ "closure", sqlite3_closure_init },
{ "csv", sqlite3_csv_init },
+ { "decimal", sqlite3_decimal_init },
{ "eval", sqlite3_eval_init },
{ "explain", sqlite3_explain_init },
{ "fileio", sqlite3_fileio_init },
@@ -8001,6 +8027,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "restore_prng_state", restore_prng_state, 0 },
{ "reset_prng_state", reset_prng_state, 0 },
{ "prng_seed", prng_seed, 0 },
+ { "extra_schema_checks", extra_schema_checks, 0},
{ "database_never_corrupt", database_never_corrupt, 0},
{ "database_may_be_corrupt", database_may_be_corrupt, 0},
{ "optimization_control", optimization_control,0},
@@ -8164,7 +8191,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
#endif
#endif
#if defined(SQLITE_ENABLE_SELECTTRACE)
- extern int sqlite3SelectTrace;
+ extern u32 sqlite3_unsupported_selecttrace;
#endif
for(i=0; izTableName ){
sqlite3_stmt *pStmt = 0;
rc = sqlite3_prepare(db,
- "SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?",
+ "SELECT sql FROM sqlite_schema WHERE type = 'table' AND name = ?",
-1, &pStmt, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_text(pStmt, 1, pVtab->zTableName, -1, 0);
diff --git a/src/test_malloc.c b/src/test_malloc.c
index 32a03e7191..8146501c9c 100644
--- a/src/test_malloc.c
+++ b/src/test_malloc.c
@@ -112,32 +112,6 @@ static void *faultsimRealloc(void *pOld, int n){
return p;
}
-/*
-** The following method calls are passed directly through to the underlying
-** malloc system:
-**
-** xFree
-** xSize
-** xRoundup
-** xInit
-** xShutdown
-*/
-static void faultsimFree(void *p){
- memfault.m.xFree(p);
-}
-static int faultsimSize(void *p){
- return memfault.m.xSize(p);
-}
-static int faultsimRoundup(int n){
- return memfault.m.xRoundup(n);
-}
-static int faultsimInit(void *p){
- return memfault.m.xInit(memfault.m.pAppData);
-}
-static void faultsimShutdown(void *p){
- memfault.m.xShutdown(memfault.m.pAppData);
-}
-
/*
** This routine configures the malloc failure simulation. After
** calling this routine, the next nDelay mallocs will succeed, followed
@@ -204,16 +178,6 @@ static void faultsimEndBenign(void){
** the argument is non-zero, the
*/
static int faultsimInstall(int install){
- static struct sqlite3_mem_methods m = {
- faultsimMalloc, /* xMalloc */
- faultsimFree, /* xFree */
- faultsimRealloc, /* xRealloc */
- faultsimSize, /* xSize */
- faultsimRoundup, /* xRoundup */
- faultsimInit, /* xInit */
- faultsimShutdown, /* xShutdown */
- 0 /* pAppData */
- };
int rc;
install = (install ? 1 : 0);
@@ -227,6 +191,9 @@ static int faultsimInstall(int install){
rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memfault.m);
assert(memfault.m.xMalloc);
if( rc==SQLITE_OK ){
+ sqlite3_mem_methods m = memfault.m;
+ m.xMalloc = faultsimMalloc;
+ m.xRealloc = faultsimRealloc;
rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
}
sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,
diff --git a/src/test_multiplex.c b/src/test_multiplex.c
index 3c9aa034cc..5ef1ec1839 100644
--- a/src/test_multiplex.c
+++ b/src/test_multiplex.c
@@ -545,7 +545,7 @@ static int multiplexOpen(
rc = pSubOpen->pMethods->xFileSize(pSubOpen, &sz64);
if( rc==SQLITE_OK && zName ){
int bExists;
- if( flags & SQLITE_OPEN_MASTER_JOURNAL ){
+ if( flags & SQLITE_OPEN_SUPER_JOURNAL ){
pGroup->bEnabled = 0;
}else
if( sz64==0 ){
@@ -591,9 +591,9 @@ static int multiplexOpen(
if( rc==SQLITE_OK ){
if( pSubOpen->pMethods->iVersion==1 ){
- pMultiplexOpen->base.pMethods = &gMultiplex.sIoMethodsV1;
+ pConn->pMethods = &gMultiplex.sIoMethodsV1;
}else{
- pMultiplexOpen->base.pMethods = &gMultiplex.sIoMethodsV2;
+ pConn->pMethods = &gMultiplex.sIoMethodsV2;
}
}else{
multiplexFreeComponents(pGroup);
diff --git a/src/test_mutex.c b/src/test_mutex.c
index 8f43e5ad30..8bd9ff85a0 100644
--- a/src/test_mutex.c
+++ b/src/test_mutex.c
@@ -30,7 +30,7 @@
extern const char *sqlite3ErrName(int);
static const char *aName[MAX_MUTEXES+1] = {
- "fast", "recursive", "static_master", "static_mem",
+ "fast", "recursive", "static_main", "static_mem",
"static_open", "static_prng", "static_lru", "static_pmem",
"static_app1", "static_app2", "static_app3", "static_vfs1",
"static_vfs2", "static_vfs3", 0
diff --git a/src/test_osinst.c b/src/test_osinst.c
index a008baba45..3e698c0324 100644
--- a/src/test_osinst.c
+++ b/src/test_osinst.c
@@ -740,7 +740,7 @@ int sqlite3_vfslog_new(
zFile = (char *)&p->base.zName[nVfs+1];
pParent->xFullPathname(pParent, zLog, pParent->mxPathname, zFile);
- flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_MASTER_JOURNAL;
+ flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_SUPER_JOURNAL;
pParent->xDelete(pParent, zFile, 0);
rc = pParent->xOpen(pParent, zFile, p->pLog, flags, &flags);
if( rc==SQLITE_OK ){
@@ -893,7 +893,7 @@ static int vlogConnect(
pVfs->xFullPathname(pVfs, zFile, pVfs->mxPathname, p->zFile);
sqlite3_free(zFile);
- flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MASTER_JOURNAL;
+ flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_SUPER_JOURNAL;
rc = pVfs->xOpen(pVfs, p->zFile, p->pFd, flags, &flags);
if( rc==SQLITE_OK ){
diff --git a/src/test_schema.c b/src/test_schema.c
index cdf085797f..d2cae7f2aa 100644
--- a/src/test_schema.c
+++ b/src/test_schema.c
@@ -192,18 +192,18 @@ static int schemaNext(sqlite3_vtab_cursor *cur){
}
/* Set zSql to the SQL to pull the list of tables from the
- ** sqlite_master (or sqlite_temp_master) table of the database
+ ** sqlite_schema (or sqlite_temp_schema) table of the database
** identified by the row pointed to by the SQL statement pCur->pDbList
** (iterating through a "PRAGMA database_list;" statement).
*/
if( sqlite3_column_int(pCur->pDbList, 0)==1 ){
zSql = sqlite3_mprintf(
- "SELECT name FROM sqlite_temp_master WHERE type='table'"
+ "SELECT name FROM sqlite_temp_schema WHERE type='table'"
);
}else{
sqlite3_stmt *pDbList = pCur->pDbList;
zSql = sqlite3_mprintf(
- "SELECT name FROM %Q.sqlite_master WHERE type='table'",
+ "SELECT name FROM %Q.sqlite_schema WHERE type='table'",
sqlite3_column_text(pDbList, 1)
);
}
diff --git a/src/test_sqllog.c b/src/test_sqllog.c
index 9b207cf07b..9ae0e50685 100644
--- a/src/test_sqllog.c
+++ b/src/test_sqllog.c
@@ -118,7 +118,7 @@ struct SLConn {
/* This object is a singleton that keeps track of all data loggers.
*/
static struct SLGlobal {
- /* Protected by MUTEX_STATIC_MASTER */
+ /* Protected by MUTEX_STATIC_MAIN */
sqlite3_mutex *mutex; /* Recursive mutex */
int nConn; /* Size of aConn[] array */
@@ -467,28 +467,28 @@ static int sqllogTraceDb(sqlite3 *db){
*/
static void testSqllog(void *pCtx, sqlite3 *db, const char *zSql, int eType){
struct SLConn *p = 0;
- sqlite3_mutex *master = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex *mainmtx = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MAIN);
assert( eType==0 || eType==1 || eType==2 );
assert( (eType==2)==(zSql==0) );
/* This is a database open command. */
if( eType==0 ){
- sqlite3_mutex_enter(master);
+ sqlite3_mutex_enter(mainmtx);
if( sqllogglobal.mutex==0 ){
sqllogglobal.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE);
}
- sqlite3_mutex_leave(master);
+ sqlite3_mutex_leave(mainmtx);
sqlite3_mutex_enter(sqllogglobal.mutex);
if( sqllogglobal.bRec==0 && sqllogTraceDb(db) ){
- sqlite3_mutex_enter(master);
+ sqlite3_mutex_enter(mainmtx);
p = &sqllogglobal.aConn[sqllogglobal.nConn++];
p->fd = 0;
p->db = db;
p->iLog = sqllogglobal.iNextLog++;
- sqlite3_mutex_leave(master);
+ sqlite3_mutex_leave(mainmtx);
/* Open the log and take a copy of the main database file */
sqllogOpenlog(p);
@@ -507,7 +507,7 @@ static void testSqllog(void *pCtx, sqlite3 *db, const char *zSql, int eType){
/* A database handle close command */
if( eType==2 ){
- sqlite3_mutex_enter(master);
+ sqlite3_mutex_enter(mainmtx);
if( ifd ) fclose(p->fd);
p->db = 0;
@@ -524,7 +524,7 @@ static void testSqllog(void *pCtx, sqlite3 *db, const char *zSql, int eType){
memmove(p, &p[1], nShift*sizeof(struct SLConn));
}
}
- sqlite3_mutex_leave(master);
+ sqlite3_mutex_leave(mainmtx);
/* An ordinary SQL command. */
}else if( ifd ){
diff --git a/src/tokenize.c b/src/tokenize.c
index 50dddbb876..833093df14 100644
--- a/src/tokenize.c
+++ b/src/tokenize.c
@@ -422,6 +422,7 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
}
/* If the next character is a digit, this is a floating point
** number that begins with ".". Fall thru into the next case */
+ /* no break */ deliberate_fall_through
}
case CC_DIGIT: {
testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' );
@@ -526,6 +527,7 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
#endif
/* If it is not a BLOB literal, then it must be an ID, since no
** SQL keywords start with the letter 'x'. Fall through */
+ /* no break */ deliberate_fall_through
}
case CC_ID: {
i = 1;
diff --git a/src/treeview.c b/src/treeview.c
index f167e588cd..187f1a07d1 100644
--- a/src/treeview.c
+++ b/src/treeview.c
@@ -582,8 +582,9 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
#endif
}
if( pExpr->op==TK_AGG_FUNCTION ){
- sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s iAgg=%d agg=%p",
+ sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s agg=%d[%d]/%p",
pExpr->op2, pExpr->u.zToken, zFlgs,
+ pExpr->pAggInfo ? pExpr->pAggInfo->selId : 0,
pExpr->iAgg, pExpr->pAggInfo);
}else if( pExpr->op2!=0 ){
const char *zOp2;
@@ -616,7 +617,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
break;
}
case TK_SELECT: {
- sqlite3TreeViewLine(pView, "SELECT-expr flags=0x%x", pExpr->flags);
+ sqlite3TreeViewLine(pView, "subquery-expr flags=0x%x", pExpr->flags);
sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
break;
}
diff --git a/src/trigger.c b/src/trigger.c
index 52b993e651..69b9ff9e98 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -26,6 +26,7 @@ void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerStep){
sqlite3SelectDelete(db, pTmp->pSelect);
sqlite3IdListDelete(db, pTmp->pIdList);
sqlite3UpsertDelete(db, pTmp->pUpsert);
+ sqlite3SrcListDelete(db, pTmp->pFrom);
sqlite3DbFree(db, pTmp->zSpan);
sqlite3DbFree(db, pTmp);
@@ -143,7 +144,7 @@ void sqlite3BeginTrigger(
** ^^^^^^^^
**
** To maintain backwards compatibility, ignore the database
- ** name on pTableName if we are reparsing out of SQLITE_MASTER.
+ ** name on pTableName if we are reparsing out of the schema table
*/
if( db->init.busy && iDb!=1 ){
sqlite3DbFree(db, pTableName->a[0].zDatabase);
@@ -339,21 +340,22 @@ void sqlite3FinishTrigger(
#endif
/* if we are not initializing,
- ** build the sqlite_master entry
+ ** build the sqlite_schema entry
*/
if( !db->init.busy ){
Vdbe *v;
char *z;
- /* Make an entry in the sqlite_master table */
+ /* Make an entry in the sqlite_schema table */
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto triggerfinish_cleanup;
sqlite3BeginWriteOperation(pParse, 0, iDb);
z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n);
testcase( z==0 );
sqlite3NestedParse(pParse,
- "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
- db->aDb[iDb].zDbSName, MASTER_NAME, zName,
+ "INSERT INTO %Q." DFLT_SCHEMA_TABLE
+ " VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
+ db->aDb[iDb].zDbSName, zName,
pTrig->table, z);
sqlite3DbFree(db, z);
sqlite3ChangeCookie(pParse, iDb);
@@ -506,6 +508,7 @@ TriggerStep *sqlite3TriggerInsertStep(
TriggerStep *sqlite3TriggerUpdateStep(
Parse *pParse, /* Parser */
Token *pTableName, /* Name of the table to be updated */
+ SrcList *pFrom,
ExprList *pEList, /* The SET clause: list of column and new values */
Expr *pWhere, /* The WHERE clause */
u8 orconf, /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
@@ -520,16 +523,20 @@ TriggerStep *sqlite3TriggerUpdateStep(
if( IN_RENAME_OBJECT ){
pTriggerStep->pExprList = pEList;
pTriggerStep->pWhere = pWhere;
+ pTriggerStep->pFrom = pFrom;
pEList = 0;
pWhere = 0;
+ pFrom = 0;
}else{
pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE);
pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
+ pTriggerStep->pFrom = sqlite3SrcListDup(db, pFrom, EXPRDUP_REDUCE);
}
pTriggerStep->orconf = orconf;
}
sqlite3ExprListDelete(db, pEList);
sqlite3ExprDelete(db, pWhere);
+ sqlite3SrcListDelete(db, pFrom);
return pTriggerStep;
}
@@ -664,8 +671,8 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
*/
if( (v = sqlite3GetVdbe(pParse))!=0 ){
sqlite3NestedParse(pParse,
- "DELETE FROM %Q.%s WHERE name=%Q AND type='trigger'",
- db->aDb[iDb].zDbSName, MASTER_NAME, pTrigger->zName
+ "DELETE FROM %Q." DFLT_SCHEMA_TABLE " WHERE name=%Q AND type='trigger'",
+ db->aDb[iDb].zDbSName, pTrigger->zName
);
sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->zName, 0);
@@ -760,25 +767,28 @@ Trigger *sqlite3TriggersExist(
** trigger is in TEMP in which case it can refer to any other database it
** wants.
*/
-static SrcList *targetSrcList(
+SrcList *sqlite3TriggerStepSrc(
Parse *pParse, /* The parsing context */
TriggerStep *pStep /* The trigger containing the target token */
){
sqlite3 *db = pParse->db;
- int iDb; /* Index of the database to use */
- SrcList *pSrc; /* SrcList to be returned */
-
+ SrcList *pSrc; /* SrcList to be returned */
+ char *zName = sqlite3DbStrDup(db, pStep->zTarget);
pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
+ assert( pSrc==0 || pSrc->nSrc==1 );
+ assert( zName || pSrc==0 );
if( pSrc ){
- assert( pSrc->nSrc>0 );
- pSrc->a[pSrc->nSrc-1].zName = sqlite3DbStrDup(db, pStep->zTarget);
- iDb = sqlite3SchemaToIndex(db, pStep->pTrig->pSchema);
- if( iDb==0 || iDb>=2 ){
- const char *zDb;
- assert( iDbnDb );
- zDb = db->aDb[iDb].zDbSName;
- pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, zDb);
+ Schema *pSchema = pStep->pTrig->pSchema;
+ pSrc->a[0].zName = zName;
+ if( pSchema!=db->aDb[1].pSchema ){
+ pSrc->a[0].pSchema = pSchema;
}
+ if( pStep->pFrom ){
+ SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0);
+ pSrc = sqlite3SrcListAppendList(pParse, pSrc, pDup);
+ }
+ }else{
+ sqlite3DbFree(db, zName);
}
return pSrc;
}
@@ -827,7 +837,7 @@ static int codeTriggerProgram(
switch( pStep->op ){
case TK_UPDATE: {
sqlite3Update(pParse,
- targetSrcList(pParse, pStep),
+ sqlite3TriggerStepSrc(pParse, pStep),
sqlite3ExprListDup(db, pStep->pExprList, 0),
sqlite3ExprDup(db, pStep->pWhere, 0),
pParse->eOrconf, 0, 0, 0
@@ -836,7 +846,7 @@ static int codeTriggerProgram(
}
case TK_INSERT: {
sqlite3Insert(pParse,
- targetSrcList(pParse, pStep),
+ sqlite3TriggerStepSrc(pParse, pStep),
sqlite3SelectDup(db, pStep->pSelect, 0),
sqlite3IdListDup(db, pStep->pIdList),
pParse->eOrconf,
@@ -846,7 +856,7 @@ static int codeTriggerProgram(
}
case TK_DELETE: {
sqlite3DeleteFrom(pParse,
- targetSrcList(pParse, pStep),
+ sqlite3TriggerStepSrc(pParse, pStep),
sqlite3ExprDup(db, pStep->pWhere, 0), 0, 0
);
break;
diff --git a/src/update.c b/src/update.c
index 470370f54f..a9c43d62eb 100644
--- a/src/update.c
+++ b/src/update.c
@@ -46,7 +46,7 @@ static void updateVirtualTable(
** literal default values specified: a number, null or a string. (If a more
** complicated default expression value was provided, it is evaluated
** when the ALTER TABLE is executed and one of the literal values written
-** into the sqlite_master table.)
+** into the sqlite_schema table.)
**
** Therefore, the P4 parameter is only required if the default value for
** the column is a literal number, string or null. The sqlite3ValueFromExpr()
@@ -130,12 +130,149 @@ static int indexWhereClauseMightChange(
aXRef, chngRowid);
}
+/*
+** Allocate and return a pointer to an expression of type TK_ROW with
+** Expr.iColumn set to value (iCol+1). The resolver will modify the
+** expression to be a TK_COLUMN reading column iCol of the first
+** table in the source-list (pSrc->a[0]).
+*/
+static Expr *exprRowColumn(Parse *pParse, int iCol){
+ Expr *pRet = sqlite3PExpr(pParse, TK_ROW, 0, 0);
+ if( pRet ) pRet->iColumn = iCol+1;
+ return pRet;
+}
+
+/*
+** Assuming both the pLimit and pOrderBy parameters are NULL, this function
+** generates VM code to run the query:
+**
+** SELECT , pChanges FROM pTabList WHERE pWhere
+**
+** and write the results to the ephemeral table already opened as cursor
+** iEph. None of pChanges, pTabList or pWhere are modified or consumed by
+** this function, they must be deleted by the caller.
+**
+** Or, if pLimit and pOrderBy are not NULL, and pTab is not a view:
+**
+** SELECT , pChanges FROM pTabList
+** WHERE pWhere
+** GROUP BY
+** ORDER BY pOrderBy LIMIT pLimit
+**
+** If pTab is a view, the GROUP BY clause is omitted.
+**
+** Exactly how results are written to table iEph, and exactly what
+** the in the query above are is determined by the type
+** of table pTabList->a[0].pTab.
+**
+** If the table is a WITHOUT ROWID table, then argument pPk must be its
+** PRIMARY KEY. In this case are the primary key columns
+** of the table, in order. The results of the query are written to ephemeral
+** table iEph as index keys, using OP_IdxInsert.
+**
+** If the table is actually a view, then are all columns of
+** the view. The results are written to the ephemeral table iEph as records
+** with automatically assigned integer keys.
+**
+** If the table is a virtual or ordinary intkey table, then
+** is its rowid. For a virtual table, the results are written to iEph as
+** records with automatically assigned integer keys For intkey tables, the
+** rowid value in is used as the integer key, and the
+** remaining fields make up the table record.
+*/
+static void updateFromSelect(
+ Parse *pParse, /* Parse context */
+ int iEph, /* Cursor for open eph. table */
+ Index *pPk, /* PK if table 0 is WITHOUT ROWID */
+ ExprList *pChanges, /* List of expressions to return */
+ SrcList *pTabList, /* List of tables to select from */
+ Expr *pWhere, /* WHERE clause for query */
+ ExprList *pOrderBy, /* ORDER BY clause */
+ Expr *pLimit /* LIMIT clause */
+){
+ int i;
+ SelectDest dest;
+ Select *pSelect = 0;
+ ExprList *pList = 0;
+ ExprList *pGrp = 0;
+ Expr *pLimit2 = 0;
+ ExprList *pOrderBy2 = 0;
+ sqlite3 *db = pParse->db;
+ Table *pTab = pTabList->a[0].pTab;
+ SrcList *pSrc;
+ Expr *pWhere2;
+ int eDest;
+
+#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+ if( pOrderBy && pLimit==0 ) {
+ sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on UPDATE");
+ return;
+ }
+ pOrderBy2 = sqlite3ExprListDup(db, pOrderBy, 0);
+ pLimit2 = sqlite3ExprDup(db, pLimit, 0);
+#else
+ UNUSED_PARAMETER(pOrderBy);
+ UNUSED_PARAMETER(pLimit);
+#endif
+
+ pSrc = sqlite3SrcListDup(db, pTabList, 0);
+ pWhere2 = sqlite3ExprDup(db, pWhere, 0);
+
+ assert( pTabList->nSrc>1 );
+ if( pSrc ){
+ pSrc->a[0].iCursor = -1;
+ pSrc->a[0].pTab->nTabRef--;
+ pSrc->a[0].pTab = 0;
+ }
+ if( pPk ){
+ for(i=0; inKeyCol; i++){
+ Expr *pNew = exprRowColumn(pParse, pPk->aiColumn[i]);
+#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+ if( pLimit ){
+ pGrp = sqlite3ExprListAppend(pParse, pGrp, sqlite3ExprDup(db, pNew, 0));
+ }
+#endif
+ pList = sqlite3ExprListAppend(pParse, pList, pNew);
+ }
+ eDest = SRT_Upfrom;
+ }else if( pTab->pSelect ){
+ for(i=0; inCol; i++){
+ pList = sqlite3ExprListAppend(pParse, pList, exprRowColumn(pParse, i));
+ }
+ eDest = SRT_Table;
+ }else{
+ eDest = IsVirtual(pTab) ? SRT_Table : SRT_Upfrom;
+ pList = sqlite3ExprListAppend(pParse, 0, sqlite3PExpr(pParse,TK_ROW,0,0));
+#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+ if( pLimit ){
+ pGrp = sqlite3ExprListAppend(pParse, 0, sqlite3PExpr(pParse,TK_ROW,0,0));
+ }
+#endif
+ }
+ if( ALWAYS(pChanges) ){
+ for(i=0; inExpr; i++){
+ pList = sqlite3ExprListAppend(pParse, pList,
+ sqlite3ExprDup(db, pChanges->a[i].pExpr, 0)
+ );
+ }
+ }
+ pSelect = sqlite3SelectNew(pParse, pList,
+ pSrc, pWhere2, pGrp, 0, pOrderBy2, SF_UpdateFrom|SF_IncludeHidden, pLimit2
+ );
+ sqlite3SelectDestInit(&dest, eDest, iEph);
+ dest.iSDParm2 = (pPk ? pPk->nKeyCol : -1);
+ sqlite3Select(pParse, pSelect, &dest);
+ sqlite3SelectDelete(db, pSelect);
+}
+
/*
** Process an UPDATE statement.
**
-** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL;
-** \_______/ \________/ \______/ \________________/
-* onError pTabList pChanges pWhere
+** UPDATE OR IGNORE tbl SET a=b, c=d FROM tbl2... WHERE e<5 AND f NOT NULL;
+** \_______/ \_/ \______/ \_____/ \________________/
+** onError | pChanges | pWhere
+** \_______________________/
+** pTabList
*/
void sqlite3Update(
Parse *pParse, /* The parser context */
@@ -150,7 +287,7 @@ void sqlite3Update(
int i, j, k; /* Loop counters */
Table *pTab; /* The table to be updated */
int addrTop = 0; /* VDBE instruction address of the start of the loop */
- WhereInfo *pWInfo; /* Information about the WHERE clause */
+ WhereInfo *pWInfo = 0; /* Information about the WHERE clause */
Vdbe *v; /* The virtual database engine */
Index *pIdx; /* For looping over indices */
Index *pPk; /* The PRIMARY KEY index for WITHOUT ROWID tables */
@@ -169,6 +306,7 @@ void sqlite3Update(
u8 chngRowid; /* Rowid changed in a normal table */
u8 chngKey; /* Either chngPk or chngRowid */
Expr *pRowidExpr = 0; /* Expression defining the new record number */
+ int iRowidExpr = -1; /* Index of "rowid=" (or IPK) assignment in pChanges */
AuthContext sContext; /* The authorization context */
NameContext sNC; /* The name-context to resolve expressions in */
int iDb; /* Database containing the table being updated */
@@ -192,6 +330,7 @@ void sqlite3Update(
i16 nPk = 0; /* Number of components of the PRIMARY KEY */
int bReplace = 0; /* True if REPLACE conflict resolution might happen */
int bFinishSeek = 1; /* The OP_FinishSeek opcode is needed */
+ int nChangeFrom = 0; /* If there is a FROM, pChanges->nExpr, else 0 */
/* Register Allocations */
int regRowCount = 0; /* A count of rows changed */
@@ -207,7 +346,6 @@ void sqlite3Update(
if( pParse->nErr || db->mallocFailed ){
goto update_cleanup;
}
- assert( pTabList->nSrc==1 );
/* Locate the table which we want to update.
*/
@@ -232,8 +370,15 @@ void sqlite3Update(
# define isView 0
#endif
+ /* If there was a FROM clause, set nChangeFrom to the number of expressions
+ ** in the change-list. Otherwise, set it to 0. There cannot be a FROM
+ ** clause if this function is being called to generate code for part of
+ ** an UPSERT statement. */
+ nChangeFrom = (pTabList->nSrc>1) ? pChanges->nExpr : 0;
+ assert( nChangeFrom==0 || pUpsert==0 );
+
#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
- if( !isView ){
+ if( !isView && nChangeFrom==0 ){
pWhere = sqlite3LimitWhere(
pParse, pTabList, pWhere, pOrderBy, pLimit, "UPDATE"
);
@@ -302,7 +447,9 @@ void sqlite3Update(
*/
chngRowid = chngPk = 0;
for(i=0; inExpr; i++){
- if( sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){
+ /* If this is an UPDATE with a FROM clause, do not resolve expressions
+ ** here. The call to sqlite3Select() below will do that. */
+ if( nChangeFrom==0 && sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){
goto update_cleanup;
}
for(j=0; jnCol; j++){
@@ -310,6 +457,7 @@ void sqlite3Update(
if( j==pTab->iPKey ){
chngRowid = 1;
pRowidExpr = pChanges->a[i].pExpr;
+ iRowidExpr = i;
}else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){
chngPk = 1;
}
@@ -332,6 +480,7 @@ void sqlite3Update(
j = -1;
chngRowid = 1;
pRowidExpr = pChanges->a[i].pExpr;
+ iRowidExpr = i;
}else{
sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zEName);
pParse->checkSchema = 1;
@@ -461,7 +610,7 @@ void sqlite3Update(
** an ephemeral table.
*/
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
- if( isView ){
+ if( nChangeFrom==0 && isView ){
sqlite3MaterializeView(pParse, pTab,
pWhere, pOrderBy, pLimit, iDataCur
);
@@ -473,7 +622,7 @@ void sqlite3Update(
/* Resolve the column names in all the expressions in the
** WHERE clause.
*/
- if( sqlite3ResolveExprNames(&sNC, pWhere) ){
+ if( nChangeFrom==0 && sqlite3ResolveExprNames(&sNC, pWhere) ){
goto update_cleanup;
}
@@ -500,105 +649,128 @@ void sqlite3Update(
sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
}
- if( HasRowid(pTab) ){
+ if( nChangeFrom==0 && HasRowid(pTab) ){
sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid);
}else{
- assert( pPk!=0 );
- nPk = pPk->nKeyCol;
+ assert( pPk!=0 || HasRowid(pTab) );
+ nPk = pPk ? pPk->nKeyCol : 0;
iPk = pParse->nMem+1;
pParse->nMem += nPk;
+ pParse->nMem += nChangeFrom;
regKey = ++pParse->nMem;
if( pUpsert==0 ){
+ int nEphCol = nPk + nChangeFrom + (isView ? pTab->nCol : 0);
iEph = pParse->nTab++;
- sqlite3VdbeAddOp3(v, OP_Null, 0, iPk, iPk+nPk-1);
- addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nPk);
- sqlite3VdbeSetP4KeyInfo(pParse, pPk);
+ if( pPk ) sqlite3VdbeAddOp3(v, OP_Null, 0, iPk, iPk+nPk-1);
+ addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nEphCol);
+ if( pPk ){
+ KeyInfo *pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pPk);
+ if( pKeyInfo ){
+ pKeyInfo->nAllField = nEphCol;
+ sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO);
+ }
+ }
+ if( nChangeFrom ){
+ updateFromSelect(
+ pParse, iEph, pPk, pChanges, pTabList, pWhere, pOrderBy, pLimit
+ );
+#ifndef SQLITE_OMIT_SUBQUERY
+ if( isView ) iDataCur = iEph;
+#endif
+ }
}
}
- if( pUpsert ){
- /* If this is an UPSERT, then all cursors have already been opened by
- ** the outer INSERT and the data cursor should be pointing at the row
- ** that is to be updated. So bypass the code that searches for the
- ** row(s) to be updated.
- */
- pWInfo = 0;
- eOnePass = ONEPASS_SINGLE;
- sqlite3ExprIfFalse(pParse, pWhere, labelBreak, SQLITE_JUMPIFNULL);
- bFinishSeek = 0;
+ if( nChangeFrom ){
+ sqlite3MultiWrite(pParse);
+ eOnePass = ONEPASS_OFF;
+ nKey = nPk;
+ regKey = iPk;
}else{
- /* Begin the database scan.
- **
- ** Do not consider a single-pass strategy for a multi-row update if
- ** there are any triggers or foreign keys to process, or rows may
- ** be deleted as a result of REPLACE conflict handling. Any of these
- ** things might disturb a cursor being used to scan through the table
- ** or index, causing a single-pass approach to malfunction. */
- flags = WHERE_ONEPASS_DESIRED|WHERE_SEEK_UNIQ_TABLE;
- if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){
- flags |= WHERE_ONEPASS_MULTIROW;
- }
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, flags, iIdxCur);
- if( pWInfo==0 ) goto update_cleanup;
-
- /* A one-pass strategy that might update more than one row may not
- ** be used if any column of the index used for the scan is being
- ** updated. Otherwise, if there is an index on "b", statements like
- ** the following could create an infinite loop:
- **
- ** UPDATE t1 SET b=b+1 WHERE b>?
- **
- ** Fall back to ONEPASS_OFF if where.c has selected a ONEPASS_MULTI
- ** strategy that uses an index for which one or more columns are being
- ** updated. */
- eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
- bFinishSeek = sqlite3WhereUsesDeferredSeek(pWInfo);
- if( eOnePass!=ONEPASS_SINGLE ){
- sqlite3MultiWrite(pParse);
- if( eOnePass==ONEPASS_MULTI ){
- int iCur = aiCurOnePass[1];
- if( iCur>=0 && iCur!=iDataCur && aToOpen[iCur-iBaseCur] ){
- eOnePass = ONEPASS_OFF;
+ if( pUpsert ){
+ /* If this is an UPSERT, then all cursors have already been opened by
+ ** the outer INSERT and the data cursor should be pointing at the row
+ ** that is to be updated. So bypass the code that searches for the
+ ** row(s) to be updated.
+ */
+ pWInfo = 0;
+ eOnePass = ONEPASS_SINGLE;
+ sqlite3ExprIfFalse(pParse, pWhere, labelBreak, SQLITE_JUMPIFNULL);
+ bFinishSeek = 0;
+ }else{
+ /* Begin the database scan.
+ **
+ ** Do not consider a single-pass strategy for a multi-row update if
+ ** there are any triggers or foreign keys to process, or rows may
+ ** be deleted as a result of REPLACE conflict handling. Any of these
+ ** things might disturb a cursor being used to scan through the table
+ ** or index, causing a single-pass approach to malfunction. */
+ flags = WHERE_ONEPASS_DESIRED|WHERE_SEEK_UNIQ_TABLE;
+ if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){
+ flags |= WHERE_ONEPASS_MULTIROW;
+ }
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, flags,iIdxCur);
+ if( pWInfo==0 ) goto update_cleanup;
+
+ /* A one-pass strategy that might update more than one row may not
+ ** be used if any column of the index used for the scan is being
+ ** updated. Otherwise, if there is an index on "b", statements like
+ ** the following could create an infinite loop:
+ **
+ ** UPDATE t1 SET b=b+1 WHERE b>?
+ **
+ ** Fall back to ONEPASS_OFF if where.c has selected a ONEPASS_MULTI
+ ** strategy that uses an index for which one or more columns are being
+ ** updated. */
+ eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
+ bFinishSeek = sqlite3WhereUsesDeferredSeek(pWInfo);
+ if( eOnePass!=ONEPASS_SINGLE ){
+ sqlite3MultiWrite(pParse);
+ if( eOnePass==ONEPASS_MULTI ){
+ int iCur = aiCurOnePass[1];
+ if( iCur>=0 && iCur!=iDataCur && aToOpen[iCur-iBaseCur] ){
+ eOnePass = ONEPASS_OFF;
+ }
+ assert( iCur!=iDataCur || !HasRowid(pTab) );
}
- assert( iCur!=iDataCur || !HasRowid(pTab) );
+ }
+ }
+
+ if( HasRowid(pTab) ){
+ /* Read the rowid of the current row of the WHERE scan. In ONEPASS_OFF
+ ** mode, write the rowid into the FIFO. In either of the one-pass modes,
+ ** leave it in register regOldRowid. */
+ sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid);
+ if( eOnePass==ONEPASS_OFF ){
+ /* We need to use regRowSet, so reallocate aRegIdx[nAllIdx] */
+ aRegIdx[nAllIdx] = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid);
+ }
+ }else{
+ /* Read the PK of the current row into an array of registers. In
+ ** ONEPASS_OFF mode, serialize the array into a record and store it in
+ ** the ephemeral table. Or, in ONEPASS_SINGLE or MULTI mode, change
+ ** the OP_OpenEphemeral instruction to a Noop (the ephemeral table
+ ** is not required) and leave the PK fields in the array of registers. */
+ for(i=0; iaiColumn[i]>=0 );
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur,
+ pPk->aiColumn[i], iPk+i);
+ }
+ if( eOnePass ){
+ if( addrOpen ) sqlite3VdbeChangeToNoop(v, addrOpen);
+ nKey = nPk;
+ regKey = iPk;
+ }else{
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey,
+ sqlite3IndexAffinityStr(db, pPk), nPk);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEph, regKey, iPk, nPk);
}
}
}
- if( HasRowid(pTab) ){
- /* Read the rowid of the current row of the WHERE scan. In ONEPASS_OFF
- ** mode, write the rowid into the FIFO. In either of the one-pass modes,
- ** leave it in register regOldRowid. */
- sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid);
- if( eOnePass==ONEPASS_OFF ){
- /* We need to use regRowSet, so reallocate aRegIdx[nAllIdx] */
- aRegIdx[nAllIdx] = ++pParse->nMem;
- sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid);
- }
- }else{
- /* Read the PK of the current row into an array of registers. In
- ** ONEPASS_OFF mode, serialize the array into a record and store it in
- ** the ephemeral table. Or, in ONEPASS_SINGLE or MULTI mode, change
- ** the OP_OpenEphemeral instruction to a Noop (the ephemeral table
- ** is not required) and leave the PK fields in the array of registers. */
- for(i=0; iaiColumn[i]>=0 );
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur,
- pPk->aiColumn[i], iPk+i);
- }
- if( eOnePass ){
- if( addrOpen ) sqlite3VdbeChangeToNoop(v, addrOpen);
- nKey = nPk;
- regKey = iPk;
- }else{
- sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey,
- sqlite3IndexAffinityStr(db, pPk), nPk);
- sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEph, regKey, iPk, nPk);
- }
- }
-
if( pUpsert==0 ){
- if( eOnePass!=ONEPASS_MULTI ){
+ if( nChangeFrom==0 && eOnePass!=ONEPASS_MULTI ){
sqlite3WhereEnd(pWInfo);
}
@@ -634,12 +806,31 @@ void sqlite3Update(
sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak);
VdbeCoverageIf(v, pPk==0);
VdbeCoverageIf(v, pPk!=0);
- }else if( pPk ){
+ }else if( pPk || nChangeFrom ){
labelContinue = sqlite3VdbeMakeLabel(pParse);
sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v);
- addrTop = sqlite3VdbeAddOp2(v, OP_RowData, iEph, regKey);
- sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey, 0);
- VdbeCoverage(v);
+ addrTop = sqlite3VdbeCurrentAddr(v);
+ if( nChangeFrom ){
+ if( !isView ){
+ if( pPk ){
+ for(i=0; i=0 );
+ if( nChangeFrom==0 ){
+ sqlite3ExprCode(pParse, pRowidExpr, regNewRowid);
+ }else{
+ sqlite3VdbeAddOp3(v, OP_Column, iEph, iRowidExpr, regNewRowid);
+ }
sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid); VdbeCoverage(v);
}
@@ -708,7 +904,13 @@ void sqlite3Update(
}else{
j = aXRef[i];
if( j>=0 ){
- sqlite3ExprCode(pParse, pChanges->a[j].pExpr, k);
+ if( nChangeFrom ){
+ int nOff = (isView ? pTab->nCol : nPk);
+ assert( eOnePass==ONEPASS_OFF );
+ sqlite3VdbeAddOp3(v, OP_Column, iEph, nOff+j, k);
+ }else{
+ sqlite3ExprCode(pParse, pChanges->a[j].pExpr, k);
+ }
}else if( 0==(tmask&TRIGGER_BEFORE) || i>31 || (newmask & MASKBIT32(i)) ){
/* This branch loads the value of a column that will not be changed
** into a register. This is done if there are no BEFORE triggers, or
@@ -740,43 +942,45 @@ void sqlite3Update(
sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
TRIGGER_BEFORE, pTab, regOldRowid, onError, labelContinue);
- /* The row-trigger may have deleted the row being updated. In this
- ** case, jump to the next row. No updates or AFTER triggers are
- ** required. This behavior - what happens when the row being updated
- ** is deleted or renamed by a BEFORE trigger - is left undefined in the
- ** documentation.
- */
- if( pPk ){
- sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue,regKey,nKey);
- VdbeCoverage(v);
- }else{
- sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid);
- VdbeCoverage(v);
- }
-
- /* After-BEFORE-trigger-reload-loop:
- ** If it did not delete it, the BEFORE trigger may still have modified
- ** some of the columns of the row being updated. Load the values for
- ** all columns not modified by the update statement into their registers
- ** in case this has happened. Only unmodified columns are reloaded.
- ** The values computed for modified columns use the values before the
- ** BEFORE trigger runs. See test case trigger1-18.0 (added 2018-04-26)
- ** for an example.
- */
- for(i=0, k=regNew; inCol; i++, k++){
- if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){
- if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) k--;
- }else if( aXRef[i]<0 && i!=pTab->iPKey ){
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k);
+ if( !isView ){
+ /* The row-trigger may have deleted the row being updated. In this
+ ** case, jump to the next row. No updates or AFTER triggers are
+ ** required. This behavior - what happens when the row being updated
+ ** is deleted or renamed by a BEFORE trigger - is left undefined in the
+ ** documentation.
+ */
+ if( pPk ){
+ sqlite3VdbeAddOp4Int(v, OP_NotFound,iDataCur,labelContinue,regKey,nKey);
+ VdbeCoverage(v);
+ }else{
+ sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue,regOldRowid);
+ VdbeCoverage(v);
+ }
+
+ /* After-BEFORE-trigger-reload-loop:
+ ** If it did not delete it, the BEFORE trigger may still have modified
+ ** some of the columns of the row being updated. Load the values for
+ ** all columns not modified by the update statement into their registers
+ ** in case this has happened. Only unmodified columns are reloaded.
+ ** The values computed for modified columns use the values before the
+ ** BEFORE trigger runs. See test case trigger1-18.0 (added 2018-04-26)
+ ** for an example.
+ */
+ for(i=0, k=regNew; inCol; i++, k++){
+ if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){
+ if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) k--;
+ }else if( aXRef[i]<0 && i!=pTab->iPKey ){
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k);
+ }
}
- }
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
- if( pTab->tabFlags & TF_HasGenerated ){
- testcase( pTab->tabFlags & TF_HasVirtual );
- testcase( pTab->tabFlags & TF_HasStored );
- sqlite3ComputeGeneratedColumns(pParse, regNew, pTab);
- }
+ if( pTab->tabFlags & TF_HasGenerated ){
+ testcase( pTab->tabFlags & TF_HasVirtual );
+ testcase( pTab->tabFlags & TF_HasStored );
+ sqlite3ComputeGeneratedColumns(pParse, regNew, pTab);
+ }
#endif
+ }
}
if( !isView ){
@@ -879,7 +1083,7 @@ void sqlite3Update(
}else if( eOnePass==ONEPASS_MULTI ){
sqlite3VdbeResolveLabel(v, labelContinue);
sqlite3WhereEnd(pWInfo);
- }else if( pPk ){
+ }else if( pPk || nChangeFrom ){
sqlite3VdbeResolveLabel(v, labelContinue);
sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop); VdbeCoverage(v);
}else{
@@ -964,7 +1168,7 @@ static void updateVirtualTable(
int i; /* Loop counter */
sqlite3 *db = pParse->db; /* Database connection */
const char *pVTab = (const char*)sqlite3GetVTable(db, pTab);
- WhereInfo *pWInfo;
+ WhereInfo *pWInfo = 0;
int nArg = 2 + pTab->nCol; /* Number of arguments to VUpdate */
int regArg; /* First register in VUpdate arg array */
int regRec; /* Register in which to assemble record */
@@ -982,69 +1186,96 @@ static void updateVirtualTable(
addr= sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, nArg);
regArg = pParse->nMem + 1;
pParse->nMem += nArg;
- regRec = ++pParse->nMem;
- regRowid = ++pParse->nMem;
-
- /* Start scanning the virtual table */
- pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0,0,WHERE_ONEPASS_DESIRED,0);
- if( pWInfo==0 ) return;
-
- /* Populate the argument registers. */
- for(i=0; inCol; i++){
- assert( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 );
- if( aXRef[i]>=0 ){
- sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
- }else{
- sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i);
- sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG);/* Enable sqlite3_vtab_nochange() */
- }
- }
- if( HasRowid(pTab) ){
- sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
+ if( pSrc->nSrc>1 ){
+ Expr *pRow;
+ ExprList *pList;
if( pRowid ){
- sqlite3ExprCode(pParse, pRowid, regArg+1);
+ pRow = sqlite3ExprDup(db, pRowid, 0);
}else{
- sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1);
+ pRow = sqlite3PExpr(pParse, TK_ROW, 0, 0);
}
+ pList = sqlite3ExprListAppend(pParse, 0, pRow);
+
+ for(i=0; inCol; i++){
+ if( aXRef[i]>=0 ){
+ pList = sqlite3ExprListAppend(pParse, pList,
+ sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr, 0)
+ );
+ }else{
+ pList = sqlite3ExprListAppend(pParse, pList, exprRowColumn(pParse, i));
+ }
+ }
+
+ updateFromSelect(pParse, ephemTab, 0, pList, pSrc, pWhere, 0, 0);
+ sqlite3ExprListDelete(db, pList);
+ eOnePass = ONEPASS_OFF;
}else{
- Index *pPk; /* PRIMARY KEY index */
- i16 iPk; /* PRIMARY KEY column */
- pPk = sqlite3PrimaryKeyIndex(pTab);
- assert( pPk!=0 );
- assert( pPk->nKeyCol==1 );
- iPk = pPk->aiColumn[0];
- sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, iPk, regArg);
- sqlite3VdbeAddOp2(v, OP_SCopy, regArg+2+iPk, regArg+1);
- }
+ regRec = ++pParse->nMem;
+ regRowid = ++pParse->nMem;
- eOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy);
+ /* Start scanning the virtual table */
+ pWInfo = sqlite3WhereBegin(pParse, pSrc,pWhere,0,0,WHERE_ONEPASS_DESIRED,0);
+ if( pWInfo==0 ) return;
- /* There is no ONEPASS_MULTI on virtual tables */
- assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE );
+ /* Populate the argument registers. */
+ for(i=0; inCol; i++){
+ assert( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 );
+ if( aXRef[i]>=0 ){
+ sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
+ }else{
+ sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i);
+ sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG);/* For sqlite3_vtab_nochange() */
+ }
+ }
+ if( HasRowid(pTab) ){
+ sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
+ if( pRowid ){
+ sqlite3ExprCode(pParse, pRowid, regArg+1);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1);
+ }
+ }else{
+ Index *pPk; /* PRIMARY KEY index */
+ i16 iPk; /* PRIMARY KEY column */
+ pPk = sqlite3PrimaryKeyIndex(pTab);
+ assert( pPk!=0 );
+ assert( pPk->nKeyCol==1 );
+ iPk = pPk->aiColumn[0];
+ sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, iPk, regArg);
+ sqlite3VdbeAddOp2(v, OP_SCopy, regArg+2+iPk, regArg+1);
+ }
- if( eOnePass ){
- /* If using the onepass strategy, no-op out the OP_OpenEphemeral coded
- ** above. */
- sqlite3VdbeChangeToNoop(v, addr);
- sqlite3VdbeAddOp1(v, OP_Close, iCsr);
- }else{
- /* Create a record from the argument register contents and insert it into
- ** the ephemeral table. */
- sqlite3MultiWrite(pParse);
- sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec);
-#ifdef SQLITE_DEBUG
- /* Signal an assert() within OP_MakeRecord that it is allowed to
- ** accept no-change records with serial_type 10 */
- sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC);
+ eOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy);
+
+ /* There is no ONEPASS_MULTI on virtual tables */
+ assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE );
+
+ if( eOnePass ){
+ /* If using the onepass strategy, no-op out the OP_OpenEphemeral coded
+ ** above. */
+ sqlite3VdbeChangeToNoop(v, addr);
+ sqlite3VdbeAddOp1(v, OP_Close, iCsr);
+ }else{
+ /* Create a record from the argument register contents and insert it into
+ ** the ephemeral table. */
+ sqlite3MultiWrite(pParse);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec);
+#if defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_NULL_TRIM)
+ /* Signal an assert() within OP_MakeRecord that it is allowed to
+ ** accept no-change records with serial_type 10 */
+ sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC);
#endif
- sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid);
- sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid);
+ sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid);
+ sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid);
+ }
}
if( eOnePass==ONEPASS_OFF ){
/* End the virtual table scan */
- sqlite3WhereEnd(pWInfo);
+ if( pSrc->nSrc==1 ){
+ sqlite3WhereEnd(pWInfo);
+ }
/* Begin scannning through the ephemeral table. */
addr = sqlite3VdbeAddOp1(v, OP_Rewind, ephemTab); VdbeCoverage(v);
diff --git a/src/utf.c b/src/utf.c
index 3a2becfbcc..5f27babdfc 100644
--- a/src/utf.c
+++ b/src/utf.c
@@ -342,9 +342,9 @@ SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
*z = 0;
assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len );
- c = pMem->flags;
+ c = MEM_Str|MEM_Term|(pMem->flags&(MEM_AffMask|MEM_Subtype));
sqlite3VdbeMemRelease(pMem);
- pMem->flags = MEM_Str|MEM_Term|(c&(MEM_AffMask|MEM_Subtype));
+ pMem->flags = c;
pMem->enc = desiredEnc;
pMem->z = (char*)zOut;
pMem->zMalloc = pMem->z;
diff --git a/src/util.c b/src/util.c
index 09520d1d62..2371aad17c 100644
--- a/src/util.c
+++ b/src/util.c
@@ -595,6 +595,30 @@ do_atof_calc:
#pragma warning(default : 4756)
#endif
+/*
+** Render an signed 64-bit integer as text. Store the result in zOut[].
+**
+** The caller must ensure that zOut[] is at least 21 bytes in size.
+*/
+void sqlite3Int64ToText(i64 v, char *zOut){
+ int i;
+ u64 x;
+ char zTemp[22];
+ if( v<0 ){
+ x = (v==SMALLEST_INT64) ? ((u64)1)<<63 : (u64)-v;
+ }else{
+ x = v;
+ }
+ i = sizeof(zTemp)-2;
+ zTemp[sizeof(zTemp)-1] = 0;
+ do{
+ zTemp[i--] = (x%10) + '0';
+ x = x/10;
+ }while( x );
+ if( v<0 ) zTemp[i--] = '-';
+ memcpy(zOut, &zTemp[i+1], sizeof(zTemp)-1-i);
+}
+
/*
** Compare the 19-character string zNum against the text representation
** value 2^63: 9223372036854775808. Return negative, zero, or positive
@@ -835,10 +859,28 @@ int sqlite3GetInt32(const char *zNum, int *pValue){
*/
int sqlite3Atoi(const char *z){
int x = 0;
- if( z ) sqlite3GetInt32(z, &x);
+ sqlite3GetInt32(z, &x);
return x;
}
+/*
+** Try to convert z into an unsigned 32-bit integer. Return true on
+** success and false if there is an error.
+**
+** Only decimal notation is accepted.
+*/
+int sqlite3GetUInt32(const char *z, u32 *pI){
+ u64 v = 0;
+ int i;
+ for(i=0; sqlite3Isdigit(z[i]); i++){
+ v = v*10 + z[i] - '0';
+ if( v>4294967296LL ){ *pI = 0; return 0; }
+ }
+ if( i==0 || z[i]!=0 ){ *pI = 0; return 0; }
+ *pI = (u32)v;
+ return 1;
+}
+
/*
** The variable-length integer encoding is as follows:
**
@@ -1141,8 +1183,7 @@ u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){
u64 v64;
u8 n;
- p -= 2;
- n = sqlite3GetVarint(p, &v64);
+ n = sqlite3GetVarint(p-2, &v64);
assert( n>3 && n<=9 );
if( (v64 & SQLITE_MAX_U32)!=v64 ){
*v = 0xffffffff;
diff --git a/src/vacuum.c b/src/vacuum.c
index f371d07bd2..35f8c98f10 100644
--- a/src/vacuum.c
+++ b/src/vacuum.c
@@ -41,7 +41,7 @@ static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
assert( sqlite3_strnicmp(zSql,"SELECT",6)==0 );
/* The secondary SQL must be one of CREATE TABLE, CREATE INDEX,
** or INSERT. Historically there have been attacks that first
- ** corrupt the sqlite_master.sql field with other kinds of statements
+ ** corrupt the sqlite_schema.sql field with other kinds of statements
** then run VACUUM to get those statements to execute at inappropriate
** times. */
if( zSubSql
@@ -273,14 +273,14 @@ SQLITE_NOINLINE int sqlite3RunVacuum(
*/
db->init.iDb = nDb; /* force new CREATE statements into vacuum_db */
rc = execSqlF(db, pzErrMsg,
- "SELECT sql FROM \"%w\".sqlite_master"
+ "SELECT sql FROM \"%w\".sqlite_schema"
" WHERE type='table'AND name<>'sqlite_sequence'"
" AND coalesce(rootpage,1)>0",
zDbMain
);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = execSqlF(db, pzErrMsg,
- "SELECT sql FROM \"%w\".sqlite_master"
+ "SELECT sql FROM \"%w\".sqlite_schema"
" WHERE type='index'",
zDbMain
);
@@ -294,7 +294,7 @@ SQLITE_NOINLINE int sqlite3RunVacuum(
rc = execSqlF(db, pzErrMsg,
"SELECT'INSERT INTO vacuum_db.'||quote(name)"
"||' SELECT*FROM\"%w\".'||quote(name)"
- "FROM vacuum_db.sqlite_master "
+ "FROM vacuum_db.sqlite_schema "
"WHERE type='table'AND coalesce(rootpage,1)>0",
zDbMain
);
@@ -305,11 +305,11 @@ SQLITE_NOINLINE int sqlite3RunVacuum(
/* Copy the triggers, views, and virtual tables from the main database
** over to the temporary database. None of these objects has any
** associated storage, so all we have to do is copy their entries
- ** from the SQLITE_MASTER table.
+ ** from the schema table.
*/
rc = execSqlF(db, pzErrMsg,
- "INSERT INTO vacuum_db.sqlite_master"
- " SELECT*FROM \"%w\".sqlite_master"
+ "INSERT INTO vacuum_db.sqlite_schema"
+ " SELECT*FROM \"%w\".sqlite_schema"
" WHERE type IN('view','trigger')"
" OR(type='table'AND rootpage=0)",
zDbMain
diff --git a/src/vdbe.c b/src/vdbe.c
index d7f14276fb..cbeda8c022 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -671,9 +671,9 @@ int sqlite3VdbeExec(
u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */
u8 encoding = ENC(db); /* The database encoding */
int iCompare = 0; /* Result of last comparison */
- unsigned nVmStep = 0; /* Number of virtual machine steps */
+ u64 nVmStep = 0; /* Number of virtual machine steps */
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
- unsigned nProgressLimit; /* Invoke xProgress() when nVmStep reaches this */
+ u64 nProgressLimit; /* Invoke xProgress() when nVmStep reaches this */
#endif
Mem *aMem = p->aMem; /* Copy of p->aMem */
Mem *pIn1 = 0; /* 1st input operand */
@@ -693,7 +693,7 @@ int sqlite3VdbeExec(
assert( 0 < db->nProgressOps );
nProgressLimit = db->nProgressOps - (iPrior % db->nProgressOps);
}else{
- nProgressLimit = 0xffffffff;
+ nProgressLimit = LARGEST_UINT64;
}
#endif
if( p->rc==SQLITE_NOMEM ){
@@ -702,6 +702,8 @@ int sqlite3VdbeExec(
goto no_mem;
}
assert( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_BUSY );
+ testcase( p->rc!=SQLITE_OK );
+ p->rc = SQLITE_OK;
assert( p->bIsReader || p->readOnly!=0 );
p->iCurrentTime = 0;
assert( p->explain==0 );
@@ -903,7 +905,7 @@ check_for_interrupt:
assert( db->nProgressOps!=0 );
nProgressLimit += db->nProgressOps;
if( db->xProgress(db->pProgressArg) ){
- nProgressLimit = 0xffffffff;
+ nProgressLimit = LARGEST_UINT64;
rc = SQLITE_INTERRUPT;
goto abort_due_to_error;
}
@@ -1031,6 +1033,7 @@ case OP_HaltIfNull: { /* in3 */
#endif
if( (pIn3->flags & MEM_Null)==0 ) break;
/* Fall through into OP_Halt */
+ /* no break */ deliberate_fall_through
}
/* Opcode: Halt P1 P2 * P4 P5
@@ -1201,6 +1204,7 @@ case OP_String8: { /* same as TK_STRING, out2 */
pOp->opcode = OP_String;
assert( rc==SQLITE_OK );
/* Fall through to the next case, OP_String */
+ /* no break */ deliberate_fall_through
}
/* Opcode: String P1 P2 P3 P4 P5
@@ -1512,7 +1516,7 @@ case OP_ResultRow: {
if( db->mallocFailed ) goto no_mem;
if( db->mTrace & SQLITE_TRACE_ROW ){
- db->xTrace(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
+ db->trace.xV2(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
}
@@ -2074,7 +2078,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
if( (flags1 | flags3)&MEM_Str ){
if( (flags1 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){
applyNumericAffinity(pIn1,0);
- assert( flags3==pIn3->flags );
+ testcase( flags3==pIn3->flags );
flags3 = pIn3->flags;
}
if( (flags3 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){
@@ -2248,10 +2252,10 @@ case OP_Compare: {
int p1;
int p2;
const KeyInfo *pKeyInfo;
- int idx;
+ u32 idx;
CollSeq *pColl; /* Collating sequence to use on this term */
int bRev; /* True for DESCENDING sort order */
- int *aPermute; /* The permutation */
+ u32 *aPermute; /* The permutation */
if( (pOp->p5 & OPFLAG_PERMUTE)==0 ){
aPermute = 0;
@@ -2271,7 +2275,7 @@ case OP_Compare: {
#ifdef SQLITE_DEBUG
if( aPermute ){
int k, mx = 0;
- for(k=0; kmx ) mx = aPermute[k];
+ for(k=0; k(u32)mx ) mx = aPermute[k];
assert( p1>0 && p1+mx<=(p->nMem+1 - p->nCursor)+1 );
assert( p2>0 && p2+mx<=(p->nMem+1 - p->nCursor)+1 );
}else{
@@ -2280,7 +2284,7 @@ case OP_Compare: {
}
#endif /* SQLITE_DEBUG */
for(i=0; ip1>=0 && pOp->p1nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
- p2 = pOp->p2;
+ p2 = (u32)pOp->p2;
/* If the cursor cache is stale (meaning it is not currently point at
** the correct row) then bring it up-to-date by doing the necessary
@@ -2621,7 +2625,7 @@ case OP_Column: {
pDest = &aMem[pOp->p3];
memAboutToChange(p, pDest);
assert( pC!=0 );
- assert( p2nField );
+ assert( p2<(u32)pC->nField );
aOffset = pC->aOffset;
assert( pC->eCurType!=CURTYPE_VTAB );
assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
@@ -2736,7 +2740,7 @@ case OP_Column: {
offset64 += sqlite3VdbeSerialTypeLen(t);
}
aOffset[++i] = (u32)(offset64 & 0xffffffff);
- }while( i<=p2 && zHdrp5==OPFLAG_NOCHNG_MAGIC || CORRUPT_DB );
+#endif
pRec->uTemp = 10;
}else{
pRec->uTemp = 0;
@@ -3614,7 +3631,7 @@ case OP_ReadCookie: { /* out2 */
break;
}
-/* Opcode: SetCookie P1 P2 P3 * *
+/* Opcode: SetCookie P1 P2 P3 * P5
**
** Write the integer value P3 into cookie number P2 of database P1.
** P2==1 is the schema version. P2==2 is the database format.
@@ -3623,6 +3640,11 @@ case OP_ReadCookie: { /* out2 */
** database file used to store temporary tables.
**
** A transaction must be started before executing this opcode.
+**
+** If P2 is the SCHEMA_VERSION cookie (cookie number 1) then the internal
+** schema version is set to P3-P5. The "PRAGMA schema_version=N" statement
+** has P5 set to 1, so that the internal schema version will be different
+** from the database schema version, resulting in a schema reset.
*/
case OP_SetCookie: {
Db *pDb;
@@ -3639,7 +3661,7 @@ case OP_SetCookie: {
rc = sqlite3BtreeUpdateMeta(pDb->pBt, pOp->p2, pOp->p3);
if( pOp->p2==BTREE_SCHEMA_VERSION ){
/* When the schema cookie changes, record the new cookie internally */
- pDb->pSchema->schema_cookie = pOp->p3;
+ pDb->pSchema->schema_cookie = pOp->p3 - pOp->p5;
db->mDbFlags |= DBFLAG_SchemaChange;
}else if( pOp->p2==BTREE_FILE_FORMAT ){
/* Record changes in the file format */
@@ -3742,7 +3764,7 @@ case OP_SetCookie: {
case OP_ReopenIdx: {
int nField;
KeyInfo *pKeyInfo;
- int p2;
+ u32 p2;
int iDb;
int wrFlag;
Btree *pX;
@@ -3773,7 +3795,7 @@ case OP_OpenWrite:
nField = 0;
pKeyInfo = 0;
- p2 = pOp->p2;
+ p2 = (u32)pOp->p2;
iDb = pOp->p3;
assert( iDb>=0 && iDbnDb );
assert( DbMaskTest(p->btreeMask, iDb) );
@@ -3792,7 +3814,7 @@ case OP_OpenWrite:
}
if( pOp->p5 & OPFLAG_P2ISREG ){
assert( p2>0 );
- assert( p2<=(p->nMem+1 - p->nCursor) );
+ assert( p2<=(u32)(p->nMem+1 - p->nCursor) );
assert( pOp->opcode==OP_OpenWrite );
pIn2 = &aMem[p2];
assert( memIsValid(pIn2) );
@@ -3945,10 +3967,10 @@ case OP_OpenEphemeral: {
*/
if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){
assert( pOp->p4type==P4_KEYINFO );
- rc = sqlite3BtreeCreateTable(pCx->pBtx, (int*)&pCx->pgnoRoot,
+ rc = sqlite3BtreeCreateTable(pCx->pBtx, &pCx->pgnoRoot,
BTREE_BLOBKEY | pOp->p5);
if( rc==SQLITE_OK ){
- assert( pCx->pgnoRoot==MASTER_ROOT+1 );
+ assert( pCx->pgnoRoot==SCHEMA_ROOT+1 );
assert( pKeyInfo->db==db );
assert( pKeyInfo->enc==ENC(db) );
rc = sqlite3BtreeCursor(pCx->pBtx, pCx->pgnoRoot, BTREE_WRCSR,
@@ -3956,8 +3978,8 @@ case OP_OpenEphemeral: {
}
pCx->isTable = 0;
}else{
- pCx->pgnoRoot = MASTER_ROOT;
- rc = sqlite3BtreeCursor(pCx->pBtx, MASTER_ROOT, BTREE_WRCSR,
+ pCx->pgnoRoot = SCHEMA_ROOT;
+ rc = sqlite3BtreeCursor(pCx->pBtx, SCHEMA_ROOT, BTREE_WRCSR,
0, pCx->uc.pCursor);
pCx->isTable = 1;
}
@@ -4365,7 +4387,7 @@ seek_not_found:
** Synopsis: seekHit=P2
**
** Set the seekHit flag on cursor P1 to the value in P2.
-* The seekHit flag is used by the IfNoHope opcode.
+** The seekHit flag is used by the IfNoHope opcode.
**
** P1 must be a valid b-tree cursor. P2 must be a boolean value,
** either 0 or 1.
@@ -4487,6 +4509,7 @@ case OP_IfNoHope: { /* jump, in3 */
assert( pC!=0 );
if( pC->seekHit ) break;
/* Fall through into OP_NotFound */
+ /* no break */ deliberate_fall_through
}
case OP_NoConflict: /* jump, in3 */
case OP_NotFound: /* jump, in3 */
@@ -4641,6 +4664,7 @@ case OP_SeekRowid: { /* jump, in3 */
goto notExistsWithKey;
}
/* Fall through into OP_NotExists */
+ /* no break */ deliberate_fall_through
case OP_NotExists: /* jump, in3 */
pIn3 = &aMem[pOp->p3];
assert( (pIn3->flags & MEM_Int)!=0 || pOp->opcode==OP_SeekRowid );
@@ -5209,10 +5233,6 @@ case OP_RowData: {
*/
assert( pC->deferredMoveto==0 );
assert( sqlite3BtreeCursorIsValid(pCrsr) );
-#if 0 /* Not required due to the previous to assert() statements */
- rc = sqlite3VdbeCursorMoveto(pC);
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
-#endif
n = sqlite3BtreePayloadSize(pCrsr);
if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
@@ -5416,6 +5436,7 @@ case OP_Sort: { /* jump */
#endif
p->aCounter[SQLITE_STMTSTATUS_SORT]++;
/* Fall through into OP_Rewind */
+ /* no break */ deliberate_fall_through
}
/* Opcode: Rewind P1 P2 * * *
**
@@ -5982,7 +6003,7 @@ case OP_Clear: {
assert( p->readOnly==0 );
assert( DbMaskTest(p->btreeMask, pOp->p2) );
rc = sqlite3BtreeClearTable(
- db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &nChange : 0)
+ db->aDb[pOp->p2].pBt, (u32)pOp->p1, (pOp->p3 ? &nChange : 0)
);
if( pOp->p3 ){
p->nChange += nChange;
@@ -6031,7 +6052,7 @@ case OP_ResetSorter: {
** The root page number of the new b-tree is stored in register P2.
*/
case OP_CreateBtree: { /* out2 */
- int pgno;
+ Pgno pgno;
Db *pDb;
sqlite3VdbeIncrWriteCounter(p, 0);
@@ -6064,7 +6085,7 @@ case OP_SqlExec: {
/* Opcode: ParseSchema P1 * * P4 *
**
-** Read and parse all entries from the SQLITE_MASTER table of database P1
+** Read and parse all entries from the schema table of database P1
** that match the WHERE clause P4. If P4 is a NULL pointer, then the
** entire schema for P1 is reparsed.
**
@@ -6073,7 +6094,7 @@ case OP_SqlExec: {
*/
case OP_ParseSchema: {
int iDb;
- const char *zMaster;
+ const char *zSchema;
char *zSql;
InitData initData;
@@ -6101,14 +6122,15 @@ case OP_ParseSchema: {
}else
#endif
{
- zMaster = MASTER_NAME;
+ zSchema = DFLT_SCHEMA_TABLE;
initData.db = db;
initData.iDb = iDb;
initData.pzErrMsg = &p->zErrMsg;
initData.mInitFlags = 0;
+ initData.mxPage = sqlite3BtreeLastPage(db->aDb[iDb].pBt);
zSql = sqlite3MPrintf(db,
"SELECT*FROM\"%w\".%s WHERE %s ORDER BY rowid",
- db->aDb[iDb].zDbSName, zMaster, pOp->p4.z);
+ db->aDb[iDb].zDbSName, zSchema, pOp->p4.z);
if( zSql==0 ){
rc = SQLITE_NOMEM_BKPT;
}else{
@@ -6122,7 +6144,7 @@ case OP_ParseSchema: {
if( rc==SQLITE_OK && initData.nInitRow==0 ){
/* The OP_ParseSchema opcode with a non-NULL P4 argument should parse
** at least one SQL statement. Any less than that indicates that
- ** the sqlite_master table is corrupt. */
+ ** the sqlite_schema table is corrupt. */
rc = SQLITE_CORRUPT_BKPT;
}
sqlite3DbFreeNN(db, zSql);
@@ -6219,7 +6241,7 @@ case OP_DropTrigger: {
*/
case OP_IntegrityCk: {
int nRoot; /* Number of tables to check. (Number of root pages.) */
- int *aRoot; /* Array of rootpage numbers for tables to be checked */
+ Pgno *aRoot; /* Array of rootpage numbers for tables to be checked */
int nErr; /* Number of errors reported */
char *z; /* Text of the error report */
Mem *pnErr; /* Register keeping track of errors remaining */
@@ -6228,7 +6250,7 @@ case OP_IntegrityCk: {
nRoot = pOp->p2;
aRoot = pOp->p4.ai;
assert( nRoot>0 );
- assert( aRoot[0]==nRoot );
+ assert( aRoot[0]==(Pgno)nRoot );
assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
pnErr = &aMem[pOp->p3];
assert( (pnErr->flags & MEM_Int)!=0 );
@@ -6768,6 +6790,7 @@ case OP_AggStep: {
pOp->opcode = OP_AggStep1;
/* Fall through into OP_AggStep */
+ /* no break */ deliberate_fall_through
}
case OP_AggStep1: {
int i;
@@ -7757,18 +7780,17 @@ case OP_Init: { /* jump */
){
#ifndef SQLITE_OMIT_DEPRECATED
if( db->mTrace & SQLITE_TRACE_LEGACY ){
- void (*x)(void*,const char*) = (void(*)(void*,const char*))db->xTrace;
char *z = sqlite3VdbeExpandSql(p, zTrace);
- x(db->pTraceArg, z);
+ db->trace.xLegacy(db->pTraceArg, z);
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);
+ (void)db->trace.xV2(SQLITE_TRACE_STMT, db->pTraceArg, p, z);
sqlite3DbFree(db, z);
}else{
- (void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace);
+ (void)db->trace.xV2(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace);
}
}
#ifdef SQLITE_USE_FCNTL_TRACE
@@ -7981,7 +8003,7 @@ vdbe_return:
while( nVmStep>=nProgressLimit && db->xProgress!=0 ){
nProgressLimit += db->nProgressOps;
if( db->xProgress(db->pProgressArg) ){
- nProgressLimit = 0xffffffff;
+ nProgressLimit = LARGEST_UINT64;
rc = SQLITE_INTERRUPT;
goto abort_due_to_error;
}
@@ -8015,8 +8037,6 @@ no_mem:
*/
abort_due_to_interrupt:
assert( AtomicLoad(&db->u1.isInterrupted) );
- rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
- p->rc = rc;
- sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
+ rc = SQLITE_INTERRUPT;
goto abort_due_to_error;
}
diff --git a/src/vdbe.h b/src/vdbe.h
index 73974e6056..2f7c7d2bf6 100644
--- a/src/vdbe.h
+++ b/src/vdbe.h
@@ -57,7 +57,7 @@ struct VdbeOp {
Mem *pMem; /* Used when p4type is P4_MEM */
VTable *pVtab; /* Used when p4type is P4_VTAB */
KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */
- int *ai; /* Used when p4type is P4_INTARRAY */
+ u32 *ai; /* Used when p4type is P4_INTARRAY */
SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */
Table *pTab; /* Used when p4type is P4_TABLE */
#ifdef SQLITE_ENABLE_CURSOR_HINTS
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index e461983122..901569742f 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -89,7 +89,7 @@ struct VdbeCursor {
Bool seekHit:1; /* See the OP_SeekHit and OP_IfNoHope opcodes */
Btree *pBtx; /* Separate file holding temporary table */
i64 seqCount; /* Sequence counter */
- int *aAltMap; /* Mapping from table to index column numbers */
+ u32 *aAltMap; /* Mapping from table to index column numbers */
/* Cached OP_Column parse information is only valid if cacheStatus matches
** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of
@@ -485,7 +485,7 @@ void sqlite3VdbeError(Vdbe*, const char *, ...);
void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
void sqliteVdbePopStack(Vdbe*,int);
int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor*);
-int sqlite3VdbeCursorMoveto(VdbeCursor**, int*);
+int sqlite3VdbeCursorMoveto(VdbeCursor**, u32*);
int sqlite3VdbeCursorRestore(VdbeCursor*);
u32 sqlite3VdbeSerialTypeLen(u32);
u8 sqlite3VdbeOneByteSerialTypeLen(u8);
diff --git a/src/vdbeapi.c b/src/vdbeapi.c
index b9ac9fa797..a9cbf92fc3 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -73,7 +73,7 @@ static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){
}
#endif
if( db->mTrace & SQLITE_TRACE_PROFILE ){
- db->xTrace(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse);
+ db->trace.xV2(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse);
}
p->startTime = 0;
}
@@ -655,6 +655,13 @@ static int sqlite3Step(Vdbe *p){
if( p->pc<0 && p->expired ){
p->rc = SQLITE_SCHEMA;
rc = SQLITE_ERROR;
+ if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ){
+ /* If this statement was prepared using saved SQL and an
+ ** error has occurred, then return the error code in p->rc to the
+ ** caller. Set the error code in the database handle to the same value.
+ */
+ rc = sqlite3VdbeTransferError(p);
+ }
goto end_of_step;
}
if( p->pc<0 ){
@@ -710,35 +717,27 @@ static int sqlite3Step(Vdbe *p){
if( p->rc!=SQLITE_OK ){
rc = SQLITE_ERROR;
}
+ }else if( rc!=SQLITE_DONE && (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ){
+ /* If this statement was prepared using saved SQL and an
+ ** error has occurred, then return the error code in p->rc to the
+ ** caller. Set the error code in the database handle to the same value.
+ */
+ rc = sqlite3VdbeTransferError(p);
}
}
db->errCode = rc;
if( SQLITE_NOMEM==sqlite3ApiExit(p->db, p->rc) ){
p->rc = SQLITE_NOMEM_BKPT;
+ if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ) rc = p->rc;
}
end_of_step:
- /* At this point local variable rc holds the value that should be
- ** returned if this statement was compiled using the legacy
- ** sqlite3_prepare() interface. According to the docs, this can only
- ** be one of the values in the first assert() below. Variable p->rc
- ** contains the value that would be returned if sqlite3_finalize()
- ** were called on statement p.
- */
- assert( rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR
+ /* There are only a limited number of result codes allowed from the
+ ** statements prepared using the legacy sqlite3_prepare() interface */
+ assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0
+ || rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR
|| (rc&0xff)==SQLITE_BUSY || rc==SQLITE_MISUSE
);
- assert( (p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE) || p->rc==p->rcApp );
- if( rc!=SQLITE_ROW
- && rc!=SQLITE_DONE
- && (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0
- ){
- /* If this statement was prepared using saved SQL and an
- ** error has occurred, then return the error code in p->rc to the
- ** caller. Set the error code in the database handle to the same value.
- */
- rc = sqlite3VdbeTransferError(p);
- }
return (rc&db->errMask);
}
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index a136898a7a..fcdccb3297 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -810,7 +810,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
switch( pOp->opcode ){
case OP_Transaction: {
if( pOp->p2!=0 ) p->readOnly = 0;
- /* fall thru */
+ /* no break */ deliberate_fall_through
}
case OP_AutoCommit:
case OP_Savepoint: {
@@ -857,6 +857,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
n = pOp[-1].p1;
if( n>nMaxArgs ) nMaxArgs = n;
/* Fall through into the default case */
+ /* no break */ deliberate_fall_through
}
#endif
default: {
@@ -1714,12 +1715,12 @@ char *sqlite3VdbeDisplayP4(sqlite3 *db, Op *pOp){
}
#endif
case P4_INTARRAY: {
- int i;
- int *ai = pOp->p4.ai;
- int n = ai[0]; /* The first element of an INTARRAY is always the
+ u32 i;
+ u32 *ai = pOp->p4.ai;
+ u32 n = ai[0]; /* The first element of an INTARRAY is always the
** count of the number of elements to follow */
for(i=1; i<=n; i++){
- sqlite3_str_appendf(&x, "%c%d", (i==1 ? '[' : ','), ai[i]);
+ sqlite3_str_appendf(&x, "%c%u", (i==1 ? '[' : ','), ai[i]);
}
sqlite3_str_append(&x, "]", 1);
break;
@@ -2631,13 +2632,13 @@ int sqlite3VdbeSetColName(
** A read or write transaction may or may not be active on database handle
** db. If a transaction is active, commit it. If there is a
** write-transaction spanning more than one database file, this routine
-** takes care of the master journal trickery.
+** takes care of the super-journal trickery.
*/
static int vdbeCommit(sqlite3 *db, Vdbe *p){
int i;
int nTrans = 0; /* Number of databases with an active write-transaction
** that are candidates for a two-phase commit using a
- ** master-journal */
+ ** super-journal */
int rc = SQLITE_OK;
int needXcommit = 0;
@@ -2650,7 +2651,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
/* Before doing anything else, call the xSync() callback for any
** virtual module tables written in this transaction. This has to
- ** be done before determining whether a master journal file is
+ ** be done before determining whether a super-journal file is
** required, as an xSync() callback may add an attached database
** to the transaction.
*/
@@ -2659,15 +2660,15 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
/* This loop determines (a) if the commit hook should be invoked and
** (b) how many database files have open write transactions, not
** including the temp database. (b) is important because if more than
- ** one database file has an open write transaction, a master journal
+ ** one database file has an open write transaction, a super-journal
** file is required for an atomic commit.
*/
for(i=0; rc==SQLITE_OK && inDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( sqlite3BtreeIsInTrans(pBt) ){
- /* Whether or not a database might need a master journal depends upon
+ /* Whether or not a database might need a super-journal depends upon
** its journal mode (among other things). This matrix determines which
- ** journal modes use a master journal and which do not */
+ ** journal modes use a super-journal and which do not */
static const u8 aMJNeeded[] = {
/* DELETE */ 1,
/* PERSIST */ 1,
@@ -2705,7 +2706,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
/* The simple case - no more than one database file (not counting the
** TEMP database) has a transaction active. There is no need for the
- ** master-journal.
+ ** super-journal.
**
** If the return value of sqlite3BtreeGetFilename() is a zero length
** string, it means the main database is :memory: or a temp file. In
@@ -2739,62 +2740,62 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
}
/* The complex case - There is a multi-file write-transaction active.
- ** This requires a master journal file to ensure the transaction is
+ ** This requires a super-journal file to ensure the transaction is
** committed atomically.
*/
#ifndef SQLITE_OMIT_DISKIO
else{
sqlite3_vfs *pVfs = db->pVfs;
- char *zMaster = 0; /* File-name for the master journal */
+ char *zSuper = 0; /* File-name for the super-journal */
char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt);
- sqlite3_file *pMaster = 0;
+ sqlite3_file *pSuperJrnl = 0;
i64 offset = 0;
int res;
int retryCount = 0;
int nMainFile;
- /* Select a master journal file name */
+ /* Select a super-journal file name */
nMainFile = sqlite3Strlen30(zMainFile);
- zMaster = sqlite3MPrintf(db, "%.4c%s%.16c", 0,zMainFile,0);
- if( zMaster==0 ) return SQLITE_NOMEM_BKPT;
- zMaster += 4;
+ zSuper = sqlite3MPrintf(db, "%.4c%s%.16c", 0,zMainFile,0);
+ if( zSuper==0 ) return SQLITE_NOMEM_BKPT;
+ zSuper += 4;
do {
u32 iRandom;
if( retryCount ){
if( retryCount>100 ){
- sqlite3_log(SQLITE_FULL, "MJ delete: %s", zMaster);
- sqlite3OsDelete(pVfs, zMaster, 0);
+ sqlite3_log(SQLITE_FULL, "MJ delete: %s", zSuper);
+ sqlite3OsDelete(pVfs, zSuper, 0);
break;
}else if( retryCount==1 ){
- sqlite3_log(SQLITE_FULL, "MJ collide: %s", zMaster);
+ sqlite3_log(SQLITE_FULL, "MJ collide: %s", zSuper);
}
}
retryCount++;
sqlite3_randomness(sizeof(iRandom), &iRandom);
- sqlite3_snprintf(13, &zMaster[nMainFile], "-mj%06X9%02X",
+ sqlite3_snprintf(13, &zSuper[nMainFile], "-mj%06X9%02X",
(iRandom>>8)&0xffffff, iRandom&0xff);
- /* The antipenultimate character of the master journal name must
+ /* The antipenultimate character of the super-journal name must
** be "9" to avoid name collisions when using 8+3 filenames. */
- assert( zMaster[sqlite3Strlen30(zMaster)-3]=='9' );
- sqlite3FileSuffix3(zMainFile, zMaster);
- rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res);
+ assert( zSuper[sqlite3Strlen30(zSuper)-3]=='9' );
+ sqlite3FileSuffix3(zMainFile, zSuper);
+ rc = sqlite3OsAccess(pVfs, zSuper, SQLITE_ACCESS_EXISTS, &res);
}while( rc==SQLITE_OK && res );
if( rc==SQLITE_OK ){
- /* Open the master journal. */
- rc = sqlite3OsOpenMalloc(pVfs, zMaster, &pMaster,
+ /* Open the super-journal. */
+ rc = sqlite3OsOpenMalloc(pVfs, zSuper, &pSuperJrnl,
SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|
- SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_MASTER_JOURNAL, 0
+ SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_SUPER_JOURNAL, 0
);
}
if( rc!=SQLITE_OK ){
- sqlite3DbFree(db, zMaster-4);
+ sqlite3DbFree(db, zSuper-4);
return rc;
}
/* Write the name of each database file in the transaction into the new
- ** master journal file. If an error occurs at this point close
- ** and delete the master journal file. All the individual journal files
- ** still have 'null' as the master journal pointer, so they will roll
+ ** super-journal file. If an error occurs at this point close
+ ** and delete the super-journal file. All the individual journal files
+ ** still have 'null' as the super-journal pointer, so they will roll
** back independently if a failure occurs.
*/
for(i=0; inDb; i++){
@@ -2805,59 +2806,59 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
continue; /* Ignore TEMP and :memory: databases */
}
assert( zFile[0]!=0 );
- rc = sqlite3OsWrite(pMaster, zFile, sqlite3Strlen30(zFile)+1, offset);
+ rc = sqlite3OsWrite(pSuperJrnl, zFile, sqlite3Strlen30(zFile)+1,offset);
offset += sqlite3Strlen30(zFile)+1;
if( rc!=SQLITE_OK ){
- sqlite3OsCloseFree(pMaster);
- sqlite3OsDelete(pVfs, zMaster, 0);
- sqlite3DbFree(db, zMaster-4);
+ sqlite3OsCloseFree(pSuperJrnl);
+ sqlite3OsDelete(pVfs, zSuper, 0);
+ sqlite3DbFree(db, zSuper-4);
return rc;
}
}
}
- /* Sync the master journal file. If the IOCAP_SEQUENTIAL device
+ /* Sync the super-journal file. If the IOCAP_SEQUENTIAL device
** flag is set this is not required.
*/
- if( 0==(sqlite3OsDeviceCharacteristics(pMaster)&SQLITE_IOCAP_SEQUENTIAL)
- && SQLITE_OK!=(rc = sqlite3OsSync(pMaster, SQLITE_SYNC_NORMAL))
+ if( 0==(sqlite3OsDeviceCharacteristics(pSuperJrnl)&SQLITE_IOCAP_SEQUENTIAL)
+ && SQLITE_OK!=(rc = sqlite3OsSync(pSuperJrnl, SQLITE_SYNC_NORMAL))
){
- sqlite3OsCloseFree(pMaster);
- sqlite3OsDelete(pVfs, zMaster, 0);
- sqlite3DbFree(db, zMaster-4);
+ sqlite3OsCloseFree(pSuperJrnl);
+ sqlite3OsDelete(pVfs, zSuper, 0);
+ sqlite3DbFree(db, zSuper-4);
return rc;
}
/* Sync all the db files involved in the transaction. The same call
- ** sets the master journal pointer in each individual journal. If
- ** an error occurs here, do not delete the master journal file.
+ ** sets the super-journal pointer in each individual journal. If
+ ** an error occurs here, do not delete the super-journal file.
**
** If the error occurs during the first call to
** sqlite3BtreeCommitPhaseOne(), then there is a chance that the
- ** master journal file will be orphaned. But we cannot delete it,
- ** in case the master journal file name was written into the journal
+ ** super-journal file will be orphaned. But we cannot delete it,
+ ** in case the super-journal file name was written into the journal
** file before the failure occurred.
*/
for(i=0; rc==SQLITE_OK && inDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
- rc = sqlite3BtreeCommitPhaseOne(pBt, zMaster);
+ rc = sqlite3BtreeCommitPhaseOne(pBt, zSuper);
}
}
- sqlite3OsCloseFree(pMaster);
+ sqlite3OsCloseFree(pSuperJrnl);
assert( rc!=SQLITE_BUSY );
if( rc!=SQLITE_OK ){
- sqlite3DbFree(db, zMaster-4);
+ sqlite3DbFree(db, zSuper-4);
return rc;
}
- /* Delete the master journal file. This commits the transaction. After
+ /* Delete the super-journal file. This commits the transaction. After
** doing this the directory is synced again before any individual
** transaction files are deleted.
*/
- rc = sqlite3OsDelete(pVfs, zMaster, 1);
- sqlite3DbFree(db, zMaster-4);
- zMaster = 0;
+ rc = sqlite3OsDelete(pVfs, zSuper, 1);
+ sqlite3DbFree(db, zSuper-4);
+ zSuper = 0;
if( rc ){
return rc;
}
@@ -3304,7 +3305,11 @@ int sqlite3VdbeReset(Vdbe *p){
*/
if( p->pc>=0 ){
vdbeInvokeSqllog(p);
- sqlite3VdbeTransferError(p);
+ if( db->pErr || p->zErrMsg ){
+ sqlite3VdbeTransferError(p);
+ }else{
+ db->errCode = p->rc;
+ }
if( p->runOnlyOnce ) p->expired = 1;
}else if( p->rc && p->expired ){
/* The expired flag was set on the VDBE before the first call
@@ -3324,8 +3329,10 @@ int sqlite3VdbeReset(Vdbe *p){
for(i=0; inMem; i++) assert( p->aMem[i].flags==MEM_Undefined );
}
#endif
- sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = 0;
+ if( p->zErrMsg ){
+ sqlite3DbFree(db, p->zErrMsg);
+ p->zErrMsg = 0;
+ }
p->pResultSet = 0;
#ifdef SQLITE_DEBUG
p->nWrite = 0;
@@ -3557,11 +3564,11 @@ int sqlite3VdbeCursorRestore(VdbeCursor *p){
** If the cursor is already pointing to the correct row and that row has
** not been deleted out from under the cursor, then this routine is a no-op.
*/
-int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){
+int sqlite3VdbeCursorMoveto(VdbeCursor **pp, u32 *piCol){
VdbeCursor *p = *pp;
assert( p->eCurType==CURTYPE_BTREE || p->eCurType==CURTYPE_PSEUDO );
if( p->deferredMoveto ){
- int iMap;
+ u32 iMap;
if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 && !p->nullRow ){
*pp = p->pAltCursor;
*piCol = iMap - 1;
diff --git a/src/vdbemem.c b/src/vdbemem.c
index 16d1ac8b08..384eacc015 100644
--- a/src/vdbemem.c
+++ b/src/vdbemem.c
@@ -104,16 +104,25 @@ int sqlite3VdbeCheckMemInvariants(Mem *p){
static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){
StrAccum acc;
assert( p->flags & (MEM_Int|MEM_Real|MEM_IntReal) );
- sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0);
+ assert( sz>22 );
if( p->flags & MEM_Int ){
- sqlite3_str_appendf(&acc, "%lld", p->u.i);
- }else if( p->flags & MEM_IntReal ){
- sqlite3_str_appendf(&acc, "%!.15g", (double)p->u.i);
+#if GCC_VERSION>=7000000
+ /* Work-around for GCC bug
+ ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270 */
+ i64 x;
+ assert( (p->flags&MEM_Int)*2==sizeof(x) );
+ memcpy(&x, (char*)&p->u, (p->flags&MEM_Int)*2);
+ sqlite3Int64ToText(x, zBuf);
+#else
+ sqlite3Int64ToText(p->u.i, zBuf);
+#endif
}else{
- sqlite3_str_appendf(&acc, "%!.15g", p->u.r);
+ sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0);
+ sqlite3_str_appendf(&acc, "%!.15g",
+ (p->flags & MEM_IntReal)!=0 ? (double)p->u.i : p->u.r);
+ assert( acc.zText==zBuf && acc.mxAlloc<=0 );
+ zBuf[acc.nChar] = 0; /* Fast version of sqlite3StrAccumFinish(&acc) */
}
- assert( acc.zText==zBuf && acc.mxAlloc<=0 );
- zBuf[acc.nChar] = 0; /* Fast version of sqlite3StrAccumFinish(&acc) */
}
#ifdef SQLITE_DEBUG
diff --git a/src/vdbevtab.c b/src/vdbevtab.c
index 2fbee62571..e9bafd450f 100644
--- a/src/vdbevtab.c
+++ b/src/vdbevtab.c
@@ -206,7 +206,7 @@ static int bytecodevtabColumn(
Schema *pSchema;
HashElem *k;
int iDb = pOp->p3;
- int iRoot = pOp->p2;
+ Pgno iRoot = (Pgno)pOp->p2;
sqlite3 *db = pVTab->db;
pSchema = db->aDb[iDb].pSchema;
pCur->zSchema = db->aDb[iDb].zDbSName;
diff --git a/src/vtab.c b/src/vtab.c
index e52d4bde81..2fc48d147c 100644
--- a/src/vtab.c
+++ b/src/vtab.c
@@ -423,7 +423,7 @@ void sqlite3VtabBeginParse(
#ifndef SQLITE_OMIT_AUTHORIZATION
/* Creating a virtual table invokes the authorization callback twice.
** The first invocation, to obtain permission to INSERT a row into the
- ** sqlite_master table, has already been made by sqlite3StartTable().
+ ** sqlite_schema table, has already been made by sqlite3StartTable().
** The second call, to obtain permission to create the table, is made now.
*/
if( pTable->azModuleArg ){
@@ -464,9 +464,9 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
/* If the CREATE VIRTUAL TABLE statement is being entered for the
** first time (in other words if the virtual table is actually being
- ** created now instead of just being read out of sqlite_master) then
+ ** created now instead of just being read out of sqlite_schema) then
** do additional initialization work and store the statement text
- ** in the sqlite_master table.
+ ** in the sqlite_schema table.
*/
if( !db->init.busy ){
char *zStmt;
@@ -484,19 +484,19 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
zStmt = sqlite3MPrintf(db, "CREATE VIRTUAL TABLE %T", &pParse->sNameToken);
/* A slot for the record has already been allocated in the
- ** SQLITE_MASTER table. We just need to update that slot with all
+ ** schema table. We just need to update that slot with all
** the information we've collected.
**
** The VM register number pParse->regRowid holds the rowid of an
- ** entry in the sqlite_master table tht was created for this vtab
+ ** entry in the sqlite_schema table tht was created for this vtab
** by sqlite3StartTable().
*/
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
sqlite3NestedParse(pParse,
- "UPDATE %Q.%s "
+ "UPDATE %Q." DFLT_SCHEMA_TABLE " "
"SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q "
"WHERE rowid=#%d",
- db->aDb[iDb].zDbSName, MASTER_NAME,
+ db->aDb[iDb].zDbSName,
pTab->zName,
pTab->zName,
zStmt,
@@ -515,7 +515,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg);
}
- /* If we are rereading the sqlite_master table create the in-memory
+ /* If we are rereading the sqlite_schema table create the in-memory
** record of the table. The xConnect() method is not called until
** the first time the virtual table is used in an SQL statement. This
** allows a schema that contains virtual tables to be loaded before
diff --git a/src/wal.c b/src/wal.c
index 52087e1296..0ef08b1377 100644
--- a/src/wal.c
+++ b/src/wal.c
@@ -508,7 +508,7 @@ typedef u16 ht_slot;
** This functionality is used by the checkpoint code (see walCheckpoint()).
*/
struct WalIterator {
- int iPrior; /* Last result returned from the iterator */
+ u32 iPrior; /* Last result returned from the iterator */
int nSegment; /* Number of entries in aSegment[] */
struct WalSegment {
int iNext; /* Next slot in aIndex[] not yet returned */
@@ -590,7 +590,9 @@ static SQLITE_NOINLINE int walIndexPageRealloc(
);
assert( pWal->apWiData[iPage]!=0 || rc!=SQLITE_OK || pWal->writeLock==0 );
testcase( pWal->apWiData[iPage]==0 && rc==SQLITE_OK );
- if( (rc&0xff)==SQLITE_READONLY ){
+ if( rc==SQLITE_OK ){
+ if( iPage>0 && sqlite3FaultSim(600) ) rc = SQLITE_NOMEM;
+ }else if( (rc&0xff)==SQLITE_READONLY ){
pWal->readOnly |= WAL_SHM_RDONLY;
if( rc==SQLITE_READONLY ){
rc = SQLITE_OK;
@@ -965,6 +967,7 @@ static int walFramePage(u32 iFrame){
&& (iHash>=2 || iFrame<=HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE)
&& (iHash<=2 || iFrame>(HASHTABLE_NPAGE_ONE+2*HASHTABLE_NPAGE))
);
+ assert( iHash>=0 );
return iHash;
}
@@ -1096,7 +1099,7 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT;
}
sLoc.aPgno[idx] = iPage;
- sLoc.aHash[iKey] = (ht_slot)idx;
+ AtomicStore(&sLoc.aHash[iKey], (ht_slot)idx);
#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
/* Verify that the number of entries in the hash table exactly equals
@@ -1161,12 +1164,6 @@ static int walIndexRecover(Wal *pWal){
assert( pWal->writeLock );
iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
rc = walLockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
- if( rc==SQLITE_OK ){
- rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
- if( rc!=SQLITE_OK ){
- walUnlockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
- }
- }
if( rc ){
return rc;
}
@@ -1182,15 +1179,16 @@ static int walIndexRecover(Wal *pWal){
if( nSize>WAL_HDRSIZE ){
u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */
+ u32 *aPrivate = 0; /* Heap copy of *-shm hash being populated */
u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */
int szFrame; /* Number of bytes in buffer aFrame[] */
u8 *aData; /* Pointer to data part of aFrame buffer */
- int iFrame; /* Index of last frame read */
- i64 iOffset; /* Next offset to read from log file */
int szPage; /* Page size according to the log */
u32 magic; /* Magic value read from WAL header */
u32 version; /* Magic value read from WAL header */
int isValid; /* True if this frame is valid */
+ u32 iPg; /* Current 32KB wal-index page */
+ u32 iLastFrame; /* Last frame in wal, based on nSize alone */
/* Read in the WAL header. */
rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
@@ -1237,38 +1235,82 @@ static int walIndexRecover(Wal *pWal){
/* Malloc a buffer to read frames into. */
szFrame = szPage + WAL_FRAME_HDRSIZE;
- aFrame = (u8 *)sqlite3_malloc64(szFrame);
+ aFrame = (u8 *)sqlite3_malloc64(szFrame + WALINDEX_PGSZ);
if( !aFrame ){
rc = SQLITE_NOMEM_BKPT;
goto recovery_error;
}
aData = &aFrame[WAL_FRAME_HDRSIZE];
+ aPrivate = (u32*)&aData[szPage];
/* Read all frames from the log file. */
- iFrame = 0;
- for(iOffset=WAL_HDRSIZE; (iOffset+szFrame)<=nSize; iOffset+=szFrame){
- u32 pgno; /* Database page number for frame */
- u32 nTruncate; /* dbsize field from frame header */
+ iLastFrame = (nSize - WAL_HDRSIZE) / szFrame;
+ for(iPg=0; iPg<=(u32)walFramePage(iLastFrame); iPg++){
+ u32 *aShare;
+ u32 iFrame; /* Index of last frame read */
+ u32 iLast = MIN(iLastFrame, HASHTABLE_NPAGE_ONE+iPg*HASHTABLE_NPAGE);
+ u32 iFirst = 1 + (iPg==0?0:HASHTABLE_NPAGE_ONE+(iPg-1)*HASHTABLE_NPAGE);
+ u32 nHdr, nHdr32;
+ rc = walIndexPage(pWal, iPg, (volatile u32**)&aShare);
+ if( rc ) break;
+ pWal->apWiData[iPg] = aPrivate;
+
+ for(iFrame=iFirst; iFrame<=iLast; iFrame++){
+ i64 iOffset = walFrameOffset(iFrame, szPage);
+ u32 pgno; /* Database page number for frame */
+ u32 nTruncate; /* dbsize field from frame header */
- /* Read and decode the next log frame. */
- iFrame++;
- rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
- if( rc!=SQLITE_OK ) break;
- isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
- if( !isValid ) break;
- rc = walIndexAppend(pWal, iFrame, pgno);
- if( rc!=SQLITE_OK ) break;
+ /* Read and decode the next log frame. */
+ rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
+ if( rc!=SQLITE_OK ) break;
+ isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
+ if( !isValid ) break;
+ rc = walIndexAppend(pWal, iFrame, pgno);
+ if( NEVER(rc!=SQLITE_OK) ) break;
- /* If nTruncate is non-zero, this is a commit record. */
- if( nTruncate ){
- pWal->hdr.mxFrame = iFrame;
- pWal->hdr.nPage = nTruncate;
- pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
- testcase( szPage<=32768 );
- testcase( szPage>=65536 );
- aFrameCksum[0] = pWal->hdr.aFrameCksum[0];
- aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
+ /* If nTruncate is non-zero, this is a commit record. */
+ if( nTruncate ){
+ pWal->hdr.mxFrame = iFrame;
+ pWal->hdr.nPage = nTruncate;
+ pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
+ testcase( szPage<=32768 );
+ testcase( szPage>=65536 );
+ aFrameCksum[0] = pWal->hdr.aFrameCksum[0];
+ aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
+ }
}
+ pWal->apWiData[iPg] = aShare;
+ nHdr = (iPg==0 ? WALINDEX_HDR_SIZE : 0);
+ nHdr32 = nHdr / sizeof(u32);
+#ifndef SQLITE_SAFER_WALINDEX_RECOVERY
+ /* Memcpy() should work fine here, on all reasonable implementations.
+ ** Technically, memcpy() might change the destination to some
+ ** intermediate value before setting to the final value, and that might
+ ** cause a concurrent reader to malfunction. Memcpy() is allowed to
+ ** do that, according to the spec, but no memcpy() implementation that
+ ** we know of actually does that, which is why we say that memcpy()
+ ** is safe for this. Memcpy() is certainly a lot faster.
+ */
+ memcpy(&aShare[nHdr32], &aPrivate[nHdr32], WALINDEX_PGSZ-nHdr);
+#else
+ /* In the event that some platform is found for which memcpy()
+ ** changes the destination to some intermediate value before
+ ** setting the final value, this alternative copy routine is
+ ** provided.
+ */
+ {
+ int i;
+ for(i=nHdr32; inBackfill = 0;
pInfo->nBackfillAttempted = pWal->hdr.mxFrame;
pInfo->aReadMark[0] = 0;
- for(i=1; iaReadMark[i] = READMARK_NOT_USED;
- if( pWal->hdr.mxFrame ) pInfo->aReadMark[1] = pWal->hdr.mxFrame;
+ for(i=1; ihdr.mxFrame ){
+ pInfo->aReadMark[i] = pWal->hdr.mxFrame;
+ }else{
+ pInfo->aReadMark[i] = READMARK_NOT_USED;
+ }
+ walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ }else if( rc!=SQLITE_BUSY ){
+ goto recovery_error;
+ }
+ }
/* If more than one frame was recovered from the log file, report an
** event via sqlite3_log(). This is to help with identifying performance
@@ -1309,7 +1362,6 @@ finished:
recovery_error:
WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok"));
walUnlockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
- walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
return rc;
}
@@ -1957,10 +2009,17 @@ static int walCheckpoint(
sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_START, 0);
rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
if( rc==SQLITE_OK && nSizepDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
+ if( (nSize+(i64)pWal->hdr.mxFrame*szPage)pDbFd, SQLITE_FCNTL_SIZE_HINT,&nReq);
+ }
}
- }
+ }
/* Iterate through the contents of the WAL, copying data to the db file */
while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
diff --git a/src/where.c b/src/where.c
index ad309006d1..e3f74351fd 100644
--- a/src/where.c
+++ b/src/where.c
@@ -59,8 +59,12 @@ int sqlite3WhereIsDistinct(WhereInfo *pWInfo){
}
/*
-** Return TRUE if the WHERE clause returns rows in ORDER BY order.
-** Return FALSE if the output needs to be sorted.
+** Return the number of ORDER BY terms that are satisfied by the
+** WHERE clause. A return of 0 means that the output must be
+** completely sorted. A return equal to the number of ORDER BY
+** terms means that no sorting is needed at all. A return that
+** is positive but less than the number of ORDER BY terms means that
+** block sorting is required.
*/
int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
return pWInfo->nOBSat;
@@ -3028,6 +3032,7 @@ static int whereLoopAddBtree(
pNew->nOut = rSize;
pNew->u.btree.pIndex = pProbe;
b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor);
+
/* The ONEPASS_DESIRED flags never occurs together with ORDER BY */
assert( (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || b==0 );
if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){
@@ -3057,6 +3062,7 @@ static int whereLoopAddBtree(
if( b
|| !HasRowid(pTab)
|| pProbe->pPartIdxWhere!=0
+ || pSrc->fg.isIndexedBy
|| ( m==0
&& pProbe->bUnordered==0
&& (pProbe->szIdxRowszTabRow)
@@ -3604,7 +3610,6 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
sqlite3 *db = pWInfo->pParse->db;
int rc = SQLITE_OK;
WhereLoop *pNew;
- u8 priorJointype = 0;
/* Loop over the tables in the join, from left to right */
pNew = pBuilder->pNew;
@@ -3615,12 +3620,13 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
pNew->iTab = iTab;
pBuilder->iPlanLimit += SQLITE_QUERY_PLANNER_LIMIT_INCR;
pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor);
- if( ((pItem->fg.jointype|priorJointype) & (JT_LEFT|JT_CROSS))!=0 ){
+ if( (pItem->fg.jointype & (JT_LEFT|JT_CROSS))!=0 ){
/* This condition is true when pItem is the FROM clause term on the
** right-hand-side of a LEFT or CROSS JOIN. */
mPrereq = mPrior;
+ }else{
+ mPrereq = 0;
}
- priorJointype = pItem->fg.jointype;
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pItem->pTab) ){
struct SrcList_item *p;
@@ -3738,7 +3744,9 @@ static i8 wherePathSatisfiesOrderBy(
orderDistinctMask = 0;
ready = 0;
eqOpMask = WO_EQ | WO_IS | WO_ISNULL;
- if( wctrlFlags & WHERE_ORDERBY_LIMIT ) eqOpMask |= WO_IN;
+ if( wctrlFlags & (WHERE_ORDERBY_LIMIT|WHERE_ORDERBY_MAX|WHERE_ORDERBY_MIN) ){
+ eqOpMask |= WO_IN;
+ }
for(iLoop=0; isOrderDistinct && obSat0 ) ready |= pLoop->maskSelf;
if( iLoopnLTerm && pTerm!=pLoop->aLTerm[j]; j++){}
if( j>=pLoop->nLTerm ) continue;
}
@@ -4422,6 +4431,11 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
}
}
}
+ }else if( nLoop
+ && pWInfo->nOBSat==1
+ && (pWInfo->wctrlFlags & (WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX))!=0
+ ){
+ pWInfo->bOrderedInnerLoop = 1;
}
}
if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP)
diff --git a/src/wherecode.c b/src/wherecode.c
index 4e8b211700..5473a0282e 100644
--- a/src/wherecode.c
+++ b/src/wherecode.c
@@ -1052,7 +1052,7 @@ static void codeDeferredSeek(
){
int i;
Table *pTab = pIdx->pTable;
- int *ai = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*(pTab->nCol+1));
+ u32 *ai = (u32*)sqlite3DbMallocZero(pParse->db, sizeof(u32)*(pTab->nCol+1));
if( ai ){
ai[0] = pTab->nCol;
for(i=0; inColumn-1; i++){
diff --git a/src/window.c b/src/window.c
index 77ec8a02e0..88ff7d314d 100644
--- a/src/window.c
+++ b/src/window.c
@@ -783,7 +783,7 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
}
}
}
- /* Fall through. */
+ /* no break */ deliberate_fall_through
case TK_AGG_FUNCTION:
case TK_COLUMN: {
@@ -803,6 +803,7 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
p->pSub = sqlite3ExprListAppend(pParse, p->pSub, pDup);
}
if( p->pSub ){
+ int f = pExpr->flags & EP_Collate;
assert( ExprHasProperty(pExpr, EP_Static)==0 );
ExprSetProperty(pExpr, EP_Static);
sqlite3ExprDelete(pParse->db, pExpr);
@@ -813,6 +814,7 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
pExpr->iColumn = (iCol<0 ? p->pSub->nExpr-1: iCol);
pExpr->iTable = p->pWin->iEphCsr;
pExpr->y.pTab = p->pTab;
+ pExpr->flags = f;
}
if( pParse->db->mallocFailed ) return WRC_Abort;
break;
@@ -953,15 +955,19 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
ExprList *pSort = 0;
ExprList *pSublist = 0; /* Expression list for sub-query */
- Window *pMWin = p->pWin; /* Master window object */
+ Window *pMWin = p->pWin; /* Main window object */
Window *pWin; /* Window object iterator */
Table *pTab;
+ Walker w;
+
u32 selFlags = p->selFlags;
pTab = sqlite3DbMallocZero(db, sizeof(Table));
if( pTab==0 ){
return sqlite3ErrorToParser(db, SQLITE_NOMEM);
}
+ sqlite3AggInfoPersistWalkerInit(&w, pParse);
+ sqlite3WalkSelect(&w, p);
p->pSrc = 0;
p->pWhere = 0;
@@ -1039,10 +1045,12 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
pSub = sqlite3SelectNew(
pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0
);
+ SELECTTRACE(1,pParse,pSub,
+ ("New window-function subquery in FROM clause of (%u/%p)\n",
+ p->selId, p));
p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
if( p->pSrc ){
Table *pTab2;
- Walker w;
p->pSrc->a[0].pSelect = pSub;
sqlite3SrcListAssignCursors(pParse, p->pSrc);
pSub->selFlags |= SF_Expanded;
@@ -1076,7 +1084,6 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
assert( pParse->db->mallocFailed );
sqlite3ErrorToParser(pParse->db, SQLITE_NOMEM);
}
- sqlite3SelectReset(pParse, p);
}
return rc;
}
diff --git a/test/aggnested.test b/test/aggnested.test
index d712c840f1..dcb1f95c99 100644
--- a/test/aggnested.test
+++ b/test/aggnested.test
@@ -17,6 +17,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
+set testprefix aggnested
do_test aggnested-1.1 {
db eval {
@@ -259,6 +260,52 @@ do_execsql_test aggnested-4.4 {
SELECT max((SELECT a FROM (SELECT count(*) AS a FROM ty) AS s)) FROM tx;
} {3}
+#--------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 5.0 {
+ CREATE TABLE x1(a, b);
+ INSERT INTO x1 VALUES(1, 2);
+ CREATE TABLE x2(x);
+ INSERT INTO x2 VALUES(NULL), (NULL), (NULL);
+}
+
+# At one point, aggregate "total()" in the query below was being processed
+# as part of the outer SELECT, not as part of the sub-select with no FROM
+# clause.
+do_execsql_test 5.1 {
+ SELECT ( SELECT total( (SELECT b FROM x1) ) ) FROM x2;
+} {2.0 2.0 2.0}
+
+do_execsql_test 5.2 {
+ SELECT ( SELECT total( (SELECT 2 FROM x1) ) ) FROM x2;
+} {2.0 2.0 2.0}
+
+do_execsql_test 5.3 {
+ CREATE TABLE t1(a);
+ CREATE TABLE t2(b);
+}
+
+do_execsql_test 5.4 {
+ SELECT(
+ SELECT max(b) LIMIT (
+ SELECT total( (SELECT a FROM t1) )
+ )
+ )
+ FROM t2;
+} {{}}
+
+do_execsql_test 5.5 {
+ CREATE TABLE a(b);
+ WITH c AS(SELECT a)
+ SELECT(SELECT(SELECT group_concat(b, b)
+ LIMIT(SELECT 0.100000 *
+ AVG(DISTINCT(SELECT 0 FROM a ORDER BY b, b, b))))
+ FROM a GROUP BY b,
+ b, b) FROM a EXCEPT SELECT b FROM a ORDER BY b,
+ b, b;
+}
+
diff --git a/test/altertab.test b/test/altertab.test
index c99010d29d..435620d1ee 100644
--- a/test/altertab.test
+++ b/test/altertab.test
@@ -658,5 +658,23 @@ do_catchsql_test 21.3 {
ALTER TABLE a RENAME TO e;
} {1 {error in view c: 1st ORDER BY term does not match any column in the result set}}
+# After forum thread https://sqlite.org/forum/forumpost/ddbe1c7efa
+# Ensure that PRAGMA schema_version=N causes a full schema reload.
+#
+reset_db
+do_execsql_test 22.0 {
+ CREATE TABLE t1(a INT, b TEXT NOT NULL);
+ INSERT INTO t1 VALUES(1,2),('a','b');
+ BEGIN;
+ PRAGMA writable_schema=ON;
+ UPDATE sqlite_schema SET sql='CREATE TABLE t1(a INT, b TEXT)' WHERE name LIKE 't1';
+ PRAGMA schema_version=1234;
+ COMMIT;
+ PRAGMA integrity_check;
+} {ok}
+do_execsql_test 22.1 {
+ ALTER TABLE t1 ADD COLUMN c INT DEFAULT 78;
+ SELECT * FROM t1;
+} {1 2 78 a b 78}
finish_test
diff --git a/test/altertab3.test b/test/altertab3.test
index b39065589c..005a0ee891 100644
--- a/test/altertab3.test
+++ b/test/altertab3.test
@@ -586,5 +586,19 @@ do_execsql_test 24.4 {
DELETE FROM v2;
END}}
+#------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 25.1 {
+ CREATE TABLE t1(a, b, c);
+ CREATE TABLE t2(a, b, c);
+ CREATE TRIGGER ttt AFTER INSERT ON t1 BEGIN
+ UPDATE t1 SET a=t2.a FROM t2 WHERE t1.a=t2.a;
+ END;
+}
+#do_execsql_test 25.2 {
+# ALTER TABLE t2 RENAME COLUMN a TO aaa;
+#}
+
finish_test
diff --git a/test/atrc.c b/test/atrc.c
index c6e4ce3d05..673f12cc44 100644
--- a/test/atrc.c
+++ b/test/atrc.c
@@ -75,7 +75,7 @@ int rename_all_tables(
int cnt = 0;
rc = sqlite3_prepare_v2(db,
- "SELECT name FROM sqlite_master WHERE type='table'"
+ "SELECT name FROM sqlite_schema WHERE type='table'"
" AND name NOT LIKE 'sqlite_%';",
-1, &pStmt, 0);
if( rc ) return rc;
diff --git a/test/busy2.test b/test/busy2.test
new file mode 100644
index 0000000000..fb9ef2301d
--- /dev/null
+++ b/test/busy2.test
@@ -0,0 +1,135 @@
+# 2020 June 30
+#
+# 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 test the busy handler
+#
+
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/lock_common.tcl
+set testprefix busy2
+
+do_multiclient_test tn {
+ do_test 1.$tn.0 {
+ sql2 {
+ CREATE TABLE t1(a, b);
+ PRAGMA journal_mode = wal;
+ INSERT INTO t1 VALUES('A', 'B');
+ }
+ } {wal}
+
+ do_test 1.$tn.1 {
+ code1 { db timeout 1000 }
+ sql1 { SELECT * FROM t1 }
+ } {A B}
+
+ do_test 1.$tn.2 {
+ sql2 {
+ BEGIN;
+ INSERT INTO t1 VALUES('C', 'D');
+ }
+ } {}
+
+ do_test 1.$tn.3 {
+ set us [lindex [time { catch { sql1 { BEGIN EXCLUSIVE } } }] 0]
+ expr {$us>950000 && $us<1500000}
+ } {1}
+
+ do_test 1.$tn.4 {
+ sql2 {
+ COMMIT
+ }
+ } {}
+}
+
+#-------------------------------------------------------------------------
+
+do_multiclient_test tn {
+ # Make the db a WAL mode db. And add a table and a row to it. Then open
+ # a second connection within process 1. Process 1 now has connections
+ # [db] and [db1.2], process 2 has connection [db2] only.
+ #
+ # Configure all connections to use a 1000 ms timeout.
+ #
+ do_test 2.$tn.0 {
+ code1 {
+ sqlite3 db1.2 test.db
+ }
+ sql1 {
+ PRAGMA auto_vacuum = off;
+ PRAGMA journal_mode = wal;
+ CREATE TABLE t1(a, b);
+ INSERT INTO t1 VALUES(1, 2);
+ }
+ code2 {
+ db2 timeout 1000
+ }
+ code1 {
+ db1.2 timeout 1000
+ db timeout 1000
+ db1.2 eval {SELECT * FROM t1}
+ }
+ } {1 2}
+
+ # Take a read lock with [db] in process 1.
+ #
+ do_test 2.$tn.1 {
+ sql1 {
+ BEGIN;
+ SELECT * FROM t1;
+ }
+ } {1 2}
+
+ # Insert a row using [db2] in process 2. Then try a passive checkpoint.
+ # It fails to checkpoint the final frame (due to the readlock taken by
+ # [db]), and returns in less than 250ms.
+ do_test 2.$tn.2 {
+ sql2 { INSERT INTO t1 VALUES(3, 4) }
+ set us [lindex [time {
+ set res [code2 { db2 eval { PRAGMA wal_checkpoint } }]
+ }] 0]
+ list [expr $us < 250000] $res
+ } {1 {0 4 3}}
+
+ # Now try a FULL checkpoint with [db2]. It returns SQLITE_BUSY. And takes
+ # over 950ms to do so.
+ do_test 2.$tn.3 {
+ set us [lindex [time {
+ set res [code2 { db2 eval { PRAGMA wal_checkpoint = FULL } }]
+ }] 0]
+ list [expr $us > 950000] $res
+ } {1 {1 4 3}}
+
+ # Passive checkpoint with [db1.2] (process 1). No SQLITE_BUSY, returns
+ # in under 250ms.
+ do_test 2.$tn.4 {
+ set us [lindex [time {
+ set res [code1 { db1.2 eval { PRAGMA wal_checkpoint } }]
+ }] 0]
+ list [expr $us < 250000] $res
+ } {1 {0 4 3}}
+
+ # Full checkpoint with [db1.2] (process 1). SQLITE_BUSY returned in
+ # a bit over 950ms.
+ do_test 2.$tn.5 {
+ set us [lindex [time {
+ set res [code1 { db1.2 eval { PRAGMA wal_checkpoint = FULL } }]
+ }] 0]
+ list [expr $us > 950000] $res
+ } {1 {1 4 3}}
+
+ code1 {
+ db1.2 close
+ }
+}
+
+finish_test
+
diff --git a/test/corrupt3.test b/test/corrupt3.test
index 3c911dadb6..7a2e174ead 100644
--- a/test/corrupt3.test
+++ b/test/corrupt3.test
@@ -94,7 +94,7 @@ do_test corrupt3-1.9 {
catchsql {
SELECT substr(x,1,10) FROM t1
}
-} [list 0 0123456789]
+} [list 1 {database disk image is malformed}]
do_test corrupt3-1.10 {
catchsql {
PRAGMA integrity_check
diff --git a/test/corruptL.test b/test/corruptL.test
index 67d308abca..4345a0103e 100644
--- a/test/corruptL.test
+++ b/test/corruptL.test
@@ -1174,6 +1174,7 @@ do_test 14.0 {
| end clusterfuzz-testcase-minimized-sqlite3_dbfuzz2_fuzzer-4806406219825152
}]} {}
+extra_schema_checks 0
do_catchsql_test 14.1 {
PRAGMA integrity_check;
} {1 {database disk image is malformed}}
@@ -1181,6 +1182,157 @@ do_catchsql_test 14.1 {
do_catchsql_test 14.2 {
ALTER TABLE t1 RENAME TO alkjalkjdfiiiwuer987lkjwer82mx97sf98788s9789s;
} {1 {database disk image is malformed}}
+extra_schema_checks 1
+
+#-------------------------------------------------------------------------
+reset_db
+do_test 15.0 {
+ sqlite3 db {}
+ db deserialize [decode_hexdb {
+| size 28672 pagesize 4096 filename crash-3afa1ca9e9c1bd.db
+| page 1 offset 0
+| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
+| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........
+| 32: 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 04 ................
+| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
+| 96: 00 00 00 00 0d 00 00 00 06 0e 88 00 0f b8 0f 6d ...............m
+| 112: 0f 3a 0f 0b 0e d5 0e 88 01 00 00 00 00 00 00 00 .:..............
+| 3712: 00 00 00 00 00 00 00 00 4b 06 06 17 25 25 01 5b ........K...%%.[
+| 3728: 74 61 62 6c 65 73 71 6c 69 74 65 5f 73 74 61 74 tablesqlite_stat
+| 3744: 31 73 71 6c 69 74 65 5f 73 74 61 74 31 07 43 52 1sqlite_stat1.CR
+| 3760: 45 41 54 45 20 54 41 42 4c 45 20 73 71 6c 69 74 EATE TABLE sqlit
+| 3776: 65 5f 73 74 61 74 31 28 74 62 6c 2c 69 64 78 2c e_stat1(tbl,idx,
+| 3792: 73 74 61 74 29 34 05 06 17 13 11 01 53 69 6e 64 stat)4......Sind
+| 3808: 65 78 63 31 63 63 31 06 43 52 45 41 54 45 20 55 exc1cc1.CREATE U
+| 3824: 4e 49 51 55 45 20 49 4e 44 45 58 20 63 31 63 20 NIQUE INDEX c1c
+| 3840: 4f 4e 20 63 31 28 63 2c 20 62 29 2d 04 06 17 13 ON c1(c, b)-....
+| 3856: 11 01 45 69 6e 64 65 78 63 31 64 63 31 05 43 52 ..Eindexc1dc1.CR
+| 3872: 45 41 54 45 20 49 4e 44 45 58 20 63 31 64 20 4f EATE INDEX c1d O
+| 3888: 4e 20 63 31 28 64 2c 20 62 29 31 03 06 17 13 11 N c1(d, b)1.....
+| 3904: 01 4d 69 6e 64 65 78 62 31 63 62 31 05 43 52 45 .Mindexb1cb1.CRE
+| 3920: 41 54 45 20 55 4e 49 51 55 45 20 49 4e 44 45 58 ATE UNIQUE INDEX
+| 3936: 20 62 31 63 20 4f 4e 20 62 31 28 63 29 49 02 06 b1c ON b1(c)I..
+| 3952: 17 11 11 0f 7f 74 61 62 6c 65 63 31 63 31 03 43 .....tablec1c1.C
+| 3968: 52 45 41 54 45 20 54 41 42 4c 45 20 63 31 28 61 REATE TABLE c1(a
+| 3984: 20 49 4e 54 20 50 52 49 4d 41 52 59 20 4b 45 59 INT PRIMARY KEY
+| 4000: 2c 20 62 2c 20 63 2c 20 64 29 20 57 49 54 48 4f , b, c, d) WITHO
+| 4016: 55 54 20 52 4f 57 49 44 46 01 06 17 11 11 01 79 UT ROWIDF......y
+| 4032: 74 61 62 6c 65 62 31 62 31 02 43 52 45 41 54 45 tableb1b1.CREATE
+| 4048: 20 54 41 42 4c 45 20 62 31 28 61 20 49 4e 54 20 TABLE b1(a INT
+| 4064: 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 62 2c 20 PRIMARY KEY, b,
+| 4080: 63 29 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 c) WITHOUT ROWID
+| page 2 offset 4096
+| 0: 0a 00 00 00 07 0f ca 00 0f fa 0f f2 0f ea 0f e2 ................
+| 16: 0f da 00 00 00 01 00 00 00 00 00 00 00 00 00 00 ................
+| 4032: 00 00 00 00 00 00 00 00 00 00 07 04 01 0f 01 06 ................
+| 4048: 67 07 07 04 01 0f 01 06 66 06 07 04 01 0f 01 05 g.......f.......
+| 4064: 65 05 07 04 01 0f 01 04 64 04 07 04 01 0f 01 03 e.......d.......
+| 4080: 63 03 07 04 01 0f 01 02 62 0f 05 04 09 0f 09 61 c.......b......a
+| page 3 offset 8192
+| 0: 0a 00 00 00 07 0f bd 00 0f f9 0f ef 0f e5 0f db ................
+| 16: 0f d1 0f c7 0f bd 00 00 00 00 01 00 00 00 00 00 ................
+| 4016: 00 00 00 00 00 00 00 00 00 00 00 00 00 09 05 01 ................
+| 4032: 0f 01 01 07 61 07 07 09 05 01 0f 01 01 06 61 06 ....a.........a.
+| 4048: 06 09 05 01 0f 01 01 05 61 05 05 09 05 01 0f 01 ........a.......
+| 4064: 01 04 61 04 04 09 05 01 0f 01 01 03 61 03 03 09 ..a.........a...
+| 4080: 05 01 0f 01 01 02 61 0f 02 06 05 09 0f 09 09 61 ......a........a
+| page 4 offset 12288
+| 0: 0a 00 00 00 07 0f d8 00 0f fc 0f f0 0f ea 0f e4 ................
+| 16: 0f de 0f d8 0f f6 00 00 00 00 00 00 00 00 00 00 ................
+| 4048: 00 00 00 00 00 00 00 00 05 03 01 01 07 07 05 03 ................
+| 4064: 01 01 06 06 05 03 01 01 05 05 05 03 01 01 04 04 ................
+| 4080: 05 03 01 01 03 03 05 03 01 01 0f 02 03 03 09 09 ................
+| page 5 offset 16384
+| 0: 0a 00 00 00 07 0f ca 00 0f fa 0f f2 0f ea 0f 00 ................
+| 4032: 00 00 00 00 00 00 00 00 00 00 07 04 01 0f 01 07 ................
+| 4048: 61 07 07 04 01 0f 01 06 61 06 07 04 01 0f 01 05 a.......a.......
+| 4064: 61 05 07 04 01 1f 01 04 61 04 07 04 01 0f 01 03 a.......a.......
+| 4080: 61 03 07 04 01 0f 01 02 61 02 05 04 09 0f 09 61 a.......a......a
+| page 6 offset 20480
+| 0: 0a 00 00 00 07 0f ca 00 0f fa 0f ea 0f e2 00 00 ................
+| 4032: 00 00 00 00 00 00 00 00 00 00 07 04 01 0f 01 07 ................
+| 4048: 61 07 07 04 01 0f 01 06 61 06 07 04 01 0f 01 05 a.......a.......
+| 4064: 61 05 07 04 01 0f 01 04 61 04 07 04 01 0f 01 03 a.......a.......
+| 4080: 61 03 07 04 01 0f 01 0f 61 02 05 04 09 0f 09 61 a.......a......a
+| page 7 offset 24576
+| 0: 0d 00 00 00 05 0f 1c 00 0f f0 0f e0 0f d3 0f c5 ................
+| 16: 0f b8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+| 4016: 00 00 00 00 00 00 00 00 0b 05 04 11 11 13 62 31 ..............b1
+| 4032: 62 31 37 20 31 0c 04 04 11 13 13 62 31 62 31 63 b17 1......b1b1c
+| 4048: 37 20 31 0b 03 04 11 11 13 63 31 63 31 37 20 31 7 1......c1c17 1
+| 4064: 0e 02 04 11 13 07 63 31 63 31 64 37 20 31 20 31 ......c1c1d7 1 1
+| 4080: 0e 01 04 11 13 17 63 31 63 31 63 37 20 31 00 00 ......c1c1c7 1..
+| end crash-3afa1ca9e9c1bd.db
+}]} {}
+
+extra_schema_checks 0
+do_execsql_test 15.1 {
+ PRAGMA cell_size_check = 0;
+ UPDATE c1 SET c= NOT EXISTS(SELECT 1 FROM c1 ORDER BY (SELECT 1 FROM c1 ORDER BY a)) +10 WHERE d BETWEEN 4 AND 7;
+} {}
+extra_schema_checks 1
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 16.0 {
+ CREATE TABLE t1(w, x, y, z, UNIQUE(w, x), UNIQUE(y, z));
+ INSERT INTO t1 VALUES(1, 1, 1, 1);
+
+ CREATE TABLE t1idx(x, y, i INTEGER, PRIMARY KEY(x)) WITHOUT ROWID;
+ INSERT INTO t1idx VALUES(10, NULL, 5);
+
+ PRAGMA writable_schema = 1;
+ UPDATE sqlite_master SET rootpage = (
+ SELECT rootpage FROM sqlite_master WHERE name='t1idx'
+ ) WHERE type = 'index';
+}
+
+extra_schema_checks 0
+db close
+sqlite3 db test.db
+extra_schema_checks 1
+
+do_catchsql_test 16.1 {
+ PRAGMA writable_schema = ON;
+ INSERT INTO t1(rowid, w, x, y, z) VALUES(5, 10, 11, 10, NULL);
+} {1 {database disk image is malformed}}
+
+#-------------------------------------------------------------------------
+# Test that corruption is reported from within a checkpoint if the
+# expected final size of the database (according to the last commit
+# frame in the wal file) is greater than the combined initial sizes
+# of the database and wal file.
+#
+if {[wal_is_capable]} {
+ reset_db
+ do_execsql_test 17.0 {
+ CREATE TABLE t1(o INTEGER PRIMARY KEY, t UNIQUE);
+ INSERT INTO t1(t) VALUES(randomblob(123));
+ INSERT INTO t1(t) SELECT randomblob(123) FROM t1;
+ INSERT INTO t1(t) SELECT randomblob(123) FROM t1;
+ INSERT INTO t1(t) SELECT randomblob(123) FROM t1;
+ INSERT INTO t1(t) SELECT randomblob(123) FROM t1;
+ INSERT INTO t1(t) SELECT randomblob(123) FROM t1;
+ INSERT INTO t1(t) SELECT randomblob(123) FROM t1;
+
+ PRAGMA journal_mode = wal;
+ INSERT INTO t1 VALUES(-1, 'b');
+ } {wal}
+
+ do_test 17.1 {
+ set fd [open test.db r+]
+ chan truncate $fd 2048
+ file size test.db
+ } {2048}
+
+ do_catchsql_test 17.2 {
+ PRAGMA wal_checkpoint
+ } {1 {database disk image is malformed}}
+
+ do_test 17.3 {
+ close $fd
+ } {}
+}
+
finish_test
-
diff --git a/test/cost.test b/test/cost.test
index 2922a0a054..592973ab56 100644
--- a/test/cost.test
+++ b/test/cost.test
@@ -230,10 +230,10 @@ do_test 9.2 {
set L [list a=? b=? c=? d=? e=? f=? g=? h=? i=? j=?]
foreach {tn nTerm nRow} {
1 1 10
- 2 2 9
+ 2 2 10
3 3 8
4 4 7
- 5 5 6
+ 5 5 7
6 6 5
7 7 5
8 8 5
diff --git a/test/dbfuzz001.test b/test/dbfuzz001.test
index 7ef4cd2a3f..2a430de12e 100644
--- a/test/dbfuzz001.test
+++ b/test/dbfuzz001.test
@@ -361,6 +361,7 @@ do_test dbfuzz001-310 {
}]
} {}
+extra_schema_checks 0
do_catchsql_test dbfuzz001-320 {
PRAGMA integrity_check;
} {1 {database disk image is malformed}}
@@ -368,5 +369,6 @@ do_catchsql_test dbfuzz001-320 {
do_catchsql_test dbfuzz001-330 {
DELETE FROM t3 WHERE x IN (SELECT x FROM t4);
} {1 {database disk image is malformed}}
+extra_schema_checks 1
finish_test
diff --git a/test/dbfuzz2.c b/test/dbfuzz2.c
index 804222ce4e..e35162937f 100644
--- a/test/dbfuzz2.c
+++ b/test/dbfuzz2.c
@@ -54,7 +54,7 @@
*/
static const char *azSql[] = {
"PRAGMA integrity_check;",
- "SELECT * FROM sqlite_master;",
+ "SELECT * FROM sqlite_schema;",
"SELECT sum(length(name)) FROM dbstat;",
"UPDATE t1 SET b=a, a=b WHERE a=0;
+} {}
+do_execsql_test 2010 {
+ SELECT *, '|'
+ FROM t1 AS a, t1 AS b
+ WHERE a.seq<>b.seq
+ AND decimal_cmp(a.val,b.val)==0;
+} {}
+do_execsql_test 2020 {
+ SELECT *, '|'
+ FROM t1 AS a, t1 AS b
+ WHERE a.seq>b.seq
+ AND decimal_cmp(a.val,b.val)<=0;
+} {}
+do_execsql_test 2030 {
+ SELECT seq FROM t1 ORDER BY val COLLATE decimal;
+} {1 2 3 4 5 6 7 8 9 10 11 12}
+do_execsql_test 2040 {
+ SELECT seq FROM t1 ORDER BY val COLLATE decimal DESC;
+} {12 11 10 9 8 7 6 5 4 3 2 1}
+
+do_execsql_test 3000 {
+ CREATE TABLE t3(seq INTEGER PRIMARY KEY, val TEXT);
+ WITH RECURSIVE c(x) AS (VALUES(1) UNION SELECT x+1 FROM c WHERE x<10)
+ INSERT INTO t3(seq, val) SELECT x, x FROM c;
+ WITH RECURSIVE c(x) AS (VALUES(1) UNION SELECT x+1 FROM c WHERE x<5)
+ INSERT INTO t3(seq, val) SELECT x+10, x*1000 FROM c;
+ SELECT decimal(val) FROM t3 ORDER BY seq;
+} {1 2 3 4 5 6 7 8 9 10 1000 2000 3000 4000 5000}
+do_execsql_test 3020 {
+ SELECT decimal_add(val,'0.5') FROM t3 WHERE seq>5 ORDER BY seq
+} {6.5 7.5 8.5 9.5 10.5 1000.5 2000.5 3000.5 4000.5 5000.5}
+do_execsql_test 3030 {
+ SELECT decimal_add(val,'-10') FROM t3 ORDER BY seq;
+} {-9 -8 -7 -6 -5 -4 -3 -2 -1 0 990 1990 2990 3990 4990}
+
+do_execsql_test 4000 {
+ SELECT decimal_sum(val) FROM t3;
+} {15055}
+do_execsql_test 4010 {
+ SELECT decimal_sum(decimal_add(val,val||'e+10')) FROM t3;
+} {150550000015055}
+do_execsql_test 4010 {
+ SELECT decimal_sum(decimal_add(val||'e+20',decimal_add(val,val||'e-20')))
+ FROM t3;
+} {1505500000000000000015055.00000000000000015055}
+
+do_execsql_test 5000 {
+ WITH RECURSIVE c(x,y,z) AS (
+ VALUES(0,'1','1')
+ UNION ALL
+ SELECT x+1, decimal_mul(y,'2'), decimal_mul(z,'0.5')
+ FROM c WHERE x<32
+ )
+ SELECT count(*) FROM c WHERE decimal_mul(y,z)='1';
+} {33}
+
+do_execsql_test 5100 {
+ SELECT decimal_mul('1234.00','2.00');
+} {2468.00}
+do_execsql_test 5101 {
+ SELECT decimal_mul('1234.00','2.0000');
+} {2468.00}
+do_execsql_test 5102 {
+ SELECT decimal_mul('1234.0000','2.000');
+} {2468.000}
+do_execsql_test 5103 {
+ SELECT decimal_mul('1234.0000','2');
+} {2468}
+
+if {[catch {load_static_extension db ieee754} error]} {
+ puts "Skipping ieee754 tests, hit load error: $error"
+ finish_test; return
+}
+
+do_execsql_test 6000 {
+ CREATE TABLE pow2(x INTEGER PRIMARY KEY, v TEXT);
+ WITH RECURSIVE c(x,v) AS (
+ VALUES(0,'1')
+ UNION ALL
+ SELECT x+1, decimal_mul(v,'2') FROM c WHERE x+1<=971
+ ) INSERT INTO pow2(x,v) SELECT x, v FROM c;
+ WITH RECURSIVE c(x,v) AS (
+ VALUES(-1,'0.5')
+ UNION ALL
+ SELECT x-1, decimal_mul(v,'0.5') FROM c WHERE x-1>=-1075
+ ) INSERT INTO pow2(x,v) SELECT x, v FROM c;
+} {}
+do_execsql_test 6010 {
+ WITH c(n) AS (SELECT ieee754_from_blob(x'0000000000000001'))
+SELECT decimal_mul(ieee754_mantissa(c.n),pow2.v)
+ FROM pow2, c WHERE pow2.x=ieee754_exponent(c.n);
+} {0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004940656458412465441765687928682213723650598026143247644255856825006755072702087518652998363616359923797965646954457177309266567103559397963987747960107818781263007131903114045278458171678489821036887186360569987307230500063874091535649843873124733972731696151400317153853980741262385655911710266585566867681870395603106249319452715914924553293054565444011274801297099995419319894090804165633245247571478690147267801593552386115501348035264934720193790268107107491703332226844753335720832431936092382893458368060106011506169809753078342277318329247904982524730776375927247874656084778203734469699533647017972677717585125660551199131504891101451037862738167250955837389733598993664809941164205702637090279242767544565229087538682506419718265533447265625}
+do_execsql_test 6020 {
+ WITH c(n) AS (SELECT ieee754_from_blob(x'7fefffffffffffff'))
+SELECT decimal_mul(ieee754_mantissa(c.n),pow2.v)
+ FROM pow2, c WHERE pow2.x=ieee754_exponent(c.n);
+} {179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368}
+
+do_execsql_test 6100 {
+ SELECT ieee754(ieee754_from_blob(x'0000000000000001'));
+} {ieee754(1,-1074)}
+do_execsql_test 6110 {
+ SELECT ieee754(ieee754_from_blob(x'7fefffffffffffff'));
+} {ieee754(9007199254740991,971)}
+do_execsql_test 6120 {
+ SELECT printf('%.8e',ieee754_from_blob(x'0000000000000001'));
+} {4.94065646e-324}
+do_execsql_test 6130 {
+ SELECT printf('%.8e',ieee754_from_blob(x'ffefffffffffffff'));
+} {-1.79769313e+308}
+
+
+
+
+finish_test
diff --git a/test/e_droptrigger.test b/test/e_droptrigger.test
index 84dfe7279a..5cd5d0a07b 100644
--- a/test/e_droptrigger.test
+++ b/test/e_droptrigger.test
@@ -127,8 +127,8 @@ foreach {tn tbl droptrigger before after} {
} $after
}
-# EVIDENCE-OF: R-50239-29811 Once removed, the trigger definition is no
-# longer present in the sqlite_master (or sqlite_temp_master) table and
+# EVIDENCE-OF: R-04950-25529 Once removed, the trigger definition is no
+# longer present in the sqlite_schema (or sqlite_temp_schema) table and
# is not fired by any subsequent INSERT, UPDATE or DELETE statements.
#
# Test cases e_droptrigger-1.* test the first part of this statement
diff --git a/test/e_fkey.test b/test/e_fkey.test
index 3636bef872..c5ac5fde38 100644
--- a/test/e_fkey.test
+++ b/test/e_fkey.test
@@ -2528,8 +2528,8 @@ test_efkey_6 3 "ALTER TABLE tbl ADD COLUMN c DEFAULT 0 REFERENCES xx" 1
#
# Test that these adjustments are visible in the sqlite_master table.
#
-# EVIDENCE-OF: R-63827-54774 The text of the child CREATE TABLE
-# statement or statements stored in the sqlite_master table are modified
+# EVIDENCE-OF: R-43040-62530 The text of the child CREATE TABLE
+# statement or statements stored in the sqlite_schema table are modified
# to reflect the new parent table name.
#
do_test e_fkey-56.1 {
diff --git a/test/filter1.test b/test/filter1.test
index ee17099d99..7b2cf9cc3a 100644
--- a/test/filter1.test
+++ b/test/filter1.test
@@ -204,4 +204,22 @@ do_execsql_test 6.3 {
SELECT (SELECT COUNT(a) FROM t2) FROM t1;
} {2}
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 7.0 {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
+ INSERT INTO t1 VALUES(321, 100000);
+ INSERT INTO t1 VALUES(111, 110000);
+ INSERT INTO t1 VALUES(444, 120000);
+ INSERT INTO t1 VALUES(222, 130000);
+}
+
+do_execsql_test 7.1 {
+ SELECT max(a), max(a) FILTER (WHERE b<12345), b FROM t1;
+} {
+ 444 {} 120000
+}
+
+
+
finish_test
diff --git a/test/fkey5.test b/test/fkey5.test
index 3c44cd319f..d467a64281 100644
--- a/test/fkey5.test
+++ b/test/fkey5.test
@@ -15,10 +15,10 @@
# EVIDENCE-OF: R-15402-03103 PRAGMA schema.foreign_key_check; PRAGMA
# schema.foreign_key_check(table-name);
#
-# EVIDENCE-OF: R-23918-17301 The foreign_key_check pragma checks the
+# EVIDENCE-OF: R-41653-15278 The foreign_key_check pragma checks the
# database, or the table called "table-name", for foreign key
-# constraints that are violated and returns one row of output for each
-# violation.
+# constraints that are violated. The foreign_key_check pragma returns
+# one row output for each foreign key violation.
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -430,4 +430,63 @@ do_catchsql_test 11.1 {
PRAGMA foreign_key_check;
} {1 {foreign key mismatch - "c11" referencing "tt"}}
+# 2020-07-03 Bug in foreign_key_check discovered while working on the
+# forum reports that pragma_foreign_key_check does not accept an argument:
+# If two separate schemas seem to reference one another, that causes
+# problems for foreign_key_check.
+#
+reset_db
+do_execsql_test 12.0 {
+ ATTACH ':memory:' as aux;
+ CREATE TABLE aux.t1(a INTEGER PRIMARY KEY, b TEXT REFERENCES t2);
+ CREATE TABLE main.t2(x TEXT PRIMARY KEY, y INT);
+ INSERT INTO main.t2 VALUES('abc',11),('def',22),('xyz',99);
+ INSERT INTO aux.t1 VALUES(5,'abc'),(7,'xyz'),(9,'oops');
+ PRAGMA foreign_key_check=t1;
+} {t1 5 t2 0 t1 7 t2 0 t1 9 t2 0}
+do_execsql_test 12.1 {
+ CREATE TABLE aux.t2(x TEXT PRIMARY KEY, y INT);
+ INSERT INTO aux.t2 VALUES('abc',11),('def',22),('xyz',99);
+ PRAGMA foreign_key_check=t1;
+} {t1 9 t2 0}
+
+# 2020-07-03: the pragma_foreign_key_check virtual table should
+# accept arguments for the table name and/or schema name.
+#
+ifcapable vtab {
+ do_execsql_test 13.0 {
+ SELECT *, 'x' FROM pragma_foreign_key_check('t1');
+ } {t1 9 t2 0 x}
+ do_catchsql_test 13.1 {
+ SELECT *, 'x' FROM pragma_foreign_key_check('t1','main');
+ } {1 {no such table: main.t1}}
+ do_execsql_test 13.2 {
+ SELECT *, 'x' FROM pragma_foreign_key_check('t1','aux');
+ } {t1 9 t2 0 x}
+}
+
+ifcapable vtab {
+ reset_db
+ do_execsql_test 13.10 {
+ PRAGMA foreign_keys=OFF;
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT REFERENCES t2);
+ CREATE TABLE t2(x TEXT PRIMARY KEY, y INT);
+ CREATE TABLE t3(w TEXT, z INT REFERENCES t1);
+ INSERT INTO t2 VALUES('abc',11),('def',22),('xyz',99);
+ INSERT INTO t1 VALUES(5,'abc'),(7,'xyz'),(9,'oops');
+ INSERT INTO t3 VALUES(11,7),(22,19);
+ } {}
+ do_execsql_test 13.11 {
+ SELECT x.*, '|'
+ FROM sqlite_schema, pragma_foreign_key_check(name) AS x
+ WHERE type='table'
+ ORDER BY x."table";
+ } {t1 9 t2 0 | t3 2 t1 0 |}
+ do_execsql_test 13.12 {
+ SELECT *, '|'
+ FROM pragma_foreign_key_check AS x
+ ORDER BY x."table";
+ } {t1 9 t2 0 | t3 2 t1 0 |}
+}
+
finish_test
diff --git a/test/fts3corrupt2.test b/test/fts3corrupt2.test
index 40783facf9..58643534f1 100644
--- a/test/fts3corrupt2.test
+++ b/test/fts3corrupt2.test
@@ -16,6 +16,7 @@ source $testdir/tester.tcl
ifcapable !fts3 { finish_test ; return }
set ::testprefix fts3corrupt2
+sqlite3_fts3_may_be_corrupt 1
set data [list]
lappend data {*}{
@@ -107,5 +108,4 @@ foreach c {50 100 150 200 250} {
-
finish_test
diff --git a/test/fts3corrupt4.test b/test/fts3corrupt4.test
index 8bbf0f5bbc..bddcc9f5de 100644
--- a/test/fts3corrupt4.test
+++ b/test/fts3corrupt4.test
@@ -27,6 +27,7 @@ ifcapable !fts3 {
sqlite3_fts3_may_be_corrupt 1
database_may_be_corrupt
+extra_schema_checks 0
do_execsql_test 1.0 {
BEGIN;
@@ -5849,8 +5850,6 @@ do_catchsql_test 37.1 {
#-------------------------------------------------------------------------
#
-reset_db
-
reset_db
do_test 38.0 {
sqlite3 db {}
@@ -6061,9 +6060,242 @@ do_execsql_test 38.1 {
UPDATE t1 SET b=a;
}
-do_catchsql_test 38.1 {
+do_catchsql_test 38.2 {
SELECT b FROM t1 WHERE a MATCH 'e*e*e*e*e*e*e*e*e*e*e*e*e*e*e*e*'
} {1 {database disk image is malformed}}
+#-------------------------------------------------------------------------
+reset_db
+set saved $sqlite_fts3_enable_parentheses
+set sqlite_fts3_enable_parentheses 1
+do_execsql_test 39.0 {
+ CREATE VIRTUAL TABLE t0 USING fts3(
+ col0 INTEGER PRIMARY KEY,
+ col1 VARCHAR(8),
+ col2 BINARY,
+ col3 BINARY
+ );
+ INSERT INTO t0_content VALUES(1,1,'1234','aaaa','bbbb');
+ INSERT INTO t0_segdir VALUES(0,0,0,0,'0 42',X'000131030782000103323334050101010200000461616161050101020200000462626262050101030200');
+}
+
+do_test 39.1 {
+ catch {
+ db eval { SELECT rowid FROM t0 WHERE t0 MATCH '1 NEAR 1' }
+ }
+} 0
+
+do_test 39.2 {
+ catch {
+ db eval {
+ SELECT matchinfo(t0,'yxy') FROM t0 WHERE t0 MATCH x'2b0a312b0a312a312a2a0b5d0a0b0b0a312a0a0b0b0a312a0b310a392a0b0a27312a2a0b5d0a312a0b310a31315d0b310a312a316d2a0b313b15bceaa50a312a0b0a27312a2a0b5d0a312a0b310a312b0b2a310a312a0b2a0b2a0b2e5d0a0bff313336e34a2a312a0b0a3c310b0a0b4b4b0b4b2a4bec40322b2a0b310a0a312a0a0a0a0a0a0a0a0a0b310a312a2a2a0b5d0a0b0b0a312a0b310a312a0b0a4e4541530b310a5df5ced70a0a0a0a0a4f520a0a0a0a0a0a0a312a0b0a4e4541520b310a5d616161610a0a0a0a4f520a0a0a0a0a0a312b0a312a312a0a0a0a0a0a0a004a0b0a310b220a0b0a310a4a22310a0b0a7e6fe0e0e030e0e0e0e0e01176e02000e0e0e0e0e01131320226310a0b0a310a4a22310a0b0a310a766f8b8b4ee0e0300ae0090909090909090909090909090909090909090909090909090909090909090947aaaa540b09090909090909090909090909090909090909090909090909090909090909fae0e0f2f22164e0e0f273e07fefefef7d6dfafafafa6d6d6d6d';
+ }
+ }
+} 0
+set sqlite_fts3_enable_parentheses $saved
+
+#-------------------------------------------------------------------------
+reset_db
+set saved $sqlite_fts3_enable_parentheses
+set sqlite_fts3_enable_parentheses 1
+
+do_execsql_test 40.1 {
+
+ CREATE VIRTUAL TABLE t0 USING fts3(col0 INTEGER PRIMARY KEY, col1, col2 ,col3 );
+ INSERT INTO t0_segdir VALUES(0,0,0,0,'0 42',
+ X'0001310301020001033233340500010102000004616161bc050101020200000462626262050101030200'
+ );
+}
+
+do_execsql_test 40.2 {
+ SELECT 0==matchinfo(t0,'sx') FROM t0 WHERE t0 MATCH '1* 2 3 4 5 6 OR 1';
+} 0
+
+set sqlite_fts3_enable_parentheses $saved
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 41.1 {
+ CREATE VIRTUAL TABLE t1 USING fts3(a,b,c);
+ INSERT INTO t1_segdir VALUES(0,0,0,0,'0 835',X'000130120106000106000106001f030001030001030000083230313630363039090107000107000107000001340901050001050001050000013509010400010400010400010730303030303030091c0400010400010400000662696e6172793c0301020200030102020003010202000301020200030102020003010202000301020200030102020003010202000301020200030102020003010202000008636f3870696c657209010200010200010200000664627374617409070300010300010300010465627567090402000102000102000006656e61626c653f07020001020001020001020001020001020001020001020001020001030001010002020001020001020001020001120001020001020001020001020001020001087874656e73696f6e091f0400010400010400000466747334090a0300010300010400030135090d03000103000103000003676363090103000103000103000106656f706f6c790910030001030001030000056a736f6e310913030001030001030000046c6f6164091f030001030001030000036d6178091c02000102000102000105656d6f7279091c03000103000103000304737973350916030001030001030000066e6f636173653c02010202000301020200030102020003010202000301020200030102020003010202000301020200030102020003010202000301020200030102020000046f6d6974091f020001020001020000057274726565091903000103000103000302696d3c010102020003010202000301020200030102020003010202000301020200030102020003010202000301020200030102020003010202000301020200000a746872656164736166650922020001020001020000047674616209070400010400010400000178b401010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200');
+}
+
+do_execsql_test 41.2 {
+ SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'rtree ner "json1^enable"';
+}
+
+#-------------------------------------------------------------------------
+do_execsql_test 42.1 {
+ CREATE VIRTUAL TABLE f USING fts3(a, b);
+}
+do_execsql_test 42.2 {
+ INSERT INTO f_segdir VALUES(0,2,1111,0,0,X'00');
+ INSERT INTO f_segdir VALUES(0,3,0 ,0,0,X'00013003010200');
+}
+do_execsql_test 42.3 {
+ INSERT INTO f(f) VALUES ('merge=107,2');
+}
+
+#-------------------------------------------------------------------------
+reset_db
+set saved $sqlite_fts3_enable_parentheses
+set sqlite_fts3_enable_parentheses 1
+do_execsql_test 43.1 {
+ CREATE VIRTUAL TABLE def USING fts3(xyz);
+ INSERT INTO def_segdir VALUES(0,0,0,0,0, X'0001310301c9000103323334050d81');
+} {}
+
+do_execsql_test 43.2 {
+ SELECT rowid FROM def WHERE def MATCH '1 NEAR 1'
+} {1}
+
+set sqlite_fts3_enable_parentheses $saved
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 44.1 {
+ CREATE VIRTUAL TABLE t0 USING fts3(col0 INTEGER PRIMARY KEY,col1 VARCHAR(8),col2 BINARY,col3 BINARY);
+ INSERT INTO t0_content VALUES(0,NULL,NULL,NULL,NULL);
+ INSERT INTO t0_segdir VALUES(0,0,0,0,'0 42',X'00013103010200010332333405010201ba00000461616161050101020200000462626262050101030200');
+}
+
+do_execsql_test 44.2 {
+ SELECT matchinfo(t0, t0) IS NULL FROM t0 WHERE t0 MATCH '1*'
+} {0}
+
+#-------------------------------------------------------------------------
+#
+reset_db
+do_test 45.0 {
+ sqlite3 db {}
+ db deserialize [decode_hexdb {
+.open --hexdb
+| size 24576 pagesize 4096 filename crash-65c98512cc9e49.db
+| page 1 offset 0
+| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
+| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 06 .....@ ........
+| 96: 00 00 00 00 0d 0e fc 00 06 0d bc 00 0f ca 0f 6c ...............l
+| 112: 0f 04 0e 13 0e c9 0d bc 00 00 00 00 00 00 00 00 ................
+| 3504: 00 00 00 00 00 00 00 00 00 00 00 00 55 06 07 17 ............U...
+| 3520: 1b 1b 01 81 01 74 61 62 6c 65 78 31 5f 73 74 61 .....tablex1_sta
+| 3536: 74 78 31 5f 73 74 61 74 06 43 52 45 41 54 45 20 tx1_stat.CREATE
+| 3552: 54 41 42 4c 45 20 27 78 31 5f 73 74 61 74 27 28 TABLE 'x1_stat'(
+| 3568: 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 id INTEGER PRIMA
+| 3584: 52 59 20 4b 45 59 2c 20 76 61 6c 75 65 20 42 4c RY KEY, value BL
+| 3600: 41 82 29 81 33 04 07 17 1f 1f 01 82 35 74 61 62 A.).3.......5tab
+| 3616: 6c 65 78 31 5f 73 65 67 64 69 72 78 31 5f 73 65 lex1_segdirx1_se
+| 3632: 67 64 69 72 04 43 52 45 41 54 45 20 54 41 42 4c gdir.CREATE TABL
+| 3648: 45 20 27 78 31 5f 73 65 67 64 69 72 27 28 6c 65 E 'x1_segdir'(le
+| 3664: 76 65 6c 20 49 4e 54 45 47 45 52 2c 69 64 78 20 vel INTEGER,idx
+| 3680: 49 4e 54 45 47 45 52 2c 73 74 61 72 74 5f 62 6c INTEGER,start_bl
+| 3696: 6f 63 6b 20 49 4e 54 45 47 45 52 2c 6c 65 61 76 ock INTEGER,leav
+| 3712: 65 73 5f 65 6e 64 5f 62 6c 6f 63 6b 20 49 4e 54 es_end_block INT
+| 3728: 45 47 45 52 2c 65 6e 64 5f 62 6c 6f 63 6b 20 49 EGER,end_block I
+| 3744: 4e 54 45 47 45 52 2c 72 6f 6f 74 20 42 4c 4f 42 NTEGER,root BLOB
+| 3760: 2c 50 52 49 4d 41 52 59 20 4b 45 59 28 6c 65 76 ,PRIMARY KEY(lev
+| 3776: 65 6c 2c 20 69 64 78 29 29 31 05 06 17 45 1f 01 el, idx))1...E..
+| 3792: 00 69 6e 64 65 78 73 71 6c 69 74 65 5f 61 75 74 .indexsqlite_aut
+| 3808: 6f 69 6e 64 65 78 5f 78 31 5f 73 65 67 64 69 72 oindex_x1_segdir
+| 3824: 5f 31 78 31 5f 73 65 67 64 69 72 05 00 00 00 08 _1x1_segdir.....
+| 3840: 60 00 00 00 66 03 07 17 23 23 01 81 13 74 61 62 `...f...##...tab
+| 3856: 6c 65 78 31 5f 73 65 67 6d 65 6e 74 73 78 31 5f lex1_segmentsx1_
+| 3872: 73 65 67 6d 65 6e 74 73 03 43 52 45 41 54 45 20 segments.CREATE
+| 3888: 54 41 42 4c 45 20 27 78 31 5f 73 65 67 6d 65 6e TABLE 'x1_segmen
+| 3904: 74 73 27 28 62 6c 6f 63 6b 69 64 20 49 4e 54 45 ts'(blockid INTE
+| 3920: 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c GER PRIMARY KEY,
+| 3936: 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 5c 02 07 17 block BLOB)....
+| 3952: 21 21 01 81 03 74 61 62 6c 65 78 31 5f 63 6f 6e !!...tablex1_con
+| 3968: 74 65 6e 74 78 31 5f 63 6f 6e 74 65 6e 74 02 43 tentx1_content.C
+| 3984: 52 45 41 54 45 20 54 41 42 4c 45 20 27 78 31 5f REATE TABLE 'x1_
+| 4000: 63 6f 6e 74 65 6e 74 27 28 64 6f 63 69 64 20 49 content'(docid I
+| 4016: 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b NTEGER PRIMARY K
+| 4032: 45 59 2c 20 27 63 30 78 27 29 34 01 06 17 11 11 EY, 'c0x')4.....
+| 4048: 08 57 74 61 62 6c 65 78 31 78 31 43 52 45 41 54 .Wtablex1x1CREAT
+| 4064: 45 20 56 49 52 54 55 41 4c 20 54 41 42 4c 45 20 E VIRTUAL TABLE
+| 4080: 78 31 20 55 53 49 4e 47 20 66 74 73 33 28 78 29 x1 USING fts3(x)
+| page 2 offset 4096
+| 0: 0d 00 00 00 11 0f 77 f0 0f f8 0f f0 0f e8 0f e0 ......w.........
+| 16: 0f d8 0f d0 0f c8 0f c0 00 00 00 00 00 00 00 00 ................
+| 3952: 00 00 00 00 00 00 00 00 06 11 03 00 13 77 78 79 .............wxy
+| 3968: 06 10 03 00 13 74 75 76 06 0f 03 00 13 71 33 73 .....tuv.....q3s
+| 3984: 06 0e 03 00 13 6e 6f 70 06 0d 03 00 13 6b 6c 6d .....nop.....klm
+| 4000: 06 0c 03 04 c3 68 69 6a 06 0b 03 00 13 65 66 67 .....hij.....efg
+| 4016: 06 0a 03 00 13 62 63 64 06 09 03 00 13 79 7a 61 .....bcd.....yza
+| 4032: 06 08 03 00 13 76 77 78 06 07 03 00 13 73 74 75 .....vwx.....stu
+| 4048: 06 06 03 00 13 70 71 72 06 05 03 00 13 6d 6e 6f .....pqr.....mno
+| 4064: 06 03 03 00 13 6a 6b 6c 06 03 03 00 13 67 68 69 .....jkl.....ghi
+| 4080: 06 02 02 00 03 64 65 66 06 01 03 00 13 61 52 63 .....def.....aRc
+| page 3 offset 8192
+| 0: 0d 00 00 00 03 0f a7 00 0f b5 0f a7 0f fa 01 00 ................
+| 4000: 00 00 00 00 00 00 00 0c 02 03 00 1e 00 03 6b 6c ..............kl
+| 4016: 6d 03 0d 02 00 43 01 04 00 81 0a 00 03 61 62 63 m....C.......abc
+| 4032: 03 0b 32 00 00 03 62 63 64 03 0a 02 00 00 03 64 ..2...bcd......d
+| 4048: 69 26 03 02 02 00 00 03 65 66 67 03 0b 02 00 00 i&......efg.....
+| 4064: 03 67 68 69 03 03 02 00 00 03 68 69 6a 03 0c 02 .ghi......hij...
+| 4080: 00 00 03 6a 6a 2c 03 04 02 00 03 81 00 03 00 00 ...jj,..........
+| page 4 offset 12288
+| 0: 0d 0f 3a 00 05 0f 25 00 0f 9e 0f 88 0f 43 0f 25 ..:...%......C.%
+| 16: 0f 72 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .r..............
+| 3856: 00 00 00 00 00 00 00 00 00 56 01 08 08 13 1e 03 .........V......
+| 3872: 30 20 39 00 03 13 05 07 08 08 18 08 13 1e 30 20 0 9...........0
+| 3888: 39 00 03 77 78 79 03 11 02 00 0f 6c 00 09 01 08 9..wxy.....l....
+| 3904: 08 15 54 27 04 07 09 01 08 08 15 42 02 30 20 33 ..T'.......B.0 3
+| 3920: 36 00 03 6e 6f 70 03 0e 02 00 00 03 71 72 73 03 6..nop......qrs.
+| 3936: 0f 02 00 00 03 74 75 76 03 10 02 00 0f cf b1 06 .....tuv........
+| 3952: 01 08 14 06 07 01 08 09 01 1b 14 02 02 31 32 38 .............128
+| 3968: 20 2d 37 32 10 01 01 6b 14 03 07 09 09 08 08 15 -72...k........
+| 3984: 1e 30 20 33 36 00 03 79 7a 61 03 09 02 00 2f 02 .0 36..yza..../.
+| 4000: 07 09 08 08 08 15 54 30 20 33 36 00 03 6d 6e 6f ......T0 36..mno
+| 4016: 03 05 02 00 00 03 70 71 72 03 06 02 00 00 03 73 ......pqr......s
+| 4032: 74 75 03 07 02 00 00 03 76 77 78 03 08 02 00 00 tu......vwx.....
+| 4048: 00 00 4a 08 08 08 15 54 30 20 33 36 00 03 61 62 ..J....T0 36..ab
+| 4064: 63 03 01 02 00 00 03 64 65 66 03 02 02 00 00 03 c......def......
+| 4080: 67 68 69 03 03 67 00 00 03 6a 6b 6c 03 04 02 00 ghi..g...jkl....
+| page 5 offset 16384
+| 0: 0a 0f e7 00 05 0f da 00 0f e1 0f fa 0f f4 0f ed ................
+| 16: 0f da 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+| 4048: 00 00 00 00 00 00 00 1a 01 03 06 04 01 08 01 02 ................
+| 4064: 06 05 04 08 08 01 05 00 00 00 06 01 03 06 04 09 ................
+| 4080: 02 01 02 04 05 04 09 09 01 03 05 04 09 08 01 02 ................
+| page 6 offset 20480
+| 0: 0d 00 10 00 01 0f f9 00 0f f9 00 00 00 00 00 00 ................
+| 4080: 00 00 00 00 00 00 00 00 00 05 01 03 00 10 01 03 ................
+| end crash-65c98512cc9e49.db
+}]} {}
+
+do_catchsql_test 45.2 {
+ INSERT INTO x1(x1) VALUES( 'merge=1' )
+} {1 {database disk image is malformed}}
+
+#-------------------------------------------------------------------------
+reset_db
+set saved $sqlite_fts3_enable_parentheses
+set sqlite_fts3_enable_parentheses 1
+do_execsql_test 46.1 {
+ CREATE VIRTUAL TABLE t0 USING fts3(a INTEGER PRIMARY KEY,b,c,d);
+ INSERT INTO t0_segdir VALUES(0,0,0,0,'0 42',X'0001310301c9000103323334050d8000f200000461616161050101020200000462626262050101030200');
+} {}
+
+do_catchsql_test 46.2 {
+ SELECT * FROM t0
+ WHERE t0 MATCH x'2b0a312b0a312a312a2a0b5d0a0b0b0a312a0a0b0b0a312a0b310a392a0b0a27312a2a0b5d0a312a0b310a31315d0b310a312a316d2a0b313b15bceaa50a312a0b0a27312a2a0b5d0a312a0b310a312b0b2a310a312a0b2a0b2a0b2e5d0a0bff313336e34a2a312a0b0a3c310b0a0b4b4b0b4b2a4bec40322b2a0b310a0a312a0a0a0a0a0a0a0a0a0b310a312a2a2a0b5d0a0b0b0a312a0b310a312a0b0a4e4541530b310a5df5ced70a0a0a0a0a4f520a0a0a0a0a0a0a312a0b0a4e4541520b310a5d616161610a0a0a0a4f520a0a0a0a0a0a312b0a312a312a0a0a0a0a0a0a004a0b0a310b220a0b0a310a4a22310a0b0a7e6fe0e0e030e0e0e0e0e01176e02000e0e0e0e0e01131320226310a0b0a310a4a22310a0b0a310a766f8b8b4ee0e0300ae0090909090909090909090909090909090909090909090909090909090909090947aaaa540b09090909090909090909090909090909090909090909090909090909090909fae0e0f2f22164e0e0f273e07fefefef7d6dfafafafa6d6d6d6d';
+} {1 {database disk image is malformed}}
+
+set sqlite_fts3_enable_parentheses $saved
+extra_schema_checks 1
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 47.1 {
+ CREATE VIRTUAL TABLE t1 USING fts3(a,b,c);
+}
+do_execsql_test 47.2 {
+ INSERT INTO t1_segdir VALUES(0,0,0,0,0,X'000130120106000106000106001f030001030001030000083230313630363039090107000107000107000001340901050001050001050000013509010400010400010400010730303030303030091c0400010400010400000662696e6172793c0301020200030102020003010202000301020200030102020003010202000301020200030102020003010202000301020200030102020003010202000008636f6d70696c657209010200010200010200000664627374617409070300010300010300010465627567090402000102000102000006656e61626c653f07020001020001020001020001020001020001020001020001020001020001020001020001010001020001020001020001020001020001020001020001020001087874656e73696f6e091f0400010400010400000466747334090a0300010300010300030135090d03000103000103000003676363090103000103000103000106656f706f6c790910030001030001030000056a736f6e310913030001030001030000046c6f6164091f030001030001030000036d6178091c02000102000102000105656d6f7279091c03000103000103000304737973350916030001030001030000066e6f636173653c02010202000301020200030102020003010202000301020200030102020003010202000301020200030102020003010202000301020200030102020000046f6d6974091f020001020001020000057274726565091903000103000103000302696d3c01010202000301020200030102020003010202000301020200030102020003010202000301a202000301020200030102020003010202000301020200000a746872656164736166650922020001020001020000047674616209070400010400010400000178b401010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200');
+ INSERT INTO t1_segdir VALUES(0,1,0,0,0,X'0001300425061b000008323031363036303903250700000134032505000001350325040001073030303030303003251a000008636f6d70696c657203250200000664627374617403250a00010465627567032508000006656e61626c650925090504040404040001087874656e73696f6e03251d0000046674733403250d0003013503250f000003676363032503000106656f706f6c790325110000056a736f6e310325130000046c6f616403251c0000036d6178032518000105656d6f7279032519000304737973350325150000046f6d697403251b000005727472656503251700000a7468726561647361666503251e0000047674616333250b00');
+}
+
+do_catchsql_test 47.3 {
+ SELECT matchinfo(t1) FROM t1 WHERE t1 MATCH '"json1 enable"';
+} {1 {database disk image is malformed}}
finish_test
diff --git a/test/fts3corrupt6.test b/test/fts3corrupt6.test
new file mode 100644
index 0000000000..9e22bdf68a
--- /dev/null
+++ b/test/fts3corrupt6.test
@@ -0,0 +1,60 @@
+# 2020 June 8
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#*************************************************************************
+# This file implements regression tests for SQLite library. The
+# focus of this script is testing the FTS3 module.
+#
+# $Id: fts3aa.test,v 1.1 2007/08/20 17:38:42 shess Exp $
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/fts3_common.tcl
+set testprefix fts3corrupt6
+
+# If SQLITE_ENABLE_FTS3 is defined, omit this file.
+ifcapable !fts3 {
+ finish_test
+ return
+}
+
+set ::saved_sqlite_fts3_enable_parentheses $::sqlite_fts3_enable_parentheses
+set sqlite_fts3_enable_parentheses 1
+sqlite3_fts3_may_be_corrupt 1
+database_may_be_corrupt
+
+do_execsql_test 1.0 {
+ BEGIN TRANSACTION;
+ CREATE TABLE t_content(col0 INTEGER);
+ PRAGMA writable_schema=ON;
+ CREATE VIRTUAL TABLE t0 USING fts3(col0 INTEGER PRIMARY KEY,col1 VARCHAR(8),col2 BINARY,col3 BINARY);
+ INSERT INTO t0_content VALUES(0,NULL,NULL,NULL,NULL);
+ INSERT INTO t0_segdir VALUES(0,0,0,0,'0 42',X'000131030102000103323334050101010200000461616161050101020200000462626262050101030200');
+ COMMIT;
+}
+
+do_execsql_test 1.1 {
+ SELECT 0+matchinfo(t0,'yxyyxy') FROM t0 WHERE t0 MATCH CAST( x'2b0a312b0a312a312a2a0b5d0a0b0b0a312a0a0b0b0a312a0b310a392a0b0a27312a2a0b5d0a312a0b310a31315d0b310a312a316d2a0b313b15bceaa50a312a0b0a27312a2a0b5d0a312a0b310a312b0b2a310a312a0b2a0b2a0b2e5d0a0bff313336e34a2a312a0b0a3c310b0a0b4b4b0b4b2a4bec40322b2a0b310a0a312a0a0a0a0a0a0a0a0a0b310a312a2a2a0b5d0a0b0b0a312a0b310a312a0b0a4e4541530b310a5df5ced70a0a0a0a0a4f520a0a0a0a0a0a0a312a0b0a4e4541520b310a5d616161610a0a0a0a4f520a0a0a0a0a0a312b0a312a312a0a0a0a0a0a0a004a0b0a310b220a0b0a310a4a22310a0b0a7e6fe0e0e030e0e0e0e0e01176e02000e0e0e0e0e01131320226310a0b0a310a4a22310a0b0a310a766f8b8b4ee0e0300ae0090909090909090909090909090909090909090909090909090909090909090947aaaa540b09090909090909090909090909090909090909090909090909090909090909fae0e0f2f22164e0e0f273e07fefefef7d6dfafafafa6d6d6d6d' AS TEXT);
+} {0}
+
+do_execsql_test 1.2 {
+ CREATE VIRTUAL TABLE t1 USING fts3(col0 INTEGER PRIMARY KEY,col1 VARCHAR(8),col2 BINARY,col3 BINARY);
+ INSERT INTO t1_content VALUES(0,NULL,NULL,NULL,NULL);
+ INSERT INTO t1_segdir VALUES(0,0,0,0,'0 42',X'000131030102000103323334050101010200000461616161050101020200000462626262050101030200');
+}
+
+do_execsql_test 1.3 {
+ SELECT 42+matchinfo(t1,'yxyyxy') FROM t1 WHERE t1 MATCH x'2b0a312b0a312a312a2a0b5d0a0b0b0a312a0a0b0b0a312a0b310a392a0b0a27312a2a0b5d0a312a0b310a31315d0b310a312a316d2a0b313b15bceaa50a312a0b0a27312a2a0b5d0a312a0b310a312b0b2a310a312a0b2a0b2a0b2e5d0a0bff313336e34a2a312a0b0a3c310b0a0b4b4b0b4b2a4bec40322b2a0b310a0a312a0a0a0a0a0a0a0a0a0b310a312a2a2a0b5d0a0b0b0a312a0b310a312a0b0a4e4541530b310a5df5ced70a0a0a0a0a4f520a0a0a0a0a0a0a312a0b0a4e4541520b310a5d616161610a0a0a0a4f520a0a0a0a0a0a312b0a312a312a0a0a0a0a0a0a004a0b0a310b220a0b0a310a4a22310a0b0a7e6fe0e0e030e0e0e0e0e01176e02000e0e0e0e0e01131320226310a0b0a310a4a22310a0b0a310a766f8b8b4ee0e0300ae0090909090909090909090909090909090909090909090909090909090909090947aaaa540b09090909090909090909090909090909090909090909090909090909090909fae0e0f2f22164e0e0f273e07fefefef7d6dfafafafa6d6d6d6d';
+} {42}
+
+set sqlite_fts3_enable_parentheses $saved_sqlite_fts3_enable_parentheses
+finish_test
+
+
diff --git a/test/fts4upfrom.test b/test/fts4upfrom.test
new file mode 100644
index 0000000000..b1b43a0374
--- /dev/null
+++ b/test/fts4upfrom.test
@@ -0,0 +1,140 @@
+# 2020 February 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.
+#
+#*************************************************************************
+# This file implements regression tests for SQLite library. The
+# focus of this script is testing UPDATE statements with FROM clauses
+# against FTS4 tables.
+#
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix fts4upfrom
+
+# If SQLITE_ENABLE_FTS3 is defined, omit this file.
+ifcapable !fts3 {
+ finish_test
+ return
+}
+
+foreach {tn create_table} {
+ 0 { CREATE VIRTUAL TABLE ft USING fts5(a, b, c) }
+ 1 { CREATE VIRTUAL TABLE ft USING fts3(a, b, c) }
+ 2 { CREATE TABLE ft(a, b, c) }
+ 3 {
+ CREATE TABLE real(a, b, c);
+ CREATE INDEX i1 ON real(a);
+ CREATE VIEW ft AS SELECT rowid, a, b, c FROM real;
+ CREATE TRIGGER tr1 INSTEAD OF INSERT ON ft BEGIN
+ INSERT INTO real(rowid, a, b, c) VALUES(new.rowid, new.a, new.b, new.c);
+ END;
+ CREATE TRIGGER tr2 INSTEAD OF UPDATE ON ft BEGIN
+ UPDATE real SET rowid=new.rowid, a=new.a, b=new.b, c=new.c
+ WHERE rowid=old.rowid;
+ END;
+ }
+} {
+ if {$tn==0} { ifcapable !fts5 { continue } }
+ catchsql { DROP VIEW IF EXISTS changes }
+ catchsql { DROP TABLE IF EXISTS ft }
+ catchsql { DROP VIEW IF EXISTS ft }
+ execsql $create_table
+
+ do_execsql_test 1.$tn.0 {
+ INSERT INTO ft(a, b, c) VALUES('a', NULL, 'apple');
+ INSERT INTO ft(a, b, c) VALUES('b', NULL, 'banana');
+ INSERT INTO ft(a, b, c) VALUES('c', NULL, 'cherry');
+ INSERT INTO ft(a, b, c) VALUES('d', NULL, 'damson plum');
+ }
+
+ do_execsql_test 1.$tn.1 {
+ SELECT a, b, c FROM ft ORDER BY rowid;
+ } {
+ a {} apple
+ b {} banana
+ c {} cherry
+ d {} {damson plum}
+ }
+
+ do_execsql_test 1.$tn.2 {
+ UPDATE ft SET b=o.c FROM ft AS o WHERE (ft.a == char(unicode(o.a)+1))
+ }
+
+ do_execsql_test 1.$tn.3 {
+ SELECT a, b, c FROM ft ORDER BY rowid;
+ } {
+ a {} apple
+ b apple banana
+ c banana cherry
+ d cherry {damson plum}
+ }
+
+ do_catchsql_test 1.$tn.4 {
+ UPDATE ft SET c=v FROM changes WHERE a=k;
+ } {1 {no such table: changes}}
+
+ do_execsql_test 1.$tn.5 {
+ create view changes(k, v) AS
+ VALUES( 'd', 'dewberry' ) UNION ALL
+ VALUES( 'c', 'clementine' ) UNION ALL
+ VALUES( 'b', 'blueberry' ) UNION ALL
+ VALUES( 'a', 'apricot' )
+ ;
+ }
+
+ do_execsql_test 1.$tn.6 {
+ UPDATE ft SET c=v FROM changes WHERE a=k;
+ }
+
+ do_execsql_test 1.$tn.7 {
+ SELECT rowid, a, b, c FROM ft ORDER BY rowid;
+ } {
+ 1 a {} apricot
+ 2 b apple blueberry
+ 3 c banana clementine
+ 4 d cherry dewberry
+ }
+
+ do_execsql_test 1.$tn.8 "
+ WITH x1(o, n) AS (
+ VALUES(1, 11) UNION ALL
+ VALUES(2, 12) UNION ALL
+ VALUES(3, 13) UNION ALL
+ VALUES(4, 14)
+ )
+ SELECT ft.rowid, a, b, c, o, n FROM ft, x1 WHERE ft.rowid = o;
+ " {
+ 1 a {} apricot 1 11
+ 2 b apple blueberry 2 12
+ 3 c banana clementine 3 13
+ 4 d cherry dewberry 4 14
+ }
+
+ set ROWID rowid
+ if {$tn==1} { set ROWID docid }
+ do_execsql_test 1.$tn.9 "
+ WITH x1(o, n) AS (
+ VALUES(1, 11) UNION ALL
+ VALUES(2, 12) UNION ALL
+ VALUES(3, 13) UNION ALL
+ VALUES(4, 14)
+ )
+ UPDATE ft SET $ROWID = n FROM x1 WHERE ft.rowid = o;
+ SELECT rowid, a, b, c FROM ft ORDER BY rowid;
+ " {
+ 11 a {} apricot
+ 12 b apple blueberry
+ 13 c banana clementine
+ 14 d cherry dewberry
+ }
+}
+
+finish_test
+
diff --git a/test/fuzzdata8.db b/test/fuzzdata8.db
index 350ffa2631..2408696440 100644
Binary files a/test/fuzzdata8.db and b/test/fuzzdata8.db differ
diff --git a/test/gencol1.test b/test/gencol1.test
index 5276d9694d..43f48dff78 100644
--- a/test/gencol1.test
+++ b/test/gencol1.test
@@ -560,4 +560,30 @@ do_catchsql_test gencol1-19.10 {
INSERT INTO t0(c1) VALUES(0.16334143182538696), (0);
} {1 {UNIQUE constraint failed: t0.c0}}
+# 2020-06-29 forum bug report.
+# https://sqlite.org/forum/forumpost/73b9a8ccfb
+#
+do_execsql_test gencol1-20.1 {
+ CREATE TEMPORARY TABLE tab (
+ prim DATE PRIMARY KEY,
+ a INTEGER,
+ comp INTEGER AS (a),
+ b INTEGER,
+ x INTEGER
+ );
+ -- Add some data
+ INSERT INTO tab (prim, a, b) VALUES ('2001-01-01', 0, 0);
+ -- Check that each column is 0 like I expect
+ SELECT * FROM tab;
+} {2001-01-01 0 0 0 {}}
+do_execsql_test gencol1-20.2 {
+ -- Do an UPSERT on the b column
+ INSERT INTO tab (prim, b)
+ VALUES ('2001-01-01',5)
+ ON CONFLICT(prim) DO UPDATE SET b=excluded.b;
+ -- Now b is NULL rather than 5
+ SELECT * FROM tab;
+} {2001-01-01 0 0 5 {}}
+
+
finish_test
diff --git a/test/hook.test b/test/hook.test
index 1c9145baef..d137e9056f 100644
--- a/test/hook.test
+++ b/test/hook.test
@@ -142,9 +142,8 @@ do_test hook-4.1.1a {
set ::update_hook {}
db update_hook [list lappend ::update_hook]
#
- # EVIDENCE-OF: R-52223-27275 The update hook is not invoked when
- # internal system tables are modified (i.e. sqlite_master and
- # sqlite_sequence).
+ # EVIDENCE-OF: R-24531-54682 The update hook is not invoked when
+ # internal system tables are modified (i.e. sqlite_sequence).
#
execsql {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
diff --git a/test/ieee754.test b/test/ieee754.test
index bf0676429b..bd806d2cf3 100644
--- a/test/ieee754.test
+++ b/test/ieee754.test
@@ -23,8 +23,8 @@ foreach {id float rep} {
3 0.5 1,-1
4 1.5 3,-1
5 0.0 0,-1075
- 6 4.9406564584124654e-324 4503599627370497,-1075
- 7 2.2250738585072009e-308 9007199254740991,-1075
+ 6 4.9406564584124654e-324 1,-1074
+ 7 2.2250738585072009e-308 4503599627370495,-1074
8 2.2250738585072014e-308 1,-1022
} {
do_test ieee754-100-$id-1 {
diff --git a/test/index7.test b/test/index7.test
index f57792e4c2..084e8c3c7d 100644
--- a/test/index7.test
+++ b/test/index7.test
@@ -339,5 +339,17 @@ do_execsql_test index7-7.1 {
SELECT * FROM t6 WHERE y IS TRUE ORDER BY x;
} {1 1}
+# 2020-05-27. tag-20200527-1.
+# Incomplete stat1 information on a table with few rows should still use the
+# index.
+reset_db
+do_execsql_test index7-8.1 {
+ CREATE TABLE t1(x INTEGER PRIMARY KEY, y);
+ CREATE INDEX t1y ON t1(y) WHERE y IS NOT NULL;
+ INSERT INTO t1(x) VALUES(1),(2);
+ ANALYZE;
+ EXPLAIN QUERY PLAN SELECT 1 FROM t1 WHERE y=5;
+} {/SEARCH TABLE t1 USING COVERING INDEX t1y/}
+
finish_test
diff --git a/test/indexedby.test b/test/indexedby.test
index 8624b10c75..18f7bb8fa3 100644
--- a/test/indexedby.test
+++ b/test/indexedby.test
@@ -95,7 +95,7 @@ do_test indexedby-2.4 {
# an error.
do_test indexedby-2.4.1 {
catchsql { SELECT b FROM t1 INDEXED BY i1 WHERE b = 'two' }
-} {1 {no query solution}}
+} {0 {}}
do_test indexedby-2.5 {
catchsql { SELECT * FROM t1 INDEXED BY i5 WHERE a = 'one' AND b = 'two'}
@@ -135,10 +135,10 @@ do_eqp_test indexedby-3.3 {
} {SEARCH TABLE t1 USING INDEX i2 (b=?)}
do_test indexedby-3.4 {
catchsql { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' }
-} {1 {no query solution}}
+} {0 {}}
do_test indexedby-3.5 {
catchsql { SELECT * FROM t1 INDEXED BY i2 ORDER BY a }
-} {1 {no query solution}}
+} {0 {}}
do_test indexedby-3.6 {
catchsql { SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' }
} {0 {}}
@@ -154,7 +154,7 @@ do_eqp_test indexedby-3.9 {
} {SEARCH TABLE t3 USING INDEX sqlite_autoindex_t3_1 (e=?)}
do_test indexedby-3.10 {
catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE f = 10 }
-} {1 {no query solution}}
+} {0 {}}
do_test indexedby-3.11 {
catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_2 WHERE f = 10 }
} {1 {no such index: sqlite_autoindex_t3_2}}
@@ -172,19 +172,19 @@ do_eqp_test indexedby-4.2 {
SELECT * FROM t1 INDEXED BY i1, t2 WHERE a = c
} {
QUERY PLAN
- |--SCAN TABLE t2
- `--SEARCH TABLE t1 USING INDEX i1 (a=?)
+ |--SCAN TABLE t1 USING INDEX i1
+ `--SEARCH TABLE t2 USING INDEX i3 (c=?)
}
do_test indexedby-4.3 {
catchsql {
SELECT * FROM t1 INDEXED BY i1, t2 INDEXED BY i3 WHERE a=c
}
-} {1 {no query solution}}
+} {0 {}}
do_test indexedby-4.4 {
catchsql {
SELECT * FROM t2 INDEXED BY i3, t1 INDEXED BY i1 WHERE a=c
}
-} {1 {no query solution}}
+} {0 {}}
# Test embedding an INDEXED BY in a CREATE VIEW statement. This block
# also tests that nothing bad happens if an index refered to by
@@ -205,7 +205,7 @@ do_test indexedby-5.4 {
# Recreate index i1 in such a way as it cannot be used by the view query.
execsql { CREATE INDEX i1 ON t1(b) }
catchsql { SELECT * FROM v2 }
-} {1 {no query solution}}
+} {0 {}}
do_test indexedby-5.5 {
# Drop and recreate index i1 again. This time, create it so that it can
# be used by the query.
@@ -245,7 +245,7 @@ do_eqp_test indexedby-7.5 {
} {SEARCH TABLE t1 USING INDEX i2 (b=?)}
do_test indexedby-7.6 {
catchsql { DELETE FROM t1 INDEXED BY i2 WHERE a = 5}
-} {1 {no query solution}}
+} {0 {}}
# Test that "INDEXED BY" can be used in an UPDATE statement.
#
@@ -266,7 +266,7 @@ do_eqp_test indexedby-8.5 {
} {SEARCH TABLE t1 USING INDEX i2 (b=?)}
do_test indexedby-8.6 {
catchsql { UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5}
-} {1 {no query solution}}
+} {0 {}}
# Test that bug #3560 is fixed.
#
@@ -284,10 +284,10 @@ do_test indexedby-9.2 {
joinme as j indexed by joinme_id_text_idx
on ( m.id = j.id_int)
}
-} {1 {no query solution}}
+} {0 {}}
do_test indexedby-9.3 {
catchsql { select * from maintable, joinme INDEXED by joinme_id_text_idx }
-} {1 {no query solution}}
+} {0 {}}
# Make sure we can still create tables, indices, and columns whose name
# is "indexed".
diff --git a/test/istrue.test b/test/istrue.test
index d2768b3798..b2f5b8d22b 100644
--- a/test/istrue.test
+++ b/test/istrue.test
@@ -172,4 +172,33 @@ do_execsql_test istrue-710 {
SELECT 0.0 IS FALSE COLLATE BINARY;
} {1 1 1 1 1 1 1 1 1}
+# 2020-06-12 bug report from Chromium
+# https://bugs.chromium.org/p/chromium/issues/detail?id=1094247
+do_catchsql_test istrue-800 {
+ SELECT 9 IN (false.false);
+} {1 {no such column: false.false}}
+do_execsql_test istrue-810 {
+ CREATE TABLE t8(a INT, true INT, false INT, d INT);
+ INSERT INTO t8(a,true,false,d) VALUES(5,6,7,8),(4,3,2,1),('a','b','c','d');
+ SELECT * FROM t8 ORDER BY false;
+} {4 3 2 1 5 6 7 8 a b c d}
+do_catchsql_test istrue-820 {
+ SELECT 9 IN (false.false) FROM t8;
+} {1 {no such column: false.false}}
+do_execsql_test istrue-830 {
+ CREATE TABLE false(true INT, false INT, x INT CHECK (5 IN (false.false)));
+} {}
+do_execsql_test istrue-840 {
+ INSERT INTO False VALUES(4,5,6);
+} {}
+do_catchsql_test istrue-841 {
+ INSERT INTO False VALUES(5,6,7);
+} {1 {CHECK constraint failed: false}}
+do_execsql_test istrue-850 {
+ SELECT 9 IN (false.false) FROM false;
+} {0}
+do_execsql_test istrue-851 {
+ SELECT 5 IN (false.false) FROM false;
+} {1}
+
finish_test
diff --git a/test/kvtest.c b/test/kvtest.c
index 8c73caf1d7..04dc01045c 100644
--- a/test/kvtest.c
+++ b/test/kvtest.c
@@ -907,7 +907,7 @@ static int runMain(int argc, char **argv){
if( eType==PATH_DB ){
/* Recover any prior crashes prior to starting the timer */
sqlite3_open(zDb, &db);
- sqlite3_exec(db, "SELECT rowid FROM sqlite_master LIMIT 1", 0, 0, 0);
+ sqlite3_exec(db, "SELECT rowid FROM sqlite_schema LIMIT 1", 0, 0, 0);
sqlite3_close(db);
db = 0;
}
diff --git a/test/misc7.test b/test/misc7.test
index e75a684099..25f96af34c 100644
--- a/test/misc7.test
+++ b/test/misc7.test
@@ -455,12 +455,13 @@ if {$tcl_platform(platform)!="windows"} {
catchsql {
SELECT count(*) FROM t3;
}
- } {1 {database disk image is malformed}}
+ } {1 {malformed database schema (t3) - invalid rootpage}}
}
}
# Ticket #2470
#
+reset_db
do_test misc7-18.1 {
execsql {
CREATE TABLE table_1 (col_10);
diff --git a/test/mutex1.test b/test/mutex1.test
index f567a0d930..aac04bf49e 100644
--- a/test/mutex1.test
+++ b/test/mutex1.test
@@ -38,7 +38,7 @@ proc mutex_counters {varname} {
#-------------------------------------------------------------------------
# Tests mutex1-1.* test that sqlite3_config() returns SQLITE_MISUSE if
# is called at the wrong time. And that the first time sqlite3_initialize
-# is called it obtains the 'static_master' mutex 3 times and a recursive
+# is called it obtains the 'static_main' mutex 3 times and a recursive
# mutex (sqlite3Config.pInitMutex) twice. Subsequent calls are no-ops
# that do not require any mutexes.
#
@@ -75,7 +75,7 @@ do_test mutex1-1.6 {
do_test mutex1-1.7 {
mutex_counters counters
- # list $counters(total) $counters(static_master)
+ # list $counters(total) $counters(static_main)
expr {$counters(total)>0}
} {1}
@@ -86,7 +86,7 @@ do_test mutex1-1.8 {
do_test mutex1-1.9 {
mutex_counters counters
- list $counters(total) $counters(static_master)
+ list $counters(total) $counters(static_main)
} {0 0}
#-------------------------------------------------------------------------
@@ -103,13 +103,13 @@ ifcapable threadsafe1&&shared_cache {
singlethread {}
multithread {
fast static_app1 static_app2 static_app3
- static_lru static_master static_mem static_open
+ static_lru static_main static_mem static_open
static_prng static_pmem static_vfs1 static_vfs2
static_vfs3
}
serialized {
fast recursive static_app1 static_app2
- static_app3 static_lru static_master static_mem
+ static_app3 static_lru static_main static_mem
static_open static_prng static_pmem static_vfs1
static_vfs2 static_vfs3
}
diff --git a/test/optfuzz-db01.c b/test/optfuzz-db01.c
index 1cd3867e18..e11f15cc2e 100644
--- a/test/optfuzz-db01.c
+++ b/test/optfuzz-db01.c
@@ -945,4 +945,3 @@ unsigned char data001[] = {
78, 32,116, 49, 32, 79, 78, 32, 40,116, 49, 46, 97, 61, 53, 48, 45, 99, 48,
46,120, 41,
};
-
diff --git a/test/pager1.test b/test/pager1.test
index 8216b467ed..20fd8bd17a 100644
--- a/test/pager1.test
+++ b/test/pager1.test
@@ -1930,6 +1930,7 @@ do_test pager1-18.4 {
catchsql { SELECT length(x||'') FROM t2 } db2
} {1 {database disk image is malformed}}
db2 close
+extra_schema_checks 0
do_test pager1-18.5 {
sqlite3 db ""
sqlite3_db_config db DEFENSIVE 0
@@ -1944,6 +1945,7 @@ do_test pager1-18.5 {
catchsql { SELECT * FROM x1 }
} {1 {database disk image is malformed}}
db close
+extra_schema_checks 1
do_test pager1-18.6 {
faultsim_delete_and_reopen
diff --git a/test/permutations.test b/test/permutations.test
index d8ec9e4a55..135f2e83c0 100644
--- a/test/permutations.test
+++ b/test/permutations.test
@@ -171,6 +171,12 @@ test_suite "veryquick" -prefix "" -description {
*fts5corrupt* *fts5big* *fts5aj*
]
+test_suite "shell" -prefix "" -description {
+ Run tests of the command-line shell
+} -files [
+ test_set [glob $testdir/shell*.test]
+]
+
test_suite "extraquick" -prefix "" -description {
"Extra" quick test suite. Runs in a few minutes on a workstation.
This test suite is the same as the "veryquick" tests, except that
@@ -968,6 +974,7 @@ test_suite "journaltest" -description {
pager1.test syscall.test tkt3457.test *malloc* mmap* multiplex* nolock*
pager2.test *fault* rowal* snapshot* superlock* symlink.test
delete_db.test shmlock.test chunksize.test
+ busy2.test
}]
if {[info commands register_demovfs] != ""} {
diff --git a/test/pg_common.tcl b/test/pg_common.tcl
index b3f35cd0ed..dd16659a67 100644
--- a/test/pg_common.tcl
+++ b/test/pg_common.tcl
@@ -18,6 +18,8 @@ sqlite3 sqlite ""
proc execsql {sql} {
+ set sql [string map {{WITHOUT ROWID} {}} $sql]
+
set lSql [list]
set frag ""
while {[string length $sql]>0} {
diff --git a/test/pragma.test b/test/pragma.test
index 1881a5c005..04f5bd0fbe 100644
--- a/test/pragma.test
+++ b/test/pragma.test
@@ -387,11 +387,15 @@ ifcapable attach {
PRAGMA integrity_check=4
}
} {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2}}
- do_test pragma-3.6 {
- execsql {
- PRAGMA integrity_check=xyz
- }
- } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
+ do_catchsql_test pragma-3.6 {
+ PRAGMA integrity_check=xyz
+ } {1 {no such table: xyz}}
+ do_catchsql_test pragma-3.6b {
+ PRAGMA integrity_check=t2
+ } {0 {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}}
+ do_catchsql_test pragma-3.6c {
+ PRAGMA integrity_check=sqlite_schema
+ } {0 ok}
do_test pragma-3.7 {
execsql {
PRAGMA integrity_check=0
@@ -423,7 +427,7 @@ ifcapable attach {
do_test pragma-3.8.2 {
execsql {PRAGMA QUICK_CHECK}
} {ok}
- do_test pragma-3.9 {
+ do_test pragma-3.9a {
execsql {
ATTACH 'testerr.db' AS t2;
PRAGMA integrity_check
@@ -432,6 +436,12 @@ ifcapable attach {
Page 4 is never used
Page 5 is never used
Page 6 is never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
+ do_execsql_test pragma-3.9b {
+ PRAGMA t2.integrity_check=t2;
+ } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
+ do_execsql_test pragma-3.9c {
+ PRAGMA t2.integrity_check=sqlite_schema;
+ } {ok}
do_test pragma-3.10 {
execsql {
PRAGMA integrity_check=1
diff --git a/test/pragma4.test b/test/pragma4.test
index 2eef060b6c..b82df81cbd 100644
--- a/test/pragma4.test
+++ b/test/pragma4.test
@@ -120,8 +120,15 @@ do_test 4.1.4 {
sqlite3 db2 test.db2
execsql { DROP TABLE t1 } db3
execsql { DROP TABLE t2 } db2
-} {}
-do_execsql_test 4.1.5 { PRAGMA table_info(t1) }
+} {}
+if {[permutation]=="prepare"} {
+ do_catchsql_test 4.1.5a {
+ PRAGMA table_info(t1)
+ } {1 {database schema has changed}}
+}
+do_execsql_test 4.1.5 {
+ PRAGMA table_info(t1)
+}
do_execsql_test 4.1.6 { PRAGMA table_info(t2) }
db2 close
diff --git a/test/printf.test b/test/printf.test
index d6acacb0f0..445470fc07 100644
--- a/test/printf.test
+++ b/test/printf.test
@@ -538,9 +538,11 @@ do_test printf-2.1.2.8 {
do_test printf-2.1.2.9 {
sqlite3_mprintf_double {abc: %d %d (%1.1g) :xyz} 1 1 1.0e-20
} {abc: 1 1 (1e-20) :xyz}
-do_test printf-2.1.2.10 {
- sqlite3_mprintf_double {abc: %*.*f} 2000000000 1000000000 1.0e-20
-} {}
+if {$SQLITE_MAX_LENGTH<=[expr 1000*1000*1000]} {
+ do_test printf-2.1.2.10 {
+ sqlite3_mprintf_double {abc: %*.*f} 2000000000 1000000000 1.0e-20
+ } {}
+}
do_test printf-2.1.3.1 {
sqlite3_mprintf_double {abc: (%*.*f) :xyz} 1 1 1.0
} {abc: (1.0) :xyz}
diff --git a/test/select3.test b/test/select3.test
index 50039c551e..fec8ba4a51 100644
--- a/test/select3.test
+++ b/test/select3.test
@@ -314,4 +314,13 @@ do_execsql_test select3-9.100 {
SELECT * FROM t0 GROUP BY c0;
} {1.0 1.0}
+reset_db
+do_execsql_test select3.10.100 {
+ CREATE TABLE t1(a, b);
+ CREATE TABLE t2(c, d);
+ SELECT max(t1.a),
+ (SELECT 'xyz' FROM (SELECT * FROM t2 WHERE 0) WHERE t1.b=1)
+ FROM t1;
+} {{} {}}
+
finish_test
diff --git a/test/selectA.test b/test/selectA.test
index 838e5f4323..7ca0096b1d 100644
--- a/test/selectA.test
+++ b/test/selectA.test
@@ -1446,5 +1446,26 @@ do_execsql_test 6.1 {
SELECT * FROM (SELECT a FROM t1 UNION SELECT b FROM t2) WHERE a=a;
} {12345}
+# 2020-06-15 ticket 8f157e8010b22af0
+#
+reset_db
+do_execsql_test 7.1 {
+ CREATE TABLE t1(c1); INSERT INTO t1 VALUES(12),(123),(1234),(NULL),('abc');
+ CREATE TABLE t2(c2); INSERT INTO t2 VALUES(44),(55),(123);
+ CREATE TABLE t3(c3,c4); INSERT INTO t3 VALUES(66,1),(123,2),(77,3);
+ CREATE VIEW t4 AS SELECT c3 FROM t3;
+ CREATE VIEW t5 AS SELECT c3 FROM t3 ORDER BY c4;
+}
+do_execsql_test 7.2 {
+ SELECT * FROM t1, t2 WHERE c1=(SELECT 123 INTERSECT SELECT c2 FROM t4) AND c1=123;
+} {123 123}
+do_execsql_test 7.3 {
+ SELECT * FROM t1, t2 WHERE c1=(SELECT 123 INTERSECT SELECT c2 FROM t5) AND c1=123;
+} {123 123}
+do_execsql_test 7.4 {
+ CREATE TABLE a(b);
+ CREATE VIEW c(d) AS SELECT b FROM a ORDER BY b;
+ SELECT sum(d) OVER( PARTITION BY(SELECT 0 FROM c JOIN a WHERE b =(SELECT b INTERSECT SELECT d FROM c) AND b = 123)) FROM c;
+} {}
finish_test
diff --git a/test/sessionfuzz.c b/test/sessionfuzz.c
index 1d0bee436c..d8cc1bebfb 100644
--- a/test/sessionfuzz.c
+++ b/test/sessionfuzz.c
@@ -698,7 +698,9 @@ static const char zHelp[] =
#include
#include
#include
+#ifndef OMIT_ZLIB
#include "zlib.h"
+#endif
/*
** Implementation of the "sqlar_uncompress(X,SZ)" SQL function
@@ -715,6 +717,9 @@ static void sqlarUncompressFunc(
int argc,
sqlite3_value **argv
){
+#ifdef OMIT_ZLIB
+ sqlite3_result_value(context, argv[0]);
+#else
uLong nData;
uLongf sz;
@@ -733,6 +738,7 @@ static void sqlarUncompressFunc(
}
sqlite3_free(pOut);
}
+#endif
}
diff --git a/test/shell1.test b/test/shell1.test
index c142ea7241..49af3aa35d 100644
--- a/test/shell1.test
+++ b/test/shell1.test
@@ -199,10 +199,10 @@ do_test shell1-2.2.4 {
} {0 {}}
do_test shell1-2.2.5 {
catchcmd "test.db" ".mode \"insert FOO"
-} {1 {Error: mode should be one of: ascii column csv html insert line list quote tabs tcl}}
+} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}}
do_test shell1-2.2.6 {
catchcmd "test.db" ".mode \'insert FOO"
-} {1 {Error: mode should be one of: ascii column csv html insert line list quote tabs tcl}}
+} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}}
# check multiple tokens, and quoted tokens
do_test shell1-2.3.1 {
@@ -230,7 +230,7 @@ do_test shell1-2.3.7 {
# check quoted args are unquoted
do_test shell1-2.4.1 {
catchcmd "test.db" ".mode FOO"
-} {1 {Error: mode should be one of: ascii column csv html insert line list quote tabs tcl}}
+} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}}
do_test shell1-2.4.2 {
catchcmd "test.db" ".mode csv"
} {0 {}}
@@ -430,7 +430,7 @@ do_test shell1-3.13.1 {
} {0 {current output mode: list}}
do_test shell1-3.13.2 {
catchcmd "test.db" ".mode FOO"
-} {1 {Error: mode should be one of: ascii column csv html insert line list quote tabs tcl}}
+} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}}
do_test shell1-3.13.3 {
catchcmd "test.db" ".mode csv"
} {0 {}}
@@ -463,10 +463,10 @@ do_test shell1-3.13.11 {
# don't allow partial mode type matches
do_test shell1-3.13.12 {
catchcmd "test.db" ".mode l"
-} {1 {Error: mode should be one of: ascii column csv html insert line list quote tabs tcl}}
+} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}}
do_test shell1-3.13.13 {
catchcmd "test.db" ".mode li"
-} {1 {Error: mode should be one of: ascii column csv html insert line list quote tabs tcl}}
+} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}}
do_test shell1-3.13.14 {
catchcmd "test.db" ".mode lin"
} {0 {}}
@@ -709,11 +709,11 @@ do_test shell1-3.26.4 {
# this should be treated the same as a '1' width for col 1 and 2
} {0 {}}
do_test shell1-3.26.5 {
- catchcmd "test.db" ".mode column\n.width 10 -10\nSELECT 'abcdefg', 123456;"
+ catchcmd "test.db" ".mode column\n.header off\n.width 10 -10\nSELECT 'abcdefg', 123456;"
# this should be treated the same as a '1' width for col 1 and 2
} {0 {abcdefg 123456}}
do_test shell1-3.26.6 {
- catchcmd "test.db" ".mode column\n.width -10 10\nSELECT 'abcdefg', 123456;"
+ catchcmd "test.db" ".mode column\n.header off\n.width -10 10\nSELECT 'abcdefg', 123456;"
# this should be treated the same as a '1' width for col 1 and 2
} {0 { abcdefg 123456 }}
diff --git a/test/speedtest1.c b/test/speedtest1.c
index 68ca5788cc..e3b9d2296c 100644
--- a/test/speedtest1.c
+++ b/test/speedtest1.c
@@ -7,7 +7,8 @@ static const char zHelp[] =
"Usage: %s [--options] DATABASE\n"
"Options:\n"
" --autovacuum Enable AUTOVACUUM mode\n"
- " --cachesize N Set the cache size to N\n"
+ " --cachesize N Set the cache size to N\n"
+ " --checkpoint Run PRAGMA wal_checkpoint after each test case\n"
" --exclusive Enable locking_mode=EXCLUSIVE\n"
" --explain Like --sqlonly but with added EXPLAIN keywords\n"
" --heap SZ MIN Memory allocator uses SZ bytes & min allocation MIN\n"
@@ -15,11 +16,13 @@ static const char zHelp[] =
" --journal M Set the journal_mode to M\n"
" --key KEY Set the encryption key to KEY\n"
" --lookaside N SZ Configure lookaside for N slots of SZ bytes each\n"
+ " --memdb Use an in-memory database\n"
" --mmap SZ MMAP the first SZ bytes of the database file\n"
" --multithread Set multithreaded mode\n"
" --nomemstat Disable memory statistics\n"
" --nosync Set PRAGMA synchronous=OFF\n"
" --notnull Add NOT NULL constraints to table columns\n"
+ " --output FILE Store SQL output in FILE\n"
" --pagesize N Set the page size to N\n"
" --pcache N SZ Configure N pages of pagecache each of size SZ bytes\n"
" --primarykey Use PRIMARY KEY instead of UNIQUE where appropriate\n"
@@ -41,7 +44,6 @@ static const char zHelp[] =
" --without-rowid Use WITHOUT ROWID where appropriate\n"
;
-
#include "sqlite3.h"
#include
#include
@@ -61,6 +63,20 @@ static const char zHelp[] =
# define sqlite3_int64 sqlite_int64
#endif
+typedef sqlite3_uint64 u64;
+
+/*
+** State structure for a Hash hash in progress
+*/
+typedef struct HashContext HashContext;
+struct HashContext {
+ unsigned char isInit; /* True if initialized */
+ unsigned char i, j; /* State variables */
+ unsigned char s[256]; /* State variables */
+ unsigned char r[32]; /* Result */
+};
+
+
/* All global state is held in this structure */
static struct Global {
sqlite3 *db; /* The open database connection */
@@ -76,12 +92,18 @@ static struct Global {
int eTemp; /* 0: no TEMP. 9: always TEMP. */
int szTest; /* Scale factor for test iterations */
int nRepeat; /* Repeat selects this many times */
+ int doCheckpoint; /* Run PRAGMA wal_checkpoint after each trans */
const char *zWR; /* Might be WITHOUT ROWID */
const char *zNN; /* Might be NOT NULL */
const char *zPK; /* Might be UNIQUE or PRIMARY KEY */
unsigned int x, y; /* Pseudo-random number generator state */
+ u64 nResByte; /* Total number of result bytes */
int nResult; /* Size of the current result */
char zResult[3000]; /* Text of the current result */
+#ifndef SPEEDTEST_OMIT_HASH
+ FILE *hashFile; /* Store all hash results in this file */
+ HashContext hash; /* Hash of all output */
+#endif
} g;
/* Return " TEMP" or "", as appropriate for creating a table.
@@ -90,7 +112,6 @@ static const char *isTemp(int N){
return g.eTemp>=N ? " TEMP" : "";
}
-
/* Print an error message and exit */
static void fatal_error(const char *zMsg, ...){
va_list ap;
@@ -100,6 +121,72 @@ static void fatal_error(const char *zMsg, ...){
exit(1);
}
+#ifndef SPEEDTEST_OMIT_HASH
+/****************************************************************************
+** Hash algorithm used to verify that compilation is not miscompiled
+** in such a was as to generate an incorrect result.
+*/
+
+/*
+** 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 HashInit(void){
+ unsigned int k;
+ g.hash.i = 0;
+ g.hash.j = 0;
+ for(k=0; k<256; k++) g.hash.s[k] = k;
+}
+
+/*
+** Make consecutive calls to the HashUpdate function to add new content
+** to the hash
+*/
+static void HashUpdate(
+ const unsigned char *aData,
+ unsigned int nData
+){
+ unsigned char t;
+ unsigned char i = g.hash.i;
+ unsigned char j = g.hash.j;
+ unsigned int k;
+ if( g.hashFile ) fwrite(aData, 1, nData, g.hashFile);
+ for(k=0; k>4];
+ zChar[1] = "0123456789abcdef"[aBlob[iBlob]&15];
+ HashUpdate(zChar,2);
+ }
+ g.nResByte += nBlob*2 + 2;
+ }else{
+ HashUpdate((unsigned char*)z, len);
+ g.nResByte += len + 2;
+ }
+ }
+#endif
if( g.nResult+len0 ) g.zResult[g.nResult++] = ' ';
memcpy(g.zResult + g.nResult, z, len+1);
@@ -1987,7 +2156,8 @@ int main(int argc, char **argv){
int showStats = 0; /* True for --stats */
int nThread = 0; /* --threads value */
int mmapSize = 0; /* How big of a memory map to use */
- const char *zTSet = "main"; /* Which --testset torun */
+ int memDb = 0; /* --memdb. Use an in-memory database */
+ char *zTSet = "main"; /* Which --testset torun */
int doTrace = 0; /* True for --trace */
const char *zEncoding = 0; /* --utf16be or --utf16le */
const char *zDbName = 0; /* Name of the test database */
@@ -2000,7 +2170,7 @@ int main(int argc, char **argv){
int rc; /* API return code */
/* Display the version of SQLite being tested */
- printf("-- Speedtest1 for SQLite %s %.50s\n",
+ printf("-- Speedtest1 for SQLite %s %.48s\n",
sqlite3_libversion(), sqlite3_sourceid());
/* Process command-line arguments */
@@ -2021,6 +2191,8 @@ int main(int argc, char **argv){
cacheSize = integerValue(argv[i]);
}else if( strcmp(z,"exclusive")==0 ){
doExclusive = 1;
+ }else if( strcmp(z,"checkpoint")==0 ){
+ g.doCheckpoint = 1;
}else if( strcmp(z,"explain")==0 ){
g.bSqlOnly = 1;
g.bExplain = 1;
@@ -2042,6 +2214,8 @@ int main(int argc, char **argv){
nLook = integerValue(argv[i+1]);
szLook = integerValue(argv[i+2]);
i += 2;
+ }else if( strcmp(z,"memdb")==0 ){
+ memDb = 1;
#if SQLITE_VERSION_NUMBER>=3006000
}else if( strcmp(z,"multithread")==0 ){
sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
@@ -2057,6 +2231,22 @@ int main(int argc, char **argv){
noSync = 1;
}else if( strcmp(z,"notnull")==0 ){
g.zNN = "NOT NULL";
+ }else if( strcmp(z,"output")==0 ){
+#ifdef SPEEDTEST_OMIT_HASH
+ fatal_error("The --output option is not supported with"
+ " -DSPEEDTEST_OMIT_HASH\n");
+#else
+ if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]);
+ i++;
+ if( strcmp(argv[i],"-")==0 ){
+ g.hashFile = stdout;
+ }else{
+ g.hashFile = fopen(argv[i], "wb");
+ if( g.hashFile==0 ){
+ fatal_error("cannot open \"%s\" for writing\n", argv[i]);
+ }
+ }
+#endif
}else if( strcmp(z,"pagesize")==0 ){
if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]);
pageSize = integerValue(argv[++i]);
@@ -2110,6 +2300,9 @@ int main(int argc, char **argv){
zEncoding = "utf16be";
}else if( strcmp(z,"verify")==0 ){
g.bVerify = 1;
+#ifndef SPEEDTEST_OMIT_HASH
+ HashInit();
+#endif
}else if( strcmp(z,"without-rowid")==0 ){
g.zWR = "WITHOUT ROWID";
g.zPK = "PRIMARY KEY";
@@ -2151,13 +2344,13 @@ int main(int argc, char **argv){
sqlite3_initialize();
/* Open the database and the input file */
- if( sqlite3_open(zDbName, &g.db) ){
+ if( sqlite3_open(memDb ? ":memory:" : zDbName, &g.db) ){
fatal_error("Cannot open database file: %s\n", zDbName);
}
#if SQLITE_VERSION_NUMBER>=3006001
if( nLook>0 && szLook>0 ){
pLook = malloc( nLook*szLook );
- rc = sqlite3_db_config(g.db, SQLITE_DBCONFIG_LOOKASIDE, pLook, szLook,nLook);
+ rc = sqlite3_db_config(g.db, SQLITE_DBCONFIG_LOOKASIDE,pLook,szLook,nLook);
if( rc ) fatal_error("lookaside configuration failed: %d\n", rc);
}
#endif
@@ -2167,6 +2360,9 @@ int main(int argc, char **argv){
#ifndef SQLITE_OMIT_DEPRECATED
if( doTrace ) sqlite3_trace(g.db, traceCallback, 0);
#endif
+ if( memDb>0 ){
+ speedtest1_exec("PRAGMA temp_store=memory");
+ }
if( mmapSize>0 ){
speedtest1_exec("PRAGMA mmap_size=%d", mmapSize);
}
@@ -2197,30 +2393,68 @@ int main(int argc, char **argv){
}
if( g.bExplain ) printf(".explain\n.echo on\n");
- if( strcmp(zTSet,"main")==0 ){
- testset_main();
- }else if( strcmp(zTSet,"debug1")==0 ){
- testset_debug1();
- }else if( strcmp(zTSet,"orm")==0 ){
- testset_orm();
- }else if( strcmp(zTSet,"cte")==0 ){
- testset_cte();
- }else if( strcmp(zTSet,"fp")==0 ){
- testset_fp();
- }else if( strcmp(zTSet,"trigger")==0 ){
- testset_trigger();
- }else if( strcmp(zTSet,"rtree")==0 ){
+ do{
+ char *zThisTest = zTSet;
+ char *zComma = strchr(zThisTest,',');
+ if( zComma ){
+ *zComma = 0;
+ zTSet = zComma+1;
+ }else{
+ zTSet = "";
+ }
+ if( g.iTotal>0 || zComma!=0 ){
+ printf(" Begin testset \"%s\"\n", zThisTest);
+ }
+ if( strcmp(zThisTest,"main")==0 ){
+ testset_main();
+ }else if( strcmp(zThisTest,"debug1")==0 ){
+ testset_debug1();
+ }else if( strcmp(zThisTest,"orm")==0 ){
+ testset_orm();
+ }else if( strcmp(zThisTest,"cte")==0 ){
+ testset_cte();
+ }else if( strcmp(zThisTest,"fp")==0 ){
+ testset_fp();
+ }else if( strcmp(zThisTest,"trigger")==0 ){
+ testset_trigger();
+ }else if( strcmp(zThisTest,"rtree")==0 ){
#ifdef SQLITE_ENABLE_RTREE
- testset_rtree(6, 147);
+ testset_rtree(6, 147);
#else
- fatal_error("compile with -DSQLITE_ENABLE_RTREE to enable "
- "the R-Tree tests\n");
+ fatal_error("compile with -DSQLITE_ENABLE_RTREE to enable "
+ "the R-Tree tests\n");
#endif
- }else{
- fatal_error("unknown testset: \"%s\"\n"
- "Choices: cte debug1 fp main orm rtree trigger\n",
- zTSet);
- }
+ }else{
+ fatal_error("unknown testset: \"%s\"\n"
+ "Choices: cte debug1 fp main orm rtree trigger\n",
+ zThisTest);
+ }
+ if( zTSet[0] ){
+ char *zSql, *zObj;
+ speedtest1_begin_test(999, "Reset the database");
+ while( 1 ){
+ zObj = speedtest1_once(
+ "SELECT name FROM main.sqlite_master"
+ " WHERE sql LIKE 'CREATE %%TABLE%%'");
+ if( zObj==0 ) break;
+ zSql = sqlite3_mprintf("DROP TABLE main.\"%w\"", zObj);
+ speedtest1_exec(zSql);
+ sqlite3_free(zSql);
+ sqlite3_free(zObj);
+ }
+ while( 1 ){
+ zObj = speedtest1_once(
+ "SELECT name FROM temp.sqlite_master"
+ " WHERE sql LIKE 'CREATE %%TABLE%%'");
+ if( zObj==0 ) break;
+ zSql = sqlite3_mprintf("DROP TABLE main.\"%w\"", zObj);
+ speedtest1_exec(zSql);
+ sqlite3_free(zSql);
+ sqlite3_free(zObj);
+ }
+ speedtest1_end_test();
+ }
+ }while( zTSet[0] );
speedtest1_final();
if( showStats ){
diff --git a/test/stat.test b/test/stat.test
index 105169df1d..5eb7d6f76a 100644
--- a/test/stat.test
+++ b/test/stat.test
@@ -59,7 +59,7 @@ if {[wal_is_capable]} {
PRAGMA journal_mode = delete;
SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload
FROM stat;
- } {wal delete sqlite_master / 1 leaf 0 0 916 0}
+ } {wal delete sqlite_schema / 1 leaf 0 0 916 0}
}
do_test stat-1.0 {
@@ -85,9 +85,9 @@ do_test stat-1.2 {
do_test stat-1.3 {
execsql {
SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload
- FROM stat WHERE name = 'sqlite_master';
+ FROM stat WHERE name = 'sqlite_schema';
}
-} {sqlite_master / 1 leaf 2 77 831 40}
+} {sqlite_schema / 1 leaf 2 77 831 40}
do_test stat-1.4 {
execsql {
DROP TABLE t1;
@@ -108,7 +108,7 @@ do_execsql_test stat-2.1 {
INSERT INTO t3 SELECT a_string(110+rowid), a_string(221+rowid) FROM t3
ORDER BY rowid;
SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload
- FROM stat WHERE name != 'sqlite_master' ORDER BY name;
+ FROM stat WHERE name != 'sqlite_schema' ORDER BY name;
} [list \
sqlite_autoindex_t3_1 / 3 internal 3 368 623 125 \
sqlite_autoindex_t3_1 /000/ 8 leaf 8 946 46 123 \
@@ -138,7 +138,7 @@ do_execsql_test stat-2.1agg {
SELECT * FROM dbstat WHERE aggregate=TRUE ORDER BY name;
} [list \
sqlite_autoindex_t3_1 {} 5 {} 32 3898 1065 132 {} 5120 \
- sqlite_master {} 1 {} 2 84 824 49 {} 1024 \
+ sqlite_schema {} 1 {} 2 84 824 49 {} 1024 \
t3 {} 17 {} 47 11188 5815 370 {} 17408 \
]
@@ -158,7 +158,7 @@ do_execsql_test stat-3.1 {
CREATE INDEX i4 ON t4(x);
INSERT INTO t4(rowid, x) VALUES(2, a_string(7777));
SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload
- FROM stat WHERE name != 'sqlite_master' ORDER BY name;
+ FROM stat WHERE name != 'sqlite_schema' ORDER BY name;
} [list \
i4 / 3 leaf 1 103 905 7782 \
i4 /000+000000 4 overflow 0 1020 0 0 \
@@ -183,7 +183,7 @@ do_execsql_test stat-3.2 {
SELECT *, '|' FROM dbstat WHERE aggregate=TRUE ORDER BY name;
} [list \
i4 {} 9 {} 1 7782 1386 7782 {} 9216 | \
- sqlite_master {} 1 {} 2 74 834 40 {} 1024 | \
+ sqlite_schema {} 1 {} 2 74 834 40 {} 1024 | \
t4 {} 8 {} 1 7780 367 7780 {} 8192 | \
]
@@ -221,11 +221,11 @@ do_execsql_test stat-5.1 {
do_execsql_test stat-5.20 {
SELECT name, quote(path), pageno, quote(pagetype), ncell, payload,
unused, mx_payload, '|' FROM dbstat('main',1);
-} {sqlite_master NULL 1 NULL 1 34 878 34 | tx NULL 1 NULL 0 0 1016 0 |}
+} {sqlite_schema NULL 1 NULL 1 34 878 34 | tx NULL 1 NULL 0 0 1016 0 |}
do_execsql_test stat-5.21 {
SELECT name, quote(path), pageno, quote(pagetype), ncell, payload,
unused, mx_payload, '|' FROM dbstat('aux1',1);
-} {sqlite_master NULL 1 NULL 1 34 878 34 | t1 NULL 3 NULL 2 3033 5 1517 |}
+} {sqlite_schema NULL 1 NULL 1 34 878 34 | t1 NULL 3 NULL 2 3033 5 1517 |}
do_catchsql_test stat-6.1 {
@@ -247,27 +247,27 @@ do_execsql_test 7.1 {
do_execsql_test 7.1.1 {
SELECT * FROM dbstat('123');
} {
- sqlite_master / 1 leaf 1 37 875 37 0 1024
+ sqlite_schema / 1 leaf 1 37 875 37 0 1024
x1 / 2 leaf 1 4 1008 4 1024 1024
}
do_execsql_test 7.1.2 {
SELECT * FROM dbstat(123);
} {
- sqlite_master / 1 leaf 1 37 875 37 0 1024
+ sqlite_schema / 1 leaf 1 37 875 37 0 1024
x1 / 2 leaf 1 4 1008 4 1024 1024
}
do_execsql_test 7.1.3 {
CREATE VIRTUAL TABLE x2 USING dbstat('123');
SELECT * FROM x2;
} {
- sqlite_master / 1 leaf 1 37 875 37 0 1024
+ sqlite_schema / 1 leaf 1 37 875 37 0 1024
x1 / 2 leaf 1 4 1008 4 1024 1024
}
do_execsql_test 7.1.4 {
CREATE VIRTUAL TABLE x3 USING dbstat(123);
SELECT * FROM x3;
} {
- sqlite_master / 1 leaf 1 37 875 37 0 1024
+ sqlite_schema / 1 leaf 1 37 875 37 0 1024
x1 / 2 leaf 1 4 1008 4 1024 1024
}
@@ -280,7 +280,7 @@ do_execsql_test 7.2 {
do_execsql_test 7.2.1 {
SELECT * FROM dbstat('123corp');
} {
- sqlite_master / 1 leaf 1 37 875 37 0 1024
+ sqlite_schema / 1 leaf 1 37 875 37 0 1024
x1 / 2 leaf 1 4 1008 4 1024 1024
}
do_catchsql_test 7.2.2 {
@@ -290,7 +290,7 @@ do_execsql_test 7.2.3 {
CREATE VIRTUAL TABLE x2 USING dbstat('123corp');
SELECT * FROM x2;
} {
- sqlite_master / 1 leaf 1 37 875 37 0 1024
+ sqlite_schema / 1 leaf 1 37 875 37 0 1024
x1 / 2 leaf 1 4 1008 4 1024 1024
}
do_catchsql_test 7.2.4 {
diff --git a/test/tester.tcl b/test/tester.tcl
index cc7f913778..b1acb0686a 100644
--- a/test/tester.tcl
+++ b/test/tester.tcl
@@ -129,6 +129,7 @@ if {[info command sqlite_orig]==""} {
set ::dbhandle [lindex $args 0]
uplevel #0 $::G(perm:dbconfig)
}
+ [lindex $args 0] cache size 3
set res
} else {
# This command is not opening a new database connection. Pass the
@@ -2478,6 +2479,7 @@ set sqlite_fts3_enable_parentheses 0
# this setting by invoking "database_can_be_corrupt"
#
database_never_corrupt
+extra_schema_checks 1
source $testdir/thread_common.tcl
source $testdir/malloc_common.tcl
diff --git a/test/triggerupfrom.test b/test/triggerupfrom.test
new file mode 100644
index 0000000000..9bfacb8430
--- /dev/null
+++ b/test/triggerupfrom.test
@@ -0,0 +1,174 @@
+# 2020 July 14
+#
+# 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 triggerupfrom
+
+do_execsql_test 1.0 {
+ CREATE TABLE map(k, v);
+ INSERT INTO map VALUES(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four');
+
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
+
+ CREATE TRIGGER tr AFTER INSERT ON t1 BEGIN
+ UPDATE t1 SET c = v FROM map WHERE k=new.a AND a=new.a;
+ END;
+}
+
+do_execsql_test 1.1 {
+ INSERT INTO t1(a) VALUES(1);
+}
+
+do_execsql_test 1.2 {
+ SELECT a, c FROM t1 ORDER BY a;
+} {1 one}
+
+do_execsql_test 1.3 {
+ INSERT INTO t1(a) VALUES(2), (3), (4), (5);
+ SELECT a, c FROM t1 ORDER BY a;
+} {1 one 2 two 3 three 4 four 5 {}}
+
+forcedelete test.db2
+do_execsql_test 2.0 {
+ ATTACH 'test.db2' AS aux;
+ CREATE TABLE aux.t3(x, y);
+ INSERT INTO aux.t3 VALUES('x', 'y');
+}
+
+do_catchsql_test 2.1 {
+ CREATE TRIGGER tr2 AFTER INSERT ON t1 BEGIN
+ UPDATE t1 SET b = y FROM aux.t3 WHERE k=new.a;
+ END;
+} {1 {trigger tr2 cannot reference objects in database aux}}
+
+do_execsql_test 2.2 {
+ CREATE TEMP TRIGGER tr2 AFTER INSERT ON t1 BEGIN
+ UPDATE t1 SET b = y FROM aux.t3 WHERE a=new.a;
+ END;
+ INSERT INTO t1(a) VALUES(10), (20);
+ SELECT * FROM t1;
+} {
+ 1 {} one
+ 2 {} two
+ 3 {} three
+ 4 {} four
+ 5 {} {}
+ 10 y {}
+ 20 y {}
+}
+
+do_execsql_test 2.3 {
+ CREATE TABLE link(f, t);
+ INSERT INTO link VALUES(5, 2), (20, 10), (2, 1);
+ CREATE TRIGGER tr3 BEFORE DELETE ON t1 BEGIN
+ UPDATE t1 SET b=coalesce(old.b,old.c) FROM main.link WHERE a=t AND old.a=f;
+ END;
+ DELETE FROM t1 WHERE a=2;
+ SELECT * FROM t1;
+} {
+ 1 two one
+ 3 {} three
+ 4 {} four
+ 5 {} {}
+ 10 y {}
+ 20 y {}
+}
+
+db close
+sqlite3 db ""
+do_catchsql_test 2.4 {
+ ATTACH 'test.db' AS yyy;
+ SELECT * FROM t1;
+} {1 {malformed database schema (tr3) - trigger tr3 cannot reference objects in database main}}
+
+#-------------------------------------------------------------------------
+reset_db
+forcedelete test.db2
+do_execsql_test 3.0 {
+ CREATE TABLE mmm(x, y);
+ INSERT INTO mmm VALUES(1, 'one');
+ INSERT INTO mmm VALUES(2, 'two');
+ INSERT INTO mmm VALUES(3, 'three');
+
+ ATTACH 'test.db2' AS aux;
+ CREATE TABLE aux.t1(a, b);
+ CREATE TABLE aux.mmm(x, y);
+ INSERT INTO aux.mmm VALUES(1, 'ONE');
+ INSERT INTO aux.mmm VALUES(2, 'TWO');
+ INSERT INTO aux.mmm VALUES(3, 'THREE');
+
+ CREATE TRIGGER aux.ttt AFTER INSERT ON t1 BEGIN
+ UPDATE t1 SET b=y FROM mmm WHERE x=new.a AND a=new.a;
+ END;
+
+ INSERT INTO t1(a) VALUES (2);
+ SELECT * FROM t1;
+} {2 TWO}
+
+#-------------------------------------------------------------------------
+# Test that INSTEAD OF UPDATE triggers on views work with UPDATE...FROM
+# statements. Including, if the library is built with ENABLE_HIDDEN_COLUMNS,
+# that they work correctly on views with hidden columns.
+#
+reset_db
+do_execsql_test 4.0 {
+ CREATE TABLE t1(k, a, b);
+ INSERT INTO t1 VALUES('a', 1, 'one');
+ INSERT INTO t1 VALUES('b', 2, 'two');
+ INSERT INTO t1 VALUES('c', 3, 'three');
+ INSERT INTO t1 VALUES('d', 4, 'four');
+
+ CREATE TABLE log(x);
+ CREATE VIEW v1 AS SELECT k, a, b AS __hidden__b FROM t1;
+ CREATE TRIGGER tr1 INSTEAD OF UPDATE ON v1 BEGIN
+ INSERT INTO log VALUES(
+ '('||old.a||','||old.__hidden__b||')->('||new.a||','||new.__hidden__b||')'
+ );
+ END;
+}
+
+ifcapable hiddencolumns {
+ do_execsql_test 4.1-hc-enabled {
+ SELECT * FROM v1
+ } {a 1 b 2 c 3 d 4}
+} else {
+ do_execsql_test 4.1-hc-disabled {
+ SELECT * FROM v1
+ } {a 1 one b 2 two c 3 three d 4 four}
+}
+
+do_execsql_test 4.2 {
+ UPDATE v1 SET a='xyz' WHERE k IN ('a', 'c');
+ SELECT * FROM log;
+ DELETE FROM log;
+} {
+ (1,one)->(xyz,one)
+ (3,three)->(xyz,three)
+}
+
+do_execsql_test 4.3 {
+ CREATE TABLE map(k, v);
+ INSERT INTO map VALUES('b', 'twelve');
+ INSERT INTO map VALUES('d', 'fourteen');
+ UPDATE v1 SET a=map.v FROM map WHERE v1.k=map.k;
+ SELECT * FROM log;
+ DELETE FROM log;
+} {
+ (2,two)->(twelve,two)
+ (4,four)->(fourteen,four)
+}
+
+
+
+finish_test
+
diff --git a/test/tt3_stress.c b/test/tt3_stress.c
index 8c9519770c..98ade3e851 100644
--- a/test/tt3_stress.c
+++ b/test/tt3_stress.c
@@ -41,7 +41,7 @@ static char *stress_thread_2(int iTid, void *pArg){
Sqlite db = {0}; /* SQLite database connection */
while( !timetostop(&err) ){
opendb(&err, &db, "test.db", 0, 0);
- sql_script(&err, &db, "SELECT * FROM sqlite_master;");
+ sql_script(&err, &db, "SELECT * FROM sqlite_schema;");
clear_error(&err, SQLITE_LOCKED);
closedb(&err, &db);
}
@@ -266,7 +266,7 @@ static char *stress2_workload19(int iTid, void *pArg){
const char *zDb = (const char*)pArg;
while( !timetostop(&err) ){
opendb(&err, &db, zDb, 0, 0);
- sql_script(&err, &db, "SELECT * FROM sqlite_master;");
+ sql_script(&err, &db, "SELECT * FROM sqlite_schema;");
clear_error(&err, SQLITE_LOCKED);
closedb(&err, &db);
}
@@ -362,7 +362,3 @@ static void stress2(int nMs){
sqlite3_enable_shared_cache(0);
print_and_free_err(&err);
}
-
-
-
-
diff --git a/test/upfrom1.tcl b/test/upfrom1.tcl
new file mode 100644
index 0000000000..22fc68a31c
--- /dev/null
+++ b/test/upfrom1.tcl
@@ -0,0 +1,115 @@
+# 2020 April 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.
+#
+#***********************************************************************
+#
+
+source [file join [file dirname $argv0] pg_common.tcl]
+
+#=========================================================================
+
+start_test upfrom1 "2020 April 22"
+
+foreach {tn wo} {
+ 1 "WITHOUT ROWID"
+ 2 ""
+} {
+eval [string map [list %TN% $tn %WITHOUT_ROWID% $wo] {
+execsql_test 1.%TN%.0 {
+ DROP TABLE IF EXISTS t2;
+ CREATE TABLE t2(a INTEGER PRIMARY KEY, b INTEGER, c INTEGER) %WITHOUT_ROWID%;
+ INSERT INTO t2 VALUES(1, 2, 3);
+ INSERT INTO t2 VALUES(4, 5, 6);
+ INSERT INTO t2 VALUES(7, 8, 9);
+
+ DROP TABLE IF EXISTS chng;
+ CREATE TABLE chng(a INTEGER, b INTEGER, c INTEGER);
+ INSERT INTO chng VALUES(1, 100, 1000);
+ INSERT INTO chng VALUES(7, 700, 7000);
+}
+
+execsql_test 1.%TN%.1 {
+ SELECT * FROM t2;
+}
+
+execsql_test 1.%TN%.2 {
+ UPDATE t2 SET b = chng.b, c = chng.c FROM chng WHERE chng.a = t2.a;
+ SELECT * FROM t2 ORDER BY a;
+}
+
+execsql_test 1.%TN%.3 {
+ DELETE FROM t2;
+ INSERT INTO t2 VALUES(1, 2, 3);
+ INSERT INTO t2 VALUES(4, 5, 6);
+ INSERT INTO t2 VALUES(7, 8, 9);
+}
+
+execsql_test 1.%TN%.4 {
+ UPDATE t2 SET (b, c) = (SELECT b, c FROM chng WHERE a=t2.a)
+ WHERE a IN (SELECT a FROM chng);
+ SELECT * FROM t2 ORDER BY a;
+}
+
+execsql_test 1.%TN%.5 {
+ DROP TABLE IF EXISTS t3;
+ CREATE TABLE t3(a INTEGER PRIMARY KEY, b INTEGER, c TEXT) %WITHOUT_ROWID%;
+ INSERT INTO t3 VALUES(1, 1, 'one');
+ INSERT INTO t3 VALUES(2, 2, 'two');
+ INSERT INTO t3 VALUES(3, 3, 'three');
+
+ DROP TABLE IF EXISTS t4;
+ CREATE TABLE t4(x TEXT);
+ INSERT INTO t4 VALUES('five');
+
+ SELECT * FROM t3 ORDER BY a;
+}
+
+execsql_test 1.%TN%.6 {
+ UPDATE t3 SET c=x FROM t4;
+ SELECT * FROM t3 ORDER BY a;
+}
+}]}
+
+execsql_test 2.1 {
+ DROP TABLE IF EXISTS t5;
+ DROP TABLE IF EXISTS m1;
+ DROP TABLE IF EXISTS m2;
+ CREATE TABLE t5(a INTEGER PRIMARY KEY, b TEXT, c TEXT);
+ CREATE TABLE m1(x INTEGER PRIMARY KEY, y TEXT);
+ CREATE TABLE m2(u INTEGER PRIMARY KEY, v TEXT);
+
+ INSERT INTO t5 VALUES(1, 'one', 'ONE');
+ INSERT INTO t5 VALUES(2, 'two', 'TWO');
+ INSERT INTO t5 VALUES(3, 'three', 'THREE');
+ INSERT INTO t5 VALUES(4, 'four', 'FOUR');
+
+ INSERT INTO m1 VALUES(1, 'i');
+ INSERT INTO m1 VALUES(2, 'ii');
+ INSERT INTO m1 VALUES(3, 'iii');
+
+ INSERT INTO m2 VALUES(1, 'I');
+ INSERT INTO m2 VALUES(3, 'II');
+ INSERT INTO m2 VALUES(4, 'III');
+}
+
+execsql_test 2.2 {
+ UPDATE t5 SET b=y, c=v FROM m1 LEFT JOIN m2 ON (x=u) WHERE x=a;
+ SELECT * FROM t5 ORDER BY a;
+}
+
+errorsql_test 2.3.1 {
+ UPDATE t5 SET b=1 FROM t5;
+}
+errorsql_test 2.3.2 {
+ UPDATE t5 AS apples SET b=1 FROM t5 AS apples;
+}
+
+
+finish_test
+
diff --git a/test/upfrom1.test b/test/upfrom1.test
new file mode 100644
index 0000000000..7996f97702
--- /dev/null
+++ b/test/upfrom1.test
@@ -0,0 +1,178 @@
+# 2020 April 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 regression tests for SQLite library.
+#
+
+####################################################
+# DO NOT EDIT! THIS FILE IS AUTOMATICALLY GENERATED!
+####################################################
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix upfrom1
+
+do_execsql_test 1.1.0 {
+ DROP TABLE IF EXISTS t2;
+ CREATE TABLE t2(a INTEGER PRIMARY KEY, b INTEGER, c INTEGER) WITHOUT ROWID;
+ INSERT INTO t2 VALUES(1, 2, 3);
+ INSERT INTO t2 VALUES(4, 5, 6);
+ INSERT INTO t2 VALUES(7, 8, 9);
+
+ DROP TABLE IF EXISTS chng;
+ CREATE TABLE chng(a INTEGER, b INTEGER, c INTEGER);
+ INSERT INTO chng VALUES(1, 100, 1000);
+ INSERT INTO chng VALUES(7, 700, 7000);
+} {}
+
+do_execsql_test 1.1.1 {
+ SELECT * FROM t2;
+} {1 2 3 4 5 6 7 8 9}
+
+do_execsql_test 1.1.2 {
+ UPDATE t2 SET b = chng.b, c = chng.c FROM chng WHERE chng.a = t2.a;
+ SELECT * FROM t2 ORDER BY a;
+} {1 100 1000 4 5 6 7 700 7000}
+
+do_execsql_test 1.1.3 {
+ DELETE FROM t2;
+ INSERT INTO t2 VALUES(1, 2, 3);
+ INSERT INTO t2 VALUES(4, 5, 6);
+ INSERT INTO t2 VALUES(7, 8, 9);
+} {}
+
+do_execsql_test 1.1.4 {
+ UPDATE t2 SET (b, c) = (SELECT b, c FROM chng WHERE a=t2.a)
+ WHERE a IN (SELECT a FROM chng);
+ SELECT * FROM t2 ORDER BY a;
+} {1 100 1000 4 5 6 7 700 7000}
+
+do_execsql_test 1.1.5 {
+ DROP TABLE IF EXISTS t3;
+ CREATE TABLE t3(a INTEGER PRIMARY KEY, b INTEGER, c TEXT) WITHOUT ROWID;
+ INSERT INTO t3 VALUES(1, 1, 'one');
+ INSERT INTO t3 VALUES(2, 2, 'two');
+ INSERT INTO t3 VALUES(3, 3, 'three');
+
+ DROP TABLE IF EXISTS t4;
+ CREATE TABLE t4(x TEXT);
+ INSERT INTO t4 VALUES('five');
+
+ SELECT * FROM t3 ORDER BY a;
+} {1 1 one 2 2 two 3 3 three}
+
+do_execsql_test 1.1.6 {
+ UPDATE t3 SET c=x FROM t4;
+ SELECT * FROM t3 ORDER BY a;
+} {1 1 five 2 2 five 3 3 five}
+
+do_execsql_test 1.2.0 {
+ DROP TABLE IF EXISTS t2;
+ CREATE TABLE t2(a INTEGER PRIMARY KEY, b INTEGER, c INTEGER) ;
+ INSERT INTO t2 VALUES(1, 2, 3);
+ INSERT INTO t2 VALUES(4, 5, 6);
+ INSERT INTO t2 VALUES(7, 8, 9);
+
+ DROP TABLE IF EXISTS chng;
+ CREATE TABLE chng(a INTEGER, b INTEGER, c INTEGER);
+ INSERT INTO chng VALUES(1, 100, 1000);
+ INSERT INTO chng VALUES(7, 700, 7000);
+} {}
+
+do_execsql_test 1.2.1 {
+ SELECT * FROM t2;
+} {1 2 3 4 5 6 7 8 9}
+
+do_execsql_test 1.2.2 {
+ UPDATE t2 SET b = chng.b, c = chng.c FROM chng WHERE chng.a = t2.a;
+ SELECT * FROM t2 ORDER BY a;
+} {1 100 1000 4 5 6 7 700 7000}
+
+do_execsql_test 1.2.3 {
+ DELETE FROM t2;
+ INSERT INTO t2 VALUES(1, 2, 3);
+ INSERT INTO t2 VALUES(4, 5, 6);
+ INSERT INTO t2 VALUES(7, 8, 9);
+} {}
+
+do_execsql_test 1.2.4 {
+ UPDATE t2 SET (b, c) = (SELECT b, c FROM chng WHERE a=t2.a)
+ WHERE a IN (SELECT a FROM chng);
+ SELECT * FROM t2 ORDER BY a;
+} {1 100 1000 4 5 6 7 700 7000}
+
+do_execsql_test 1.2.5 {
+ DROP TABLE IF EXISTS t3;
+ CREATE TABLE t3(a INTEGER PRIMARY KEY, b INTEGER, c TEXT) ;
+ INSERT INTO t3 VALUES(1, 1, 'one');
+ INSERT INTO t3 VALUES(2, 2, 'two');
+ INSERT INTO t3 VALUES(3, 3, 'three');
+
+ DROP TABLE IF EXISTS t4;
+ CREATE TABLE t4(x TEXT);
+ INSERT INTO t4 VALUES('five');
+
+ SELECT * FROM t3 ORDER BY a;
+} {1 1 one 2 2 two 3 3 three}
+
+do_execsql_test 1.2.6 {
+ UPDATE t3 SET c=x FROM t4;
+ SELECT * FROM t3 ORDER BY a;
+} {1 1 five 2 2 five 3 3 five}
+
+do_execsql_test 2.1 {
+ DROP TABLE IF EXISTS t5;
+ DROP TABLE IF EXISTS m1;
+ DROP TABLE IF EXISTS m2;
+ CREATE TABLE t5(a INTEGER PRIMARY KEY, b TEXT, c TEXT);
+ CREATE TABLE m1(x INTEGER PRIMARY KEY, y TEXT);
+ CREATE TABLE m2(u INTEGER PRIMARY KEY, v TEXT);
+
+ INSERT INTO t5 VALUES(1, 'one', 'ONE');
+ INSERT INTO t5 VALUES(2, 'two', 'TWO');
+ INSERT INTO t5 VALUES(3, 'three', 'THREE');
+ INSERT INTO t5 VALUES(4, 'four', 'FOUR');
+
+ INSERT INTO m1 VALUES(1, 'i');
+ INSERT INTO m1 VALUES(2, 'ii');
+ INSERT INTO m1 VALUES(3, 'iii');
+
+ INSERT INTO m2 VALUES(1, 'I');
+ INSERT INTO m2 VALUES(3, 'II');
+ INSERT INTO m2 VALUES(4, 'III');
+} {}
+
+do_execsql_test 2.2 {
+ UPDATE t5 SET b=y, c=v FROM m1 LEFT JOIN m2 ON (x=u) WHERE x=a;
+ SELECT * FROM t5 ORDER BY a;
+} {1 i I 2 ii {} 3 iii II 4 four FOUR}
+
+# PG says ERROR: table name "t5" specified more than once
+do_test 2.3.1 { catch { execsql {
+ UPDATE t5 SET b=1 FROM t5;
+} } } 1
+
+# PG says ERROR: table name "apples" specified more than once
+do_test 2.3.2 { catch { execsql {
+ UPDATE t5 AS apples SET b=1 FROM t5 AS apples;
+} } } 1
+
+# Problem found by OSSFuzz on 2020-07-20
+# https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=24282
+#
+reset_db
+do_execsql_test 3.1 {
+ CREATE TABLE t0(a);
+ CREATE TABLE t1(b);
+ UPDATE t1 SET b=sum(a) FROM t0;
+ SELECT * FROM t0, t1;
+} {}
+
+finish_test
diff --git a/test/upfrom2.test b/test/upfrom2.test
new file mode 100644
index 0000000000..f903c1f4f7
--- /dev/null
+++ b/test/upfrom2.test
@@ -0,0 +1,371 @@
+# 2020 April 29
+#
+# 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 upfrom2
+
+# Test cases:
+#
+# 1.*: Test that triggers are fired correctly for UPDATE FROM statements,
+# and only once for each row. Except for INSTEAD OF triggers on
+# views - these are fired once for each row returned by the join,
+# including duplicates.
+#
+# 2.*: Test adding ORDER BY and LIMIT clauses with UPDATE FROM statements.
+#
+# 5.*: Test that specifying the target table name or alias in the FROM
+# clause of an UPDATE statement is an error.
+#
+
+foreach {tn wo} {
+ 1 ""
+ 2 "WITHOUT ROWID"
+} {
+ reset_db
+
+ eval [string map [list %WO% $wo %TN% $tn] {
+ do_execsql_test 1.%TN%.0 {
+ CREATE TABLE log(t TEXT);
+ CREATE TABLE t1(x PRIMARY KEY, y, z UNIQUE) %WO%;
+ CREATE INDEX t1y ON t1(y);
+
+ INSERT INTO t1 VALUES(1, 'i', 'one');
+ INSERT INTO t1 VALUES(2, 'ii', 'two');
+ INSERT INTO t1 VALUES(3, 'iii', 'three');
+ INSERT INTO t1 VALUES(4, 'iv', 'four');
+
+ CREATE TRIGGER tr1 BEFORE UPDATE ON t1 BEGIN
+ INSERT INTO log VALUES(old.z || '->' || new.z);
+ END;
+ CREATE TRIGGER tr2 AFTER UPDATE ON t1 BEGIN
+ INSERT INTO log VALUES(old.y || '->' || new.y);
+ END;
+ }
+
+ do_execsql_test 1.%TN%.1 {
+ WITH data(k, v) AS (
+ VALUES(3, 'thirty'), (1, 'ten')
+ )
+ UPDATE t1 SET z=v FROM data WHERE x=k;
+
+ SELECT * FROM t1;
+ SELECT * FROM log;
+ } {
+ 1 i ten 2 ii two 3 iii thirty 4 iv four
+ one->ten i->i
+ three->thirty iii->iii
+ }
+
+ do_execsql_test 1.%TN%.2 {
+ CREATE TABLE t2(a, b);
+ CREATE TABLE t3(k, v);
+
+ INSERT INTO t3 VALUES(5, 'v');
+ INSERT INTO t3 VALUES(12, 'xii');
+
+ INSERT INTO t2 VALUES(2, 12);
+ INSERT INTO t2 VALUES(3, 5);
+
+ DELETE FROM log;
+ UPDATE t1 SET y=v FROM t2, t3 WHERE t1.x=t2.a AND t3.k=t2.b;
+
+ SELECT * FROM t1;
+ SELECT * FROM log;
+ } {
+ 1 i ten 2 xii two 3 v thirty 4 iv four
+ two->two ii->xii
+ thirty->thirty iii->v
+ }
+
+ do_execsql_test 1.%TN%.3 {
+ DELETE FROM log;
+ WITH data(k, v) AS (
+ VALUES(1, 'seven'), (1, 'eight'), (2, 'eleven'), (2, 'twelve')
+ )
+ UPDATE t1 SET z=v FROM data WHERE x=k;
+
+ SELECT * FROM t1;
+ SELECT * FROM log;
+ } {
+ 1 i eight 2 xii twelve 3 v thirty 4 iv four
+ ten->eight i->i
+ two->twelve xii->xii
+ }
+
+ do_test 1.%TN%.4 { db changes } {2}
+
+ do_execsql_test 1.%TN%.5 {
+ CREATE VIEW v1 AS SELECT * FROM t1;
+ CREATE TRIGGER v1tr INSTEAD OF UPDATE ON v1 BEGIN
+ UPDATE t1 SET y=new.y, z=new.z WHERE x=new.x;
+ END;
+
+ DELETE FROM log;
+ WITH data(k, v) AS (
+ VALUES(3, 'thirteen'), (3, 'fourteen'), (4, 'fifteen'), (4, 'sixteen')
+ )
+ UPDATE v1 SET z=v FROM data WHERE x=k;
+ }
+
+ do_execsql_test 1.%TN%.6 {
+ SELECT * FROM v1;
+ SELECT * FROM log;
+ } {
+ 1 i eight 2 xii twelve 3 v fourteen 4 iv sixteen
+ thirty->thirteen v->v
+ thirteen->fourteen v->v
+ four->fifteen iv->iv
+ fifteen->sixteen iv->iv
+ }
+
+ #--------------------------------------------------------------
+
+ do_execsql_test 1.%TN%.7 {
+ CREATE TABLE o1(w, x, y, z UNIQUE, PRIMARY KEY(w, x)) %WO%;
+ CREATE INDEX o1y ON t1(y);
+
+ INSERT INTO o1 VALUES(0, 0, 'i', 'one');
+ INSERT INTO o1 VALUES(0, 1, 'ii', 'two');
+ INSERT INTO o1 VALUES(1, 0, 'iii', 'three');
+ INSERT INTO o1 VALUES(1, 1, 'iv', 'four');
+
+ CREATE TRIGGER tro1 BEFORE UPDATE ON o1 BEGIN
+ INSERT INTO log VALUES(old.z || '->' || new.z);
+ END;
+ CREATE TRIGGER tro2 AFTER UPDATE ON o1 BEGIN
+ INSERT INTO log VALUES(old.y || '->' || new.y);
+ END;
+ }
+
+ do_execsql_test 1.%TN%.8 {
+ DELETE FROM log;
+ WITH data(k, v) AS (
+ VALUES(3, 'thirty'), (1, 'ten')
+ )
+ UPDATE o1 SET z=v FROM data WHERE (1+x+w*2)=k;
+
+ SELECT * FROM o1;
+ SELECT * FROM log;
+ } {
+ 0 0 i ten 0 1 ii two 1 0 iii thirty 1 1 iv four
+ one->ten i->i
+ three->thirty iii->iii
+ }
+
+ do_execsql_test 1.%TN%.9 {
+ DELETE FROM log;
+ UPDATE o1 SET y=v FROM t2, t3 WHERE (1+o1.w*2+o1.x)=t2.a AND t3.k=t2.b;
+
+ SELECT * FROM o1;
+ SELECT * FROM log;
+ } {
+ 0 0 i ten 0 1 xii two 1 0 v thirty 1 1 iv four
+ two->two ii->xii
+ thirty->thirty iii->v
+ }
+
+ do_execsql_test 1.%TN%.10 {
+ DELETE FROM log;
+ WITH data(k, v) AS (
+ VALUES(1, 'seven'), (1, 'eight'), (2, 'eleven'), (2, 'twelve')
+ )
+ UPDATE o1 SET z=v FROM data WHERE (1+w*2+x)=k;
+
+ SELECT * FROM o1;
+ SELECT * FROM log;
+ } {
+ 0 0 i eight 0 1 xii twelve 1 0 v thirty 1 1 iv four
+ ten->eight i->i
+ two->twelve xii->xii
+ }
+
+ do_test 1.%TN%.11 { db changes } {2}
+
+ do_execsql_test 1.%TN%.12 {
+ CREATE VIEW w1 AS SELECT * FROM o1;
+ CREATE TRIGGER w1tr INSTEAD OF UPDATE ON w1 BEGIN
+ UPDATE o1 SET y=new.y, z=new.z WHERE w=new.w AND x=new.x;
+ END;
+
+ DELETE FROM log;
+ WITH data(k, v) AS (
+ VALUES(3, 'thirteen'), (3, 'fourteen'), (4, 'fifteen'), (4, 'sixteen')
+ )
+ UPDATE w1 SET z=v FROM data WHERE (1+w*2+x)=k;
+ }
+
+ do_execsql_test 1.%TN%.13 {
+ SELECT * FROM w1;
+ SELECT * FROM log;
+ } {
+ 0 0 i eight 0 1 xii twelve 1 0 v fourteen 1 1 iv sixteen
+ thirty->thirteen v->v
+ thirteen->fourteen v->v
+ four->fifteen iv->iv
+ fifteen->sixteen iv->iv
+ }
+
+}]
+}
+
+ifcapable update_delete_limit {
+foreach {tn wo} {
+ 1 ""
+ 2 "WITHOUT ROWID"
+} {
+ reset_db
+
+eval [string map [list %WO% $wo %TN% $tn] {
+ do_execsql_test 2.%TN%.1 {
+ CREATE TABLE x1(a INTEGER PRIMARY KEY, b) %WO%;
+ INSERT INTO x1 VALUES
+ (1, 'one'), (2, 'two'), (3, 'three'), (4, 'four'),
+ (5, 'five'), (6, 'six'), (7, 'seven'), (8, 'eight');
+ }
+
+ do_execsql_test 2.%TN%.2 {
+ CREATE TABLE data1(x, y);
+ INSERT INTO data1 VALUES
+ (1, 'eleven'), (1, 'twenty-one'), (2, 'twelve'), (2, 'twenty-two'),
+ (3, 'thirteen'), (3, 'twenty-three'), (4, 'fourteen'), (4, 'twenty-four');
+ }
+
+ do_execsql_test 2.%TN%.3 {
+ UPDATE x1 SET b=y FROM data1 WHERE a=x ORDER BY a LIMIT 3;
+ SELECT * FROM x1;
+ } {
+ 1 eleven 2 twelve 3 thirteen 4 four 5 five 6 six 7 seven 8 eight
+ }
+
+ do_execsql_test 2.%TN%.4 {
+ UPDATE x1 SET b=b||y FROM data1 WHERE a=x ORDER BY b LIMIT 3;
+ SELECT * FROM x1;
+ } {
+ 1 eleveneleven 2 twelve 3 thirteenthirteen 4 fourfourteen
+ 5 five 6 six 7 seven 8 eight
+ }
+
+ do_catchsql_test 2.%TN%.5 {
+ UPDATE x1 SET b=b||b ORDER BY b;
+ } {1 {ORDER BY without LIMIT on UPDATE}}
+ do_catchsql_test 2.%TN%.6 {
+ UPDATE x1 SET b=b||y FROM data1 WHERE a=x ORDER BY b;
+ } {1 {ORDER BY without LIMIT on UPDATE}}
+
+ #-----------------------------------------------------------------------
+
+ do_execsql_test 2.%TN%.6 {
+ DROP TABLE x1;
+ CREATE TABLE x1(u, v, b, PRIMARY KEY(u, v)) %WO%;
+ INSERT INTO x1 VALUES
+ (0, 1, 'one'), (1, 0, 'two'), (1, 1, 'three'), (2, 0, 'four'),
+ (2, 1, 'five'), (3, 0, 'six'), (3, 1, 'seven'), (4, 0, 'eight');
+ }
+
+ do_execsql_test 2.%TN%.7 {
+ UPDATE x1 SET b=y FROM data1 WHERE (u*2+v)=x ORDER BY u, v LIMIT 3;
+ SELECT * FROM x1;
+ } {
+ 0 1 eleven 1 0 twelve 1 1 thirteen 2 0 four
+ 2 1 five 3 0 six 3 1 seven 4 0 eight
+ }
+
+ do_execsql_test 2.%TN%.8 {
+ UPDATE x1 SET b=b||y FROM data1 WHERE (u*2+v)=x ORDER BY b LIMIT 3;
+ SELECT * FROM x1;
+ } {
+ 0 1 eleveneleven 1 0 twelve 1 1 thirteenthirteen 2 0 fourfourteen
+ 2 1 five 3 0 six 3 1 seven 4 0 eight
+ }
+
+
+}]
+}}
+
+reset_db
+do_execsql_test 3.0 {
+ CREATE TABLE data(x, y, z);
+ CREATE VIEW t1 AS SELECT * FROM data;
+ CREATE TRIGGER t1_insert INSTEAD OF INSERT ON t1 BEGIN
+ INSERT INTO data VALUES(new.x, new.y, new.z);
+ END;
+ CREATE TRIGGER t1_update INSTEAD OF UPDATE ON t1 BEGIN
+ INSERT INTO log VALUES(old.z || '->' || new.z);
+ END;
+
+ CREATE TABLE log(t TEXT);
+
+ INSERT INTO t1 VALUES(1, 'i', 'one');
+ INSERT INTO t1 VALUES(2, 'ii', 'two');
+ INSERT INTO t1 VALUES(3, 'iii', 'three');
+ INSERT INTO t1 VALUES(4, 'iv', 'four');
+}
+
+do_execsql_test 3.1 {
+ WITH input(k, v) AS (
+ VALUES(3, 'thirty'), (1, 'ten')
+ )
+ UPDATE t1 SET z=v FROM input WHERE x=k;
+}
+
+foreach {tn sql} {
+ 2 {
+ CREATE TABLE x1(a INT PRIMARY KEY, b, c) WITHOUT ROWID;
+ }
+ 1 {
+ CREATE TABLE x1(a INTEGER PRIMARY KEY, b, c);
+ }
+ 3 {
+ CREATE TABLE x1(a INT PRIMARY KEY, b, c);
+ }
+} {
+
+ reset_db
+ execsql $sql
+
+ do_execsql_test 4.$tn.0 {
+ INSERT INTO x1 VALUES(1, 1, 1);
+ INSERT INTO x1 VALUES(2, 2, 2);
+ INSERT INTO x1 VALUES(3, 3, 3);
+ INSERT INTO x1 VALUES(4, 4, 4);
+ INSERT INTO x1 VALUES(5, 5, 5);
+ CREATE TABLE map(o, t);
+ INSERT INTO map VALUES(3, 30), (4, 40), (1, 10);
+ }
+
+ do_execsql_test 4.$tn.1 {
+ UPDATE x1 SET a=t FROM map WHERE a=o;
+ SELECT * FROM x1 ORDER BY a;
+ } {2 2 2 5 5 5 10 1 1 30 3 3 40 4 4}
+}
+
+reset_db
+do_execsql_test 5.0 {
+ CREATE TABLE x1(a, b, c);
+ CREATE TABLE x2(a, b, c);
+}
+
+foreach {tn update nm} {
+ 1 "UPDATE x1 SET a=5 FROM x1" x1
+ 2 "UPDATE x1 AS grapes SET a=5 FROM x1 AS grapes" grapes
+ 3 "UPDATE x1 SET a=5 FROM x2, x1" x1
+ 4 "UPDATE x1 AS grapes SET a=5 FROM x2, x1 AS grapes" grapes
+} {
+ do_catchsql_test 5.$tn $update \
+ "1 {target object/alias may not appear in FROM clause: $nm}"
+}
+
+
+finish_test
+
+
diff --git a/test/upfrom3.test b/test/upfrom3.test
new file mode 100644
index 0000000000..d30b3fa28c
--- /dev/null
+++ b/test/upfrom3.test
@@ -0,0 +1,262 @@
+# 2020 July 14
+#
+# 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 upfrom3
+
+# Test plan:
+#
+# 1.*: Test UPDATE ... FROM statements that modify IPK fields. And that
+# modify "INTEGER PRIMARY KEY" fields on WITHOUT ROWID tables.
+#
+# 2.*: Test UPDATE ... FROM statements that modify PK fields of WITHOUT
+# ROWID tables.
+#
+# 3.*: Test that UPDATE ... FROM statements are not confused if there
+# are multiple tables of the same name in attached databases.
+#
+# 4.*: Tests for UPDATE ... FROM statements and foreign keys.
+#
+
+foreach {tn wo} {
+ 1 ""
+ 2 "WITHOUT ROWID"
+} {
+ reset_db
+ eval [string map [list %WO% $wo %TN% $tn] {
+
+ do_execsql_test 1.%TN%.0 {
+ CREATE TABLE log(t TEXT);
+ CREATE TABLE t1(x INTEGER PRIMARY KEY, y, z UNIQUE) %WO%;
+ CREATE INDEX t1y ON t1(y);
+
+ INSERT INTO t1 VALUES(1, 'i', 'one');
+ INSERT INTO t1 VALUES(2, 'ii', 'two');
+ INSERT INTO t1 VALUES(3, 'iii', 'three');
+ INSERT INTO t1 VALUES(4, 'iv', 'four');
+ }
+
+ do_execsql_test 1.%TN%.1 {
+ CREATE TABLE x1(o, n);
+ INSERT INTO x1 VALUES(1, 11);
+ INSERT INTO x1 VALUES(2, 12);
+ INSERT INTO x1 VALUES(3, 13);
+ INSERT INTO x1 VALUES(4, 14);
+ UPDATE t1 SET x=n FROM x1 WHERE x=o;
+ SELECT x, y, z FROM t1 ORDER BY 1;
+ } {
+ 11 i one
+ 12 ii two
+ 13 iii three
+ 14 iv four
+ }
+
+ do_test 1.%TN%.2 { db changes } 4
+
+ do_execsql_test 1.%TN%.3 {
+ INSERT INTO x1 VALUES(11, 21);
+ INSERT INTO x1 VALUES(12, 22);
+ INSERT INTO x1 VALUES(13, 23);
+ INSERT INTO x1 VALUES(14, 24);
+
+ INSERT INTO x1 VALUES(21, 31);
+ INSERT INTO x1 VALUES(22, 32);
+ INSERT INTO x1 VALUES(23, 33);
+ INSERT INTO x1 VALUES(24, 34);
+ UPDATE t1 SET x=n FROM x1 WHERE x=o;
+ SELECT x, y, z FROM t1 ORDER BY 1;
+ } {
+ 21 i one
+ 22 ii two
+ 23 iii three
+ 24 iv four
+ }
+
+ do_execsql_test 1.%TN%.4 {
+ UPDATE t1 SET x=n FROM x1 WHERE x=o;
+ SELECT x, y, z FROM t1 ORDER BY 1;
+ } {
+ 31 i one
+ 32 ii two
+ 33 iii three
+ 34 iv four
+ }
+
+ do_execsql_test 1.%TN%.5 {
+ INSERT INTO x1 VALUES(31, 32);
+ INSERT INTO x1 VALUES(33, 34);
+ UPDATE OR REPLACE t1 SET x=n FROM x1 WHERE x=o;
+ SELECT x, y, z FROM t1 ORDER BY 1;
+ } {
+ 32 i one
+ 34 iii three
+ }
+
+ do_execsql_test 1.%TN%.6 {
+ INSERT INTO t1 VALUES(33, 'ii', 'two');
+ INSERT INTO t1 VALUES(35, 'iv', 'four');
+ }
+
+ do_execsql_test 1.%TN%.7 {
+ CREATE TABLE x2(o, n, zz);
+ INSERT INTO x2 VALUES(32, 41, 'four');
+ INSERT INTO x2 VALUES(33, 42, 'three');
+ UPDATE OR IGNORE t1 SET x=n, z=zz FROM x2 WHERE x=o;
+ SELECT x, y, z FROM t1 ORDER BY 1;
+ } {
+ 32 i one
+ 33 ii two
+ 34 iii three
+ 35 iv four
+ }
+
+ do_execsql_test 1.%TN%.8 {
+ UPDATE OR REPLACE t1 SET x=n, z=zz FROM x2 WHERE x=o;
+ SELECT x, y, z FROM t1 ORDER BY 1;
+ } {
+ 41 i four
+ 42 ii three
+ }
+
+ }]
+}
+
+do_execsql_test 2.1.1 {
+ CREATE TABLE u1(a, b, c, PRIMARY KEY(b, c)) WITHOUT ROWID;
+ INSERT INTO u1 VALUES(0, 0, 0);
+ INSERT INTO u1 VALUES(1, 0, 1);
+ INSERT INTO u1 VALUES(2, 1, 0);
+ INSERT INTO u1 VALUES(3, 1, 1);
+}
+
+do_execsql_test 2.1.2 {
+ CREATE TABLE map(f, t);
+ INSERT INTO map VALUES(0, 10);
+ INSERT INTO map VALUES(1, 11);
+ UPDATE u1 SET c=t FROM map WHERE c=f;
+ SELECT * FROM u1 ORDER BY a;
+} {
+ 0 0 10
+ 1 0 11
+ 2 1 10
+ 3 1 11
+}
+
+do_execsql_test 2.1.3 {
+ UPDATE u1 SET b=t FROM map WHERE b=f;
+ SELECT * FROM u1 ORDER BY a;
+} {
+ 0 10 10
+ 1 10 11
+ 2 11 10
+ 3 11 11
+}
+
+do_execsql_test 2.1.4 {
+ CREATE TABLE map2(o1, o2, n1, n2);
+ INSERT INTO map2 VALUES
+ (10, 10, 50, 50), (10, 11, 50, 60),
+ (11, 10, 60, 50), (11, 11, 60, 60);
+ UPDATE u1 SET b=n1, c=n2 FROM map2 WHERE b=o1 AND c=o2;
+ SELECT * FROM u1 ORDER BY a;
+} {
+ 0 50 50
+ 1 50 60
+ 2 60 50
+ 3 60 60
+}
+
+#-------------------------------------------------------------------------
+foreach {tn wo} {
+ 1 ""
+ 2 "WITHOUT ROWID"
+} {
+ reset_db
+ forcedelete test.db2
+ eval [string map [list %WO% $wo %TN% $tn] {
+ do_execsql_test 3.$tn.1 {
+ CREATE TABLE g1(a, b, c, PRIMARY KEY(a, b)) %WO%;
+ INSERT INTO g1 VALUES(1, 1, 1);
+
+ ATTACH 'test.db2' AS aux;
+ CREATE TABLE aux.g1(a, b, c, PRIMARY KEY(a, b)) %WO%;
+ INSERT INTO aux.g1 VALUES(10, 1, 10);
+ INSERT INTO aux.g1 VALUES(20, 2, 20);
+ INSERT INTO aux.g1 VALUES(30, 3, 30);
+ }
+
+ do_execsql_test 3.$tn.2 {
+ UPDATE aux.g1 SET c=101 FROM main.g1;
+ }
+ do_execsql_test 3.$tn.3 {
+ SELECT * FROM aux.g1;
+ } {10 1 101 20 2 101 30 3 101}
+
+ do_execsql_test 3.$tn.4 {
+ UPDATE g1 SET c=101 FROM g1 AS g2;
+ }
+ do_execsql_test 3.$tn.5 {
+ SELECT * FROM g1;
+ } {1 1 101}
+ }]
+}
+
+#-------------------------------------------------------------------------
+reset_db
+foreach {tn wo} {
+ 1 ""
+ 2 "WITHOUT ROWID"
+} {
+ reset_db
+ forcedelete test.db2
+ eval [string map [list %WO% $wo %TN% $tn] {
+
+ do_execsql_test 4.$tn.1 {
+ CREATE TABLE p1(a INTEGER PRIMARY KEY, b) %WO%;
+ CREATE TABLE c1(x PRIMARY KEY, y REFERENCES p1 ON UPDATE CASCADE) %WO%;
+ PRAGMA foreign_keys = 1;
+
+ INSERT INTO p1 VALUES(1, 'one');
+ INSERT INTO p1 VALUES(11, 'eleven');
+ INSERT INTO p1 VALUES(111, 'eleventyone');
+
+ INSERT INTO c1 VALUES('a', 1);
+ INSERT INTO c1 VALUES('b', 11);
+ INSERT INTO c1 VALUES('c', 111);
+ }
+
+ do_execsql_test 4.$tn.2 {
+ CREATE TABLE map(f, t);
+ INSERT INTO map VALUES('a', 111);
+ INSERT INTO map VALUES('c', 112);
+ }
+
+ do_catchsql_test 4.$tn.3 {
+ UPDATE c1 SET y=t FROM map WHERE x=f;
+ } {1 {FOREIGN KEY constraint failed}}
+
+ do_execsql_test 4.$tn.4 {
+ INSERT INTO map VALUES('eleven', 12);
+ INSERT INTO map VALUES('eleventyone', 112);
+ UPDATE p1 SET a=t FROM map WHERE b=f;
+ }
+
+ do_execsql_test 4.$tn.5 {
+ SELECT * FROM c1
+ } {a 1 b 12 c 112}
+
+ }]
+}
+
+finish_test
+
diff --git a/test/upfromfault.test b/test/upfromfault.test
new file mode 100644
index 0000000000..fcb5956089
--- /dev/null
+++ b/test/upfromfault.test
@@ -0,0 +1,140 @@
+# 2020 April 29
+#
+# 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 upfromfault
+
+foreach {tn sql} {
+ 1 {
+ CREATE TABLE t1(x PRIMARY KEY, y, z UNIQUE);
+ CREATE INDEX t1y ON t1(y);
+ }
+ 2 {
+ CREATE TABLE t1(x PRIMARY KEY, y, z UNIQUE) WITHOUT ROWID;
+ CREATE INDEX t1y ON t1(y);
+ }
+ 3 {
+ CREATE TABLE t1(x, y, z UNIQUE, PRIMARY KEY(x,y)) WITHOUT ROWID;
+ }
+ 4 {
+ CREATE VIRTUAL TABLE t1 USING fts5(x, y, z);
+ }
+ 5 {
+ CREATE TABLE real(x, y, z);
+ CREATE VIEW t1 AS SELECT * FROM real;
+ CREATE TRIGGER t1_insert INSTEAD OF INSERT ON t1 BEGIN
+ INSERT INTO real VALUES(new.x, new.y, new.z);
+ END;
+ CREATE TRIGGER t1_update INSTEAD OF UPDATE ON t1 BEGIN
+ INSERT INTO log VALUES(old.z || '->' || new.z);
+ UPDATE real SET y=new.y, z=new.z WHERE x=old.x;
+ END;
+ }
+} {
+if {$tn<5} continue
+ reset_db
+
+ ifcapable !fts5 { if {$tn==4} continue }
+
+ execsql $sql
+ do_execsql_test 1.$tn.0 {
+ CREATE TABLE log(t TEXT);
+
+ INSERT INTO t1 VALUES(1, 'i', 'one');
+ INSERT INTO t1 VALUES(2, 'ii', 'two');
+ INSERT INTO t1 VALUES(3, 'iii', 'three');
+ INSERT INTO t1 VALUES(4, 'iv', 'four');
+ }
+ if {$tn!=4 && $tn!=5} {
+ do_execsql_test 1.$tn.0b {
+ CREATE TRIGGER tr1 BEFORE UPDATE ON t1 BEGIN
+ INSERT INTO log VALUES(old.z || '->' || new.z);
+ END;
+ CREATE TRIGGER tr2 AFTER UPDATE ON t1 BEGIN
+ INSERT INTO log VALUES(old.y || '->' || new.y);
+ END;
+ }
+ }
+
+ faultsim_save_and_close
+
+ do_faultsim_test 1.$tn -prep {
+ faultsim_restore_and_reopen
+ execsql { SELECT * FROM t1 }
+ } -body {
+ execsql {
+ WITH data(k, v) AS (
+ VALUES(3, 'thirty'), (1, 'ten')
+ )
+ UPDATE t1 SET z=v FROM data WHERE x=k;
+ }
+ } -test {
+ faultsim_test_result {0 {}} {1 {vtable constructor failed: t1}}
+ if {$testrc==0} {
+ set res [execsql { SELECT * FROM t1 }]
+ if {$res!="1 i ten 2 ii two 3 iii thirty 4 iv four"} {
+ error "unexpected result: $res"
+ }
+ }
+ }
+}
+
+reset_db
+do_execsql_test 2.0 {
+ CREATE TABLE t1(a, b, c);
+ CREATE TABLE t2(x, y, z);
+}
+faultsim_save_and_close
+do_faultsim_test 2.1 -prep {
+ faultsim_restore_and_reopen
+} -body {
+ execsql {
+ CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
+ UPDATE t2 SET x=a FROM t1 WHERE c=z;
+ END;
+ }
+} -test {
+ faultsim_test_result {0 {}}
+}
+
+faultsim_restore_and_reopen
+do_execsql_test 2.2 {
+ CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
+ UPDATE t1 SET a=x FROM t2 WHERE c=z;
+ END;
+
+ INSERT INTO t2 VALUES(1, 1, 1);
+ INSERT INTO t2 VALUES(2, 2, 2);
+ INSERT INTO t2 VALUES(3, 3, 3);
+}
+faultsim_save_and_close
+
+do_faultsim_test 2.3 -prep {
+ faultsim_restore_and_reopen
+} -body {
+ execsql {
+ INSERT INTO t1 VALUES(NULL, NULL, 1), (NULL, NULL, 3);
+ }
+} -test {
+ faultsim_test_result {0 {}}
+ if {$testrc==0} {
+ set res [execsql { SELECT * FROM t1 }]
+ if {$res!="1 {} 1 3 {} 3"} {
+ error "unexpected result: $res"
+ }
+ }
+}
+
+
+finish_test
+
diff --git a/test/wal2.test b/test/wal2.test
index 9a56eb41fe..ae6134d8b5 100644
--- a/test/wal2.test
+++ b/test/wal2.test
@@ -122,8 +122,12 @@ do_test wal2-1.1 {
} {4 10}
set RECOVER [list \
- {0 1 lock exclusive} {1 2 lock exclusive} {4 4 lock exclusive} \
- {1 2 unlock exclusive} {4 4 unlock exclusive} {0 1 unlock exclusive} \
+ {0 1 lock exclusive} {1 2 lock exclusive} \
+ {4 1 lock exclusive} {4 1 unlock exclusive} \
+ {5 1 lock exclusive} {5 1 unlock exclusive} \
+ {6 1 lock exclusive} {6 1 unlock exclusive} \
+ {7 1 lock exclusive} {7 1 unlock exclusive} \
+ {1 2 unlock exclusive} {0 1 unlock exclusive} \
]
set READ [list \
{4 1 lock shared} {4 1 unlock shared} \
@@ -394,9 +398,17 @@ set expected_locks [list]
lappend expected_locks {1 1 lock exclusive} ;# Lock checkpoint
lappend expected_locks {0 1 lock exclusive} ;# Lock writer
lappend expected_locks {2 1 lock exclusive} ;# Lock recovery
-lappend expected_locks {4 4 lock exclusive} ;# Lock all aReadMark[]
+# lappend expected_locks {4 4 lock exclusive} ;# Lock all aReadMark[]
+lappend expected_locks {4 1 lock exclusive} ;# Lock aReadMark[1]
+lappend expected_locks {4 1 unlock exclusive} ;# Unlock aReadMark[1]
+lappend expected_locks {5 1 lock exclusive}
+lappend expected_locks {5 1 unlock exclusive}
+lappend expected_locks {6 1 lock exclusive}
+lappend expected_locks {6 1 unlock exclusive}
+lappend expected_locks {7 1 lock exclusive}
+lappend expected_locks {7 1 unlock exclusive}
lappend expected_locks {2 1 unlock exclusive} ;# Unlock recovery
-lappend expected_locks {4 4 unlock exclusive} ;# Unlock all aReadMark[]
+# lappend expected_locks {4 4 unlock exclusive} ;# Unlock all aReadMark[]
lappend expected_locks {0 1 unlock exclusive} ;# Unlock writer
lappend expected_locks {3 1 lock exclusive} ;# Lock aReadMark[0]
lappend expected_locks {3 1 unlock exclusive} ;# Unlock aReadMark[0]
@@ -625,8 +637,12 @@ do_test wal2-6.4.1 {
} {}
set RECOVERY {
- {0 1 lock exclusive} {1 2 lock exclusive} {4 4 lock exclusive}
- {1 2 unlock exclusive} {4 4 unlock exclusive} {0 1 unlock exclusive}
+ {0 1 lock exclusive} {1 2 lock exclusive}
+ {4 1 lock exclusive} {4 1 unlock exclusive}
+ {5 1 lock exclusive} {5 1 unlock exclusive}
+ {6 1 lock exclusive} {6 1 unlock exclusive}
+ {7 1 lock exclusive} {7 1 unlock exclusive}
+ {1 2 unlock exclusive} {0 1 unlock exclusive}
}
set READMARK0_READ {
{3 1 lock shared} {3 1 unlock shared}
diff --git a/test/walprotocol.test b/test/walprotocol.test
index b1d9e8c01f..a262cdd76d 100644
--- a/test/walprotocol.test
+++ b/test/walprotocol.test
@@ -52,18 +52,28 @@ do_test 1.1 {
set ::locks [list]
sqlite3 db test.db -vfs T
execsql { SELECT * FROM x }
- lrange $::locks 0 5
-} [list {0 1 lock exclusive} {1 2 lock exclusive} {4 4 lock exclusive} \
- {1 2 unlock exclusive} {4 4 unlock exclusive} {0 1 unlock exclusive} \
+ lrange $::locks 0 11
+} [list {0 1 lock exclusive} {1 2 lock exclusive} \
+ {4 1 lock exclusive} {4 1 unlock exclusive} \
+ {5 1 lock exclusive} {5 1 unlock exclusive} \
+ {6 1 lock exclusive} {6 1 unlock exclusive} \
+ {7 1 lock exclusive} {7 1 unlock exclusive} \
+ {1 2 unlock exclusive} \
+ {0 1 unlock exclusive} \
]
do_test 1.2 {
db close
set ::locks [list]
sqlite3 db test.db -vfs T
execsql { SELECT * FROM x }
- lrange $::locks 0 5
-} [list {0 1 lock exclusive} {1 2 lock exclusive} {4 4 lock exclusive} \
- {1 2 unlock exclusive} {4 4 unlock exclusive} {0 1 unlock exclusive} \
+ lrange $::locks 0 11
+} [list {0 1 lock exclusive} {1 2 lock exclusive} \
+ {4 1 lock exclusive} {4 1 unlock exclusive} \
+ {5 1 lock exclusive} {5 1 unlock exclusive} \
+ {6 1 lock exclusive} {6 1 unlock exclusive} \
+ {7 1 lock exclusive} {7 1 unlock exclusive} \
+ {1 2 unlock exclusive} \
+ {0 1 unlock exclusive} \
]
proc lock_callback {method filename handle lock} {
if {$lock == "1 2 lock exclusive"} { return SQLITE_BUSY }
@@ -101,7 +111,7 @@ do_test 1.5 {
set ::locks [list]
sqlite3 db test.db -vfs T
catchsql { SELECT * FROM x }
-} {1 {locking protocol}}
+} {0 z}
db close
T delete
@@ -160,7 +170,7 @@ do_test 2.5 {
} {Tehran Qom Markazi Qazvin Gilan Ardabil}
do_test 2.6 {
set ::r
-} {1 {locking protocol}}
+} {0 {Tehran Qom Markazi Qazvin Gilan Ardabil}}
db close
db2 close
@@ -182,7 +192,7 @@ do_test 2.7 {
} {Tehran Qom Markazi Qazvin Gilan Ardabil}
do_test 2.8 {
set ::r
-} {1 {locking protocol}}
+} {0 {Tehran Qom Markazi Qazvin Gilan Ardabil}}
db close
db2 close
diff --git a/test/walvfs.test b/test/walvfs.test
index da0f43c3b1..f21b65e7e9 100644
--- a/test/walvfs.test
+++ b/test/walvfs.test
@@ -145,7 +145,7 @@ proc xWrite {method file args} {
if {[file tail $file]=="test.db"} {
incr ::cnt -1
if {$::cnt==0} {
- sqlite3_memdebug_fail 5 -repeat 0
+ sqlite3_memdebug_fail 1 -repeat 0
catchsql { SELECT 'a big long string!' }
sqlite3_interrupt db
}
diff --git a/test/where.test b/test/where.test
index 26bf3a0402..9b072da677 100644
--- a/test/where.test
+++ b/test/where.test
@@ -1496,8 +1496,8 @@ do_execsql_test where-25.0 {
INSERT INTO t2 VALUES(3, 'three', 'iii');
PRAGMA writable_schema = 1;
- UPDATE sqlite_master SET rootpage = (
- SELECT rootpage FROM sqlite_master WHERE name = 'i2'
+ UPDATE sqlite_schema SET rootpage = (
+ SELECT rootpage FROM sqlite_schema WHERE name = 'i2'
) WHERE name = 'i1';
}
db close
@@ -1524,8 +1524,8 @@ do_execsql_test where-25.3 {
INSERT INTO t2 VALUES(3, 'three', 'iii');
PRAGMA writable_schema = 1;
- UPDATE sqlite_master SET rootpage = (
- SELECT rootpage FROM sqlite_master WHERE name = 'i2'
+ UPDATE sqlite_schema SET rootpage = (
+ SELECT rootpage FROM sqlite_schema WHERE name = 'i2'
) WHERE name = 'i1';
}
db close
diff --git a/test/where9.test b/test/where9.test
index b274609364..0f770dfee8 100644
--- a/test/where9.test
+++ b/test/where9.test
@@ -426,7 +426,7 @@ do_test where9-4.5 {
AND (c=31031 OR d IS NULL)
ORDER BY +a
}
-} {1 {no query solution}}
+} {0 {92 93 97}}
do_test where9-4.6 {
count_steps {
SELECT a FROM t1 NOT INDEXED
@@ -442,7 +442,7 @@ do_test where9-4.7 {
AND (c=31031 OR d IS NULL)
ORDER BY +a
}
-} {1 {no query solution}}
+} {0 {92 93 97}}
do_test where9-4.8 {
catchsql {
SELECT a FROM t1 INDEXED BY t1d
@@ -450,7 +450,7 @@ do_test where9-4.8 {
AND (c=31031 OR d IS NULL)
ORDER BY +a
}
-} {1 {no query solution}}
+} {0 {92 93 97}}
# The (c=31031 OR d IS NULL) clause is preferred over b>1000 because
# the former is an equality test which is expected to return fewer rows.
@@ -776,7 +776,7 @@ do_test where9-6.8.1 {
OR (b NOT NULL AND c IS NULL AND d NOT NULL)
OR (b NOT NULL AND c NOT NULL AND d IS NULL)
}
-} {1 {no query solution}}
+} {0 {}}
do_test where9-6.8.2 {
catchsql {
UPDATE t1 INDEXED BY t1b SET a=a+100
@@ -784,7 +784,7 @@ do_test where9-6.8.2 {
OR (b NOT NULL AND c IS NULL AND d NOT NULL)
OR (b NOT NULL AND c NOT NULL AND d IS NULL)
}
-} {1 {no query solution}}
+} {0 {}}
set solution_possible 0
ifcapable stat4 {
@@ -818,7 +818,7 @@ if $solution_possible {
OR (b NOT NULL AND c IS NULL AND d NOT NULL)
OR (b NOT NULL AND c NOT NULL AND d IS NULL)
}
- } {1 {no query solution}}
+ } {0 {}}
do_test where9-6.8.4 {
catchsql {
DELETE FROM t1 INDEXED BY t1b
@@ -826,7 +826,7 @@ if $solution_possible {
OR (b NOT NULL AND c IS NULL AND d NOT NULL)
OR (b NOT NULL AND c NOT NULL AND d IS NULL)
}
- } {1 {no query solution}}
+ } {0 {}}
}
############################################################################
# Test cases where terms inside an OR series are combined with AND terms
diff --git a/test/whereG.test b/test/whereG.test
index 9d4cde7b4d..c6ae3ce325 100644
--- a/test/whereG.test
+++ b/test/whereG.test
@@ -317,4 +317,15 @@ do_execsql_test 9.10 {
SELECT coalesce(max(quote(a)),10) FROM t1 GROUP BY a;
} {NULL '' 'X'}
+# 2020-06-14: assert() changed back into testcase()
+# ticket 9fb26d37cefaba40
+#
+reset_db
+do_execsql_test 10.1 {
+ CREATE TABLE a(b TEXT); INSERT INTO a VALUES(0),(4),(9);
+ CREATE TABLE c(d NUM);
+ CREATE VIEW f(g, h) AS SELECT b, 0 FROM a UNION SELECT d, d FROM c;
+ SELECT g = g FROM f GROUP BY h;
+} {1}
+
finish_test
diff --git a/test/wherelimit2.test b/test/wherelimit2.test
index 83c04b14cf..8e39127ac8 100644
--- a/test/wherelimit2.test
+++ b/test/wherelimit2.test
@@ -218,18 +218,22 @@ do_execsql_test 4.1 {
ROLLBACK;
} {3 4 5 6}
-do_catchsql_test 4.2 {
- DELETE FROM x1 INDEXED BY x1bc WHERE d=3 LIMIT 1;
-} {1 {no query solution}}
+# 2020-06-03: Query planner improved so that a solution is possible.
+#
+#do_catchsql_test 4.2 {
+# DELETE FROM x1 INDEXED BY x1bc WHERE d=3 LIMIT 1;
+#} {1 {no query solution}}
do_execsql_test 4.3 {
DELETE FROM x1 INDEXED BY x1bc WHERE b=3 LIMIT 1;
SELECT a FROM x1;
} {1 2 3 4 6}
-do_catchsql_test 4.4 {
- UPDATE x1 INDEXED BY x1bc SET d=5 WHERE d=3 LIMIT 1;
-} {1 {no query solution}}
+# 2020-06-03: Query planner improved so that a solution is possible.
+#
+#do_catchsql_test 4.4 {
+# UPDATE x1 INDEXED BY x1bc SET d=5 WHERE d=3 LIMIT 1;
+#} {1 {no query solution}}
do_execsql_test 4.5 {
UPDATE x1 INDEXED BY x1bc SET d=5 WHERE b=2 LIMIT 1;
diff --git a/test/window1.test b/test/window1.test
index 677297fc89..dbaf4388fb 100644
--- a/test/window1.test
+++ b/test/window1.test
@@ -1743,5 +1743,262 @@ do_execsql_test 53.0 {
WHERE a.c);
} {4 4 4 4}
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 54.1 {
+ CREATE TABLE t1(a VARCHAR(20), b FLOAT);
+ INSERT INTO t1 VALUES('1',10.0);
+}
+
+do_catchsql_test 54.2 {
+ SELECT * FROM (
+ SELECT sum(b) OVER() AS c FROM t1
+ UNION
+ SELECT b AS c FROM t1
+ ) WHERE c>10;
+} {0 {}}
+
+do_execsql_test 54.3 {
+ INSERT INTO t1 VALUES('2',5.0);
+ INSERT INTO t1 VALUES('3',15.0);
+}
+
+do_catchsql_test 54.4 {
+ SELECT * FROM (
+ SELECT sum(b) OVER() AS c FROM t1
+ UNION
+ SELECT b AS c FROM t1
+ ) WHERE c>10;
+} {0 {15.0 30.0}}
+
+# 2020-06-05 ticket c8d3b9f0a750a529
+reset_db
+do_execsql_test 55.1 {
+ CREATE TABLE a(b);
+ SELECT
+ (SELECT b FROM a
+ GROUP BY b
+ HAVING (SELECT COUNT()OVER() + lead(b)OVER(ORDER BY SUM(DISTINCT b) + b))
+ )
+ FROM a
+ UNION
+ SELECT 99
+ ORDER BY 1;
+} {99}
+
+#------------------------------------------------------------------------
+reset_db
+do_execsql_test 56.1 {
+ CREATE TABLE t1(a, b INTEGER);
+ CREATE TABLE t2(c, d);
+}
+do_catchsql_test 56.2 {
+ SELECT avg(b) FROM t1
+ UNION ALL
+ SELECT min(c) OVER () FROM t2
+ ORDER BY nosuchcolumn;
+} {1 {1st ORDER BY term does not match any column in the result set}}
+
+reset_db
+do_execsql_test 57.1 {
+ CREATE TABLE t4(a, b, c, d, e);
+}
+
+do_catchsql_test 57.2 {
+ SELECT b FROM t4
+ UNION
+ SELECT a FROM t4
+ ORDER BY (
+ SELECT sum(x) OVER() FROM (
+ SELECT c AS x FROM t4
+ UNION
+ SELECT d FROM t4
+ ORDER BY (SELECT e FROM t4)
+ )
+ );
+} {1 {1st ORDER BY term does not match any column in the result set}}
+
+# 2020-06-06 various dbsqlfuzz finds and
+# ticket 0899cf62f597d7e7
+#
+reset_db
+do_execsql_test 57.1 {
+ CREATE TABLE t1(a, b, c);
+ INSERT INTO t1 VALUES(NULL,NULL,NULL);
+ SELECT
+ sum(a),
+ min(b) OVER (),
+ count(c) OVER (ORDER BY b)
+ FROM t1;
+} {{} {} 0}
+do_execsql_test 57.2 {
+ CREATE TABLE v0 ( v1 INTEGER PRIMARY KEY ) ;
+ INSERT INTO v0 VALUES ( 10 ) ;
+ SELECT DISTINCT v1, lead(v1) OVER() FROM v0 GROUP BY v1 ORDER BY 2;
+} {10 {}}
+do_catchsql_test 57.3 {
+ DROP TABLE t1;
+ CREATE TABLE t1(a);
+ INSERT INTO t1(a) VALUES(22);
+ CREATE TABLE t3(y);
+ INSERT INTO t3(y) VALUES(5),(11),(-9);
+ SELECT (
+ SELECT max(y) OVER( ORDER BY (SELECT x FROM (SELECT sum(y) AS x FROM t1)))
+ )
+ FROM t3;
+} {1 {misuse of aggregate: sum()}}
+
+# 2020-06-06 ticket 1f6f353b684fc708
+reset_db
+do_execsql_test 58.1 {
+ CREATE TABLE a(a, b, c);
+ INSERT INTO a VALUES(1, 2, 3);
+ INSERT INTO a VALUES(4, 5, 6);
+ SELECT sum(345+b) OVER (ORDER BY b),
+ sum(avg(678)) OVER (ORDER BY c) FROM a;
+} {347 678.0}
+
+# 2020-06-06 ticket e5504e987e419fb0
+do_catchsql_test 59.1 {
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1(x INTEGER PRIMARY KEY);
+ INSERT INTO t1 VALUES (123);
+ SELECT
+ ntile( (SELECT sum(x)) ) OVER(ORDER BY x),
+ min(x) OVER(ORDER BY x)
+ FROM t1;
+} {1 {misuse of aggregate: sum()}}
+
+# 2020-06-07 ticket f7d890858f361402
+do_execsql_test 60.1 {
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (x INTEGER PRIMARY KEY);
+ INSERT INTO t1 VALUES (99);
+ SELECT EXISTS(SELECT count(*) OVER() FROM t1 ORDER BY sum(x) OVER());
+} {1}
+
+# 2020-06-07 test case generated by dbsqlfuzz showing how an AggInfo
+# object might be referenced after the sqlite3Select() call that created
+# it returns. This proves the need to persist all AggInfo objects until
+# the Parse object is destroyed.
+#
+reset_db
+do_execsql_test 61.1 {
+CREATE TABLE t1(a);
+INSERT INTO t1 VALUES(5),(NULL),('seventeen');
+SELECT (SELECT max(x)OVER(ORDER BY x) % min(x)OVER(ORDER BY CASE x WHEN 889 THEN x WHEN x THEN x END)) FROM (SELECT (SELECT sum(CAST(a IN(SELECT (SELECT max(x)OVER(ORDER BY CASE x WHEN 889 THEN 299 WHEN 863 THEN 863 END)) FROM (SELECT (SELECT sum(CAST((SELECT (SELECT max(x)OVER(ORDER BY x) / min(x)OVER(ORDER BY CASE x WHEN 889 THEN 299 WHEN -true THEN 863 END)) FROM (SELECT (SELECT sum(CAST(a IN(SELECT (SELECT max(x) & sum ( a )OVER(ORDER BY CASE x WHEN -8 THEN 299 WHEN 863 THEN 863 END)) FROM (SELECT (SELECT sum(CAST(a AS )) FROM t1) AS x FROM t1)) AS t1 )) FROM t1) AS x FROM t1)) AS x )) FROM t1) AS x FROM t1)) AS real)) FROM t1) AS x FROM t1);
+} {{} {} {}}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 62.1 {
+ CREATE TABLE t1(a VARCHAR(20), b FLOAT);
+ INSERT INTO t1 VALUES('1',10.0);
+}
+
+do_execsql_test 62.2 {
+ SELECT * FROM (
+ SELECT sum(b) OVER() AS c FROM t1
+ UNION
+ SELECT b AS c FROM t1
+ ) WHERE c>10;
+}
+
+do_execsql_test 62.3 {
+ INSERT INTO t1 VALUES('2',5.0);
+ INSERT INTO t1 VALUES('3',15.0);
+}
+
+do_execsql_test 62.4 {
+ SELECT * FROM (
+ SELECT sum(b) OVER() AS c FROM t1
+ UNION
+ SELECT b AS c FROM t1
+ ) WHERE c>10;
+} {15.0 30.0}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 63.1 {
+ CREATE TABLE t1(b, x);
+ CREATE TABLE t2(c, d);
+ CREATE TABLE t3(e, f);
+}
+
+do_execsql_test 63.2 {
+ SELECT max(b) OVER(
+ ORDER BY SUM(
+ (SELECT c FROM t2 UNION SELECT x ORDER BY c)
+ )
+ ) FROM t1;
+} {{}}
+
+do_execsql_test 63.3 {
+ SELECT sum(b) over(
+ ORDER BY (
+ SELECT max(b) OVER(
+ ORDER BY sum(
+ (SELECT x AS c UNION SELECT 1234 ORDER BY c)
+ )
+ ) AS e
+ ORDER BY e
+ )
+ )
+ FROM t1;
+} {{}}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 64.1 {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
+ INSERT INTO t1 VALUES(1, 'abcd');
+ INSERT INTO t1 VALUES(2, 'BCDE');
+ INSERT INTO t1 VALUES(3, 'cdef');
+ INSERT INTO t1 VALUES(4, 'DEFG');
+}
+
+do_execsql_test 64.2 {
+ SELECT rowid, max(b COLLATE nocase)||''
+ FROM t1
+ GROUP BY rowid
+ ORDER BY max(b COLLATE nocase)||'';
+} {1 abcd 2 BCDE 3 cdef 4 DEFG}
+
+do_execsql_test 64.3 {
+ SELECT count() OVER (), rowid, max(b COLLATE nocase)||''
+ FROM t1
+ GROUP BY rowid
+ ORDER BY max(b COLLATE nocase)||'';
+} {4 1 abcd 4 2 BCDE 4 3 cdef 4 4 DEFG}
+
+do_execsql_test 64.4 {
+ SELECT count() OVER (), rowid, max(b COLLATE nocase)
+ FROM t1
+ GROUP BY rowid
+ ORDER BY max(b COLLATE nocase);
+} {4 1 abcd 4 2 BCDE 4 3 cdef 4 4 DEFG}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 65.1 {
+ CREATE TABLE t1(c1);
+ INSERT INTO t1 VALUES('abcd');
+}
+do_execsql_test 65.2 {
+ SELECT max(c1 COLLATE nocase) IN (SELECT 'aBCd') FROM t1;
+} {1}
+
+do_execsql_test 65.3 {
+ SELECT
+ count() OVER (),
+ group_concat(c1 COLLATE nocase) IN (SELECT 'aBCd') FROM t1;
+} {1 1}
+
+do_execsql_test 65.4 {
+ SELECT COUNT() OVER () LIKE lead(102030) OVER(
+ ORDER BY sum('abcdef' COLLATE nocase) IN (SELECT 54321)
+ )
+ FROM t1;
+} {{}}
finish_test
diff --git a/test/window9.test b/test/window9.test
index 46d746c4ff..c342a4d790 100644
--- a/test/window9.test
+++ b/test/window9.test
@@ -255,7 +255,7 @@ do_execsql_test 8.2 {
do_catchsql_test 8.3 {
SELECT min( max((SELECT x FROM v1)) ) OVER()
-} {1 {misuse of aggregate: max()}}
+} {0 0}
do_execsql_test 8.4 {
SELECT(
@@ -263,6 +263,6 @@ do_execsql_test 8.4 {
SELECT sum( avg((SELECT x FROM v1)) ) OVER()
)
FROM v1;
-} {0.0}
+} {0.0 0.0}
finish_test
diff --git a/test/without_rowid3.test b/test/without_rowid3.test
index a9839e147e..eae7e3c856 100644
--- a/test/without_rowid3.test
+++ b/test/without_rowid3.test
@@ -942,7 +942,7 @@ ifcapable altertable {
PRAGMA foreign_keys = off;
ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1;
PRAGMA foreign_keys = on;
- SELECT sql FROM sqlite_master WHERE name='t2';
+ SELECT sql FROM sqlite_schema WHERE name='t2';
}
} {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}}
@@ -976,7 +976,7 @@ ifcapable altertable {
WITHOUT rowid;
CREATE TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1);
}
- execsql { SELECT sql FROM sqlite_master WHERE type = 'table'}
+ execsql { SELECT sql FROM sqlite_schema WHERE type = 'table'}
} [list \
{CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1) WITHOUT rowid} \
{CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2)
@@ -985,7 +985,7 @@ ifcapable altertable {
]
do_test without_rowid3-14.2.2.2 {
execsql { ALTER TABLE t1 RENAME TO t4 }
- execsql { SELECT sql FROM sqlite_master WHERE type = 'table'}
+ execsql { SELECT sql FROM sqlite_schema WHERE type = 'table'}
} [list \
{CREATE TABLE "t4"(a PRIMARY KEY, b REFERENCES "t4") WITHOUT rowid} \
{CREATE TABLE t2(a PRIMARY KEY, b REFERENCES "t4", c REFERENCES t2)
@@ -1037,7 +1037,7 @@ ifcapable altertable {
PRAGMA foreign_keys = off;
ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1;
PRAGMA foreign_keys = on;
- SELECT sql FROM temp.sqlite_master WHERE name='t2';
+ SELECT sql FROM temp.sqlite_schema WHERE name='t2';
}
} {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}}
@@ -1063,7 +1063,7 @@ ifcapable altertable {
WITHOUT rowid;
CREATE TEMP TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1);
}
- execsql { SELECT sql FROM sqlite_temp_master WHERE type = 'table'}
+ execsql { SELECT sql FROM sqlite_temp_schema WHERE type = 'table'}
} [list \
{CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1) WITHOUT rowid} \
{CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2)
@@ -1072,7 +1072,7 @@ ifcapable altertable {
]
do_test without_rowid3-14.2tmp.2.2 {
execsql { ALTER TABLE t1 RENAME TO t4 }
- execsql { SELECT sql FROM temp.sqlite_master WHERE type = 'table'}
+ execsql { SELECT sql FROM temp.sqlite_schema WHERE type = 'table'}
} [list \
{CREATE TABLE "t4"(a PRIMARY KEY, b REFERENCES "t4") WITHOUT rowid} \
{CREATE TABLE t2(a PRIMARY KEY, b REFERENCES "t4", c REFERENCES t2)
@@ -1125,7 +1125,7 @@ ifcapable altertable {
PRAGMA foreign_keys = off;
ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1;
PRAGMA foreign_keys = on;
- SELECT sql FROM aux.sqlite_master WHERE name='t2';
+ SELECT sql FROM aux.sqlite_schema WHERE name='t2';
}
} {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}}
@@ -1151,7 +1151,7 @@ ifcapable altertable {
WITHOUT rowid;
CREATE TABLE aux.t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1);
}
- execsql { SELECT sql FROM aux.sqlite_master WHERE type = 'table'}
+ execsql { SELECT sql FROM aux.sqlite_schema WHERE type = 'table'}
} [list \
{CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1) WITHOUT rowid} \
{CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2)
@@ -1160,7 +1160,7 @@ ifcapable altertable {
]
do_test without_rowid3-14.2aux.2.2 {
execsql { ALTER TABLE t1 RENAME TO t4 }
- execsql { SELECT sql FROM aux.sqlite_master WHERE type = 'table'}
+ execsql { SELECT sql FROM aux.sqlite_schema WHERE type = 'table'}
} [list \
{CREATE TABLE "t4"(a PRIMARY KEY, b REFERENCES "t4") WITHOUT rowid} \
{CREATE TABLE t2(a PRIMARY KEY, b REFERENCES "t4", c REFERENCES t2)
diff --git a/tool/dbhash.c b/tool/dbhash.c
index 7696ddbde6..78685dcd6c 100644
--- a/tool/dbhash.c
+++ b/tool/dbhash.c
@@ -440,7 +440,7 @@ int main(int argc, char **argv){
fprintf(stderr, "cannot open database file '%s'\n", zDb);
continue;
}
- rc = sqlite3_exec(g.db, "SELECT * FROM sqlite_master", 0, 0, &zErrMsg);
+ rc = sqlite3_exec(g.db, "SELECT * FROM sqlite_schema", 0, 0, &zErrMsg);
if( rc || zErrMsg ){
sqlite3_close(g.db);
g.db = 0;
@@ -454,7 +454,7 @@ int main(int argc, char **argv){
/* Hash table content */
if( !omitContent ){
pStmt = db_prepare(
- "SELECT name FROM sqlite_master\n"
+ "SELECT name FROM sqlite_schema\n"
" WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n"
" AND name NOT LIKE 'sqlite_%%'\n"
" AND name LIKE '%q'\n"
@@ -476,7 +476,7 @@ int main(int argc, char **argv){
/* Hash the database schema */
if( !omitSchema ){
hash_one_query(
- "SELECT type, name, tbl_name, sql FROM sqlite_master\n"
+ "SELECT type, name, tbl_name, sql FROM sqlite_schema\n"
" WHERE tbl_name LIKE '%q'\n"
" ORDER BY name COLLATE nocase;\n",
zLike
diff --git a/tool/enlargedb.c b/tool/enlargedb.c
new file mode 100644
index 0000000000..dab5ef1f1c
--- /dev/null
+++ b/tool/enlargedb.c
@@ -0,0 +1,68 @@
+/*
+** Try to enlarge an SQLite database by appending many unused pages.
+** The resulting database will fail PRAGMA integrity_check due to the
+** appended unused pages, but it should work otherwise.
+**
+** Usage:
+**
+** enlargedb DATABASE N
+**
+** Adds N blank pages onto the end of DATABASE. N can be decimal
+** or hex. The total number of pages after adding must be no greater
+** than 4294967297
+*/
+#include
+#include
+#include
+
+int main(int argc, char **argv){
+ char *zEnd;
+ long long int toAppend;
+ long long int currentSz;
+ long long int newSz;
+ FILE *f;
+ size_t got;
+ int pgsz;
+ char zero = 0;
+ unsigned char buf[100];
+
+ if( argc!=3 ) goto usage_error;
+ toAppend = strtoll(argv[2], &zEnd, 0);
+ if( zEnd==argv[2] || zEnd[0] ) goto usage_error;
+ if( toAppend<1 ){
+ fprintf(stderr, "N must be at least 1\n");
+ exit(1);
+ }
+ f = fopen(argv[1], "r+b");
+ if( f==0 ){
+ fprintf(stderr, "cannot open \"%s\" for reading and writing\n", argv[1]);
+ exit(1);
+ }
+ got = fread(buf, 1, sizeof(buf), f);
+ if( got!=sizeof(buf) ) goto not_valid_db;
+ if( strcmp((char*)buf,"SQLite format 3")!=0 ) goto not_valid_db;
+ pgsz = (buf[16]<<8) + buf[17];
+ if( pgsz==1 ) pgsz = 65536;
+ if( pgsz<512 || pgsz>65536 || (pgsz&(pgsz-1))!=0 ) goto not_valid_db;
+ currentSz = (buf[28]<<24) + (buf[29]<<16) + (buf[30]<<8) + buf[31];
+ newSz = currentSz + toAppend;
+ if( newSz > 0xffffffff ) newSz = 0xffffffff;
+ buf[28] = (newSz>>24) & 0xff;
+ buf[29] = (newSz>>16) & 0xff;
+ buf[30] = (newSz>>8) & 0xff;
+ buf[31] = newSz & 0xff;
+ fseek(f, 28, SEEK_SET);
+ fwrite(&buf[28],4,1,f);
+ fseek(f, (long)(newSz*pgsz - 1), SEEK_SET);
+ fwrite(&zero,1,1,f);
+ fclose(f);
+ return 0;
+
+not_valid_db:
+ fprintf(stderr,"not a valid database: %s\n", argv[1]);
+ exit(1);
+
+usage_error:
+ fprintf(stderr,"Usage: %s DATABASE N\n", argv[0]);
+ exit(1);
+}
diff --git a/tool/fast_vacuum.c b/tool/fast_vacuum.c
index 6a50dcc680..5ca0271dc9 100644
--- a/tool/fast_vacuum.c
+++ b/tool/fast_vacuum.c
@@ -150,7 +150,7 @@ int main(int argc, char **argv){
*/
/* The vacuum will occur inside of a transaction. Set writable_schema
- ** to ON so that we can directly update the sqlite_master table in the
+ ** to ON so that we can directly update the sqlite_schema table in the
** zTempDb database.
*/
execSql(db, "PRAGMA writable_schema=ON");
@@ -162,16 +162,16 @@ int main(int argc, char **argv){
*/
execExecSql(db,
"SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14) "
- " FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
+ " FROM sqlite_schema WHERE type='table' AND name!='sqlite_sequence'"
" AND rootpage>0"
);
execExecSql(db,
"SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14)"
- " FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %'"
+ " FROM sqlite_schema WHERE sql LIKE 'CREATE INDEX %'"
);
execExecSql(db,
"SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21) "
- " FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'"
+ " FROM sqlite_schema WHERE sql LIKE 'CREATE UNIQUE INDEX %'"
);
/* Loop through the tables in the main database. For each, do
@@ -181,7 +181,7 @@ int main(int argc, char **argv){
execExecSql(db,
"SELECT 'INSERT INTO vacuum_db.' || quote(name) "
"|| ' SELECT * FROM main.' || quote(name) "
- "FROM main.sqlite_master "
+ "FROM main.sqlite_schema "
"WHERE type = 'table' AND name!='sqlite_sequence' "
" AND rootpage>0"
);
@@ -190,12 +190,12 @@ int main(int argc, char **argv){
*/
execExecSql(db,
"SELECT 'DELETE FROM vacuum_db.' || quote(name) "
- "FROM vacuum_db.sqlite_master WHERE name='sqlite_sequence'"
+ "FROM vacuum_db.sqlite_schema WHERE name='sqlite_sequence'"
);
execExecSql(db,
"SELECT 'INSERT INTO vacuum_db.' || quote(name) "
"|| ' SELECT * FROM main.' || quote(name) "
- "FROM vacuum_db.sqlite_master WHERE name=='sqlite_sequence'"
+ "FROM vacuum_db.sqlite_schema WHERE name=='sqlite_sequence'"
);
/* Copy the triggers, views, and virtual tables from the main database
@@ -204,9 +204,9 @@ int main(int argc, char **argv){
** from the SQLITE_MASTER table.
*/
execSql(db,
- "INSERT INTO vacuum_db.sqlite_master "
+ "INSERT INTO vacuum_db.sqlite_schema "
" SELECT type, name, tbl_name, rootpage, sql"
- " FROM main.sqlite_master"
+ " FROM main.sqlite_schema"
" WHERE type='view' OR type='trigger'"
" OR (type='table' AND rootpage=0)"
);
diff --git a/tool/index_usage.c b/tool/index_usage.c
index 451fa65c34..9bd3c9fdce 100644
--- a/tool/index_usage.c
+++ b/tool/index_usage.c
@@ -104,7 +104,7 @@ int main(int argc, char **argv){
printf("Cannot open \"%s\" for reading: %s\n", argv[1], sqlite3_errmsg(db));
goto errorOut;
}
- rc = sqlite3_prepare_v2(db, "SELECT * FROM sqlite_master", -1, &pStmt, 0);
+ rc = sqlite3_prepare_v2(db, "SELECT * FROM sqlite_schema", -1, &pStmt, 0);
if( rc ){
printf("Cannot read the schema from \"%s\" - %s\n", argv[1],
sqlite3_errmsg(db));
@@ -126,7 +126,7 @@ int main(int argc, char **argv){
}
rc = sqlite3_exec(db,
"INSERT INTO temp.idxu(tbl,idx,cnt)"
- " SELECT tbl_name, name, 0 FROM sqlite_master"
+ " SELECT tbl_name, name, 0 FROM sqlite_schema"
" WHERE type='index' AND sql IS NOT NULL", 0, 0, 0);
/* Open the LOG database */
@@ -205,9 +205,9 @@ int main(int argc, char **argv){
rc = sqlite3_prepare_v2(db,
"SELECT tbl, idx, cnt, "
" (SELECT group_concat(name,',') FROM pragma_index_info(idx))"
- " FROM temp.idxu, main.sqlite_master"
- " WHERE temp.idxu.tbl=main.sqlite_master.tbl_name"
- " AND temp.idxu.idx=main.sqlite_master.name"
+ " FROM temp.idxu, main.sqlite_schema"
+ " WHERE temp.idxu.tbl=main.sqlite_schema.tbl_name"
+ " AND temp.idxu.idx=main.sqlite_schema.name"
" ORDER BY cnt DESC, tbl, idx",
-1, &pStmt, 0);
if( rc ){
diff --git a/tool/lemon.c b/tool/lemon.c
index 8dcf65179f..40e4e2894f 100644
--- a/tool/lemon.c
+++ b/tool/lemon.c
@@ -423,6 +423,7 @@ struct lemon {
int nlookaheadtab; /* Number of entries in yy_lookahead[] */
int tablesize; /* Total table size of all tables in bytes */
int basisflag; /* Print only basis configurations */
+ int printPreprocessed; /* Show preprocessor output on stdout */
int has_fallback; /* True if any %fallback is seen in the grammar */
int nolinenosflag; /* True if #line statements should not be printed */
char *argv0; /* Name of the program */
@@ -1636,12 +1637,14 @@ int main(int argc, char **argv)
static int nolinenosflag = 0;
static int noResort = 0;
static int sqlFlag = 0;
+ static int printPP = 0;
static struct s_options options[] = {
{OPT_FLAG, "b", (char*)&basisflag, "Print only the basis in report."},
{OPT_FLAG, "c", (char*)&compress, "Don't compress the action table."},
{OPT_FSTR, "d", (char*)&handle_d_option, "Output directory. Default '.'"},
{OPT_FSTR, "D", (char*)handle_D_option, "Define an %ifdef macro."},
+ {OPT_FLAG, "E", (char*)&printPP, "Print input file after preprocessing."},
{OPT_FSTR, "f", 0, "Ignored. (Placeholder for -f compiler options.)"},
{OPT_FLAG, "g", (char*)&rpflag, "Print grammar without actions."},
{OPT_FSTR, "I", 0, "Ignored. (Placeholder for '-I' compiler options.)"},
@@ -1686,11 +1689,12 @@ int main(int argc, char **argv)
lem.filename = OptArg(0);
lem.basisflag = basisflag;
lem.nolinenosflag = nolinenosflag;
+ lem.printPreprocessed = printPP;
Symbol_new("$");
/* Parse the input file */
Parse(&lem);
- if( lem.errorcnt ) exit(lem.errorcnt);
+ if( lem.printPreprocessed || lem.errorcnt ) exit(lem.errorcnt);
if( lem.nrule==0 ){
fprintf(stderr,"Empty grammar.\n");
exit(1);
@@ -2779,13 +2783,108 @@ static void parseonetoken(struct pstate *psp)
}
}
+/* The text in the input is part of the argument to an %ifdef or %ifndef.
+** Evaluate the text as a boolean expression. Return true or false.
+*/
+static int eval_preprocessor_boolean(char *z, int lineno){
+ int neg = 0;
+ int res = 0;
+ int okTerm = 1;
+ int i;
+ for(i=0; z[i]!=0; i++){
+ if( ISSPACE(z[i]) ) continue;
+ if( z[i]=='!' ){
+ if( !okTerm ) goto pp_syntax_error;
+ neg = !neg;
+ continue;
+ }
+ if( z[i]=='|' && z[i+1]=='|' ){
+ if( okTerm ) goto pp_syntax_error;
+ if( res ) return 1;
+ i++;
+ okTerm = 1;
+ continue;
+ }
+ if( z[i]=='&' && z[i+1]=='&' ){
+ if( okTerm ) goto pp_syntax_error;
+ if( !res ) return 0;
+ i++;
+ okTerm = 1;
+ continue;
+ }
+ if( z[i]=='(' ){
+ int k;
+ int n = 1;
+ if( !okTerm ) goto pp_syntax_error;
+ for(k=i+1; z[k]; k++){
+ if( z[k]==')' ){
+ n--;
+ if( n==0 ){
+ z[k] = 0;
+ res = eval_preprocessor_boolean(&z[i+1], -1);
+ z[k] = ')';
+ if( res<0 ){
+ i = i-res;
+ goto pp_syntax_error;
+ }
+ i = k;
+ break;
+ }
+ }else if( z[k]=='(' ){
+ n++;
+ }else if( z[k]==0 ){
+ i = k;
+ goto pp_syntax_error;
+ }
+ }
+ if( neg ){
+ res = !res;
+ neg = 0;
+ }
+ okTerm = 0;
+ continue;
+ }
+ if( ISALPHA(z[i]) ){
+ int j, k, n;
+ if( !okTerm ) goto pp_syntax_error;
+ for(k=i+1; ISALNUM(z[k]) || z[k]=='_'; k++){}
+ n = k - i;
+ res = 0;
+ for(j=0; j0 ){
+ fprintf(stderr, "%%if syntax error on line %d.\n", lineno);
+ fprintf(stderr, " %.*s <-- syntax error here\n", i+1, z);
+ exit(1);
+ }else{
+ return -(i+1);
+ }
+}
+
/* Run the preprocessor over the input file text. The global variables
** azDefine[0] through azDefine[nDefine-1] contains the names of all defined
** macros. This routine looks for "%ifdef" and "%ifndef" and "%endif" and
** comments them out. Text in between is also commented out as appropriate.
*/
static void preprocess_input(char *z){
- int i, j, k, n;
+ int i, j, k;
int exclude = 0;
int start = 0;
int lineno = 1;
@@ -2801,21 +2900,33 @@ static void preprocess_input(char *z){
}
}
for(j=i; z[j] && z[j]!='\n'; j++) z[j] = ' ';
- }else if( (strncmp(&z[i],"%ifdef",6)==0 && ISSPACE(z[i+6]))
- || (strncmp(&z[i],"%ifndef",7)==0 && ISSPACE(z[i+7])) ){
+ }else if( strncmp(&z[i],"%else",5)==0 && ISSPACE(z[i+5]) ){
+ if( exclude==1){
+ exclude = 0;
+ for(j=start; jprintPreprocessed ){
+ printf("%s\n", filebuf);
+ return;
+ }
/* Now scan the text of the input file */
lineno = 1;
diff --git a/tool/mkautoconfamal.sh b/tool/mkautoconfamal.sh
index 7cd7da35f6..eacd9fa515 100644
--- a/tool/mkautoconfamal.sh
+++ b/tool/mkautoconfamal.sh
@@ -2,8 +2,8 @@
# This script is used to build the amalgamation autoconf package.
# It assumes the following:
#
-# 1. The files "sqlite3.c", "sqlite3.h" and "sqlite3ext.h"
-# are available in the current directory.
+# 1. The files "sqlite3.c", "sqlite3.h", "sqlite3ext.h", "shell.c",
+# and "sqlite3rc.h" are available in the current directory.
#
# 2. Variable $TOP is set to the full path of the root directory
# of the SQLite source tree.
@@ -49,6 +49,7 @@ cp -R $TOP/autoconf $TMPSPACE
cp sqlite3.c $TMPSPACE
cp sqlite3.h $TMPSPACE
cp sqlite3ext.h $TMPSPACE
+cp sqlite3rc.h $TMPSPACE
cp $TOP/sqlite3.1 $TMPSPACE
cp $TOP/sqlite3.pc.in $TMPSPACE
cp shell.c $TMPSPACE
diff --git a/tool/mkpragmatab.tcl b/tool/mkpragmatab.tcl
index 0e7fb66aae..4f39ca9e18 100644
--- a/tool/mkpragmatab.tcl
+++ b/tool/mkpragmatab.tcl
@@ -289,7 +289,7 @@ set pragma_def {
IF: !defined(SQLITE_OMIT_FOREIGN_KEY)
NAME: foreign_key_check
- FLAG: NeedSchema Result0 OneSchema
+ FLAG: NeedSchema Result0 Result1 SchemaOpt
COLS: table rowid parent fkid
IF: !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
diff --git a/tool/mksqlite3c.tcl b/tool/mksqlite3c.tcl
index 55ad89d086..36663ff3b1 100644
--- a/tool/mksqlite3c.tcl
+++ b/tool/mksqlite3c.tcl
@@ -183,7 +183,7 @@ proc copy_file {filename} {
}
set declpattern ^$declpattern\$
while {![eof $in]} {
- set line [gets $in]
+ set line [string trimright [gets $in]]
incr ln
if {[regexp {^\s*#\s*include\s+["<]([^">]+)[">]} $line all hdr]} {
if {[info exists available_hdr($hdr)]} {
diff --git a/tool/mksqlite3h.tcl b/tool/mksqlite3h.tcl
index 216bd4e60b..9078a15753 100644
--- a/tool/mksqlite3h.tcl
+++ b/tool/mksqlite3h.tcl
@@ -107,7 +107,7 @@ foreach file $filelist {
}
while {![eof $in]} {
- set line [gets $in]
+ set line [string trimright [gets $in]]
# File sqlite3rtree.h contains a line "#include ". Omit this
# line when copying sqlite3rtree.h into sqlite3.h.
diff --git a/tool/offsets.c b/tool/offsets.c
index 8e098e71cb..26ee9fcef2 100644
--- a/tool/offsets.c
+++ b/tool/offsets.c
@@ -75,7 +75,7 @@ static void ofstRootAndColumn(
ofstError(p, "cannot open database file \"%s\"", zFile);
goto rootAndColumn_exit;
}
- zSql = sqlite3_mprintf("SELECT rootpage FROM sqlite_master WHERE name=%Q",
+ zSql = sqlite3_mprintf("SELECT rootpage FROM sqlite_schema WHERE name=%Q",
zTable);
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
if( rc ) ofstError(p, "%s: [%s]", sqlite3_errmsg(db), zSql);
diff --git a/tool/showdb.c b/tool/showdb.c
index fe4e9aca01..09c4d9de44 100644
--- a/tool/showdb.c
+++ b/tool/showdb.c
@@ -20,21 +20,22 @@
#include
#include "sqlite3.h"
+typedef unsigned char u8; /* unsigned 8-bit */
+typedef unsigned int u32; /* unsigned 32-bit */
+typedef sqlite3_int64 i64; /* signed 64-bit */
+typedef sqlite3_uint64 u64; /* unsigned 64-bit */
+
static struct GlobalData {
- int pagesize; /* Size of a database page */
+ u32 pagesize; /* Size of a database page */
int dbfd; /* File descriptor for reading the DB */
- int mxPage; /* Last page number */
+ u32 mxPage; /* Last page number */
int perLine; /* HEX elements to print per line */
int bRaw; /* True to access db file via OS APIs */
sqlite3_file *pFd; /* File descriptor for non-raw mode */
sqlite3 *pDb; /* Database handle that owns pFd */
} g = {1024, -1, 0, 16, 0, 0, 0};
-
-typedef long long int i64; /* Datatype for 64-bit integers */
-
-
/*
** Convert the var-int format into i64. Return the number of bytes
** in the var-int. Write the var-int value into *pVal.
@@ -54,7 +55,7 @@ static int decodeVarint(const unsigned char *z, i64 *pVal){
/*
** Extract a big-endian 32-bit integer
*/
-static unsigned int decodeInt32(const unsigned char *z){
+static u32 decodeInt32(const u8 *z){
return (z[0]<<24) + (z[1]<<16) + (z[2]<<8) + z[3];
}
@@ -141,7 +142,7 @@ static void fileClose(){
static unsigned char *fileRead(sqlite3_int64 ofst, int nByte){
unsigned char *aData;
int got;
- aData = sqlite3_malloc(nByte+32);
+ aData = sqlite3_malloc64(32+(i64)nByte);
if( aData==0 ) out_of_memory();
memset(aData, 0, nByte+32);
if( g.bRaw==0 ){
@@ -161,8 +162,8 @@ static unsigned char *fileRead(sqlite3_int64 ofst, int nByte){
/*
** Return the size of the file in byte.
*/
-static sqlite3_int64 fileGetsize(void){
- sqlite3_int64 res = 0;
+static i64 fileGetsize(void){
+ i64 res = 0;
if( g.bRaw==0 ){
int rc = g.pFd->pMethods->xFileSize(g.pFd, &res);
if( rc!=SQLITE_OK ){
@@ -185,9 +186,9 @@ static sqlite3_int64 fileGetsize(void){
** Print a range of bytes as hex and as ascii.
*/
static unsigned char *print_byte_range(
- int ofst, /* First byte in the range of bytes to print */
- int nByte, /* Number of bytes to print */
- int printOfst /* Add this amount to the index on the left column */
+ sqlite3_int64 ofst, /* First byte in the range of bytes to print */
+ int nByte, /* Number of bytes to print */
+ int printOfst /* Add this amount to the index on the left column */
){
unsigned char *aData;
int i, j;
@@ -207,6 +208,12 @@ static unsigned char *print_byte_range(
aData = fileRead(ofst, nByte);
for(i=0; inByte ){ break; }
+ if( aData[i+j] ){ go = 1; break; }
+ }
+ if( !go && i>0 && i+g.perLinenByte ){
@@ -230,18 +237,18 @@ static unsigned char *print_byte_range(
/*
** Print an entire page of content as hex
*/
-static void print_page(int iPg){
- int iStart;
+static void print_page(u32 iPg){
+ i64 iStart;
unsigned char *aData;
- iStart = (iPg-1)*g.pagesize;
- fprintf(stdout, "Page %d: (offsets 0x%x..0x%x)\n",
+ iStart = ((i64)(iPg-1))*g.pagesize;
+ fprintf(stdout, "Page %u: (offsets 0x%llx..0x%llx)\n",
iPg, iStart, iStart+g.pagesize-1);
aData = print_byte_range(iStart, g.pagesize, 0);
sqlite3_free(aData);
}
-/* Print a line of decode output showing a 4-byte integer.
+/* Print a line of decoded output showing a 4-byte unsigned integer.
*/
static void print_decode_line(
unsigned char *aData, /* Content being decoded */
@@ -249,7 +256,7 @@ static void print_decode_line(
const char *zMsg /* Message to append */
){
int i, j;
- int val = aData[ofst];
+ u32 val = aData[ofst];
char zBuf[100];
sprintf(zBuf, " %03x: %02x", ofst, aData[ofst]);
i = (int)strlen(zBuf);
@@ -262,7 +269,7 @@ static void print_decode_line(
}
i += (int)strlen(&zBuf[i]);
}
- sprintf(&zBuf[i], " %9d", val);
+ sprintf(&zBuf[i], " %10u", val);
printf("%s %s\n", zBuf, zMsg);
}
@@ -296,6 +303,7 @@ static void print_db_header(void){
print_decode_line(aData, 88, 4, "meta[12]");
print_decode_line(aData, 92, 4, "Change counter for version number");
print_decode_line(aData, 96, 4, "SQLite version number");
+ sqlite3_free(aData);
}
/*
@@ -408,7 +416,7 @@ static i64 describeCell(
int i;
i64 nDesc = 0;
int n = 0;
- int leftChild;
+ u32 leftChild;
i64 nPayload;
i64 rowid;
i64 nLocal;
@@ -418,7 +426,7 @@ static i64 describeCell(
leftChild = ((a[0]*256 + a[1])*256 + a[2])*256 + a[3];
a += 4;
n += 4;
- sprintf(zDesc, "lx: %d ", leftChild);
+ sprintf(zDesc, "lx: %u ", leftChild);
nDesc = strlen(zDesc);
}
if( cType!=5 ){
@@ -439,10 +447,10 @@ static i64 describeCell(
nDesc += strlen(&zDesc[nDesc]);
}
if( nLocal0 ){
a = fileRead((pgno-1)*g.pagesize, g.pagesize);
@@ -741,9 +750,9 @@ static void decode_trunk_page(
print_decode_line(a, 0, 4, "Next freelist trunk page");
print_decode_line(a, 4, 4, "Number of entries on this page");
if( detail ){
- n = (int)decodeInt32(&a[4]);
- for(i=0; ig.mxPage ){
- printf("ERROR: page %d out of range 1..%d: %s\n",
+ printf("ERROR: page %d out of range 1..%u: %s\n",
pgno, g.mxPage, zMsg);
sqlite3_free(zMsg);
return;
@@ -796,7 +805,7 @@ static void page_usage_msg(int pgno, const char *zFormat, ...){
static void page_usage_cell(
unsigned char cType, /* Page type */
unsigned char *a, /* Cell content */
- int pgno, /* page containing the cell */
+ u32 pgno, /* page containing the cell */
int cellno /* Index of the cell on the page */
){
int i;
@@ -823,10 +832,10 @@ static void page_usage_cell(
n += i;
}
if( nLocallwr ){
- cnt += showLocksInRange(fd, lwr, x.l_start-1);
+ nPending = 1;
+ aPending = malloc( sizeof(aPending[0]) );
+ if( aPending==0 ){
+ fprintf(stderr, "out of memory\n");
+ exit(1);
}
- if( x.l_start+x.l_len=upr ) continue;
+ x.l_type = F_WRLCK;
+ x.l_whence = SEEK_SET;
+ x.l_start = lwr;
+ x.l_len = upr - lwr;
+ fcntl(fd, F_GETLK, &x);
+ if( x.l_type==F_UNLCK ) continue;
+ printf("start: %-12d len: %-5d pid: %-5d type: %s\n",
+ (int)x.l_start, (int)x.l_len,
+ x.l_pid, x.l_type==F_WRLCK ? "WRLCK" : "RDLCK");
+ cnt++;
+ if( nPending+2 > nAlloc ){
+ nAlloc = nAlloc*2 + 2;
+ aPending = realloc(aPending, sizeof(aPending[0])*nAlloc );
+ }
+ if( aPending==0 ){
+ fprintf(stderr, "unable to realloc for %d bytes\n",
+ (int)sizeof(aPending[0])*(nPending+2));
+ exit(1);
+ }
+ if( lwr0 }
-foreach {name tblname} [concat sqlite_master sqlite_master [db eval $sql]] {
+set sql { SELECT name, tbl_name FROM sqlite_schema WHERE rootpage>0 }
+foreach {name tblname} [concat sqlite_schema sqlite_schema [db eval $sql]] {
set is_index [expr {$name!=$tblname}]
set is_without_rowid [is_without_rowid $name]
@@ -560,7 +560,7 @@ proc autovacuum_overhead {filePages pageSize} {
# nautoindex: Number of indices created automatically.
# nmanindex: Number of indices created manually.
# user_payload: Number of bytes of payload in table btrees
-# (not including sqlite_master)
+# (not including sqlite_schema)
# user_percent: $user_payload as a percentage of total file size.
### The following, setting $file_bytes based on the actual size of the file
@@ -590,15 +590,15 @@ set file_pgcnt2 [expr {$inuse_pgcnt+$free_pgcnt2+$av_pgcnt}]
# Account for the lockbyte page
if {$file_pgcnt2*$pageSize>1073742335} {incr file_pgcnt2}
-set ntable [db eval {SELECT count(*)+1 FROM sqlite_master WHERE type='table'}]
-set nindex [db eval {SELECT count(*) FROM sqlite_master WHERE type='index'}]
-set sql {SELECT count(*) FROM sqlite_master WHERE name LIKE 'sqlite_autoindex%'}
+set ntable [db eval {SELECT count(*)+1 FROM sqlite_schema WHERE type='table'}]
+set nindex [db eval {SELECT count(*) FROM sqlite_schema WHERE type='index'}]
+set sql {SELECT count(*) FROM sqlite_schema WHERE name LIKE 'sqlite_autoindex%'}
set nautoindex [db eval $sql]
set nmanindex [expr {$nindex-$nautoindex}]
# set total_payload [mem eval "SELECT sum(payload) FROM space_used"]
set user_payload [mem one {SELECT int(sum(payload)) FROM space_used
- WHERE NOT is_index AND name NOT LIKE 'sqlite_master'}]
+ WHERE NOT is_index AND name NOT LIKE 'sqlite_schema'}]
set user_percent [percent $user_payload $file_bytes]
# Output the summary statistics calculated above.
diff --git a/tool/speed-check.sh b/tool/speed-check.sh
index 414e4b4482..b77660eb71 100644
--- a/tool/speed-check.sh
+++ b/tool/speed-check.sh
@@ -79,6 +79,10 @@ while test "$1" != ""; do
;;
--legacy)
doWal=0
+ CC_OPTS="$CC_OPTS -DSPEEDTEST_OMIT_HASH"
+ ;;
+ --verify)
+ SPEEDTEST_OPTS="$SPEEDTEST_OPTS --verify"
;;
--wal)
doWal=1
@@ -89,6 +93,9 @@ while test "$1" != ""; do
--cachesize)
shift; SPEEDTEST_OPTS="$SPEEDTEST_OPTS --cachesize $1"
;;
+ --checkpoint)
+ SPEEDTEST_OPTS="$SPEEDTEST_OPTS --checkpoint"
+ ;;
--explain)
doExplain=1
;;
diff --git a/tool/sqldiff.c b/tool/sqldiff.c
index 9f5b6fe6d9..3590e2c06a 100644
--- a/tool/sqldiff.c
+++ b/tool/sqldiff.c
@@ -416,7 +416,7 @@ static void dump_table(const char *zTab, FILE *out){
const char *zSep; /* Separator string */
Str ins; /* Beginning of the INSERT statement */
- pStmt = db_prepare("SELECT sql FROM aux.sqlite_master WHERE name=%Q", zTab);
+ pStmt = db_prepare("SELECT sql FROM aux.sqlite_schema WHERE name=%Q", zTab);
if( SQLITE_ROW==sqlite3_step(pStmt) ){
fprintf(out, "%s;\n", sqlite3_column_text(pStmt,0));
}
@@ -466,7 +466,7 @@ static void dump_table(const char *zTab, FILE *out){
sqlite3_finalize(pStmt);
strFree(&ins);
} /* endif !g.bSchemaOnly */
- pStmt = db_prepare("SELECT sql FROM aux.sqlite_master"
+ pStmt = db_prepare("SELECT sql FROM aux.sqlite_schema"
" WHERE type='index' AND tbl_name=%Q AND sql IS NOT NULL",
zTab);
while( SQLITE_ROW==sqlite3_step(pStmt) ){
@@ -639,10 +639,10 @@ static void diff_one_table(const char *zTab, FILE *out){
/* Drop indexes that are missing in the destination */
pStmt = db_prepare(
- "SELECT name FROM main.sqlite_master"
+ "SELECT name FROM main.sqlite_schema"
" WHERE type='index' AND tbl_name=%Q"
" AND sql IS NOT NULL"
- " AND sql NOT IN (SELECT sql FROM aux.sqlite_master"
+ " AND sql NOT IN (SELECT sql FROM aux.sqlite_schema"
" WHERE type='index' AND tbl_name=%Q"
" AND sql IS NOT NULL)",
zTab, zTab);
@@ -700,10 +700,10 @@ static void diff_one_table(const char *zTab, FILE *out){
/* Create indexes that are missing in the source */
pStmt = db_prepare(
- "SELECT sql FROM aux.sqlite_master"
+ "SELECT sql FROM aux.sqlite_schema"
" WHERE type='index' AND tbl_name=%Q"
" AND sql IS NOT NULL"
- " AND sql NOT IN (SELECT sql FROM main.sqlite_master"
+ " AND sql NOT IN (SELECT sql FROM main.sqlite_schema"
" WHERE type='index' AND tbl_name=%Q"
" AND sql IS NOT NULL)",
zTab, zTab);
@@ -728,7 +728,7 @@ end_diff_one_table:
*/
static void checkSchemasMatch(const char *zTab){
sqlite3_stmt *pStmt = db_prepare(
- "SELECT A.sql=B.sql FROM main.sqlite_master A, aux.sqlite_master B"
+ "SELECT A.sql=B.sql FROM main.sqlite_schema A, aux.sqlite_schema B"
" WHERE A.name=%Q AND B.name=%Q", zTab, zTab
);
if( SQLITE_ROW==sqlite3_step(pStmt) ){
@@ -1757,7 +1757,7 @@ const char *gobble_token(const char *zIn, char *zBuf, int nBuf){
** module_name(SQL)
**
** The only argument should be an SQL statement of the type that may appear
-** in the sqlite_master table. If the statement is a "CREATE VIRTUAL TABLE"
+** in the sqlite_schema table. If the statement is a "CREATE VIRTUAL TABLE"
** statement, then the value returned is the name of the module that it
** uses. Otherwise, if the statement is not a CVT, NULL is returned.
*/
@@ -1816,32 +1816,32 @@ const char *all_tables_sql(){
assert( rc==SQLITE_OK );
return
- "SELECT name FROM main.sqlite_master\n"
+ "SELECT name FROM main.sqlite_schema\n"
" WHERE type='table' AND (\n"
" module_name(sql) IS NULL OR \n"
" module_name(sql) IN (SELECT module FROM temp.tblmap)\n"
" ) AND name NOT IN (\n"
" SELECT a.name || b.postfix \n"
- "FROM main.sqlite_master AS a, temp.tblmap AS b \n"
+ "FROM main.sqlite_schema AS a, temp.tblmap AS b \n"
"WHERE module_name(a.sql) = b.module\n"
" )\n"
"UNION \n"
- "SELECT name FROM aux.sqlite_master\n"
+ "SELECT name FROM aux.sqlite_schema\n"
" WHERE type='table' AND (\n"
" module_name(sql) IS NULL OR \n"
" module_name(sql) IN (SELECT module FROM temp.tblmap)\n"
" ) AND name NOT IN (\n"
" SELECT a.name || b.postfix \n"
- "FROM aux.sqlite_master AS a, temp.tblmap AS b \n"
+ "FROM aux.sqlite_schema AS a, temp.tblmap AS b \n"
"WHERE module_name(a.sql) = b.module\n"
" )\n"
" ORDER BY name";
}else{
return
- "SELECT name FROM main.sqlite_master\n"
+ "SELECT name FROM main.sqlite_schema\n"
" WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n"
" UNION\n"
- "SELECT name FROM aux.sqlite_master\n"
+ "SELECT name FROM aux.sqlite_schema\n"
" WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n"
" ORDER BY name";
}
@@ -1955,7 +1955,7 @@ int main(int argc, char **argv){
if( rc ){
cmdlineError("cannot open database file \"%s\"", zDb1);
}
- rc = sqlite3_exec(g.db, "SELECT * FROM sqlite_master", 0, 0, &zErrMsg);
+ rc = sqlite3_exec(g.db, "SELECT * FROM sqlite_schema", 0, 0, &zErrMsg);
if( rc || zErrMsg ){
cmdlineError("\"%s\" does not appear to be a valid SQLite database", zDb1);
}
@@ -1974,7 +1974,7 @@ int main(int argc, char **argv){
if( rc || zErrMsg ){
cmdlineError("cannot attach database \"%s\"", zDb2);
}
- rc = sqlite3_exec(g.db, "SELECT * FROM aux.sqlite_master", 0, 0, &zErrMsg);
+ rc = sqlite3_exec(g.db, "SELECT * FROM aux.sqlite_schema", 0, 0, &zErrMsg);
if( rc || zErrMsg ){
cmdlineError("\"%s\" does not appear to be a valid SQLite database", zDb2);
}
diff --git a/vsixtest/App.xaml.cpp b/vsixtest/App.xaml.cpp
index da8f327fa0..c90604a830 100644
--- a/vsixtest/App.xaml.cpp
+++ b/vsixtest/App.xaml.cpp
@@ -117,4 +117,4 @@ void App::OnSuspending(Object^ sender, SuspendingEventArgs^ e)
void App::OnNavigationFailed(Platform::Object ^sender, Windows::UI::Xaml::Navigation::NavigationFailedEventArgs ^e)
{
throw ref new FailureException("Failed to load Page " + e->SourcePageType.Name);
-}
\ No newline at end of file
+}