mirror of
https://github.com/status-im/sqlcipher.git
synced 2026-08-30 22:11:14 +00:00
Merge sqlite-release(3.33.0) into prerelease-integration
This commit is contained in:
+16
-4
@@ -465,6 +465,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 \
|
||||
@@ -1104,6 +1105,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
|
||||
@@ -1112,9 +1119,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 \
|
||||
@@ -1323,6 +1332,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
|
||||
|
||||
@@ -1425,10 +1437,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
|
||||
|
||||
+28
-11
@@ -1503,7 +1503,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.
|
||||
#
|
||||
@@ -1568,6 +1568,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 \
|
||||
@@ -1854,15 +1855,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
|
||||
@@ -1877,7 +1879,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 \
|
||||
@@ -2177,7 +2180,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
|
||||
@@ -2190,8 +2194,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)
|
||||
@@ -2203,10 +2212,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 \
|
||||
@@ -2337,7 +2348,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
|
||||
|
||||
@@ -2345,11 +2357,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
|
||||
@@ -2460,6 +2474,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 > $@
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.69 for sqlcipher 3.32.3.
|
||||
# Generated by GNU Autoconf 2.69 for sqlcipher 3.33.0.
|
||||
#
|
||||
#
|
||||
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
|
||||
@@ -587,8 +587,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='sqlcipher'
|
||||
PACKAGE_TARNAME='sqlcipher'
|
||||
PACKAGE_VERSION='3.32.3'
|
||||
PACKAGE_STRING='sqlcipher 3.32.3'
|
||||
PACKAGE_VERSION='3.33.0'
|
||||
PACKAGE_STRING='sqlcipher 3.33.0'
|
||||
PACKAGE_BUGREPORT=''
|
||||
PACKAGE_URL=''
|
||||
|
||||
@@ -1349,7 +1349,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 sqlcipher 3.32.3 to adapt to many kinds of systems.
|
||||
\`configure' configures sqlcipher 3.33.0 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1415,7 +1415,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlcipher 3.32.3:";;
|
||||
short | recursive ) echo "Configuration of sqlcipher 3.33.0:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1552,7 +1552,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlcipher configure 3.32.3
|
||||
sqlcipher configure 3.33.0
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
@@ -1971,7 +1971,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 sqlcipher $as_me 3.32.3, which was
|
||||
It was created by sqlcipher $as_me 3.33.0, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -12875,7 +12875,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
|
||||
|
||||
@@ -13226,7 +13226,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
|
||||
|
||||
@@ -13850,7 +13850,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 sqlcipher $as_me 3.32.3, which was
|
||||
This file was extended by sqlcipher $as_me 3.33.0, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -13916,7 +13916,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="\\
|
||||
sqlcipher config.status 3.32.3
|
||||
sqlcipher config.status 3.33.0
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
+2
-2
@@ -624,7 +624,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)
|
||||
@@ -706,7 +706,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
|
||||
|
||||
|
||||
+26
-9
@@ -104,9 +104,13 @@ Write all output files into <i>directory</i>. Normally, output files
|
||||
are written into the directory that contains the input grammar file.
|
||||
<li><b>-D<i>name</i></b>
|
||||
Define C preprocessor macro <i>name</i>. This macro is usable by
|
||||
"<tt><a href='#pifdef'>%ifdef</a></tt>" and
|
||||
"<tt><a href='#pifdef'>%ifndef</a></tt>" lines
|
||||
"<tt><a href='#pifdef'>%ifdef</a></tt>",
|
||||
"<tt><a href='#pifdef'>%ifndef</a></tt>", and
|
||||
"<tt><a href="#pifdef">%if</a></tt> lines
|
||||
in the grammar file.
|
||||
<li><b>-E</b>
|
||||
Run the "%if" preprocessor step only and print the revised grammar
|
||||
file.
|
||||
<li><b>-g</b>
|
||||
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.</p>
|
||||
<li><tt><a href='#default_destructor'>%default_destructor</a></tt>
|
||||
<li><tt><a href='#default_type'>%default_type</a></tt>
|
||||
<li><tt><a href='#destructor'>%destructor</a></tt>
|
||||
<li><tt><a href='#pifdef'>%else</a></tt>
|
||||
<li><tt><a href='#pifdef'>%endif</a></tt>
|
||||
<li><tt><a href='#extraarg'>%extra_argument</a></tt>
|
||||
<li><tt><a href='#pfallback'>%fallback</a></tt>
|
||||
<li><tt><a href='#pifdef'>%if</a></tt>
|
||||
<li><tt><a href='#pifdef'>%ifdef</a></tt>
|
||||
<li><tt><a href='#pifdef'>%ifndef</a></tt>
|
||||
<li><tt><a href='#pinclude'>%include</a></tt>
|
||||
@@ -737,10 +743,11 @@ arguments are tokens which fall back to the token identified by the first
|
||||
argument.</p>
|
||||
|
||||
<a name='pifdef'></a>
|
||||
<h4>The <tt>%ifdef</tt>, <tt>%ifndef</tt>, and <tt>%endif</tt> directives</h4>
|
||||
<h4>The <tt>%if</tt> directive and its friends</h4>
|
||||
|
||||
<p>The <tt>%ifdef</tt>, <tt>%ifndef</tt>, and <tt>%endif</tt> directives
|
||||
are similar to #ifdef, #ifndef, and #endif in the C-preprocessor,
|
||||
<p>The <tt>%if</tt>, <tt>%ifdef</tt>, <tt>%ifndef</tt>, <tt>%else</tt>,
|
||||
and <tt>%endif</tt> 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.</p>
|
||||
@@ -749,12 +756,22 @@ is allowed between the "%" and the directive name.</p>
|
||||
"<tt>%endif</tt>" is
|
||||
ignored unless the "-DMACRO" command-line option is used. Grammar text
|
||||
betwen "<tt>%ifndef MACRO</tt>" and the next nested "<tt>%endif</tt>" is
|
||||
included except when the "-DMACRO" command-line option is used.</p>
|
||||
included except when the "-DMACRO" command-line option is used.<p>
|
||||
|
||||
<p>Note that the argument to <tt>%ifdef</tt> and <tt>%ifndef</tt> must
|
||||
be a single preprocessor symbol name, not a general expression.
|
||||
There is no "<tt>%else</tt>" directive.</p>
|
||||
<p>The text in between "<tt>%if</tt> <i>CONDITIONAL</i>" and its
|
||||
corresponding <tt>%endif</tt> is included only if <i>CONDITIONAL</i>
|
||||
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.</p>
|
||||
|
||||
<p>An optional "<tt>%else</tt>" directive can occur anywhere in between a
|
||||
<tt>%ifdef</tt>, <tt>%ifndef</tt>, or <tt>%if</tt> directive and
|
||||
its corresponding <tt>%endif</tt>.</p>
|
||||
|
||||
<p>Note that the argument to <tt>%ifdef</tt> and <tt>%ifndef</tt> is
|
||||
intended to be a single preprocessor symbol name, not a general expression.
|
||||
Use the "<tt>%if</tt>" directive for general expressions.</p>
|
||||
|
||||
<a name='pinclude'></a>
|
||||
<h4>The <tt>%include</tt> directive</h4>
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -1704,4 +1704,3 @@ int sqlite3async_control(int op, ...){
|
||||
}
|
||||
|
||||
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ASYNCIO) */
|
||||
|
||||
|
||||
@@ -220,4 +220,3 @@ int sqlite3async_control(int op, ...);
|
||||
} /* End of the 'extern "C"' block */
|
||||
#endif
|
||||
#endif /* ifndef __SQLITEASYNC_H_ */
|
||||
|
||||
|
||||
@@ -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) ){
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
|
||||
+18
-8
@@ -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;
|
||||
}
|
||||
@@ -3479,7 +3479,7 @@ static int fts3ColumnMethod(
|
||||
break;
|
||||
}else{
|
||||
iCol = p->nColumn;
|
||||
/* fall-through */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -3722,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 ){
|
||||
@@ -5208,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;
|
||||
}
|
||||
@@ -5563,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;
|
||||
}
|
||||
@@ -5826,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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -188,7 +188,8 @@ static int fts3tokConnectMethod(
|
||||
|
||||
assert( (rc==SQLITE_OK)==(pMod!=0) );
|
||||
if( rc==SQLITE_OK ){
|
||||
const char * const *azArg = (const char * const *)&azDequote[1];
|
||||
const char * const *azArg = 0;
|
||||
if( nDequote>1 ) azArg = (const char * const *)&azDequote[1];
|
||||
rc = pMod->xCreate((nDequote>1 ? nDequote-1 : 0), azArg, &pTok);
|
||||
}
|
||||
|
||||
|
||||
+23
-11
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -24,4 +24,3 @@ int sqlite3IcuInit(sqlite3 *db);
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
@@ -654,5 +654,3 @@ void test_data_3(
|
||||
testFree(zName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -322,5 +322,3 @@ void do_writer_crash_test(const char *zPattern, int *pRc){
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -138,6 +138,3 @@ void test_data_4(
|
||||
testFree(zName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -69,7 +69,3 @@ int do_bt(int nArg, char **azArg){
|
||||
sqlite4_buffer_clear(&buf.output);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -367,4 +367,3 @@ int test_mdb_scan(
|
||||
}
|
||||
|
||||
#endif /* HAVE_MDB */
|
||||
|
||||
|
||||
@@ -978,5 +978,3 @@ static int bgc_detach(BtDb *pDb){
|
||||
/*
|
||||
** End of background checkpointer.
|
||||
*************************************************************************/
|
||||
|
||||
|
||||
|
||||
+8
-1
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
+2
-2
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
+7
-7
@@ -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",
|
||||
|
||||
@@ -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 <assert.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* 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<n && zIn[i]=='0' ) i++;
|
||||
while( i<n ){
|
||||
char c = zIn[i];
|
||||
if( c>='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<n && iExp<1000000 ){
|
||||
if( zIn[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( j<p->nDigit );
|
||||
}
|
||||
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( nSig<pB->nDigit-pB->nFrac ){
|
||||
nSig = pB->nDigit - pB->nFrac;
|
||||
}
|
||||
nFrac = pA->nFrac;
|
||||
if( nFrac<pB->nFrac ) 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->nFrac<minFrac ) minFrac = pB->nFrac;
|
||||
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<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
|
||||
rc = sqlite3_create_function(db, aFunc[i].zFuncName, aFunc[i].nArg,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
|
||||
0, aFunc[i].xFunc, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_window_function(db, "decimal_sum", 1,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, 0,
|
||||
decimalSumStep, decimalSumFinalize,
|
||||
decimalSumValue, decimalSumInverse, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_collation(db, "decimal", SQLITE_UTF8,
|
||||
0, decimalCollFunc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
** Usage example:
|
||||
**
|
||||
** .load ./explain
|
||||
** SELECT p2 FROM explain('SELECT * FROM sqlite_master')
|
||||
** SELECT p2 FROM explain('SELECT * FROM sqlite_schema')
|
||||
** WHERE opcode='OpenRead';
|
||||
**
|
||||
** This module was originally written to help simplify SQLite testing,
|
||||
|
||||
+169
-21
@@ -26,16 +26,76 @@
|
||||
**
|
||||
** Examples:
|
||||
**
|
||||
** ieee754(2.0) -> '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 <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
/* 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<sizeof(r); i++){
|
||||
v = (v<<8) | x[i];
|
||||
}
|
||||
memcpy(&r, &v, sizeof(r));
|
||||
}else{
|
||||
r = sqlite3_value_double(argv[0]);
|
||||
}
|
||||
if( r<0.0 ){
|
||||
isNeg = 1;
|
||||
r = -r;
|
||||
@@ -66,17 +137,31 @@ static void ieee754func(
|
||||
}else{
|
||||
e = a>>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<sizeof(r); i++){
|
||||
v = (v<<8) | x[i];
|
||||
}
|
||||
memcpy(&r, &v, sizeof(r));
|
||||
sqlite3_result_double(context, r);
|
||||
}
|
||||
}
|
||||
static void ieee754func_to_blob(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
UNUSED_PARAMETER(argc);
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_FLOAT
|
||||
|| sqlite3_value_type(argv[0])==SQLITE_INTEGER
|
||||
){
|
||||
double r = sqlite3_value_double(argv[0]);
|
||||
sqlite3_uint64 v;
|
||||
unsigned char a[sizeof(r)];
|
||||
unsigned int i;
|
||||
memcpy(&v, &r, sizeof(r));
|
||||
for(i=1; i<=sizeof(r); i++){
|
||||
a[sizeof(r)-i] = v&0xff;
|
||||
v >>= 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; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
|
||||
rc = sqlite3_create_function(db, aFunc[i].zFName, aFunc[i].nArg,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS,
|
||||
(void*)&aFunc[i].iAux,
|
||||
aFunc[i].xFunc, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
+7
-2
@@ -42,6 +42,10 @@ SQLITE_EXTENSION_INIT1
|
||||
# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
|
||||
#endif
|
||||
|
||||
#ifndef deliberate_fall_through
|
||||
# define deliberate_fall_through
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Versions of isspace(), isalnum() and isdigit() to which it is safe
|
||||
** to pass signed char values.
|
||||
@@ -460,7 +464,7 @@ static void jsonRenderNode(
|
||||
jsonAppendString(pOut, pNode->u.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;
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
+2
-2
@@ -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);
|
||||
|
||||
+18
-18
@@ -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 ){
|
||||
|
||||
@@ -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 ){
|
||||
|
||||
@@ -683,6 +683,8 @@ static GeoPoly *geopolyBBox(
|
||||
aCoord[2].f = mnY;
|
||||
aCoord[3].f = mxY;
|
||||
}
|
||||
}else{
|
||||
memset(aCoord, 0, sizeof(RtreeCoord)*4);
|
||||
}
|
||||
return pOut;
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ typedef unsigned int u32;
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* 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 <intrin.h>
|
||||
# pragma intrinsic(_byteswap_ulong)
|
||||
# pragma intrinsic(_byteswap_uint64)
|
||||
# else
|
||||
# include <cmnintrin.h>
|
||||
# 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.
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -2956,8 +2956,13 @@ static int sessionChangesetReadTblhdr(sqlite3_changeset_iter *p){
|
||||
}
|
||||
|
||||
p->apValue = (sqlite3_value**)p->tblhdr.aBuf;
|
||||
p->abPK = (u8*)&p->apValue[p->nCol*2];
|
||||
p->zTab = (char*)&p->abPK[p->nCol];
|
||||
if( p->apValue==0 ){
|
||||
p->abPK = 0;
|
||||
p->zTab = 0;
|
||||
}else{
|
||||
p->abPK = (u8*)&p->apValue[p->nCol*2];
|
||||
p->zTab = p->abPK ? (char*)&p->abPK[p->nCol] : 0;
|
||||
}
|
||||
return (p->rc = rc);
|
||||
}
|
||||
|
||||
@@ -3479,6 +3484,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 +4257,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 +4326,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);
|
||||
|
||||
@@ -363,6 +363,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 \
|
||||
@@ -727,6 +728,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
|
||||
@@ -735,9 +742,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 \
|
||||
@@ -975,6 +984,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.
|
||||
@@ -1076,10 +1088,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
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
7ebdfa80be8e8e73324b8d66b3460222eb74c7e9dfd655b48d6ca7e1933cc8fd
|
||||
fca8dc8b578f215a969cd899336378966156154710873e68b3d9ac5881b0ff3f
|
||||
|
||||
+40
-33
@@ -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; i<pSrc->nSrc && rc==SQLITE_OK; 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);
|
||||
|
||||
+31
-7
@@ -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;
|
||||
@@ -215,7 +215,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{
|
||||
@@ -235,7 +235,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,7 +243,7 @@ static void openStatTable(
|
||||
/* Open the sqlite_stat[134] tables for writing. */
|
||||
for(i=0; i<nToOpen; i++){
|
||||
assert( i<ArraySize(aTable) );
|
||||
sqlite3VdbeAddOp4Int(v, OP_OpenWrite, iStatCur+i, aRoot[i], iDb, 3);
|
||||
sqlite3VdbeAddOp4Int(v, OP_OpenWrite, iStatCur+i, (int)aRoot[i], iDb, 3);
|
||||
sqlite3VdbeChangeP5(v, aCreateTbl[i]);
|
||||
VdbeComment((v, aTable[i].zName));
|
||||
}
|
||||
@@ -951,6 +951,30 @@ static void callStatGet(Parse *pParse, int regStat, int iParam, int regOut){
|
||||
&statGetFuncdef, 0);
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||
/* Add a comment to the most recent VDBE opcode that is the name
|
||||
** of the k-th column of the pIdx index.
|
||||
*/
|
||||
static void analyzeVdbeCommentIndexWithColumnName(
|
||||
Vdbe *v, /* Prepared statement under construction */
|
||||
Index *pIdx, /* Index whose column is being loaded */
|
||||
int k /* Which column index */
|
||||
){
|
||||
int i; /* Index of column in the table */
|
||||
assert( k>=0 && k<pIdx->nColumn );
|
||||
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.
|
||||
@@ -1167,7 +1191,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);
|
||||
@@ -1188,7 +1212,7 @@ static void analyzeOneTable(
|
||||
for(i=0; i<nColTest; i++){
|
||||
sqlite3VdbeJumpHere(v, aGotoChng[i]);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regPrev+i);
|
||||
VdbeComment((v, "%s.column(%d)", pIdx->zName, i));
|
||||
analyzeVdbeCommentIndexWithColumnName(v,pIdx,i);
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, endDistinctTest);
|
||||
sqlite3DbFree(db, aGotoChng);
|
||||
@@ -1214,7 +1238,7 @@ static void analyzeOneTable(
|
||||
k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]);
|
||||
assert( k>=0 && k<pIdx->nColumn );
|
||||
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);
|
||||
|
||||
@@ -636,6 +636,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;
|
||||
|
||||
+120
-85
@@ -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;
|
||||
@@ -357,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 );
|
||||
|
||||
@@ -993,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 );
|
||||
@@ -2139,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);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2422,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){
|
||||
@@ -2541,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 ){
|
||||
@@ -2630,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 ){
|
||||
@@ -2655,7 +2654,7 @@ static int removeFromSharingList(BtShared *pBt){
|
||||
}
|
||||
removed = 1;
|
||||
}
|
||||
sqlite3_mutex_leave(pMaster);
|
||||
sqlite3_mutex_leave(pMainMtx);
|
||||
return removed;
|
||||
#else
|
||||
return 1;
|
||||
@@ -2932,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);
|
||||
@@ -3431,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;
|
||||
@@ -3886,7 +3885,7 @@ int sqlite3BtreeIncrVacuum(Btree *p){
|
||||
Pgno nFree = get4byte(&pBt->pPage1->aData[36]);
|
||||
Pgno nFin = finalDbSize(pBt, nOrig, nFree);
|
||||
|
||||
if( nOrig<nFin ){
|
||||
if( nOrig<nFin || nFree>=nOrig ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
}else if( nFree>0 ){
|
||||
rc = saveAllCursors(pBt, 0, 0);
|
||||
@@ -3983,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;
|
||||
@@ -4011,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;
|
||||
@@ -4074,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
|
||||
@@ -4372,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 */
|
||||
@@ -4415,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;
|
||||
@@ -4425,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;
|
||||
}
|
||||
@@ -4437,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 */
|
||||
@@ -4450,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 */
|
||||
@@ -4836,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
|
||||
@@ -4875,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 );
|
||||
@@ -6290,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;
|
||||
@@ -8772,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;
|
||||
}
|
||||
|
||||
@@ -9090,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;
|
||||
@@ -9123,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
|
||||
@@ -9132,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
|
||||
@@ -9230,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);
|
||||
@@ -9479,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 );
|
||||
|
||||
@@ -9632,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 */
|
||||
@@ -9697,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;
|
||||
}
|
||||
@@ -9717,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;
|
||||
@@ -9849,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 */
|
||||
){
|
||||
@@ -9885,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;
|
||||
@@ -9912,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() */
|
||||
|
||||
@@ -9932,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
|
||||
@@ -10073,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;
|
||||
@@ -10088,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);
|
||||
}
|
||||
}
|
||||
@@ -10116,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 */
|
||||
@@ -10130,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 );
|
||||
@@ -10142,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;
|
||||
@@ -10156,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;
|
||||
}
|
||||
|
||||
@@ -10170,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)i<nRoot; i++) if( mx<aRoot[i] ) mx = aRoot[i];
|
||||
mxInHdr = get4byte(&pBt->pPage1->aData[52]);
|
||||
if( mx!=mxInHdr ){
|
||||
if( !bPartial ){
|
||||
if( pBt->autoVacuum ){
|
||||
Pgno mx = 0;
|
||||
Pgno mxInHdr;
|
||||
for(i=0; (int)i<nRoot; i++) if( mx<aRoot[i] ) mx = aRoot[i];
|
||||
mxInHdr = get4byte(&pBt->pPage1->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 );
|
||||
@@ -10201,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
|
||||
@@ -10211,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.
|
||||
@@ -10236,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++;
|
||||
}
|
||||
@@ -10356,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;
|
||||
|
||||
+6
-6
@@ -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*);
|
||||
|
||||
|
||||
+4
-3
@@ -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 */
|
||||
|
||||
+130
-82
@@ -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 */
|
||||
){
|
||||
@@ -253,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, ...){
|
||||
@@ -335,9 +335,21 @@ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
|
||||
}
|
||||
}
|
||||
p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName);
|
||||
if( p==0 && i==1 && sqlite3StrICmp(zName, MASTER_NAME)==0 ){
|
||||
/* All temp.sqlite_master to be an alias for sqlite_temp_master */
|
||||
p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, TEMP_MASTER_NAME);
|
||||
if( p==0 && sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){
|
||||
if( i==1 ){
|
||||
if( sqlite3StrICmp(zName+7, &ALT_TEMP_SCHEMA_TABLE[7])==0
|
||||
|| sqlite3StrICmp(zName+7, &ALT_SCHEMA_TABLE[7])==0
|
||||
|| sqlite3StrICmp(zName+7, &DFLT_SCHEMA_TABLE[7])==0
|
||||
){
|
||||
p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash,
|
||||
DFLT_TEMP_SCHEMA_TABLE);
|
||||
}
|
||||
}else{
|
||||
if( sqlite3StrICmp(zName+7, &ALT_SCHEMA_TABLE[7])==0 ){
|
||||
p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash,
|
||||
DFLT_SCHEMA_TABLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
/* Match against TEMP first */
|
||||
@@ -352,6 +364,14 @@ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
|
||||
p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName);
|
||||
if( p ) break;
|
||||
}
|
||||
if( p==0 && sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){
|
||||
if( sqlite3StrICmp(zName+7, &ALT_SCHEMA_TABLE[7])==0 ){
|
||||
p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, DFLT_SCHEMA_TABLE);
|
||||
}else if( sqlite3StrICmp(zName+7, &ALT_TEMP_SCHEMA_TABLE[7])==0 ){
|
||||
p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash,
|
||||
DFLT_TEMP_SCHEMA_TABLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
@@ -743,13 +763,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;
|
||||
}
|
||||
@@ -857,7 +877,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.
|
||||
*/
|
||||
@@ -868,7 +888,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;
|
||||
}
|
||||
@@ -877,10 +900,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))
|
||||
@@ -1029,7 +1050,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;
|
||||
@@ -1135,7 +1156,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
|
||||
@@ -1171,7 +1192,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().
|
||||
**
|
||||
@@ -1189,7 +1210,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);
|
||||
@@ -1999,9 +2020,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
|
||||
@@ -2088,13 +2109,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 */
|
||||
@@ -2236,12 +2257,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
|
||||
@@ -2272,12 +2293,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 ){
|
||||
@@ -2364,7 +2385,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.
|
||||
@@ -2466,14 +2487,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,
|
||||
@@ -2601,7 +2622,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:
|
||||
@@ -2682,10 +2703,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;
|
||||
@@ -2733,9 +2752,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
||||
sqlite3DeleteTable(db, pSelTab);
|
||||
sqlite3SelectDelete(db, pSel);
|
||||
EnableLookaside;
|
||||
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||
pParse->eParseMode = eParseMode;
|
||||
#endif
|
||||
} else {
|
||||
nErr++;
|
||||
}
|
||||
@@ -2790,7 +2807,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;
|
||||
@@ -2816,7 +2833,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).
|
||||
*/
|
||||
@@ -2829,7 +2846,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
|
||||
@@ -2837,15 +2854,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).
|
||||
*/
|
||||
@@ -2866,18 +2884,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 || iTab<iDestroyed ){
|
||||
iLargest = iTab;
|
||||
}
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
int iIdx = pIdx->tnum;
|
||||
Pgno iIdx = pIdx->tnum;
|
||||
assert( pIdx->pSchema==pTab->pSchema );
|
||||
if( (iDestroyed==0 || (iIdx<iDestroyed)) && iIdx>iLargest ){
|
||||
iLargest = iIdx;
|
||||
@@ -2938,8 +2956,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 ){
|
||||
@@ -2963,16 +2981,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);
|
||||
}
|
||||
@@ -3108,7 +3127,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);
|
||||
@@ -3299,7 +3318,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 */
|
||||
@@ -3320,7 +3339,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;
|
||||
}
|
||||
@@ -3345,7 +3364,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));
|
||||
|
||||
@@ -3562,10 +3581,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;
|
||||
}
|
||||
@@ -3587,7 +3603,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.
|
||||
**
|
||||
@@ -3931,8 +3947,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.
|
||||
**
|
||||
@@ -3957,7 +3973,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
|
||||
@@ -3976,11 +3992,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,
|
||||
@@ -3999,7 +4015,7 @@ void sqlite3CreateIndex(
|
||||
sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
|
||||
}
|
||||
|
||||
sqlite3VdbeJumpHere(v, pIndex->tnum);
|
||||
sqlite3VdbeJumpHere(v, (int)pIndex->tnum);
|
||||
}
|
||||
}
|
||||
if( db->init.busy || pTblName==0 ){
|
||||
@@ -4056,9 +4072,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;
|
||||
|
||||
@@ -4067,10 +4084,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.
|
||||
*/
|
||||
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. */
|
||||
@@ -4133,13 +4161,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);
|
||||
@@ -4538,6 +4566,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.
|
||||
|
||||
+5
-5
@@ -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);
|
||||
|
||||
+2
-2
@@ -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);
|
||||
|
||||
+2
-2
@@ -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
|
||||
**
|
||||
|
||||
+35
-34
@@ -52,12 +52,10 @@ char sqlite3ExprAffinity(const Expr *pExpr){
|
||||
op = pExpr->op;
|
||||
if( op==TK_SELECT ){
|
||||
assert( pExpr->flags&EP_xIsSelect );
|
||||
if( ALWAYS(pExpr->x.pSelect)
|
||||
&& pExpr->x.pSelect->pEList
|
||||
&& ALWAYS(pExpr->x.pSelect->pEList->a[0].pExpr)
|
||||
){
|
||||
return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
|
||||
}
|
||||
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;
|
||||
#ifndef SQLITE_OMIT_CAST
|
||||
@@ -200,7 +198,7 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){
|
||||
&& ALWAYS(!ExprHasProperty(p, EP_xIsSelect))
|
||||
){
|
||||
int i;
|
||||
for(i=0; i<p->x.pList->nExpr; i++){
|
||||
for(i=0; ALWAYS(i<p->x.pList->nExpr); i++){
|
||||
if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){
|
||||
pNext = p->x.pList->a[i].pExpr;
|
||||
break;
|
||||
@@ -1993,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.
|
||||
@@ -2031,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:
|
||||
@@ -2045,7 +2043,7 @@ 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:
|
||||
@@ -2058,7 +2056,7 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
|
||||
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
|
||||
@@ -2066,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 */
|
||||
@@ -2191,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.
|
||||
@@ -2559,7 +2557,7 @@ int sqlite3FindInIndex(
|
||||
if( pParse->nErr==0 && (p = isCandidateForInOpt(pX))!=0 ){
|
||||
sqlite3 *db = pParse->db; /* Database connection */
|
||||
Table *pTab; /* Table <table>. */
|
||||
i16 iDb; /* Database idx for pTab */
|
||||
int iDb; /* Database idx for pTab */
|
||||
ExprList *pEList = p->pEList;
|
||||
int nExpr = pEList->nExpr;
|
||||
|
||||
@@ -2570,6 +2568,7 @@ int sqlite3FindInIndex(
|
||||
|
||||
/* Code an OP_Transaction and OP_TableLock for <table>. */
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
assert( iDb>=0 && iDb<SQLITE_MAX_ATTACHED );
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
||||
|
||||
@@ -3803,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 ){
|
||||
@@ -3840,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;
|
||||
@@ -4272,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);
|
||||
@@ -4636,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;
|
||||
@@ -4902,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:
|
||||
@@ -5078,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:
|
||||
@@ -5390,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:
|
||||
@@ -5545,6 +5545,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
||||
){
|
||||
return WRC_Prune;
|
||||
}
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
default:
|
||||
return WRC_Continue;
|
||||
@@ -5757,20 +5758,20 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
|
||||
assert( pExpr->op==TK_AGG_COLUMN || pExpr->op==TK_AGG_FUNCTION );
|
||||
if( pExpr->op==TK_AGG_COLUMN ){
|
||||
assert( iAgg>=0 && iAgg<pAggInfo->nColumn );
|
||||
if( pAggInfo->aCol[iAgg].pExpr==pExpr ){
|
||||
if( pAggInfo->aCol[iAgg].pCExpr==pExpr ){
|
||||
pExpr = sqlite3ExprDup(db, pExpr, 0);
|
||||
if( pExpr ){
|
||||
pAggInfo->aCol[iAgg].pExpr = pExpr;
|
||||
pAggInfo->aCol[iAgg].pCExpr = pExpr;
|
||||
pParse->pConstExpr =
|
||||
sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
assert( iAgg>=0 && iAgg<pAggInfo->nFunc );
|
||||
if( pAggInfo->aFunc[iAgg].pExpr==pExpr ){
|
||||
if( pAggInfo->aFunc[iAgg].pFExpr==pExpr ){
|
||||
pExpr = sqlite3ExprDup(db, pExpr, 0);
|
||||
if( pExpr ){
|
||||
pAggInfo->aFunc[iAgg].pExpr = pExpr;
|
||||
pAggInfo->aFunc[iAgg].pFExpr = pExpr;
|
||||
pParse->pConstExpr =
|
||||
sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr);
|
||||
}
|
||||
@@ -5872,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;
|
||||
@@ -5915,7 +5916,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
||||
*/
|
||||
struct AggInfo_func *pItem = pAggInfo->aFunc;
|
||||
for(i=0; i<pAggInfo->nFunc; i++, pItem++){
|
||||
if( sqlite3ExprCompare(0, pItem->pExpr, pExpr, -1)==0 ){
|
||||
if( sqlite3ExprCompare(0, pItem->pFExpr, pExpr, -1)==0 ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -5927,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,
|
||||
|
||||
@@ -1359,6 +1359,7 @@ static Trigger *fkActionTrigger(
|
||||
pStep->op = TK_DELETE;
|
||||
break;
|
||||
}
|
||||
/* no break */ deliberate_fall_through
|
||||
default:
|
||||
pStep->op = TK_UPDATE;
|
||||
}
|
||||
|
||||
@@ -309,6 +309,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
|
||||
|
||||
+6
-6
@@ -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) ){
|
||||
|
||||
+5
-5
@@ -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;
|
||||
|
||||
+19
-13
@@ -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
|
||||
@@ -1202,7 +1202,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 */
|
||||
@@ -2091,7 +2091,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;
|
||||
@@ -2115,7 +2115,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;
|
||||
@@ -3149,7 +3149,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
|
||||
@@ -4138,8 +4138,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 setting is always enabled
|
||||
** in production.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS: {
|
||||
sqlite3GlobalConfig.bExtraSchemaChecks = va_arg(ap, int);
|
||||
|
||||
+2
-4
@@ -730,11 +730,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;
|
||||
|
||||
+3
-3
@@ -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 */
|
||||
|
||||
+74
-74
@@ -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<N_HASH; i++){
|
||||
memsys3Merge(&mem3.aiHash[i]);
|
||||
@@ -415,10 +415,10 @@ static void *memsys3MallocUnsafe(int nByte){
|
||||
for(i=0; i<MX_SMALL-1; i++){
|
||||
memsys3Merge(&mem3.aiSmall[i]);
|
||||
}
|
||||
if( mem3.szMaster ){
|
||||
memsys3Unlink(mem3.iMaster);
|
||||
if( mem3.szMaster>=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; i<MX_SMALL-1; i++){
|
||||
@@ -645,9 +645,9 @@ void sqlite3Memsys3Dump(const char *zFilename){
|
||||
}
|
||||
fprintf(out, "\n");
|
||||
}
|
||||
fprintf(out, "master=%d\n", mem3.iMaster);
|
||||
fprintf(out, "nowUsed=%d\n", mem3.nPool*8 - mem3.szMaster*8);
|
||||
fprintf(out, "mxUsed=%d\n", mem3.nPool*8 - mem3.mnMaster*8);
|
||||
fprintf(out, "key=%d\n", mem3.iKeyBlk);
|
||||
fprintf(out, "nowUsed=%d\n", mem3.nPool*8 - mem3.szKeyBlk*8);
|
||||
fprintf(out, "mxUsed=%d\n", mem3.nPool*8 - mem3.mnKeyBlk*8);
|
||||
sqlite3_mutex_leave(mem3.mutex);
|
||||
if( out==stdout ){
|
||||
fflush(stdout);
|
||||
|
||||
+2
-2
@@ -339,12 +339,12 @@ static int memdbOpen(
|
||||
p->mFlags = 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,
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+1
-1
@@ -112,7 +112,7 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; }
|
||||
** <ul>
|
||||
** <li> SQLITE_MUTEX_FAST
|
||||
** <li> SQLITE_MUTEX_RECURSIVE
|
||||
** <li> SQLITE_MUTEX_STATIC_MASTER
|
||||
** <li> SQLITE_MUTEX_STATIC_MAIN
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM
|
||||
** <li> SQLITE_MUTEX_STATIC_OPEN
|
||||
** <li> SQLITE_MUTEX_STATIC_PRNG
|
||||
|
||||
+1
-1
@@ -171,7 +171,7 @@ static int winMutexEnd(void){
|
||||
** <ul>
|
||||
** <li> SQLITE_MUTEX_FAST
|
||||
** <li> SQLITE_MUTEX_RECURSIVE
|
||||
** <li> SQLITE_MUTEX_STATIC_MASTER
|
||||
** <li> SQLITE_MUTEX_STATIC_MAIN
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM
|
||||
** <li> SQLITE_MUTEX_STATIC_OPEN
|
||||
** <li> SQLITE_MUTEX_STATIC_PRNG
|
||||
|
||||
+8
-8
@@ -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 */
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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);
|
||||
|
||||
+15
-12
@@ -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);
|
||||
|
||||
|
||||
+10
-10
@@ -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 ){
|
||||
|
||||
+174
-178
@@ -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
|
||||
@@ -504,29 +504,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
|
||||
@@ -658,7 +658,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() */
|
||||
@@ -810,11 +810,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.
|
||||
@@ -949,7 +944,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:
|
||||
@@ -1309,66 +1304,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; u<len; u++){
|
||||
cksum -= zMaster[u];
|
||||
cksum -= zSuper[u];
|
||||
}
|
||||
if( cksum ){
|
||||
/* If the checksum doesn't add up, then one or more of the disk sectors
|
||||
** containing the master journal filename is corrupted. This means
|
||||
** containing the super-journal filename is corrupted. This means
|
||||
** definitely roll back, so just return SQLITE_OK and report a (nul)
|
||||
** master-journal filename.
|
||||
** super-journal filename.
|
||||
*/
|
||||
len = 0;
|
||||
}
|
||||
zMaster[len] = '\0';
|
||||
zMaster[len+1] = '\0';
|
||||
zSuper[len] = '\0';
|
||||
zSuper[len+1] = '\0';
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -1696,50 +1691,50 @@ static int readJournalHdr(
|
||||
|
||||
|
||||
/*
|
||||
** Write the supplied master journal name into the journal file for pager
|
||||
** pPager at the current location. The master journal name must be the last
|
||||
** Write the supplied super-journal name into the journal file for pager
|
||||
** pPager at the current location. The super-journal name must be the last
|
||||
** thing written to a journal file. If the pager is in full-sync mode, the
|
||||
** journal file descriptor is advanced to the next sector boundary before
|
||||
** anything is written. The format is:
|
||||
**
|
||||
** + 4 bytes: PAGER_MJ_PGNO.
|
||||
** + N bytes: Master journal filename in utf-8.
|
||||
** + 4 bytes: N (length of master journal name in bytes, no nul-terminator).
|
||||
** + 4 bytes: Master journal name checksum.
|
||||
** + N bytes: super-journal filename in utf-8.
|
||||
** + 4 bytes: N (length of super-journal name in bytes, no nul-terminator).
|
||||
** + 4 bytes: super-journal name checksum.
|
||||
** + 8 bytes: aJournalMagic[].
|
||||
**
|
||||
** The master journal page checksum is the sum of the bytes in the master
|
||||
** journal name, where each byte is interpreted as a signed 8-bit integer.
|
||||
** The super-journal page checksum is the sum of the bytes in thesuper-journal
|
||||
** name, where each byte is interpreted as a signed 8-bit integer.
|
||||
**
|
||||
** If zMaster is a NULL pointer (occurs for a single database transaction),
|
||||
** If zSuper is a NULL pointer (occurs for a single database transaction),
|
||||
** this call is a no-op.
|
||||
*/
|
||||
static int writeMasterJournal(Pager *pPager, const char *zMaster){
|
||||
static int writeSuperJournal(Pager *pPager, const char *zSuper){
|
||||
int rc; /* Return code */
|
||||
int nMaster; /* Length of string zMaster */
|
||||
int nSuper; /* Length of string zSuper */
|
||||
i64 iHdrOff; /* Offset of header in journal file */
|
||||
i64 jrnlSize; /* Size of journal file on disk */
|
||||
u32 cksum = 0; /* Checksum of string zMaster */
|
||||
u32 cksum = 0; /* Checksum of string zSuper */
|
||||
|
||||
assert( pPager->setMaster==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 ){
|
||||
@@ -1747,25 +1742,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
|
||||
@@ -1926,7 +1921,7 @@ static void pager_unlock(Pager *pPager){
|
||||
|
||||
pPager->journalOff = 0;
|
||||
pPager->journalHdr = 0;
|
||||
pPager->setMaster = 0;
|
||||
pPager->setSuper = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2042,7 +2037,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 */
|
||||
|
||||
@@ -2094,7 +2089,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
|
||||
@@ -2167,7 +2162,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);
|
||||
}
|
||||
@@ -2541,36 +2536,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
|
||||
@@ -2579,99 +2574,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)<nMasterJournal ){
|
||||
zJournal = zSuperJournal;
|
||||
while( (zJournal-zSuperJournal)<nSuperJournal ){
|
||||
int exists;
|
||||
rc = sqlite3OsAccess(pVfs, zJournal, SQLITE_ACCESS_EXISTS, &exists);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto delmaster_out;
|
||||
goto delsuper_out;
|
||||
}
|
||||
if( exists ){
|
||||
/* One of the journals pointed to by the master journal exists.
|
||||
** Open it and check if it points at the master journal. If
|
||||
** so, return without deleting the master journal file.
|
||||
/* One of the journals pointed to by the super-journal exists.
|
||||
** Open it and check if it points at the super-journal. If
|
||||
** so, return without deleting the super-journal file.
|
||||
** NB: zJournal is really a MAIN_JOURNAL. But call it a
|
||||
** MASTER_JOURNAL here so that the VFS will not send the zJournal
|
||||
** SUPER_JOURNAL here so that the VFS will not send the zJournal
|
||||
** name into sqlite3_database_file_object().
|
||||
*/
|
||||
int c;
|
||||
int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL);
|
||||
int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_SUPER_JOURNAL);
|
||||
rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto delmaster_out;
|
||||
goto delsuper_out;
|
||||
}
|
||||
|
||||
rc = readMasterJournal(pJournal, zMasterPtr, nMasterPtr);
|
||||
rc = readSuperJournal(pJournal, zSuperPtr, nSuperPtr);
|
||||
sqlite3OsClose(pJournal);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto delmaster_out;
|
||||
goto delsuper_out;
|
||||
}
|
||||
|
||||
c = zMasterPtr[0]!=0 && strcmp(zMasterPtr, zMaster)==0;
|
||||
c = zSuperPtr[0]!=0 && strcmp(zSuperPtr, zSuper)==0;
|
||||
if( c ){
|
||||
/* We have a match. Do not delete the master journal file. */
|
||||
goto delmaster_out;
|
||||
/* We have a match. Do not delete the super-journal file. */
|
||||
goto delsuper_out;
|
||||
}
|
||||
}
|
||||
zJournal += (sqlite3Strlen30(zJournal)+1);
|
||||
}
|
||||
|
||||
sqlite3OsClose(pMaster);
|
||||
rc = sqlite3OsDelete(pVfs, zMaster, 0);
|
||||
sqlite3OsClose(pSuper);
|
||||
rc = sqlite3OsDelete(pVfs, zSuper, 0);
|
||||
|
||||
delmaster_out:
|
||||
sqlite3_free(zMasterJournal);
|
||||
if( pMaster ){
|
||||
sqlite3OsClose(pMaster);
|
||||
delsuper_out:
|
||||
sqlite3_free(zSuperJournal);
|
||||
if( pSuper ){
|
||||
sqlite3OsClose(pSuper);
|
||||
assert( !isOpen(pJournal) );
|
||||
sqlite3_free(pMaster);
|
||||
sqlite3_free(pSuper);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -2749,7 +2745,7 @@ int sqlite3SectorSize(sqlite3_file *pFile){
|
||||
** pager based on the value returned by the xSectorSize method
|
||||
** of the open database file. The sector size will be used
|
||||
** to determine the size and alignment of journal header and
|
||||
** master journal pointers within created journal files.
|
||||
** super-journal pointers within created journal files.
|
||||
**
|
||||
** For temporary files the effective sector size is always 512 bytes.
|
||||
**
|
||||
@@ -2848,7 +2844,7 @@ static int pager_playback(Pager *pPager, int isHot){
|
||||
Pgno mxPg = 0; /* Size of the original file in pages */
|
||||
int rc; /* Result code of a subroutine */
|
||||
int res = 1; /* Value returned by sqlite3OsAccess() */
|
||||
char *zMaster = 0; /* Name of master journal file if any */
|
||||
char *zSuper = 0; /* Name of super-journal file if any */
|
||||
int needPagerReset; /* True to reset page prior to first page rollback */
|
||||
int nPlayback = 0; /* Total number of pages restored from journal */
|
||||
u32 savedPageSize = pPager->pageSize;
|
||||
@@ -2862,8 +2858,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.
|
||||
**
|
||||
@@ -2873,12 +2869,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;
|
||||
}
|
||||
@@ -3005,8 +3001,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
|
||||
@@ -3015,14 +3011,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 ){
|
||||
@@ -3403,7 +3399,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.
|
||||
**
|
||||
@@ -3867,7 +3863,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;
|
||||
}
|
||||
@@ -5160,8 +5156,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
|
||||
@@ -5610,7 +5606,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;
|
||||
|
||||
@@ -5618,10 +5614,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;
|
||||
}
|
||||
@@ -5911,7 +5907,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);
|
||||
}
|
||||
@@ -6423,9 +6419,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 ){
|
||||
@@ -6463,10 +6459,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:
|
||||
**
|
||||
@@ -6478,9 +6474,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
|
||||
@@ -6490,7 +6486,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 */
|
||||
@@ -6508,8 +6504,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->eState<PAGER_WRITER_CACHEMOD ) return SQLITE_OK;
|
||||
@@ -6548,7 +6544,7 @@ int sqlite3PagerCommitPhaseOne(
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
|
||||
sqlite3_file *fd = pPager->fd;
|
||||
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);
|
||||
@@ -6586,7 +6582,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)
|
||||
@@ -6607,7 +6603,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 );
|
||||
@@ -6617,11 +6613,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.
|
||||
@@ -6689,7 +6685,7 @@ int sqlite3PagerCommitPhaseOne(
|
||||
|
||||
/* Finally, sync the database file. */
|
||||
if( !noSync ){
|
||||
rc = sqlite3PagerSync(pPager, zMaster);
|
||||
rc = sqlite3PagerSync(pPager, zSuper);
|
||||
}
|
||||
IOTRACE(("DBSYNC %p\n", pPager))
|
||||
}
|
||||
@@ -6754,7 +6750,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);
|
||||
}
|
||||
|
||||
@@ -6799,7 +6795,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;
|
||||
|
||||
+5
-5
@@ -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))
|
||||
@@ -133,7 +133,7 @@ int sqlite3PagerSetPagesize(Pager*, u32*, int);
|
||||
void sqlite3PagerAlignReserve(Pager*,Pager*);
|
||||
#endif
|
||||
/* END SQLCIPHER */
|
||||
int sqlite3PagerMaxPageCount(Pager*, int);
|
||||
Pgno sqlite3PagerMaxPageCount(Pager*, Pgno);
|
||||
void sqlite3PagerSetCachesize(Pager*, int);
|
||||
int sqlite3PagerSetSpillsize(Pager*, int);
|
||||
void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
|
||||
@@ -166,9 +166,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);
|
||||
|
||||
+51
-20
@@ -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
|
||||
|
||||
+46
-16
@@ -626,13 +626,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;
|
||||
@@ -1153,15 +1159,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; i<pTab->nCol; i++, pCol++){
|
||||
int isHidden = 0;
|
||||
@@ -1418,7 +1423,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;
|
||||
@@ -1427,23 +1431,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{
|
||||
@@ -1536,9 +1541,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');
|
||||
|
||||
@@ -1561,9 +1579,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 */
|
||||
@@ -1592,15 +1614,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;
|
||||
@@ -1634,6 +1662,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);
|
||||
@@ -1905,6 +1934,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[] = {
|
||||
|
||||
+1
-1
@@ -282,7 +282,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,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt,
|
||||
/* ColNames: */ 37, 4,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
|
||||
+30
-16
@@ -115,7 +115,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;
|
||||
@@ -148,12 +154,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");
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -177,7 +188,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);
|
||||
|
||||
@@ -189,13 +200,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,"
|
||||
@@ -207,6 +218,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
|
||||
initData.pzErrMsg = pzErrMsg;
|
||||
initData.mInitFlags = mFlags;
|
||||
initData.nInitRow = 0;
|
||||
initData.mxPage = 0;
|
||||
sqlite3InitCallback(&initData, 5, (char **)azArg, 0);
|
||||
db->mDbFlags &= mask;
|
||||
if( initData.rc ){
|
||||
@@ -329,11 +341,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;
|
||||
@@ -363,7 +376,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);
|
||||
@@ -504,17 +517,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 ){
|
||||
@@ -742,7 +756,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){
|
||||
|
||||
+2
-2
@@ -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;
|
||||
|
||||
+14
-11
@@ -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( iCol<pTab->nCol ){
|
||||
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:
|
||||
|
||||
+121
-83
@@ -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; i<pTab->nCol; i++){
|
||||
if( sqlite3StrICmp(pTab->aCol[i].zName, zCol)==0 ) return i;
|
||||
u8 h = sqlite3StrIHash(zCol);
|
||||
Column *pCol;
|
||||
for(pCol=pTab->aCol, i=0; i<pTab->nCol; 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 );
|
||||
@@ -3171,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. */
|
||||
@@ -3220,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;
|
||||
@@ -4176,7 +4186,7 @@ static int flattenSubquery(
|
||||
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);
|
||||
}
|
||||
@@ -4999,8 +5009,8 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; 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
|
||||
@@ -5388,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 */
|
||||
@@ -5405,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; i<pAggInfo->nFunc; 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 "
|
||||
@@ -5429,8 +5439,8 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
|
||||
int i;
|
||||
struct AggInfo_func *pF;
|
||||
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; 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);
|
||||
}
|
||||
@@ -5459,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);
|
||||
@@ -5525,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; i<pAggInfo->nAccumulator; i++, pC++){
|
||||
sqlite3ExprCode(pParse, pC->pExpr, pC->iMem);
|
||||
sqlite3ExprCode(pParse, pC->pCExpr, pC->iMem);
|
||||
}
|
||||
|
||||
pAggInfo->directMode = 0;
|
||||
@@ -5610,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);
|
||||
}
|
||||
@@ -5732,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);
|
||||
}
|
||||
@@ -5785,7 +5799,7 @@ int sqlite3Select(
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
|
||||
#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
|
||||
@@ -5812,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; i<p->pSrc->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);
|
||||
}
|
||||
@@ -5829,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);
|
||||
}
|
||||
@@ -5840,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)
|
||||
@@ -5849,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.
|
||||
*/
|
||||
@@ -5931,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
|
||||
@@ -5950,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);
|
||||
}
|
||||
@@ -6038,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);
|
||||
@@ -6138,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);
|
||||
}
|
||||
@@ -6174,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);
|
||||
}
|
||||
@@ -6240,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);
|
||||
}
|
||||
@@ -6379,6 +6416,7 @@ int sqlite3Select(
|
||||
}
|
||||
pAggInfo->pNext = pParse->pAggList;
|
||||
pParse->pAggList = pAggInfo;
|
||||
pAggInfo->selId = p->selId;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = pParse;
|
||||
sNC.pSrcList = pTabList;
|
||||
@@ -6401,12 +6439,12 @@ int sqlite3Select(
|
||||
}
|
||||
pAggInfo->nAccumulator = pAggInfo->nColumn;
|
||||
if( p->pGroupBy==0 && p->pHaving==0 && pAggInfo->nFunc==1 ){
|
||||
minMaxFlag = minMaxQuery(db, pAggInfo->aFunc[0].pExpr, &pMinMaxOrderBy);
|
||||
minMaxFlag = minMaxQuery(db, pAggInfo->aFunc[0].pFExpr, &pMinMaxOrderBy);
|
||||
}else{
|
||||
minMaxFlag = WHERE_ORDERBY_NORMAL;
|
||||
}
|
||||
for(i=0; i<pAggInfo->nFunc; i++){
|
||||
Expr *pExpr = pAggInfo->aFunc[i].pExpr;
|
||||
Expr *pExpr = pAggInfo->aFunc[i].pFExpr;
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
sNC.ncFlags |= NC_InAggFunc;
|
||||
sqlite3ExprAnalyzeAggList(&sNC, pExpr->x.pList);
|
||||
@@ -6421,19 +6459,19 @@ int sqlite3Select(
|
||||
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", pAggInfo));
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
for(ii=0; ii<pAggInfo->nColumn; ii++){
|
||||
sqlite3DebugPrintf("agg-column[%d] iMem=%d\n",
|
||||
ii, pAggInfo->aCol[ii].iMem);
|
||||
sqlite3TreeViewExpr(0, pAggInfo->aCol[ii].pExpr, 0);
|
||||
sqlite3TreeViewExpr(0, pAggInfo->aCol[ii].pCExpr, 0);
|
||||
}
|
||||
for(ii=0; ii<pAggInfo->nFunc; ii++){
|
||||
sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n",
|
||||
ii, pAggInfo->aFunc[ii].iMem);
|
||||
sqlite3TreeViewExpr(0, pAggInfo->aFunc[ii].pExpr, 0);
|
||||
sqlite3TreeViewExpr(0, pAggInfo->aFunc[ii].pFExpr, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -6685,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);
|
||||
@@ -6717,7 +6755,7 @@ 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);
|
||||
}
|
||||
@@ -6726,6 +6764,7 @@ int sqlite3Select(
|
||||
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
|
||||
@@ -6738,7 +6777,7 @@ int sqlite3Select(
|
||||
** function visits zero rows. */
|
||||
if( pAggInfo->nAccumulator ){
|
||||
for(i=0; i<pAggInfo->nFunc; i++){
|
||||
if( ExprHasProperty(pAggInfo->aFunc[i].pExpr, EP_WinFunc) ){
|
||||
if( ExprHasProperty(pAggInfo->aFunc[i].pFExpr, EP_WinFunc) ){
|
||||
continue;
|
||||
}
|
||||
if( pAggInfo->aFunc[i].pFunc->funcFlags&SQLITE_FUNC_NEEDCOLL ){
|
||||
@@ -6774,10 +6813,9 @@ int sqlite3Select(
|
||||
}
|
||||
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, pAggInfo);
|
||||
@@ -6822,14 +6860,14 @@ select_end:
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( pAggInfo && !db->mallocFailed ){
|
||||
for(i=0; i<pAggInfo->nColumn; i++){
|
||||
Expr *pExpr = pAggInfo->aCol[i].pExpr;
|
||||
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; i<pAggInfo->nFunc; i++){
|
||||
Expr *pExpr = pAggInfo->aFunc[i].pExpr;
|
||||
Expr *pExpr = pAggInfo->aFunc[i].pFExpr;
|
||||
assert( pExpr!=0 || db->mallocFailed );
|
||||
if( pExpr==0 ) continue;
|
||||
assert( pExpr->pAggInfo==pAggInfo );
|
||||
@@ -6840,7 +6878,7 @@ select_end:
|
||||
|
||||
#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
|
||||
|
||||
+523
-154
File diff suppressed because it is too large
Load Diff
+16
-10
@@ -564,7 +564,7 @@ int sqlite3_exec(
|
||||
#define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */
|
||||
#define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */
|
||||
#define SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */
|
||||
#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */
|
||||
#define SQLITE_OPEN_SUPER_JOURNAL 0x00004000 /* VFS only */
|
||||
#define SQLITE_OPEN_NOMUTEX 0x00008000 /* Ok for sqlite3_open_v2() */
|
||||
#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */
|
||||
#define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */
|
||||
@@ -573,6 +573,9 @@ int sqlite3_exec(
|
||||
#define SQLITE_OPEN_NOFOLLOW 0x01000000 /* Ok for sqlite3_open_v2() */
|
||||
|
||||
/* Reserved: 0x00F00000 */
|
||||
/* Legacy compatibility: */
|
||||
#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */
|
||||
|
||||
|
||||
/*
|
||||
** CAPI3REF: Device Characteristics
|
||||
@@ -870,7 +873,7 @@ struct sqlite3_io_methods {
|
||||
** of the xSync method. In most cases, the pointer argument passed with
|
||||
** this file-control is NULL. However, if the database file is being synced
|
||||
** as part of a multi-database commit, the argument points to a nul-terminated
|
||||
** string containing the transactions master-journal file name. VFSes that
|
||||
** string containing the transactions super-journal file name. VFSes that
|
||||
** do not need this signal should silently ignore this opcode. Applications
|
||||
** should not call [sqlite3_file_control()] with this opcode as doing so may
|
||||
** disrupt the operation of the specialized VFSes that do require it.
|
||||
@@ -1267,7 +1270,7 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
|
||||
** <li> [SQLITE_OPEN_TEMP_JOURNAL]
|
||||
** <li> [SQLITE_OPEN_TRANSIENT_DB]
|
||||
** <li> [SQLITE_OPEN_SUBJOURNAL]
|
||||
** <li> [SQLITE_OPEN_MASTER_JOURNAL]
|
||||
** <li> [SQLITE_OPEN_SUPER_JOURNAL]
|
||||
** <li> [SQLITE_OPEN_WAL]
|
||||
** </ul>)^
|
||||
**
|
||||
@@ -1645,7 +1648,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
|
||||
@@ -2283,8 +2286,7 @@ struct sqlite3_mem_methods {
|
||||
** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]]
|
||||
** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</td>
|
||||
** <dd>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:
|
||||
@@ -6321,7 +6323,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
|
||||
@@ -7423,7 +7425,7 @@ int sqlite3_vfs_unregister(sqlite3_vfs*);
|
||||
** <ul>
|
||||
** <li> SQLITE_MUTEX_FAST
|
||||
** <li> SQLITE_MUTEX_RECURSIVE
|
||||
** <li> SQLITE_MUTEX_STATIC_MASTER
|
||||
** <li> SQLITE_MUTEX_STATIC_MAIN
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM
|
||||
** <li> SQLITE_MUTEX_STATIC_OPEN
|
||||
** <li> SQLITE_MUTEX_STATIC_PRNG
|
||||
@@ -7625,7 +7627,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() */
|
||||
@@ -7640,6 +7642,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
|
||||
@@ -9435,7 +9441,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.
|
||||
|
||||
+78
-44
@@ -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
|
||||
@@ -1173,9 +1195,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"
|
||||
@@ -1469,7 +1491,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 */
|
||||
@@ -1484,7 +1506,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 */
|
||||
@@ -1546,7 +1571,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
|
||||
@@ -1588,7 +1613,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 */
|
||||
@@ -2108,7 +2133,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 */
|
||||
@@ -2382,7 +2407,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
|
||||
@@ -2401,7 +2426,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 */
|
||||
@@ -2506,7 +2531,7 @@ struct AggInfo {
|
||||
ExprList *pGroupBy; /* The group by clause */
|
||||
struct AggInfo_col { /* For each column used in source tables */
|
||||
Table *pTab; /* Source table */
|
||||
Expr *pExpr; /* The original expression */
|
||||
Expr *pCExpr; /* The original expression */
|
||||
int iTable; /* Cursor number of the source table */
|
||||
int iMem; /* Memory location that acts as accumulator */
|
||||
i16 iColumn; /* Column number within the source table */
|
||||
@@ -2517,23 +2542,16 @@ struct AggInfo {
|
||||
** 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[] */
|
||||
#ifdef SQLITE_DEBUG
|
||||
int iAggMagic; /* Magic number when valid */
|
||||
#endif
|
||||
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
|
||||
@@ -2710,7 +2728,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 */
|
||||
|
||||
/*
|
||||
@@ -2890,7 +2908,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 */
|
||||
@@ -3011,7 +3029,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
|
||||
@@ -3115,6 +3133,7 @@ struct Select {
|
||||
#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
|
||||
@@ -3179,6 +3198,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 */
|
||||
@@ -3198,14 +3225,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 */
|
||||
@@ -3361,9 +3390,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
|
||||
@@ -3551,6 +3578,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 */
|
||||
@@ -3606,6 +3634,7 @@ typedef struct {
|
||||
int rc; /* Result code stored here */
|
||||
u32 mInitFlags; /* Flags controlling error messages */
|
||||
u32 nInitRow; /* Number of rows processed */
|
||||
Pgno mxPage; /* Maximum page number. 0 for no limit. */
|
||||
} InitData;
|
||||
|
||||
/*
|
||||
@@ -4136,7 +4165,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
|
||||
@@ -4225,6 +4254,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*);
|
||||
@@ -4243,7 +4273,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);
|
||||
@@ -4395,13 +4424,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
|
||||
@@ -4415,6 +4445,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*);
|
||||
@@ -4443,8 +4474,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);
|
||||
@@ -4564,14 +4597,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*);
|
||||
@@ -4685,7 +4719,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
|
||||
|
||||
+1
-1
@@ -352,7 +352,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:{
|
||||
|
||||
+67
-4
@@ -4658,7 +4658,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 },
|
||||
@@ -6465,6 +6465,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
|
||||
**
|
||||
@@ -7285,6 +7309,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*);
|
||||
@@ -7310,6 +7335,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 },
|
||||
@@ -7804,6 +7830,41 @@ static int SQLITE_TCLAPI test_mmap_warm(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: test_write_db DB OFFSET DATA
|
||||
**
|
||||
** Obtain the sqlite3_file* object for the database file for the "main" db
|
||||
** of handle DB. Then invoke its xWrite method to write data DATA to offset
|
||||
** OFFSET.
|
||||
*/
|
||||
static int SQLITE_TCLAPI test_write_db(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3 *db = 0;
|
||||
Tcl_WideInt iOff = 0;
|
||||
const unsigned char *aData = 0;
|
||||
int nData = 0;
|
||||
sqlite3_file *pFile = 0;
|
||||
int rc;
|
||||
|
||||
if( objc!=4 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB OFFSET DATA");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
if( Tcl_GetWideIntFromObj(interp, objv[2], &iOff) ) return TCL_ERROR;
|
||||
aData = Tcl_GetByteArrayFromObj(objv[3], &nData);
|
||||
|
||||
sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, (void*)&pFile);
|
||||
rc = pFile->pMethods->xWrite(pFile, aData, nData, iOff);
|
||||
|
||||
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: decode_hexdb TEXT
|
||||
**
|
||||
@@ -8029,6 +8090,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},
|
||||
@@ -8167,6 +8229,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_mmap_warm", test_mmap_warm, 0 },
|
||||
{ "sqlite3_config_sorterref", test_config_sorterref, 0 },
|
||||
{ "decode_hexdb", test_decode_hexdb, 0 },
|
||||
{ "test_write_db", test_write_db, 0 },
|
||||
};
|
||||
static int bitmask_size = sizeof(Bitmask)*8;
|
||||
static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
|
||||
@@ -8192,7 +8255,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; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
|
||||
@@ -8280,8 +8343,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
Tcl_LinkVar(interp, "sqlite_fullsync_count",
|
||||
(char*)&sqlite3_fullsync_count, TCL_LINK_INT);
|
||||
#if defined(SQLITE_ENABLE_SELECTTRACE)
|
||||
Tcl_LinkVar(interp, "sqlite3SelectTrace",
|
||||
(char*)&sqlite3SelectTrace, TCL_LINK_INT);
|
||||
Tcl_LinkVar(interp, "sqlite3_unsupported_selecttrace",
|
||||
(char*)&sqlite3_unsupported_selecttrace, TCL_LINK_INT);
|
||||
#endif
|
||||
#if defined(SQLITE_ENABLE_FTS3) && defined(SQLITE_TEST)
|
||||
Tcl_LinkVar(interp, "sqlite_fts3_enable_parentheses",
|
||||
|
||||
+2
-2
@@ -32,7 +32,7 @@ extern const char *sqlite3ErrName(int);
|
||||
*/
|
||||
typedef struct Thread Thread;
|
||||
struct Thread {
|
||||
/* The first group of fields are writable by the master and read-only
|
||||
/* The first group of fields are writable by the leader and read-only
|
||||
** to the thread. */
|
||||
char *zFilename; /* Name of database file */
|
||||
void (*xOp)(Thread*); /* next operation to do */
|
||||
@@ -41,7 +41,7 @@ struct Thread {
|
||||
int busy; /* True if this thread is in use */
|
||||
|
||||
/* The next group of fields are writable by the thread but read-only to the
|
||||
** master. */
|
||||
** leader. */
|
||||
int completed; /* Number of operations completed */
|
||||
sqlite3 *db; /* Open database */
|
||||
sqlite3_stmt *pStmt; /* Pending operation */
|
||||
|
||||
+1
-1
@@ -341,7 +341,7 @@ static int echoDeclareVtab(
|
||||
if( pVtab->zTableName ){
|
||||
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);
|
||||
|
||||
+3
-36
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+2
-2
@@ -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 ){
|
||||
|
||||
+3
-3
@@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
+8
-8
@@ -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( i<sqllogglobal.nConn ){
|
||||
if( p->fd ) 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( i<sqllogglobal.nConn && p->fd ){
|
||||
|
||||
@@ -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;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user