Compare commits
193 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4ffaa7c5de | |||
| 5289c51050 | |||
| 2bfd35b8d2 | |||
| 64185e31fc | |||
| b695bab055 | |||
| 5cbb442ea3 | |||
| 30b5db1261 | |||
| 22f874168a | |||
| 0581214577 | |||
| 6df54c30fc | |||
| 85c4754697 | |||
| 3c99dbb18b | |||
| d8d335d737 | |||
| 0f40e8dd41 | |||
| 99f363b35e | |||
| 8cda77d44a | |||
| ec18b6e5b9 | |||
| b5b9bf8540 | |||
| 9f683de872 | |||
| e6b430b178 | |||
| 9e44f265a7 | |||
| 24aee8af6e | |||
| e78c027b64 | |||
| 6b64718618 | |||
| 427af8dc3d | |||
| beb9def059 | |||
| 3259295533 | |||
| a764709bf3 | |||
| 96e3c39bd5 | |||
| 7cff0e34e0 | |||
| 067b92ba00 | |||
| 1e32bed3c1 | |||
| ccb2113a62 | |||
| 877859f2d3 | |||
| 0ad1b3284a | |||
| 5d237bfab1 | |||
| 74bbd37dae | |||
| dd853c382a | |||
| dc8339eaac | |||
| b65ce39607 | |||
| 346a70ca1e | |||
| 999429882e | |||
| b13c3a33fd | |||
| b7cbf5c1b2 | |||
| 86d2de2571 | |||
| cd653a3266 | |||
| 74e0d96695 | |||
| 0dc90d43e5 | |||
| 56e38185fe | |||
| 6aa7515c46 | |||
| b5aaee5e31 | |||
| 46daa99b8d | |||
| 9216de8a23 | |||
| ac4f7cf8d3 | |||
| f65e379919 | |||
| 7b4c4d4a67 | |||
| d124549fce | |||
| bc050b8f27 | |||
| ed41a96bc1 | |||
| cfb8bf6a50 | |||
| 81185a5138 | |||
| e26d428a59 | |||
| 5c10930fa9 | |||
| e6463a717a | |||
| 2f82acc036 | |||
| bf7909734a | |||
| 896366282d | |||
| a0365c487c | |||
| c060508445 | |||
| 0908e38536 | |||
| 634af38115 | |||
| b55389412f | |||
| ec206a7d34 | |||
| 21b473de78 | |||
| a5f3fb3015 | |||
| 56f1873d10 | |||
| 094afffaec | |||
| e566cebb26 | |||
| e557b0155b | |||
| 375b0b014b | |||
| 42c2a04eb7 | |||
| 02c17a4da7 | |||
| 9776784f94 | |||
| 7da29a3ad3 | |||
| 1d29fd85a3 | |||
| 8c748633a9 | |||
| 0285d98de7 | |||
| d6f252490e | |||
| d31fcd4751 | |||
| 69c093da98 | |||
| 30c54a01db | |||
| c683573fd4 | |||
| 56c65c92cb | |||
| b639a2094a | |||
| 399062cccb | |||
| a3d6b8e5a7 | |||
| ed505ce3e4 | |||
| 47937cfd8d | |||
| ed1e910448 | |||
| bdd4f7d91c | |||
| d63c76fb31 | |||
| b6907e2993 | |||
| 0934d64045 | |||
| efc752b131 | |||
| 91960aa53f | |||
| d3bf766127 | |||
| e859e43bb8 | |||
| c37577bb2d | |||
| e40cc16b47 | |||
| ca74fbf6f1 | |||
| 16dc07f756 | |||
| dd6c33d372 | |||
| 8e50d65aaf | |||
| 0b0274a90c | |||
| f25f8d5834 | |||
| 23e3c340b5 | |||
| 4f1315a432 | |||
| 5a8cd2e40c | |||
| 10757ed0ca | |||
| 1a7feefac5 | |||
| f16cf653f4 | |||
| a5ee67d5b3 | |||
| c795e3df7a | |||
| d924e7bc78 | |||
| b2eb7e46eb | |||
| 8c1febb2f9 | |||
| becd68ba0d | |||
| c48428899d | |||
| 62c94d0afe | |||
| b2c6fe225a | |||
| d48eafb984 | |||
| cc1d9109c4 | |||
| bbf6d4328e | |||
| 2629adc7b2 | |||
| 34d1566763 | |||
| a796de8300 | |||
| a8e41ecaca | |||
| 043c8f60a8 | |||
| 856408abf4 | |||
| 219b8e7e75 | |||
| 3d863b5e4e | |||
| 3c0e606bba | |||
| ffe421c76a | |||
| 8b4f231c47 | |||
| 2493dcdd07 | |||
| efa78884a8 | |||
| 9e5fdc41c1 | |||
| 98aa1d735e | |||
| 91d4c374e2 | |||
| acc175215a | |||
| 2d3ed22a3f | |||
| b28f44eba2 | |||
| 11a8182e5c | |||
| 4cbe5d3588 | |||
| e937df81f0 | |||
| a8aae52391 | |||
| bc9fc18e45 | |||
| 783e159e48 | |||
| 7a623e1d25 | |||
| 7bb8b8a4f7 | |||
| fc87ab8c4a | |||
| 861fb1e9dc | |||
| e0a8b712c1 | |||
| d0e6d13301 | |||
| 293e9f5d6c | |||
| 58021b237a | |||
| fde2592503 | |||
| 85bd353ac2 | |||
| eb8305bbc7 | |||
| 3d42fb788a | |||
| 8714de97c0 | |||
| 44a5c86c6c | |||
| 20e34f9110 | |||
| 995e1af9fa | |||
| 278b0517d8 | |||
| 477a357278 | |||
| f72981f2d9 | |||
| c75921ac4e | |||
| fcf31b28ff | |||
| e754830eae | |||
| ad996da0f6 | |||
| 31e3744ecb | |||
| 49a76a8fe5 | |||
| dcdd707a9c | |||
| 78a50d7280 | |||
| 59a8cb7931 | |||
| 9f27463684 | |||
| e50478d727 | |||
| dc4a1687b8 | |||
| 9d8c287309 | |||
| e31f00bbef | |||
| 2e51dc6c9b | |||
| 9d33d9e7ac |
+17
-4
@@ -443,6 +443,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 \
|
||||
@@ -619,6 +620,7 @@ FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000
|
||||
FUZZCHECK_OPT += -DSQLITE_PRINTF_PRECISION_LIMIT=1000
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_DESERIALIZE
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS4
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS3_PARENTHESIS
|
||||
#FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS5
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_RTREE
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_GEOPOLY
|
||||
@@ -1066,6 +1068,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
|
||||
@@ -1074,9 +1082,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 \
|
||||
@@ -1285,6 +1295,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
|
||||
|
||||
@@ -1387,10 +1400,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
|
||||
|
||||
+40
-13
@@ -234,6 +234,15 @@ OSTRACE = 0
|
||||
DEBUG = 0
|
||||
!ENDIF
|
||||
|
||||
# <<mark>>
|
||||
# Disable use of the --linemacros argument to the mksqlite3c.tcl tool, which
|
||||
# is used to build the amalgamation.
|
||||
#
|
||||
!IFNDEF NO_LINEMACROS
|
||||
NO_LINEMACROS = 0
|
||||
!ENDIF
|
||||
# <</mark>>
|
||||
|
||||
# Enable use of available compiler optimizations? Normally, this should be
|
||||
# non-zero. Setting this to zero, thus disabling all compiler optimizations,
|
||||
# can be useful for testing.
|
||||
@@ -776,7 +785,7 @@ MKSQLITE3C_TOOL = $(TOP)\tool\mksqlite3c.tcl
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF MKSQLITE3C_ARGS
|
||||
!IF $(DEBUG)>1
|
||||
!IF $(DEBUG)>1 && $(NO_LINEMACROS)==0
|
||||
MKSQLITE3C_ARGS = --linemacros
|
||||
!ELSE
|
||||
MKSQLITE3C_ARGS =
|
||||
@@ -1247,7 +1256,8 @@ LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.lo \
|
||||
table.lo threads.lo tokenize.lo treeview.lo trigger.lo \
|
||||
update.lo upsert.lo util.lo vacuum.lo \
|
||||
vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \
|
||||
vdbetrace.lo wal.lo walker.lo where.lo wherecode.lo whereexpr.lo \
|
||||
vdbetrace.lo vdbevtab.lo wal.lo walker.lo where.lo wherecode.lo \
|
||||
whereexpr.lo \
|
||||
window.lo utf.lo vtab.lo
|
||||
# <</mark>>
|
||||
|
||||
@@ -1485,7 +1495,7 @@ SRC12 =
|
||||
|
||||
# All source code files.
|
||||
#
|
||||
SRC = $(SRC00) $(SRC01) $(SRC03) $(SRC04) $(SRC05) $(SRC06) $(SRC07) $(SRC08) $(SRC09) $(SRC10) $(SRC11)
|
||||
SRC = $(SRC00) $(SRC01) $(SRC03) $(SRC04) $(SRC05) $(SRC06) $(SRC07) $(SRC08) $(SRC09) $(SRC10) $(SRC11) $(SRC12)
|
||||
|
||||
# Source code to the test files.
|
||||
#
|
||||
@@ -1550,6 +1560,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 \
|
||||
@@ -1836,15 +1847,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
|
||||
@@ -1859,7 +1871,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 \
|
||||
@@ -2159,7 +2172,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
|
||||
@@ -2172,8 +2186,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)
|
||||
@@ -2185,10 +2204,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 \
|
||||
@@ -2319,7 +2340,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
|
||||
|
||||
@@ -2327,11 +2349,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
|
||||
@@ -2442,6 +2466,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
|
||||
|
||||
|
||||
@@ -196,6 +196,7 @@ OSTRACE = 0
|
||||
DEBUG = 0
|
||||
!ENDIF
|
||||
|
||||
|
||||
# Enable use of available compiler optimizations? Normally, this should be
|
||||
# non-zero. Setting this to zero, thus disabling all compiler optimizations,
|
||||
# can be useful for testing.
|
||||
@@ -288,6 +289,7 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_JSON1=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBSTAT_VTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DESERIALIZE=1
|
||||
!ENDIF
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.69 for sqlite 3.32.0.
|
||||
# Generated by GNU Autoconf 2.69 for sqlite 3.33.0.
|
||||
#
|
||||
#
|
||||
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
|
||||
@@ -726,8 +726,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='sqlite'
|
||||
PACKAGE_TARNAME='sqlite'
|
||||
PACKAGE_VERSION='3.32.0'
|
||||
PACKAGE_STRING='sqlite 3.32.0'
|
||||
PACKAGE_VERSION='3.33.0'
|
||||
PACKAGE_STRING='sqlite 3.33.0'
|
||||
PACKAGE_BUGREPORT=''
|
||||
PACKAGE_URL=''
|
||||
|
||||
@@ -1467,7 +1467,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures sqlite 3.32.0 to adapt to many kinds of systems.
|
||||
\`configure' configures sqlite 3.33.0 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1532,7 +1532,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlite 3.32.0:";;
|
||||
short | recursive ) echo "Configuration of sqlite 3.33.0:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1659,7 +1659,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlite configure 3.32.0
|
||||
sqlite configure 3.33.0
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
@@ -2078,7 +2078,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by sqlite $as_me 3.32.0, which was
|
||||
It was created by sqlite $as_me 3.33.0, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -11619,7 +11619,7 @@ if test "${enable_update_limit+set}" = set; then :
|
||||
enableval=$enable_update_limit;
|
||||
fi
|
||||
|
||||
if test "${enable_udlimit}" = "yes" ; then
|
||||
if test "${enable_update_limit}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT"
|
||||
fi
|
||||
|
||||
@@ -12243,7 +12243,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by sqlite $as_me 3.32.0, which was
|
||||
This file was extended by sqlite $as_me 3.33.0, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -12309,7 +12309,7 @@ _ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||
ac_cs_version="\\
|
||||
sqlite config.status 3.32.0
|
||||
sqlite config.status 3.33.0
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
+1
-1
@@ -651,7 +651,7 @@ fi
|
||||
# statements.
|
||||
AC_ARG_ENABLE(update-limit, AC_HELP_STRING([--enable-update-limit],
|
||||
[Enable the UPDATE/DELETE LIMIT clause]))
|
||||
if test "${enable_udlimit}" = "yes" ; then
|
||||
if test "${enable_update_limit}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT"
|
||||
fi
|
||||
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
|
||||
+17
-12
@@ -1128,14 +1128,19 @@ int idxFindIndexes(
|
||||
/* int iParent = sqlite3_column_int(pExplain, 1); */
|
||||
/* int iNotUsed = sqlite3_column_int(pExplain, 2); */
|
||||
const char *zDetail = (const char*)sqlite3_column_text(pExplain, 3);
|
||||
int nDetail = STRLEN(zDetail);
|
||||
int nDetail;
|
||||
int i;
|
||||
|
||||
if( !zDetail ) continue;
|
||||
nDetail = STRLEN(zDetail);
|
||||
|
||||
for(i=0; i<nDetail; i++){
|
||||
const char *zIdx = 0;
|
||||
if( memcmp(&zDetail[i], " USING INDEX ", 13)==0 ){
|
||||
if( i+13<nDetail && memcmp(&zDetail[i], " USING INDEX ", 13)==0 ){
|
||||
zIdx = &zDetail[i+13];
|
||||
}else if( memcmp(&zDetail[i], " USING COVERING INDEX ", 22)==0 ){
|
||||
}else if( i+22<nDetail
|
||||
&& memcmp(&zDetail[i], " USING COVERING INDEX ", 22)==0
|
||||
){
|
||||
zIdx = &zDetail[i+22];
|
||||
}
|
||||
if( zIdx ){
|
||||
@@ -1218,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;
|
||||
@@ -1318,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) ){
|
||||
@@ -1493,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'";
|
||||
@@ -1646,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 =
|
||||
@@ -1720,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);
|
||||
@@ -1759,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) ){
|
||||
@@ -1950,4 +1955,4 @@ void sqlite3_expert_destroy(sqlite3expert *p){
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* ifndef SQLITE_OMIT_VIRTUAL_TABLE */
|
||||
#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
|
||||
+20
-9
@@ -2185,7 +2185,9 @@ static void fts3ReadNextPos(
|
||||
sqlite3_int64 *pi /* IN/OUT: Value read from position-list */
|
||||
){
|
||||
if( (**pp)&0xFE ){
|
||||
fts3GetDeltaVarint(pp, pi);
|
||||
int iVal;
|
||||
*pp += fts3GetVarint32((*pp), &iVal);
|
||||
*pi += iVal;
|
||||
*pi -= 2;
|
||||
}else{
|
||||
*pi = POSITION_LIST_END;
|
||||
@@ -2265,6 +2267,9 @@ static int fts3PoslistMerge(
|
||||
*/
|
||||
fts3GetDeltaVarint(&p1, &i1);
|
||||
fts3GetDeltaVarint(&p2, &i2);
|
||||
if( i1<2 || i2<2 ){
|
||||
break;
|
||||
}
|
||||
do {
|
||||
fts3PutDeltaVarint(&p, &iPrev, (i1<i2) ? i1 : i2);
|
||||
iPrev -= 2;
|
||||
@@ -2333,7 +2338,7 @@ static int fts3PoslistPhraseMerge(
|
||||
/* Never set both isSaveLeft and isExact for the same invocation. */
|
||||
assert( isSaveLeft==0 || isExact==0 );
|
||||
|
||||
assert( p!=0 && *p1!=0 && *p2!=0 );
|
||||
assert_fts3_nc( p!=0 && *p1!=0 && *p2!=0 );
|
||||
if( *p1==POS_COLUMN ){
|
||||
p1++;
|
||||
p1 += fts3GetVarint32(p1, &iCol1);
|
||||
@@ -4518,7 +4523,7 @@ void sqlite3Fts3DoclistNext(
|
||||
|
||||
assert( nDoclist>0 );
|
||||
assert( *pbEof==0 );
|
||||
assert( p || *piDocid==0 );
|
||||
assert_fts3_nc( p || *piDocid==0 );
|
||||
assert( !p || (p>=aDoclist && p<=&aDoclist[nDoclist]) );
|
||||
|
||||
if( p==0 ){
|
||||
@@ -5168,7 +5173,7 @@ static void fts3EvalInvalidatePoslist(Fts3Phrase *pPhrase){
|
||||
**
|
||||
** Parameter nNear is passed the NEAR distance of the expression (5 in
|
||||
** the example above). When this function is called, *paPoslist points to
|
||||
** the position list, and *pnToken is the number of phrase tokens in, the
|
||||
** the position list, and *pnToken is the number of phrase tokens in the
|
||||
** phrase on the other side of the NEAR operator to pPhrase. For example,
|
||||
** if pPhrase refers to the "def ghi" phrase, then *paPoslist points to
|
||||
** the position list associated with phrase "abc".
|
||||
@@ -5203,10 +5208,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;
|
||||
}
|
||||
@@ -5315,6 +5322,7 @@ static void fts3EvalNextRow(
|
||||
fts3EvalNextRow(pCsr, pLeft, pRc);
|
||||
}
|
||||
}
|
||||
pRight->bEof = pLeft->bEof = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -5557,7 +5565,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;
|
||||
}
|
||||
|
||||
@@ -876,7 +876,7 @@ static int fts3ExprLHits(
|
||||
iStart = pExpr->iPhrase * ((p->nCol + 31) / 32);
|
||||
}
|
||||
|
||||
while( 1 ){
|
||||
if( pIter ) while( 1 ){
|
||||
int nHit = fts3ColumnlistCount(&pIter);
|
||||
if( (pPhrase->iColumn>=pTab->nColumn || pPhrase->iColumn==iCol) ){
|
||||
if( p->flag==FTS3_MATCHINFO_LHITS ){
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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");
|
||||
|
||||
+2
-1
@@ -116,7 +116,8 @@ SQLite. Documentation follows.
|
||||
and use it as a dynamically loadable SQLite extension. To do this
|
||||
using gcc on *nix:
|
||||
|
||||
gcc -shared icu.c `icu-config --ldflags` -o libSqliteIcu.so
|
||||
gcc -fPIC -shared icu.c `pkg-config --libs --cflags icu-uc icu-io` \
|
||||
-o libSqliteIcu.so
|
||||
|
||||
You may need to add "-I" flags so that gcc can find sqlite3ext.h
|
||||
and sqlite3.h. The resulting shared lib, libSqliteIcu.so, may be
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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;
|
||||
|
||||
+33
-14
@@ -195,6 +195,7 @@ struct CksmFile {
|
||||
** Always true if reserve size is 8. */
|
||||
char verifyCksm; /* True to verify checksums */
|
||||
char isWal; /* True if processing a WAL file */
|
||||
char inCkpt; /* Currently doing a checkpoint */
|
||||
CksmFile *pPartner; /* Ptr from WAL to main-db, or from main-db to WAL */
|
||||
};
|
||||
|
||||
@@ -366,6 +367,20 @@ static int cksmClose(sqlite3_file *pFile){
|
||||
return pFile->pMethods->xClose(pFile);
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the computeCkSm and verifyCksm flags, if they need to be
|
||||
** changed.
|
||||
*/
|
||||
static void cksmSetFlags(CksmFile *p, int hasCorrectReserveSize){
|
||||
if( hasCorrectReserveSize!=p->computeCksm ){
|
||||
p->computeCksm = p->verifyCksm = hasCorrectReserveSize;
|
||||
if( p->pPartner ){
|
||||
p->pPartner->verifyCksm = hasCorrectReserveSize;
|
||||
p->pPartner->computeCksm = hasCorrectReserveSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Read data from a cksm-file.
|
||||
*/
|
||||
@@ -383,22 +398,21 @@ static int cksmRead(
|
||||
if( iOfst==0 && iAmt>=100 && memcmp(zBuf,"SQLite format 3",16)==0 ){
|
||||
u8 *d = (u8*)zBuf;
|
||||
char hasCorrectReserveSize = (d[20]==8);
|
||||
if( hasCorrectReserveSize!=p->computeCksm ){
|
||||
p->computeCksm = p->verifyCksm = hasCorrectReserveSize;
|
||||
}
|
||||
cksmSetFlags(p, hasCorrectReserveSize);
|
||||
}
|
||||
/* Verify the checksum if (1) the size seems appropriate for a database
|
||||
** page, and if (2) checksum verification is enabled. But (3) do not
|
||||
** verify the checksums on a WAL page if the main database file
|
||||
** has subsequently turned off checksums.
|
||||
/* Verify the checksum if
|
||||
** (1) the size indicates that we are dealing with a complete
|
||||
** database page
|
||||
** (2) checksum verification is enabled
|
||||
** (3) we are not in the middle of checkpoint
|
||||
*/
|
||||
if( iAmt>=512 /* (1) */
|
||||
&& p->verifyCksm /* (2) */
|
||||
&& (!p->isWal || (p->pPartner!=0 && p->pPartner->verifyCksm)) /* (3) */
|
||||
&& !p->inCkpt /* (3) */
|
||||
){
|
||||
u8 cksum[8];
|
||||
cksmCompute((u8*)zBuf, iAmt-8, cksum);
|
||||
if( memcmp(zBuf+iAmt-8, cksum, 8)!=0 ){
|
||||
if( memcmp((u8*)zBuf+iAmt-8, cksum, 8)!=0 ){
|
||||
sqlite3_log(SQLITE_IOERR_DATA,
|
||||
"checksum fault offset %lld of \"%s\"",
|
||||
iOfst, p->zFName);
|
||||
@@ -423,9 +437,7 @@ static int cksmWrite(
|
||||
if( iOfst==0 && iAmt>=100 && memcmp(zBuf,"SQLite format 3",16)==0 ){
|
||||
u8 *d = (u8*)zBuf;
|
||||
char hasCorrectReserveSize = (d[20]==8);
|
||||
if( hasCorrectReserveSize!=p->computeCksm ){
|
||||
p->computeCksm = p->verifyCksm = hasCorrectReserveSize;
|
||||
}
|
||||
cksmSetFlags(p, hasCorrectReserveSize);
|
||||
}
|
||||
/* If the write size is appropriate for a database page and if
|
||||
** checksums where ever enabled, then it will be safe to compute
|
||||
@@ -433,7 +445,10 @@ static int cksmWrite(
|
||||
** it will never decrease. And because it cannot decrease, the
|
||||
** checksum will not overwrite anything.
|
||||
*/
|
||||
if( iAmt>=512 && p->computeCksm ){
|
||||
if( iAmt>=512
|
||||
&& p->computeCksm
|
||||
&& !p->inCkpt
|
||||
){
|
||||
cksmCompute((u8*)zBuf, iAmt-8, ((u8*)zBuf)+iAmt-8);
|
||||
}
|
||||
return pFile->pMethods->xWrite(pFile, zBuf, iAmt, iOfst);
|
||||
@@ -510,6 +525,7 @@ static int cksmFileControl(sqlite3_file *pFile, int op, void *pArg){
|
||||
}else{
|
||||
p->verifyCksm = 0;
|
||||
}
|
||||
if( p->pPartner ) p->pPartner->verifyCksm = p->verifyCksm;
|
||||
}
|
||||
azArg[0] = sqlite3_mprintf("%d",p->verifyCksm);
|
||||
return SQLITE_OK;
|
||||
@@ -518,6 +534,9 @@ static int cksmFileControl(sqlite3_file *pFile, int op, void *pArg){
|
||||
/* Do not allow page size changes on a checksum database */
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}else if( op==SQLITE_FCNTL_CKPT_START || op==SQLITE_FCNTL_CKPT_DONE ){
|
||||
p->inCkpt = op==SQLITE_FCNTL_CKPT_START;
|
||||
if( p->pPartner ) p->pPartner->inCkpt = p->inCkpt;
|
||||
}
|
||||
rc = pFile->pMethods->xFileControl(pFile, op, pArg);
|
||||
if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){
|
||||
@@ -724,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,619 @@
|
||||
/*
|
||||
** 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>
|
||||
|
||||
|
||||
/* 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);
|
||||
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;
|
||||
|
||||
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;
|
||||
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);
|
||||
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);
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
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 },
|
||||
};
|
||||
int i;
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
|
||||
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,
|
||||
|
||||
+161
-21
@@ -26,10 +26,64 @@
|
||||
**
|
||||
** 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
|
||||
@@ -51,8 +105,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]);
|
||||
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 +131,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 +165,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 +178,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 +193,49 @@ static void ieee754func(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Functions to convert between blobs and floats.
|
||||
*/
|
||||
static void ieee754func_from_blob(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
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]);
|
||||
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
|
||||
){
|
||||
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)];
|
||||
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 +245,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 },
|
||||
|
||||
};
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -254,6 +254,7 @@ static int jsonGrow(JsonString *p, u32 N){
|
||||
/* Append N bytes from zIn onto the end of the JsonString string.
|
||||
*/
|
||||
static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
|
||||
if( N==0 ) return;
|
||||
if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return;
|
||||
memcpy(p->zBuf+p->nUsed, zIn, N);
|
||||
p->nUsed += N;
|
||||
|
||||
+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;
|
||||
|
||||
+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);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <zlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
** Implementation of the "sqlar_compress(X)" SQL function.
|
||||
|
||||
+2
-1
@@ -168,7 +168,8 @@ static int stmtColumn(
|
||||
sqlite3_result_int(ctx, sqlite3_stmt_busy(pCur->pStmt));
|
||||
break;
|
||||
}
|
||||
case STMT_COLUMN_MEM: {
|
||||
default: {
|
||||
assert( i==STMT_COLUMN_MEM );
|
||||
i = SQLITE_STMTSTATUS_MEMUSED +
|
||||
STMT_COLUMN_NSCAN - SQLITE_STMTSTATUS_FULLSCAN_STEP;
|
||||
/* Fall thru */
|
||||
|
||||
@@ -45,6 +45,7 @@ static int uintCollFunc(
|
||||
const unsigned char *zA = (const unsigned char*)pKey1;
|
||||
const unsigned char *zB = (const unsigned char*)pKey2;
|
||||
int i=0, j=0, x;
|
||||
(void)notUsed;
|
||||
while( i<nKey1 && j<nKey2 ){
|
||||
x = zA[i] - zB[j];
|
||||
if( isdigit(zA[i]) ){
|
||||
|
||||
+1
-1
@@ -811,7 +811,7 @@ int sqlite3_vfsstat_init(
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = vstatRegister(db, pzErrMsg, pApi);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_auto_extension(vstatRegister);
|
||||
rc = sqlite3_auto_extension((void(*)(void))vstatRegister);
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
|
||||
|
||||
+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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -3479,6 +3479,7 @@ struct SessionApplyCtx {
|
||||
u8 *abPK; /* Boolean array - true if column is in PK */
|
||||
int bStat1; /* True if table is sqlite_stat1 */
|
||||
int bDeferConstraints; /* True to defer constraints */
|
||||
int bInvertConstraints; /* Invert when iterating constraints buffer */
|
||||
SessionBuffer constraints; /* Deferred constraints are stored here */
|
||||
SessionBuffer rebase; /* Rebase information (if any) here */
|
||||
u8 bRebaseStarted; /* If table header is already in rebase */
|
||||
@@ -4251,7 +4252,9 @@ static int sessionRetryConstraints(
|
||||
SessionBuffer cons = pApply->constraints;
|
||||
memset(&pApply->constraints, 0, sizeof(SessionBuffer));
|
||||
|
||||
rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf, 0);
|
||||
rc = sessionChangesetStart(
|
||||
&pIter2, 0, 0, cons.nBuf, cons.aBuf, pApply->bInvertConstraints
|
||||
);
|
||||
if( rc==SQLITE_OK ){
|
||||
size_t nByte = 2*pApply->nCol*sizeof(sqlite3_value*);
|
||||
int rc2;
|
||||
@@ -4318,6 +4321,7 @@ static int sessionChangesetApply(
|
||||
pIter->in.bNoDiscard = 1;
|
||||
memset(&sApply, 0, sizeof(sApply));
|
||||
sApply.bRebase = (ppRebase && pnRebase);
|
||||
sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
|
||||
sqlite3_mutex_enter(sqlite3_db_mutex(db));
|
||||
if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
|
||||
rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
|
||||
|
||||
@@ -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 \
|
||||
@@ -423,6 +424,7 @@ TESTSRC2 = \
|
||||
$(TOP)/src/vdbeaux.c \
|
||||
$(TOP)/src/vdbe.c \
|
||||
$(TOP)/src/vdbemem.c \
|
||||
$(TOP)/src/vdbevtab.c \
|
||||
$(TOP)/src/where.c \
|
||||
$(TOP)/src/wherecode.c \
|
||||
$(TOP)/src/whereexpr.c \
|
||||
@@ -726,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
|
||||
@@ -734,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 \
|
||||
@@ -974,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.
|
||||
@@ -1075,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 @@
|
||||
baa720e4a88f268ed95337daab5f434fd3263b00f09101cddc6424765bf3b722
|
||||
9c2b4bdd03716bf492ba85198717f3084ebf187bdb068893bd1ff8662362df89
|
||||
+44
-27
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -123,7 +123,10 @@ void sqlite3AlterRenameTable(
|
||||
/* Check that a table or index named 'zName' does not already exist
|
||||
** in database iDb. If so, this is an error.
|
||||
*/
|
||||
if( sqlite3FindTable(db, zName, zDb) || sqlite3FindIndex(db, zName, zDb) ){
|
||||
if( sqlite3FindTable(db, zName, zDb)
|
||||
|| sqlite3FindIndex(db, zName, zDb)
|
||||
|| sqlite3IsShadowTableOf(db, pTab, zName)
|
||||
){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"there is already another table or index with this name: %s", zName);
|
||||
goto exit_rename_table;
|
||||
@@ -182,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 "
|
||||
@@ -202,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
|
||||
);
|
||||
@@ -223,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 "
|
||||
@@ -255,6 +258,22 @@ exit_rename_table:
|
||||
db->mDbFlags = savedDbFlags;
|
||||
}
|
||||
|
||||
/*
|
||||
** Write code that will raise an error if the table described by
|
||||
** zDb and zTab is not empty.
|
||||
*/
|
||||
static void sqlite3ErrorIfNotEmpty(
|
||||
Parse *pParse, /* Parsing context */
|
||||
const char *zDb, /* Schema holding the table */
|
||||
const char *zTab, /* Table to check for empty */
|
||||
const char *zErr /* Error message text */
|
||||
){
|
||||
sqlite3NestedParse(pParse,
|
||||
"SELECT raise(ABORT,%Q) FROM \"%w\".\"%w\"",
|
||||
zErr, zDb, zTab
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called after an "ALTER TABLE ... ADD" statement
|
||||
** has been parsed. Argument pColDef contains the text of the new
|
||||
@@ -307,7 +326,8 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
||||
return;
|
||||
}
|
||||
if( pNew->pIndex ){
|
||||
sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column");
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"Cannot add a UNIQUE column");
|
||||
return;
|
||||
}
|
||||
if( (pCol->colFlags & COLFLAG_GENERATED)==0 ){
|
||||
@@ -320,16 +340,15 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
||||
pDflt = 0;
|
||||
}
|
||||
if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
|
||||
"Cannot add a REFERENCES column with non-NULL default value");
|
||||
return;
|
||||
}
|
||||
if( pCol->notNull && !pDflt ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
|
||||
"Cannot add a NOT NULL column with default value NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Ensure the default expression is something that sqlite3ValueFromExpr()
|
||||
** can handle (i.e. not CURRENT_TIME etc.)
|
||||
*/
|
||||
@@ -343,14 +362,13 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
||||
return;
|
||||
}
|
||||
if( !pVal ){
|
||||
sqlite3ErrorMsg(pParse,"Cannot add a column with non-constant default");
|
||||
return;
|
||||
sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
|
||||
"Cannot add a column with non-constant default");
|
||||
}
|
||||
sqlite3ValueFree(pVal);
|
||||
}
|
||||
}else if( pCol->colFlags & COLFLAG_STORED ){
|
||||
sqlite3ErrorMsg(pParse, "cannot add a STORED column");
|
||||
return;
|
||||
sqlite3ErrorIfNotEmpty(pParse, zDb, zTab, "cannot add a STORED column");
|
||||
}
|
||||
|
||||
|
||||
@@ -364,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);
|
||||
@@ -569,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);
|
||||
@@ -577,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
|
||||
);
|
||||
|
||||
|
||||
+155
-84
@@ -188,6 +188,11 @@ static void openStatTable(
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
int aRoot[ArraySize(aTable)];
|
||||
u8 aCreateTbl[ArraySize(aTable)];
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
const int nToOpen = OptimizationEnabled(db,SQLITE_Stat4) ? 2 : 1;
|
||||
#else
|
||||
const int nToOpen = 1;
|
||||
#endif
|
||||
|
||||
if( v==0 ) return;
|
||||
assert( sqlite3BtreeHoldsAllMutexes(db) );
|
||||
@@ -200,8 +205,9 @@ static void openStatTable(
|
||||
for(i=0; i<ArraySize(aTable); i++){
|
||||
const char *zTab = aTable[i].zName;
|
||||
Table *pStat;
|
||||
aCreateTbl[i] = 0;
|
||||
if( (pStat = sqlite3FindTable(db, zTab, pDb->zDbSName))==0 ){
|
||||
if( aTable[i].zCols ){
|
||||
if( i<nToOpen ){
|
||||
/* The sqlite_statN table does not exist. Create it. Note that a
|
||||
** side-effect of the CREATE TABLE statement is to leave the rootpage
|
||||
** of the new table in register pParse->regRoot. This is important
|
||||
@@ -217,7 +223,6 @@ static void openStatTable(
|
||||
** associated with the table zWhere. If zWhere is NULL, delete the
|
||||
** entire contents of the table. */
|
||||
aRoot[i] = pStat->tnum;
|
||||
aCreateTbl[i] = 0;
|
||||
sqlite3TableLock(pParse, iDb, aRoot[i], 1, zTab);
|
||||
if( zWhere ){
|
||||
sqlite3NestedParse(pParse,
|
||||
@@ -236,7 +241,7 @@ static void openStatTable(
|
||||
}
|
||||
|
||||
/* Open the sqlite_stat[134] tables for writing. */
|
||||
for(i=0; aTable[i].zCols; i++){
|
||||
for(i=0; i<nToOpen; i++){
|
||||
assert( i<ArraySize(aTable) );
|
||||
sqlite3VdbeAddOp4Int(v, OP_OpenWrite, iStatCur+i, aRoot[i], iDb, 3);
|
||||
sqlite3VdbeChangeP5(v, aCreateTbl[i]);
|
||||
@@ -275,9 +280,12 @@ struct StatSample {
|
||||
};
|
||||
struct StatAccum {
|
||||
sqlite3 *db; /* Database connection, for malloc() */
|
||||
tRowcnt nRow; /* Number of rows in the entire table */
|
||||
tRowcnt nEst; /* Estimated number of rows */
|
||||
tRowcnt nRow; /* Number of rows visited so far */
|
||||
int nLimit; /* Analysis row-scan limit */
|
||||
int nCol; /* Number of columns in index + pk/rowid */
|
||||
int nKeyCol; /* Number of index columns w/o the pk/rowid */
|
||||
u8 nSkipAhead; /* Number of times of skip-ahead */
|
||||
StatSample current; /* Current row as a StatSample */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
tRowcnt nPSample; /* How often to do a periodic sample */
|
||||
@@ -357,27 +365,28 @@ static void sampleCopy(StatAccum *p, StatSample *pTo, StatSample *pFrom){
|
||||
static void statAccumDestructor(void *pOld){
|
||||
StatAccum *p = (StatAccum*)pOld;
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
int i;
|
||||
for(i=0; i<p->nCol; i++) sampleClear(p->db, p->aBest+i);
|
||||
for(i=0; i<p->mxSample; i++) sampleClear(p->db, p->a+i);
|
||||
sampleClear(p->db, &p->current);
|
||||
if( p->mxSample ){
|
||||
int i;
|
||||
for(i=0; i<p->nCol; i++) sampleClear(p->db, p->aBest+i);
|
||||
for(i=0; i<p->mxSample; i++) sampleClear(p->db, p->a+i);
|
||||
sampleClear(p->db, &p->current);
|
||||
}
|
||||
#endif
|
||||
sqlite3DbFree(p->db, p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the stat_init(N,K,C) SQL function. The three parameters
|
||||
** Implementation of the stat_init(N,K,C,L) SQL function. The four parameters
|
||||
** are:
|
||||
** N: The number of columns in the index including the rowid/pk (note 1)
|
||||
** K: The number of columns in the index excluding the rowid/pk.
|
||||
** C: The number of rows in the index (note 2)
|
||||
** C: Estimated number of rows in the index
|
||||
** L: A limit on the number of rows to scan, or 0 for no-limit
|
||||
**
|
||||
** Note 1: In the special case of the covering index that implements a
|
||||
** WITHOUT ROWID table, N is the number of PRIMARY KEY columns, not the
|
||||
** total number of columns in the table.
|
||||
**
|
||||
** Note 2: C is only used for STAT4.
|
||||
**
|
||||
** For indexes on ordinary rowid tables, N==K+1. But for indexes on
|
||||
** WITHOUT ROWID tables, N=K+P where P is the number of columns in the
|
||||
** PRIMARY KEY of the table. The covering index that implements the
|
||||
@@ -398,9 +407,10 @@ static void statInit(
|
||||
int nKeyCol; /* Number of key columns */
|
||||
int nColUp; /* nCol rounded up for alignment */
|
||||
int n; /* Bytes of space to allocate */
|
||||
sqlite3 *db; /* Database connection */
|
||||
sqlite3 *db = sqlite3_context_db_handle(context); /* Database connection */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
int mxSample = SQLITE_STAT4_SAMPLES;
|
||||
/* Maximum number of samples. 0 if STAT4 data is not collected */
|
||||
int mxSample = OptimizationEnabled(db,SQLITE_Stat4) ?SQLITE_STAT4_SAMPLES :0;
|
||||
#endif
|
||||
|
||||
/* Decode the three function arguments */
|
||||
@@ -415,13 +425,14 @@ static void statInit(
|
||||
/* Allocate the space required for the StatAccum object */
|
||||
n = sizeof(*p)
|
||||
+ sizeof(tRowcnt)*nColUp /* StatAccum.anEq */
|
||||
+ sizeof(tRowcnt)*nColUp /* StatAccum.anDLt */
|
||||
+ sizeof(tRowcnt)*nColUp; /* StatAccum.anDLt */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
+ sizeof(tRowcnt)*nColUp /* StatAccum.anLt */
|
||||
+ sizeof(StatSample)*(nCol+mxSample) /* StatAccum.aBest[], a[] */
|
||||
+ sizeof(tRowcnt)*3*nColUp*(nCol+mxSample)
|
||||
if( mxSample ){
|
||||
n += sizeof(tRowcnt)*nColUp /* StatAccum.anLt */
|
||||
+ sizeof(StatSample)*(nCol+mxSample) /* StatAccum.aBest[], a[] */
|
||||
+ sizeof(tRowcnt)*3*nColUp*(nCol+mxSample);
|
||||
}
|
||||
#endif
|
||||
;
|
||||
db = sqlite3_context_db_handle(context);
|
||||
p = sqlite3DbMallocZero(db, n);
|
||||
if( p==0 ){
|
||||
@@ -430,20 +441,23 @@ static void statInit(
|
||||
}
|
||||
|
||||
p->db = db;
|
||||
p->nEst = sqlite3_value_int64(argv[2]);
|
||||
p->nRow = 0;
|
||||
p->nLimit = sqlite3_value_int64(argv[3]);
|
||||
p->nCol = nCol;
|
||||
p->nKeyCol = nKeyCol;
|
||||
p->nSkipAhead = 0;
|
||||
p->current.anDLt = (tRowcnt*)&p[1];
|
||||
p->current.anEq = &p->current.anDLt[nColUp];
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
{
|
||||
p->mxSample = p->nLimit==0 ? mxSample : 0;
|
||||
if( mxSample ){
|
||||
u8 *pSpace; /* Allocated space not yet assigned */
|
||||
int i; /* Used to iterate through p->aSample[] */
|
||||
|
||||
p->iGet = -1;
|
||||
p->mxSample = mxSample;
|
||||
p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[2])/(mxSample/3+1) + 1);
|
||||
p->nPSample = (tRowcnt)(p->nEst/(mxSample/3+1) + 1);
|
||||
p->current.anLt = &p->current.anEq[nColUp];
|
||||
p->iPrn = 0x689e962d*(u32)nCol ^ 0xd0944565*(u32)sqlite3_value_int(argv[2]);
|
||||
|
||||
@@ -471,7 +485,7 @@ static void statInit(
|
||||
sqlite3_result_blob(context, p, sizeof(*p), statAccumDestructor);
|
||||
}
|
||||
static const FuncDef statInitFuncdef = {
|
||||
2+IsStat4, /* nArg */
|
||||
4, /* nArg */
|
||||
SQLITE_UTF8, /* funcFlags */
|
||||
0, /* pUserData */
|
||||
0, /* pNext */
|
||||
@@ -675,10 +689,13 @@ static void samplePushPrevious(StatAccum *p, int iChng){
|
||||
** R Rowid for the current row. Might be a key record for
|
||||
** WITHOUT ROWID tables.
|
||||
**
|
||||
** This SQL function always returns NULL. It's purpose it to accumulate
|
||||
** statistical data and/or samples in the StatAccum object about the
|
||||
** index being analyzed. The stat_get() SQL function will later be used to
|
||||
** extract relevant information for constructing the sqlite_statN tables.
|
||||
** The purpose of this routine is to collect statistical data and/or
|
||||
** samples from the index being analyzed into the StatAccum object.
|
||||
** The stat_get() SQL function will be used afterwards to
|
||||
** retrieve the information gathered.
|
||||
**
|
||||
** This SQL function usually returns NULL, but might return an integer
|
||||
** if it wants the byte-code to do special processing.
|
||||
**
|
||||
** The R parameter is only used for STAT4
|
||||
*/
|
||||
@@ -704,7 +721,7 @@ static void statPush(
|
||||
}else{
|
||||
/* Second and subsequent calls get processed here */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
samplePushPrevious(p, iChng);
|
||||
if( p->mxSample ) samplePushPrevious(p, iChng);
|
||||
#endif
|
||||
|
||||
/* Update anDLt[], anLt[] and anEq[] to reflect the values that apply
|
||||
@@ -715,26 +732,25 @@ static void statPush(
|
||||
for(i=iChng; i<p->nCol; i++){
|
||||
p->current.anDLt[i]++;
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
p->current.anLt[i] += p->current.anEq[i];
|
||||
if( p->mxSample ) p->current.anLt[i] += p->current.anEq[i];
|
||||
#endif
|
||||
p->current.anEq[i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
p->nRow++;
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
if( sqlite3_value_type(argv[2])==SQLITE_INTEGER ){
|
||||
sampleSetRowidInt64(p->db, &p->current, sqlite3_value_int64(argv[2]));
|
||||
}else{
|
||||
sampleSetRowid(p->db, &p->current, sqlite3_value_bytes(argv[2]),
|
||||
sqlite3_value_blob(argv[2]));
|
||||
}
|
||||
p->current.iHash = p->iPrn = p->iPrn*1103515245 + 12345;
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
{
|
||||
tRowcnt nLt = p->current.anLt[p->nCol-1];
|
||||
if( p->mxSample ){
|
||||
tRowcnt nLt;
|
||||
if( sqlite3_value_type(argv[2])==SQLITE_INTEGER ){
|
||||
sampleSetRowidInt64(p->db, &p->current, sqlite3_value_int64(argv[2]));
|
||||
}else{
|
||||
sampleSetRowid(p->db, &p->current, sqlite3_value_bytes(argv[2]),
|
||||
sqlite3_value_blob(argv[2]));
|
||||
}
|
||||
p->current.iHash = p->iPrn = p->iPrn*1103515245 + 12345;
|
||||
|
||||
nLt = p->current.anLt[p->nCol-1];
|
||||
/* Check if this is to be a periodic sample. If so, add it. */
|
||||
if( (nLt/p->nPSample)!=(nLt+1)/p->nPSample ){
|
||||
p->current.isPSample = 1;
|
||||
@@ -750,9 +766,14 @@ static void statPush(
|
||||
sampleCopy(p, &p->aBest[i], &p->current);
|
||||
}
|
||||
}
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
if( p->nLimit && p->nRow>(tRowcnt)p->nLimit*(p->nSkipAhead+1) ){
|
||||
p->nSkipAhead++;
|
||||
sqlite3_result_int(context, p->current.anDLt[0]>0);
|
||||
}
|
||||
}
|
||||
|
||||
static const FuncDef statPushFuncdef = {
|
||||
2+IsStat4, /* nArg */
|
||||
SQLITE_UTF8, /* funcFlags */
|
||||
@@ -804,6 +825,7 @@ static void statGet(
|
||||
|| eCall==STAT_GET_ROWID || eCall==STAT_GET_NLT
|
||||
|| eCall==STAT_GET_NDLT
|
||||
);
|
||||
assert( eCall==STAT_GET_STAT1 || p->mxSample );
|
||||
if( eCall==STAT_GET_STAT1 )
|
||||
#else
|
||||
assert( argc==1 );
|
||||
@@ -839,7 +861,8 @@ static void statGet(
|
||||
return;
|
||||
}
|
||||
|
||||
sqlite3_snprintf(24, zRet, "%llu", (u64)p->nRow);
|
||||
sqlite3_snprintf(24, zRet, "%llu",
|
||||
p->nSkipAhead ? (u64)p->nEst : (u64)p->nRow);
|
||||
z = zRet + sqlite3Strlen30(zRet);
|
||||
for(i=0; i<p->nKeyCol; i++){
|
||||
u64 nDistinct = p->current.anDLt[i] + 1;
|
||||
@@ -915,19 +938,43 @@ static const FuncDef statGetFuncdef = {
|
||||
{0}
|
||||
};
|
||||
|
||||
static void callStatGet(Parse *pParse, int regStat4, int iParam, int regOut){
|
||||
static void callStatGet(Parse *pParse, int regStat, int iParam, int regOut){
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
sqlite3VdbeAddOp2(pParse->pVdbe, OP_Integer, iParam, regStat4+1);
|
||||
sqlite3VdbeAddOp2(pParse->pVdbe, OP_Integer, iParam, regStat+1);
|
||||
#elif SQLITE_DEBUG
|
||||
assert( iParam==STAT_GET_STAT1 );
|
||||
#else
|
||||
UNUSED_PARAMETER( iParam );
|
||||
#endif
|
||||
assert( regOut!=regStat4 && regOut!=regStat4+1 );
|
||||
sqlite3VdbeAddFunctionCall(pParse, 0, regStat4, regOut, 1+IsStat4,
|
||||
assert( regOut!=regStat && regOut!=regStat+1 );
|
||||
sqlite3VdbeAddFunctionCall(pParse, 0, regStat, regOut, 1+IsStat4,
|
||||
&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.
|
||||
@@ -950,12 +997,11 @@ static void analyzeOneTable(
|
||||
int iDb; /* Index of database containing pTab */
|
||||
u8 needTableCnt = 1; /* True to count the table */
|
||||
int regNewRowid = iMem++; /* Rowid for the inserted record */
|
||||
int regStat4 = iMem++; /* Register to hold StatAccum object */
|
||||
int regStat = iMem++; /* Register to hold StatAccum object */
|
||||
int regChng = iMem++; /* Index of changed index field */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
int regRowid = iMem++; /* Rowid argument passed to stat_push() */
|
||||
#endif
|
||||
int regTemp = iMem++; /* Temporary use register */
|
||||
int regTemp2 = iMem++; /* Second temporary use register */
|
||||
int regTabname = iMem++; /* Register containing table name */
|
||||
int regIdxname = iMem++; /* Register containing index name */
|
||||
int regStat1 = iMem++; /* Value for the stat column of sqlite_stat1 */
|
||||
@@ -1083,17 +1129,26 @@ static void analyzeOneTable(
|
||||
** (1) the number of columns in the index including the rowid
|
||||
** (or for a WITHOUT ROWID table, the number of PK columns),
|
||||
** (2) the number of columns in the key without the rowid/pk
|
||||
** (3) the number of rows in the index,
|
||||
**
|
||||
**
|
||||
** The third argument is only used for STAT4
|
||||
** (3) estimated number of rows in the index,
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat+1);
|
||||
assert( regRowid==regStat+2 );
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regRowid);
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+3);
|
||||
if( OptimizationEnabled(db, SQLITE_Stat4) ){
|
||||
sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regTemp);
|
||||
addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
|
||||
VdbeCoverage(v);
|
||||
}else
|
||||
#endif
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2);
|
||||
sqlite3VdbeAddFunctionCall(pParse, 0, regStat4+1, regStat4, 2+IsStat4,
|
||||
{
|
||||
addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_Count, iIdxCur, regTemp, 1);
|
||||
}
|
||||
assert( regTemp2==regStat+4 );
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, db->nAnalysisLimit, regTemp2);
|
||||
sqlite3VdbeAddFunctionCall(pParse, 0, regStat+1, regStat, 4,
|
||||
&statInitFuncdef, 0);
|
||||
|
||||
/* Implementation of the following:
|
||||
@@ -1104,8 +1159,6 @@ static void analyzeOneTable(
|
||||
** goto next_push_0;
|
||||
**
|
||||
*/
|
||||
addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng);
|
||||
addrNextRow = sqlite3VdbeCurrentAddr(v);
|
||||
|
||||
@@ -1138,6 +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);
|
||||
analyzeVdbeCommentIndexWithColumnName(v,pIdx,i);
|
||||
aGotoChng[i] =
|
||||
sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, regPrev+i, pColl, P4_COLLSEQ);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
|
||||
@@ -1158,6 +1212,7 @@ static void analyzeOneTable(
|
||||
for(i=0; i<nColTest; i++){
|
||||
sqlite3VdbeJumpHere(v, aGotoChng[i]);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regPrev+i);
|
||||
analyzeVdbeCommentIndexWithColumnName(v,pIdx,i);
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, endDistinctTest);
|
||||
sqlite3DbFree(db, aGotoChng);
|
||||
@@ -1171,30 +1226,46 @@ static void analyzeOneTable(
|
||||
** if !eof(csr) goto next_row;
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
assert( regRowid==(regStat4+2) );
|
||||
if( HasRowid(pTab) ){
|
||||
sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, regRowid);
|
||||
}else{
|
||||
Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
|
||||
int j, k, regKey;
|
||||
regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
|
||||
for(j=0; j<pPk->nKeyCol; j++){
|
||||
k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]);
|
||||
assert( k>=0 && k<pIdx->nColumn );
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
|
||||
VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName));
|
||||
if( OptimizationEnabled(db, SQLITE_Stat4) ){
|
||||
assert( regRowid==(regStat+2) );
|
||||
if( HasRowid(pTab) ){
|
||||
sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, regRowid);
|
||||
}else{
|
||||
Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
|
||||
int j, k, regKey;
|
||||
regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
|
||||
for(j=0; j<pPk->nKeyCol; j++){
|
||||
k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]);
|
||||
assert( k>=0 && k<pIdx->nColumn );
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
|
||||
analyzeVdbeCommentIndexWithColumnName(v,pIdx,k);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid);
|
||||
sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid);
|
||||
sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol);
|
||||
}
|
||||
#endif
|
||||
assert( regChng==(regStat4+1) );
|
||||
sqlite3VdbeAddFunctionCall(pParse, 1, regStat4, regTemp, 2+IsStat4,
|
||||
&statPushFuncdef, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
|
||||
assert( regChng==(regStat+1) );
|
||||
{
|
||||
sqlite3VdbeAddFunctionCall(pParse, 1, regStat, regTemp, 2+IsStat4,
|
||||
&statPushFuncdef, 0);
|
||||
if( db->nAnalysisLimit ){
|
||||
int j1, j2, j3;
|
||||
j1 = sqlite3VdbeAddOp1(v, OP_IsNull, regTemp); VdbeCoverage(v);
|
||||
j2 = sqlite3VdbeAddOp1(v, OP_If, regTemp); VdbeCoverage(v);
|
||||
j3 = sqlite3VdbeAddOp4Int(v, OP_SeekGT, iIdxCur, 0, regPrev, 1);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, j2);
|
||||
sqlite3VdbeJumpHere(v, j3);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the entry to the stat1 table. */
|
||||
callStatGet(pParse, regStat4, STAT_GET_STAT1, regStat1);
|
||||
callStatGet(pParse, regStat, STAT_GET_STAT1, regStat1);
|
||||
assert( "BBB"[0]==SQLITE_AFF_TEXT );
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
|
||||
@@ -1206,7 +1277,7 @@ static void analyzeOneTable(
|
||||
|
||||
/* Add the entries to the stat4 table. */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
{
|
||||
if( OptimizationEnabled(db, SQLITE_Stat4) && db->nAnalysisLimit==0 ){
|
||||
int regEq = regStat1;
|
||||
int regLt = regStat1+1;
|
||||
int regDLt = regStat1+2;
|
||||
@@ -1220,12 +1291,12 @@ static void analyzeOneTable(
|
||||
pParse->nMem = MAX(pParse->nMem, regCol+nCol);
|
||||
|
||||
addrNext = sqlite3VdbeCurrentAddr(v);
|
||||
callStatGet(pParse, regStat4, STAT_GET_ROWID, regSampleRowid);
|
||||
callStatGet(pParse, regStat, STAT_GET_ROWID, regSampleRowid);
|
||||
addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regSampleRowid);
|
||||
VdbeCoverage(v);
|
||||
callStatGet(pParse, regStat4, STAT_GET_NEQ, regEq);
|
||||
callStatGet(pParse, regStat4, STAT_GET_NLT, regLt);
|
||||
callStatGet(pParse, regStat4, STAT_GET_NDLT, regDLt);
|
||||
callStatGet(pParse, regStat, STAT_GET_NEQ, regEq);
|
||||
callStatGet(pParse, regStat, STAT_GET_NLT, regLt);
|
||||
callStatGet(pParse, regStat, STAT_GET_NDLT, regDLt);
|
||||
sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0);
|
||||
VdbeCoverage(v);
|
||||
for(i=0; i<nCol; i++){
|
||||
|
||||
+1
-1
@@ -112,7 +112,7 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
|
||||
*/
|
||||
static int setDestPgsz(sqlite3_backup *p){
|
||||
int rc;
|
||||
rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),-1,0);
|
||||
rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),0,0);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
+56
-42
@@ -69,7 +69,7 @@ int sqlite3BtreeTrace=1; /* True to enable tracing */
|
||||
** but the test harness needs to access it so we make it global for
|
||||
** test builds.
|
||||
**
|
||||
** Access to this variable is protected by SQLITE_MUTEX_STATIC_MASTER.
|
||||
** Access to this variable is protected by SQLITE_MUTEX_STATIC_MAIN.
|
||||
*/
|
||||
#ifdef SQLITE_TEST
|
||||
BtShared *SQLITE_WSD sqlite3SharedCacheList = 0;
|
||||
@@ -200,16 +200,18 @@ static int hasSharedCacheTableLock(
|
||||
** table. */
|
||||
if( isIndex ){
|
||||
HashElem *p;
|
||||
int bSeen = 0;
|
||||
for(p=sqliteHashFirst(&pSchema->idxHash); p; p=sqliteHashNext(p)){
|
||||
Index *pIdx = (Index *)sqliteHashData(p);
|
||||
if( pIdx->tnum==(int)iRoot ){
|
||||
if( iTab ){
|
||||
if( bSeen ){
|
||||
/* Two or more indexes share the same root page. There must
|
||||
** be imposter tables. So just return true. The assert is not
|
||||
** useful in that case. */
|
||||
return 1;
|
||||
}
|
||||
iTab = pIdx->pTable->tnum;
|
||||
bSeen = 1;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
@@ -355,7 +357,7 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
|
||||
|
||||
/* A connection with the read-uncommitted flag set will never try to
|
||||
** obtain a read-lock using this function. The only read-lock obtained
|
||||
** by a connection in read-uncommitted mode is on the sqlite_master
|
||||
** by a connection in read-uncommitted mode is on the sqlite_schema
|
||||
** table, and that lock is obtained in BtreeBeginTrans(). */
|
||||
assert( 0==(p->db->flags&SQLITE_ReadUncommit) || eLock==WRITE_LOCK );
|
||||
|
||||
@@ -991,7 +993,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){
|
||||
if( *pRC ) return;
|
||||
|
||||
assert( sqlite3_mutex_held(pBt->mutex) );
|
||||
/* The master-journal page number must never be used as a pointer map page */
|
||||
/* The super-journal page number must never be used as a pointer map page */
|
||||
assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) );
|
||||
|
||||
assert( pBt->autoVacuum );
|
||||
@@ -1751,7 +1753,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
||||
nFrag = iFreeBlk - iEnd;
|
||||
if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage);
|
||||
iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]);
|
||||
if( NEVER(iEnd > pPage->pBt->usableSize) ){
|
||||
if( iEnd > pPage->pBt->usableSize ){
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
iSize = iEnd - iStart;
|
||||
@@ -2304,8 +2306,7 @@ static int btreeInvokeBusyHandler(void *pArg){
|
||||
BtShared *pBt = (BtShared*)pArg;
|
||||
assert( pBt->db );
|
||||
assert( sqlite3_mutex_held(pBt->db->mutex) );
|
||||
return sqlite3InvokeBusyHandler(&pBt->db->busyHandler,
|
||||
sqlite3PagerFile(pBt->pPager));
|
||||
return sqlite3InvokeBusyHandler(&pBt->db->busyHandler);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2421,7 +2422,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){
|
||||
@@ -2540,7 +2541,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 ){
|
||||
@@ -2629,13 +2630,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 ){
|
||||
@@ -2654,7 +2655,7 @@ static int removeFromSharingList(BtShared *pBt){
|
||||
}
|
||||
removed = 1;
|
||||
}
|
||||
sqlite3_mutex_leave(pMaster);
|
||||
sqlite3_mutex_leave(pMainMtx);
|
||||
return removed;
|
||||
#else
|
||||
return 1;
|
||||
@@ -2856,19 +2857,17 @@ int sqlite3BtreeSetPagerFlags(
|
||||
*/
|
||||
int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){
|
||||
int rc = SQLITE_OK;
|
||||
int x;
|
||||
BtShared *pBt = p->pBt;
|
||||
assert( nReserve>=-1 && nReserve<=254 );
|
||||
assert( nReserve>=0 && nReserve<=255 );
|
||||
sqlite3BtreeEnter(p);
|
||||
if( nReserve>=0 ){
|
||||
pBt->nReserveWanted = nReserve + 1;
|
||||
}
|
||||
pBt->nReserveWanted = nReserve;
|
||||
x = pBt->pageSize - pBt->usableSize;
|
||||
if( nReserve<x ) nReserve = x;
|
||||
if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){
|
||||
sqlite3BtreeLeave(p);
|
||||
return SQLITE_READONLY;
|
||||
}
|
||||
if( nReserve<0 ){
|
||||
nReserve = pBt->pageSize - pBt->usableSize;
|
||||
}
|
||||
assert( nReserve>=0 && nReserve<=255 );
|
||||
if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE &&
|
||||
((pageSize-1)&pageSize)==0 ){
|
||||
@@ -2919,12 +2918,12 @@ int sqlite3BtreeGetReserveNoMutex(Btree *p){
|
||||
** The amount of reserve can only grow - never shrink.
|
||||
*/
|
||||
int sqlite3BtreeGetRequestedReserve(Btree *p){
|
||||
int n;
|
||||
int n1, n2;
|
||||
sqlite3BtreeEnter(p);
|
||||
n = ((int)p->pBt->nReserveWanted) - 1;
|
||||
if( n<0 ) n = sqlite3BtreeGetReserveNoMutex(p);
|
||||
n1 = (int)p->pBt->nReserveWanted;
|
||||
n2 = sqlite3BtreeGetReserveNoMutex(p);
|
||||
sqlite3BtreeLeave(p);
|
||||
return n;
|
||||
return n1>n2 ? n1 : n2;
|
||||
}
|
||||
|
||||
|
||||
@@ -3374,6 +3373,7 @@ int sqlite3BtreeNewDb(Btree *p){
|
||||
*/
|
||||
int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
|
||||
BtShared *pBt = p->pBt;
|
||||
Pager *pPager = pBt->pPager;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
sqlite3BtreeEnter(p);
|
||||
@@ -3389,7 +3389,7 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
|
||||
assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 );
|
||||
|
||||
if( (p->db->flags & SQLITE_ResetDatabase)
|
||||
&& sqlite3PagerIsreadonly(pBt->pPager)==0
|
||||
&& sqlite3PagerIsreadonly(pPager)==0
|
||||
){
|
||||
pBt->btsFlags &= ~BTS_READ_ONLY;
|
||||
}
|
||||
@@ -3431,12 +3431,24 @@ 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;
|
||||
if( pBt->nPage==0 ) pBt->btsFlags |= BTS_INITIALLY_EMPTY;
|
||||
do {
|
||||
sqlite3PagerWalDb(pPager, p->db);
|
||||
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
/* If transitioning from no transaction directly to a write transaction,
|
||||
** block for the WRITER lock first if possible. */
|
||||
if( pBt->pPage1==0 && wrflag ){
|
||||
assert( pBt->inTransaction==TRANS_NONE );
|
||||
rc = sqlite3PagerWalWriteLock(pPager, 1);
|
||||
if( rc!=SQLITE_BUSY && rc!=SQLITE_OK ) break;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Call lockBtree() until either pBt->pPage1 is populated or
|
||||
** lockBtree() returns something other than SQLITE_OK. lockBtree()
|
||||
** may return SQLITE_OK but leave pBt->pPage1 set to 0 if after
|
||||
@@ -3450,7 +3462,7 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
|
||||
if( (pBt->btsFlags & BTS_READ_ONLY)!=0 ){
|
||||
rc = SQLITE_READONLY;
|
||||
}else{
|
||||
rc = sqlite3PagerBegin(pBt->pPager,wrflag>1,sqlite3TempInMemory(p->db));
|
||||
rc = sqlite3PagerBegin(pPager, wrflag>1, sqlite3TempInMemory(p->db));
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = newDatabase(pBt);
|
||||
}else if( rc==SQLITE_BUSY_SNAPSHOT && pBt->inTransaction==TRANS_NONE ){
|
||||
@@ -3463,11 +3475,15 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
(void)sqlite3PagerWalWriteLock(pPager, 0);
|
||||
unlockBtreeIfUnused(pBt);
|
||||
}
|
||||
}while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
|
||||
btreeInvokeBusyHandler(pBt) );
|
||||
sqlite3PagerResetLockTimeout(pBt->pPager);
|
||||
sqlite3PagerWalDb(pPager, 0);
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY;
|
||||
#endif
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
if( p->inTrans==TRANS_NONE ){
|
||||
@@ -3519,7 +3535,7 @@ trans_begun:
|
||||
** open savepoints. If the second parameter is greater than 0 and
|
||||
** the sub-journal is not already open, then it will be opened here.
|
||||
*/
|
||||
rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint);
|
||||
rc = sqlite3PagerOpenSavepoint(pPager, p->db->nSavepoint);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3967,18 +3983,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;
|
||||
@@ -3995,7 +4011,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;
|
||||
@@ -4058,7 +4074,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
|
||||
@@ -7155,7 +7171,7 @@ static int editPage(
|
||||
assert( nCell>=0 );
|
||||
if( iOld<iNew ){
|
||||
int nShift = pageFreeArray(pPg, iOld, iNew-iOld, pCArray);
|
||||
if( nShift>nCell ) return SQLITE_CORRUPT_BKPT;
|
||||
if( NEVER(nShift>nCell) ) return SQLITE_CORRUPT_BKPT;
|
||||
memmove(pPg->aCellIdx, &pPg->aCellIdx[nShift*2], nCell*2);
|
||||
nCell -= nShift;
|
||||
}
|
||||
@@ -9463,7 +9479,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 );
|
||||
|
||||
@@ -9512,7 +9528,6 @@ int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_BTREECOUNT
|
||||
/*
|
||||
** The first argument, pCur, is a cursor opened on some b-tree. Count the
|
||||
** number of entries in the b-tree and write the result to *pnEntry.
|
||||
@@ -9585,7 +9600,6 @@ int sqlite3BtreeCount(sqlite3 *db, BtCursor *pCur, i64 *pnEntry){
|
||||
/* An error has occurred. Return an error code. */
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Return the pager associated with a BTree. This routine is used for
|
||||
@@ -10342,13 +10356,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;
|
||||
|
||||
+1
-3
@@ -79,7 +79,7 @@ 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);
|
||||
@@ -336,9 +336,7 @@ int sqlite3BtreeCursorIsValid(BtCursor*);
|
||||
#endif
|
||||
int sqlite3BtreeCursorIsValidNN(BtCursor*);
|
||||
|
||||
#ifndef SQLITE_OMIT_BTREECOUNT
|
||||
int sqlite3BtreeCount(sqlite3*, BtCursor*, i64*);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
|
||||
|
||||
+2
-2
@@ -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.
|
||||
@@ -417,7 +417,7 @@ struct BtShared {
|
||||
#endif
|
||||
u8 inTransaction; /* Transaction state */
|
||||
u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
|
||||
u8 nReserveWanted; /* 1 more than desired number of extra bytes per page */
|
||||
u8 nReserveWanted; /* Desired number of extra bytes per page */
|
||||
u16 btsFlags; /* Boolean parameters. See BTS_* macros below */
|
||||
u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
|
||||
u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */
|
||||
|
||||
+155
-81
@@ -207,12 +207,21 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
*/
|
||||
sqlite3AutoincrementBegin(pParse);
|
||||
|
||||
/* Code constant expressions that where factored out of inner loops */
|
||||
/* Code constant expressions that where factored out of inner loops.
|
||||
**
|
||||
** The pConstExpr list might also contain expressions that we simply
|
||||
** want to keep around until the Parse object is deleted. Such
|
||||
** expressions have iConstExprReg==0. Do not generate code for
|
||||
** those expressions, of course.
|
||||
*/
|
||||
if( pParse->pConstExpr ){
|
||||
ExprList *pEL = pParse->pConstExpr;
|
||||
pParse->okConstFactor = 0;
|
||||
for(i=0; i<pEL->nExpr; i++){
|
||||
sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg);
|
||||
int iReg = pEL->a[i].u.iConstExprReg;
|
||||
if( iReg>0 ){
|
||||
sqlite3ExprCode(pParse, pEL->a[i].pExpr, iReg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,7 +253,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
** outermost parser.
|
||||
**
|
||||
** Not everything is nestable. This facility is designed to permit
|
||||
** INSERT, UPDATE, and DELETE operations against SQLITE_MASTER. Use
|
||||
** INSERT, UPDATE, and DELETE operations against the schema table. Use
|
||||
** care if you decide to try to use this routine for some other purposes.
|
||||
*/
|
||||
void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
|
||||
@@ -312,22 +321,59 @@ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
while(1){
|
||||
for(i=OMIT_TEMPDB; i<db->nDb; i++){
|
||||
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
|
||||
if( zDatabase==0 || sqlite3DbIsNamed(db, j, zDatabase) ){
|
||||
assert( sqlite3SchemaMutexHeld(db, j, 0) );
|
||||
p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
|
||||
if( p ) return p;
|
||||
if( zDatabase ){
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( sqlite3StrICmp(zDatabase, db->aDb[i].zDbSName)==0 ) break;
|
||||
}
|
||||
if( i>=db->nDb ){
|
||||
/* No match against the official names. But always match "main"
|
||||
** to schema 0 as a legacy fallback. */
|
||||
if( sqlite3StrICmp(zDatabase,"main")==0 ){
|
||||
i = 0;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName);
|
||||
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 */
|
||||
p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, zName);
|
||||
if( p ) return p;
|
||||
/* The main database is second */
|
||||
p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, zName);
|
||||
if( p ) return p;
|
||||
/* Attached databases are in order of attachment */
|
||||
for(i=2; i<db->nDb; i++){
|
||||
assert( sqlite3SchemaMutexHeld(db, i, 0) );
|
||||
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);
|
||||
}
|
||||
}
|
||||
/* Not found. If the name we were looking for was temp.sqlite_master
|
||||
** then change the name to sqlite_temp_master and try again. */
|
||||
if( sqlite3StrICmp(zName, MASTER_NAME)!=0 ) break;
|
||||
if( sqlite3_stricmp(zDatabase, db->aDb[1].zDbSName)!=0 ) break;
|
||||
zName = TEMP_MASTER_NAME;
|
||||
}
|
||||
return 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -717,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;
|
||||
}
|
||||
@@ -831,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.
|
||||
*/
|
||||
@@ -1003,7 +1049,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;
|
||||
@@ -1109,7 +1155,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
|
||||
@@ -1145,7 +1191,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().
|
||||
**
|
||||
@@ -1163,7 +1209,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);
|
||||
@@ -1973,9 +2019,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
|
||||
@@ -2062,7 +2108,7 @@ 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). */
|
||||
@@ -2131,6 +2177,28 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
recomputeColumnsNotIndexed(pPk);
|
||||
}
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
/*
|
||||
** Return true if pTab is a virtual table and zName is a shadow table name
|
||||
** for that virtual table.
|
||||
*/
|
||||
int sqlite3IsShadowTableOf(sqlite3 *db, Table *pTab, const char *zName){
|
||||
int nName; /* Length of zName */
|
||||
Module *pMod; /* Module for the virtual table */
|
||||
|
||||
if( !IsVirtual(pTab) ) return 0;
|
||||
nName = sqlite3Strlen30(pTab->zName);
|
||||
if( sqlite3_strnicmp(zName, pTab->zName, nName)!=0 ) return 0;
|
||||
if( zName[nName]!='_' ) return 0;
|
||||
pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->azModuleArg[0]);
|
||||
if( pMod==0 ) return 0;
|
||||
if( pMod->pModule->iVersion<3 ) return 0;
|
||||
if( pMod->pModule->xShadowName==0 ) return 0;
|
||||
return pMod->pModule->xShadowName(zName+nName+1);
|
||||
}
|
||||
#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
/*
|
||||
** Return true if zName is a shadow table name in the current database
|
||||
@@ -2142,8 +2210,6 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
int sqlite3ShadowTableName(sqlite3 *db, const char *zName){
|
||||
char *zTail; /* Pointer to the last "_" in zName */
|
||||
Table *pTab; /* Table that zName is a shadow of */
|
||||
Module *pMod; /* Module for the virtual table */
|
||||
|
||||
zTail = strrchr(zName, '_');
|
||||
if( zTail==0 ) return 0;
|
||||
*zTail = 0;
|
||||
@@ -2151,14 +2217,11 @@ int sqlite3ShadowTableName(sqlite3 *db, const char *zName){
|
||||
*zTail = '_';
|
||||
if( pTab==0 ) return 0;
|
||||
if( !IsVirtual(pTab) ) return 0;
|
||||
pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->azModuleArg[0]);
|
||||
if( pMod==0 ) return 0;
|
||||
if( pMod->pModule->iVersion<3 ) return 0;
|
||||
if( pMod->pModule->xShadowName==0 ) return 0;
|
||||
return pMod->pModule->xShadowName(zTail+1);
|
||||
return sqlite3IsShadowTableOf(db, pTab, zName);
|
||||
}
|
||||
#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
** Mark all nodes of an expression as EP_Immutable, indicating that
|
||||
@@ -2193,12 +2256,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
|
||||
@@ -2229,12 +2292,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 ){
|
||||
@@ -2321,7 +2384,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.
|
||||
@@ -2423,14 +2486,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,
|
||||
@@ -2558,7 +2621,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:
|
||||
@@ -2773,7 +2836,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).
|
||||
*/
|
||||
@@ -2786,7 +2849,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
|
||||
@@ -2794,15 +2857,16 @@ static void destroyRootPage(Parse *pParse, int iTable, int iDb){
|
||||
** token for additional information.
|
||||
*/
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE %Q.%s SET rootpage=%d WHERE #%d AND rootpage=#%d",
|
||||
pParse->db->aDb[iDb].zDbSName, MASTER_NAME, iTable, r1, r1);
|
||||
"UPDATE %Q." DFLT_SCHEMA_TABLE
|
||||
" SET rootpage=%d WHERE #%d AND rootpage=#%d",
|
||||
pParse->db->aDb[iDb].zDbSName, iTable, r1, r1);
|
||||
#endif
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Write VDBE code to erase table pTab and all associated indices on disk.
|
||||
** Code to update the sqlite_master tables and internal schema definitions
|
||||
** Code to update the sqlite_schema tables and internal schema definitions
|
||||
** in case a root-page belonging to another table is moved by the btree layer
|
||||
** is also added (this can happen with an auto-vacuum database).
|
||||
*/
|
||||
@@ -2895,8 +2959,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 ){
|
||||
@@ -2920,16 +2984,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);
|
||||
}
|
||||
@@ -3065,7 +3130,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);
|
||||
@@ -3519,10 +3584,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;
|
||||
}
|
||||
@@ -3544,7 +3606,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.
|
||||
**
|
||||
@@ -3888,8 +3950,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.
|
||||
**
|
||||
@@ -3933,11 +3995,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,
|
||||
@@ -4013,9 +4075,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;
|
||||
|
||||
@@ -4024,10 +4087,21 @@ void sqlite3DefaultRowEst(Index *pIdx){
|
||||
|
||||
/* Set the first entry (number of rows in the index) to the estimated
|
||||
** number of rows in the table, or half the number of rows in the table
|
||||
** for a partial index. But do not let the estimate drop below 10. */
|
||||
a[0] = pIdx->pTable->nRowLogEst;
|
||||
if( pIdx->pPartIdxWhere!=0 ) a[0] -= 10; assert( 10==sqlite3LogEst(2) );
|
||||
if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) );
|
||||
** for a partial index.
|
||||
**
|
||||
** 2020-05-27: If some of the stat data is coming from the sqlite_stat1
|
||||
** table but other parts we are having to guess at, then do not let the
|
||||
** estimated number of rows in the table be less than 1000 (LogEst 99).
|
||||
** Failure to do this can cause the indexes for which we do not have
|
||||
** stat1 data to be ignored by the query planner. tag-20200527-1
|
||||
*/
|
||||
x = pIdx->pTable->nRowLogEst;
|
||||
assert( 99==sqlite3LogEst(1000) );
|
||||
if( x<99 ){
|
||||
pIdx->pTable->nRowLogEst = x = 99;
|
||||
}
|
||||
if( pIdx->pPartIdxWhere!=0 ) x -= 10; assert( 10==sqlite3LogEst(2) );
|
||||
a[0] = x;
|
||||
|
||||
/* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is
|
||||
** 6 and each subsequent value (if any) is 5. */
|
||||
@@ -4090,13 +4164,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);
|
||||
@@ -4630,7 +4704,7 @@ int sqlite3OpenTempDatabase(Parse *pParse){
|
||||
}
|
||||
db->aDb[1].pBt = pBt;
|
||||
assert( db->aDb[1].pSchema );
|
||||
if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
|
||||
if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, 0, 0) ){
|
||||
sqlite3OomFault(db);
|
||||
return 1;
|
||||
}
|
||||
@@ -4741,7 +4815,7 @@ void sqlite3HaltConstraint(
|
||||
u8 p5Errmsg /* P5_ErrMsg type */
|
||||
){
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
assert( (errCode&0xff)==SQLITE_CONSTRAINT );
|
||||
assert( (errCode&0xff)==SQLITE_CONSTRAINT || pParse->nested );
|
||||
if( onError==OE_Abort ){
|
||||
sqlite3MayAbort(pParse);
|
||||
}
|
||||
|
||||
@@ -514,9 +514,6 @@ static const char * const sqlite3azCompileOpt[] = {
|
||||
#if SQLITE_OMIT_BLOB_LITERAL
|
||||
"OMIT_BLOB_LITERAL",
|
||||
#endif
|
||||
#if SQLITE_OMIT_BTREECOUNT
|
||||
"OMIT_BTREECOUNT",
|
||||
#endif
|
||||
#if SQLITE_OMIT_CAST
|
||||
"OMIT_CAST",
|
||||
#endif
|
||||
|
||||
+3
-3
@@ -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);
|
||||
@@ -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
-1
@@ -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
|
||||
**
|
||||
@@ -858,6 +858,7 @@ void sqlite3GenerateRowIndexDelete(
|
||||
&iPartIdxLabel, pPrior, r1);
|
||||
sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
|
||||
pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
|
||||
sqlite3VdbeChangeP5(v, 1); /* Cause IdxDelete to error if no entry found */
|
||||
sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
|
||||
pPrior = pIdx;
|
||||
}
|
||||
|
||||
+123
-36
@@ -52,7 +52,12 @@ char sqlite3ExprAffinity(const Expr *pExpr){
|
||||
op = pExpr->op;
|
||||
if( op==TK_SELECT ){
|
||||
assert( pExpr->flags&EP_xIsSelect );
|
||||
return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
|
||||
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);
|
||||
}
|
||||
}
|
||||
if( op==TK_REGISTER ) op = pExpr->op2;
|
||||
#ifndef SQLITE_OMIT_CAST
|
||||
@@ -1988,10 +1993,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.
|
||||
@@ -2043,15 +2048,17 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
|
||||
/* Fall through */
|
||||
case TK_IF_NULL_ROW:
|
||||
case TK_REGISTER:
|
||||
case TK_DOT:
|
||||
testcase( pExpr->op==TK_REGISTER );
|
||||
testcase( pExpr->op==TK_IF_NULL_ROW );
|
||||
testcase( pExpr->op==TK_DOT );
|
||||
pWalker->eCode = 0;
|
||||
return WRC_Abort;
|
||||
case TK_VARIABLE:
|
||||
if( pWalker->eCode==5 ){
|
||||
/* Silently convert bound parameters that appear inside of CREATE
|
||||
** statements into a NULL when parsing the CREATE statement text out
|
||||
** of the sqlite_master table */
|
||||
** of the sqlite_schema table */
|
||||
pExpr->op = TK_NULL;
|
||||
}else if( pWalker->eCode==4 ){
|
||||
/* A bound parameter in a CREATE statement that originates from
|
||||
@@ -2184,12 +2191,12 @@ int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprList *pGroupBy){
|
||||
** the expression is constant or a function call with constant arguments.
|
||||
** Return and 0 if there are any variables.
|
||||
**
|
||||
** isInit is true when parsing from sqlite_master. isInit is false when
|
||||
** isInit is true when parsing from sqlite_schema. isInit is false when
|
||||
** processing a new CREATE TABLE statement. When isInit is true, parameters
|
||||
** (such as ? or $abc) in the expression are converted into NULL. When
|
||||
** isInit is false, parameters raise an error. Parameters should not be
|
||||
** allowed in a CREATE TABLE statement, but some legacy versions of SQLite
|
||||
** allowed it, so we need to support it when reading sqlite_master for
|
||||
** allowed it, so we need to support it when reading sqlite_schema for
|
||||
** backwards compatibility.
|
||||
**
|
||||
** If isInit is true, set EP_FromDDL on every TK_FUNCTION node.
|
||||
@@ -2552,7 +2559,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;
|
||||
|
||||
@@ -2563,6 +2570,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);
|
||||
|
||||
@@ -3700,6 +3708,13 @@ static int exprCodeInlineFunction(
|
||||
sqlite3VdbeResolveLabel(v, endCoalesce);
|
||||
break;
|
||||
}
|
||||
case INLINEFUNC_iif: {
|
||||
Expr caseExpr;
|
||||
memset(&caseExpr, 0, sizeof(caseExpr));
|
||||
caseExpr.op = TK_CASE;
|
||||
caseExpr.x.pList = pFarg;
|
||||
return sqlite3ExprCodeTarget(pParse, &caseExpr, target);
|
||||
}
|
||||
|
||||
default: {
|
||||
/* The UNLIKELY() function is a no-op. The result is the value
|
||||
@@ -3789,10 +3804,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 ){
|
||||
@@ -3804,7 +3816,10 @@ expr_code_doover:
|
||||
switch( op ){
|
||||
case TK_AGG_COLUMN: {
|
||||
AggInfo *pAggInfo = pExpr->pAggInfo;
|
||||
struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg];
|
||||
struct AggInfo_col *pCol;
|
||||
assert( pAggInfo!=0 );
|
||||
assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn );
|
||||
pCol = &pAggInfo->aCol[pExpr->iAgg];
|
||||
if( !pAggInfo->directMode ){
|
||||
assert( pCol->iMem>0 );
|
||||
return pCol->iMem;
|
||||
@@ -4104,7 +4119,10 @@ expr_code_doover:
|
||||
}
|
||||
case TK_AGG_FUNCTION: {
|
||||
AggInfo *pInfo = pExpr->pAggInfo;
|
||||
if( pInfo==0 ){
|
||||
if( pInfo==0
|
||||
|| NEVER(pExpr->iAgg<0)
|
||||
|| NEVER(pExpr->iAgg>=pInfo->nFunc)
|
||||
){
|
||||
assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
||||
sqlite3ErrorMsg(pParse, "misuse of aggregate: %s()", pExpr->u.zToken);
|
||||
}else{
|
||||
@@ -4252,7 +4270,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);
|
||||
@@ -4482,7 +4502,7 @@ expr_code_doover:
|
||||
|| pExpr->affExpr==OE_Fail
|
||||
|| pExpr->affExpr==OE_Ignore
|
||||
);
|
||||
if( !pParse->pTriggerTab ){
|
||||
if( !pParse->pTriggerTab && !pParse->nested ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"RAISE() may only be used within a trigger-program");
|
||||
return 0;
|
||||
@@ -4496,8 +4516,9 @@ expr_code_doover:
|
||||
v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0);
|
||||
VdbeCoverage(v);
|
||||
}else{
|
||||
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_TRIGGER,
|
||||
pExpr->affExpr, pExpr->u.zToken, 0, 0);
|
||||
sqlite3HaltConstraint(pParse,
|
||||
pParse->pTriggerTab ? SQLITE_CONSTRAINT_TRIGGER : SQLITE_ERROR,
|
||||
pExpr->affExpr, pExpr->u.zToken, 0, 0);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -4615,9 +4636,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;
|
||||
@@ -5636,10 +5658,25 @@ int sqlite3ExprCoveredByIndex(
|
||||
*/
|
||||
struct SrcCount {
|
||||
SrcList *pSrc; /* One particular FROM clause in a nested query */
|
||||
int iSrcInner; /* Smallest cursor number in this context */
|
||||
int nThis; /* Number of references to columns in pSrcList */
|
||||
int nOther; /* Number of references to columns in other FROM clauses */
|
||||
};
|
||||
|
||||
/*
|
||||
** xSelect callback for sqlite3FunctionUsesThisSrc(). If this is the first
|
||||
** SELECT with a FROM clause encountered during this iteration, set
|
||||
** SrcCount.iSrcInner to the cursor number of the leftmost object in
|
||||
** the FROM cause.
|
||||
*/
|
||||
static int selectSrcCount(Walker *pWalker, Select *pSel){
|
||||
struct SrcCount *p = pWalker->u.pSrcCount;
|
||||
if( p->iSrcInner==0x7FFFFFFF && ALWAYS(pSel->pSrc) && pSel->pSrc->nSrc ){
|
||||
pWalker->u.pSrcCount->iSrcInner = pSel->pSrc->a[0].iCursor;
|
||||
}
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
/*
|
||||
** Count the number of references to columns.
|
||||
*/
|
||||
@@ -5660,7 +5697,7 @@ static int exprSrcCount(Walker *pWalker, Expr *pExpr){
|
||||
}
|
||||
if( i<nSrc ){
|
||||
p->nThis++;
|
||||
}else if( nSrc==0 || pExpr->iTable<pSrc->a[0].iCursor ){
|
||||
}else if( pExpr->iTable<p->iSrcInner ){
|
||||
/* In a well-formed parse tree (no name resolution errors),
|
||||
** TK_COLUMN nodes with smaller Expr.iTable values are in an
|
||||
** outer context. Those are the only ones to count as "other" */
|
||||
@@ -5682,9 +5719,10 @@ int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){
|
||||
assert( pExpr->op==TK_AGG_FUNCTION );
|
||||
memset(&w, 0, sizeof(w));
|
||||
w.xExprCallback = exprSrcCount;
|
||||
w.xSelectCallback = sqlite3SelectWalkNoop;
|
||||
w.xSelectCallback = selectSrcCount;
|
||||
w.u.pSrcCount = &cnt;
|
||||
cnt.pSrc = pSrcList;
|
||||
cnt.iSrcInner = (pSrcList&&pSrcList->nSrc)?pSrcList->a[0].iCursor:0x7FFFFFFF;
|
||||
cnt.nThis = 0;
|
||||
cnt.nOther = 0;
|
||||
sqlite3WalkExprList(&w, pExpr->x.pList);
|
||||
@@ -5696,6 +5734,64 @@ int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){
|
||||
return cnt.nThis>0 || cnt.nOther==0;
|
||||
}
|
||||
|
||||
/*
|
||||
** This is a Walker expression node callback.
|
||||
**
|
||||
** For Expr nodes that contain pAggInfo pointers, make sure the AggInfo
|
||||
** object that is referenced does not refer directly to the Expr. If
|
||||
** it does, make a copy. This is done because the pExpr argument is
|
||||
** subject to change.
|
||||
**
|
||||
** The copy is stored on pParse->pConstExpr with a register number of 0.
|
||||
** This will cause the expression to be deleted automatically when the
|
||||
** Parse object is destroyed, but the zero register number means that it
|
||||
** will not generate any code in the preamble.
|
||||
*/
|
||||
static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
|
||||
if( ALWAYS(!ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced))
|
||||
&& pExpr->pAggInfo!=0
|
||||
){
|
||||
AggInfo *pAggInfo = pExpr->pAggInfo;
|
||||
int iAgg = pExpr->iAgg;
|
||||
Parse *pParse = pWalker->pParse;
|
||||
sqlite3 *db = pParse->db;
|
||||
assert( pExpr->op==TK_AGG_COLUMN || pExpr->op==TK_AGG_FUNCTION );
|
||||
if( pExpr->op==TK_AGG_COLUMN ){
|
||||
assert( iAgg>=0 && iAgg<pAggInfo->nColumn );
|
||||
if( pAggInfo->aCol[iAgg].pCExpr==pExpr ){
|
||||
pExpr = sqlite3ExprDup(db, pExpr, 0);
|
||||
if( pExpr ){
|
||||
pAggInfo->aCol[iAgg].pCExpr = pExpr;
|
||||
pParse->pConstExpr =
|
||||
sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
assert( iAgg>=0 && iAgg<pAggInfo->nFunc );
|
||||
if( pAggInfo->aFunc[iAgg].pFExpr==pExpr ){
|
||||
pExpr = sqlite3ExprDup(db, pExpr, 0);
|
||||
if( pExpr ){
|
||||
pAggInfo->aFunc[iAgg].pFExpr = pExpr;
|
||||
pParse->pConstExpr =
|
||||
sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize a Walker object so that will persist AggInfo entries referenced
|
||||
** by the tree that is walked.
|
||||
*/
|
||||
void sqlite3AggInfoPersistWalkerInit(Walker *pWalker, Parse *pParse){
|
||||
memset(pWalker, 0, sizeof(*pWalker));
|
||||
pWalker->pParse = pParse;
|
||||
pWalker->xExprCallback = agginfoPersistExprCb;
|
||||
pWalker->xSelectCallback = sqlite3SelectWalkNoop;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add a new element to the pAggInfo->aCol[] array. Return the index of
|
||||
** the new element. Return a negative number if malloc fails.
|
||||
@@ -5726,7 +5822,7 @@ static int addAggInfoFunc(sqlite3 *db, AggInfo *pInfo){
|
||||
&i
|
||||
);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This is the xExprCallback for a tree walker. It is used to
|
||||
@@ -5777,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;
|
||||
@@ -5820,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;
|
||||
}
|
||||
}
|
||||
@@ -5832,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,
|
||||
@@ -5859,15 +5955,6 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
||||
}
|
||||
return WRC_Continue;
|
||||
}
|
||||
static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
|
||||
UNUSED_PARAMETER(pSelect);
|
||||
pWalker->walkerDepth++;
|
||||
return WRC_Continue;
|
||||
}
|
||||
static void analyzeAggregatesInSelectEnd(Walker *pWalker, Select *pSelect){
|
||||
UNUSED_PARAMETER(pSelect);
|
||||
pWalker->walkerDepth--;
|
||||
}
|
||||
|
||||
/*
|
||||
** Analyze the pExpr expression looking for aggregate functions and
|
||||
@@ -5881,8 +5968,8 @@ static void analyzeAggregatesInSelectEnd(Walker *pWalker, Select *pSelect){
|
||||
void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
|
||||
Walker w;
|
||||
w.xExprCallback = analyzeAggregate;
|
||||
w.xSelectCallback = analyzeAggregatesInSelect;
|
||||
w.xSelectCallback2 = analyzeAggregatesInSelectEnd;
|
||||
w.xSelectCallback = sqlite3WalkerDepthIncrease;
|
||||
w.xSelectCallback2 = sqlite3WalkerDepthDecrease;
|
||||
w.walkerDepth = 0;
|
||||
w.u.pNC = pNC;
|
||||
w.pParse = 0;
|
||||
|
||||
+4
-3
@@ -1283,7 +1283,7 @@ static void replaceFunc(
|
||||
** whose index is a power of two: 1, 2, 4, 8, 16, 32, ... */
|
||||
u8 *zOld;
|
||||
zOld = zOut;
|
||||
zOut = sqlite3_realloc64(zOut, (int)nOut + (nOut - nStr - 1));
|
||||
zOut = sqlite3Realloc(zOut, (int)nOut + (nOut - nStr - 1));
|
||||
if( zOut==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
sqlite3_free(zOld);
|
||||
@@ -1980,7 +1980,7 @@ void sqlite3RegisterBuiltinFunctions(void){
|
||||
FUNCTION(upper, 1, 0, 0, upperFunc ),
|
||||
FUNCTION(lower, 1, 0, 0, lowerFunc ),
|
||||
FUNCTION(hex, 1, 0, 0, hexFunc ),
|
||||
INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, SQLITE_FUNC_COALESCE),
|
||||
INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ),
|
||||
VFUNCTION(random, 0, 0, 0, randomFunc ),
|
||||
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
|
||||
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
|
||||
@@ -2020,7 +2020,8 @@ void sqlite3RegisterBuiltinFunctions(void){
|
||||
#endif
|
||||
FUNCTION(coalesce, 1, 0, 0, 0 ),
|
||||
FUNCTION(coalesce, 0, 0, 0, 0 ),
|
||||
INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, SQLITE_FUNC_COALESCE),
|
||||
INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ),
|
||||
INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ),
|
||||
};
|
||||
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||
sqlite3AlterFunctions();
|
||||
|
||||
@@ -300,6 +300,11 @@ sqlite3_uint64 sqlite3NProfileCnt = 0;
|
||||
int sqlite3PendingByte = 0x40000000;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Flags for select tracing and the ".selecttrace" macro of the CLI
|
||||
*/
|
||||
/**/ u32 sqlite3SelectTrace = 0;
|
||||
|
||||
#include "opcodes.h"
|
||||
/*
|
||||
** Properties of opcodes. The OPFLG_INITIALIZER macro is
|
||||
|
||||
+2
-2
@@ -1944,7 +1944,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
sqlite3TableAffinity(v, pTab, regNewData+1);
|
||||
bAffinityDone = 1;
|
||||
}
|
||||
VdbeNoopComment((v, "uniqueness check for %s", pIdx->zName));
|
||||
VdbeNoopComment((v, "prep index %s", pIdx->zName));
|
||||
iThisCur = iIdxCur+ix;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
+88
-123
@@ -25,15 +25,78 @@
|
||||
#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
|
||||
# include "sqliteicu.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This is an extension initializer that is a no-op and always
|
||||
** succeeds, except that it fails if the fault-simulation is set
|
||||
** to 500.
|
||||
*/
|
||||
static int sqlite3TestExtInit(sqlite3 *db){
|
||||
(void)db;
|
||||
return sqlite3FaultSim(500);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Forward declarations of external module initializer functions
|
||||
** for modules that need them.
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_FTS1
|
||||
int sqlite3Fts1Init(sqlite3*);
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_FTS2
|
||||
int sqlite3Fts2Init(sqlite3*);
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_FTS5
|
||||
int sqlite3Fts5Init(sqlite3*);
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_JSON1
|
||||
int sqlite3Json1Init(sqlite3*);
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_STMTVTAB
|
||||
int sqlite3StmtVtabInit(sqlite3*);
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_FTS5
|
||||
int sqlite3Fts5Init(sqlite3*);
|
||||
|
||||
/*
|
||||
** An array of pointers to extension initializer functions for
|
||||
** built-in extensions.
|
||||
*/
|
||||
static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = {
|
||||
#ifdef SQLITE_ENABLE_FTS1
|
||||
sqlite3Fts1Init,
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_FTS2
|
||||
sqlite3Fts2Init,
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_FTS3
|
||||
sqlite3Fts3Init,
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_FTS5
|
||||
sqlite3Fts5Init,
|
||||
#endif
|
||||
#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
|
||||
sqlite3IcuInit,
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_RTREE
|
||||
sqlite3RtreeInit,
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_DBPAGE_VTAB
|
||||
sqlite3DbpageRegister,
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_DBSTAT_VTAB
|
||||
sqlite3DbstatRegister,
|
||||
#endif
|
||||
sqlite3TestExtInit,
|
||||
#ifdef SQLITE_ENABLE_JSON1
|
||||
sqlite3Json1Init,
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_STMTVTAB
|
||||
sqlite3StmtVtabInit,
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_BYTECODE_VTAB
|
||||
sqlite3VdbeBytecodeVtabInit,
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef SQLITE_AMALGAMATION
|
||||
/* IMPLEMENTATION-OF: R-46656-45156 The sqlite3_version[] string constant
|
||||
@@ -138,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 */
|
||||
@@ -178,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();
|
||||
@@ -202,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
|
||||
@@ -250,6 +313,7 @@ int sqlite3_initialize(void){
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage,
|
||||
sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage);
|
||||
sqlite3MemoryBarrier();
|
||||
sqlite3GlobalConfig.isInit = 1;
|
||||
#ifdef SQLITE_EXTRA_INIT
|
||||
bRunExtraInit = 1;
|
||||
@@ -262,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
|
||||
@@ -1551,8 +1615,7 @@ const char *sqlite3ErrStr(int rc){
|
||||
*/
|
||||
static int sqliteDefaultBusyCallback(
|
||||
void *ptr, /* Database connection */
|
||||
int count, /* Number of times table has been busy */
|
||||
sqlite3_file *pFile /* The file on which the lock occurred */
|
||||
int count /* Number of times table has been busy */
|
||||
){
|
||||
#if SQLITE_OS_WIN || HAVE_USLEEP
|
||||
/* This case is for systems that have support for sleeping for fractions of
|
||||
@@ -1566,31 +1629,6 @@ static int sqliteDefaultBusyCallback(
|
||||
int tmout = db->busyTimeout;
|
||||
int delay, prior;
|
||||
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
if( sqlite3OsFileControl(pFile,SQLITE_FCNTL_LOCK_TIMEOUT,&tmout)==SQLITE_OK ){
|
||||
if( count ){
|
||||
/* If this is the second or later invocation of the busy-handler,
|
||||
** but tmout==0, then code in wal.c must have disabled the blocking
|
||||
** lock before the SQLITE_BUSY error was hit. In this case, no delay
|
||||
** occurred while waiting for the lock, so fall through to the xSleep()
|
||||
** code below to delay a while before retrying the lock.
|
||||
**
|
||||
** Alternatively, if tmout!=0, then SQLite has already waited
|
||||
** sqlite3.busyTimeout ms for a lock. In this case, return 0 to
|
||||
** indicate that the lock should not be retried and the SQLITE_BUSY
|
||||
** error returned to the application. */
|
||||
if( tmout ){
|
||||
tmout = 0;
|
||||
sqlite3OsFileControl(pFile, SQLITE_FCNTL_LOCK_TIMEOUT, &tmout);
|
||||
return 0;
|
||||
}
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
UNUSED_PARAMETER(pFile);
|
||||
#endif
|
||||
assert( count>=0 );
|
||||
if( count < NDELAY ){
|
||||
delay = delays[count];
|
||||
@@ -1610,7 +1648,6 @@ static int sqliteDefaultBusyCallback(
|
||||
** must be done in increments of whole seconds */
|
||||
sqlite3 *db = (sqlite3 *)ptr;
|
||||
int tmout = ((sqlite3 *)ptr)->busyTimeout;
|
||||
UNUSED_PARAMETER(pFile);
|
||||
if( (count+1)*1000 > tmout ){
|
||||
return 0;
|
||||
}
|
||||
@@ -1628,19 +1665,10 @@ static int sqliteDefaultBusyCallback(
|
||||
** If this routine returns non-zero, the lock is retried. If it
|
||||
** returns 0, the operation aborts with an SQLITE_BUSY error.
|
||||
*/
|
||||
int sqlite3InvokeBusyHandler(BusyHandler *p, sqlite3_file *pFile){
|
||||
int sqlite3InvokeBusyHandler(BusyHandler *p){
|
||||
int rc;
|
||||
if( p->xBusyHandler==0 || p->nBusy<0 ) return 0;
|
||||
if( p->bExtraFileArg ){
|
||||
/* Add an extra parameter with the pFile pointer to the end of the
|
||||
** callback argument list */
|
||||
int (*xTra)(void*,int,sqlite3_file*);
|
||||
xTra = (int(*)(void*,int,sqlite3_file*))p->xBusyHandler;
|
||||
rc = xTra(p->pBusyArg, p->nBusy, pFile);
|
||||
}else{
|
||||
/* Legacy style busy handler callback */
|
||||
rc = p->xBusyHandler(p->pBusyArg, p->nBusy);
|
||||
}
|
||||
rc = p->xBusyHandler(p->pBusyArg, p->nBusy);
|
||||
if( rc==0 ){
|
||||
p->nBusy = -1;
|
||||
}else{
|
||||
@@ -1665,7 +1693,6 @@ int sqlite3_busy_handler(
|
||||
db->busyHandler.xBusyHandler = xBusy;
|
||||
db->busyHandler.pBusyArg = pArg;
|
||||
db->busyHandler.nBusy = 0;
|
||||
db->busyHandler.bExtraFileArg = 0;
|
||||
db->busyTimeout = 0;
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return SQLITE_OK;
|
||||
@@ -1716,7 +1743,6 @@ int sqlite3_busy_timeout(sqlite3 *db, int ms){
|
||||
sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback,
|
||||
(void*)db);
|
||||
db->busyTimeout = ms;
|
||||
db->busyHandler.bExtraFileArg = 1;
|
||||
}else{
|
||||
sqlite3_busy_handler(db, 0, 0);
|
||||
}
|
||||
@@ -3042,6 +3068,7 @@ static int openDatabase(
|
||||
int isThreadsafe; /* True for threadsafe connections */
|
||||
char *zOpen = 0; /* Filename argument to pass to BtreeOpen() */
|
||||
char *zErrMsg = 0; /* Error message from sqlite3ParseUri() */
|
||||
int i; /* Loop counter */
|
||||
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( ppDb==0 ) return SQLITE_MISUSE_BKPT;
|
||||
@@ -3085,7 +3112,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
|
||||
@@ -3189,6 +3216,9 @@ static int openDatabase(
|
||||
#endif
|
||||
#if defined(SQLITE_DEFAULT_DEFENSIVE)
|
||||
| SQLITE_Defensive
|
||||
#endif
|
||||
#if defined(SQLITE_DEFAULT_LEGACY_ALTER_TABLE)
|
||||
| SQLITE_LegacyAlter
|
||||
#endif
|
||||
;
|
||||
sqlite3HashInit(&db->aCollSeq);
|
||||
@@ -3232,7 +3262,7 @@ static int openDatabase(
|
||||
testcase( (1<<(flags&7))==0x04 ); /* READWRITE */
|
||||
testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */
|
||||
if( ((1<<(flags&7)) & 0x46)==0 ){
|
||||
rc = SQLITE_MISUSE_BKPT; /* IMP: R-65497-44594 */
|
||||
rc = SQLITE_MISUSE_BKPT; /* IMP: R-18321-05872 */
|
||||
}else{
|
||||
rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
|
||||
}
|
||||
@@ -3282,14 +3312,11 @@ static int openDatabase(
|
||||
sqlite3RegisterPerConnectionBuiltinFunctions(db);
|
||||
rc = sqlite3_errcode(db);
|
||||
|
||||
#ifdef SQLITE_ENABLE_FTS5
|
||||
/* Register any built-in FTS5 module before loading the automatic
|
||||
** extensions. This allows automatic extensions to register FTS5
|
||||
** tokenizers and auxiliary functions. */
|
||||
if( !db->mallocFailed && rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5Init(db);
|
||||
|
||||
/* Load compiled-in extensions */
|
||||
for(i=0; rc==SQLITE_OK && i<ArraySize(sqlite3BuiltinExtensions); i++){
|
||||
rc = sqlite3BuiltinExtensions[i](db);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Load automatic extensions - extensions that have been registered
|
||||
** using the sqlite3_automatic_extension() API.
|
||||
@@ -3302,68 +3329,6 @@ static int openDatabase(
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_FTS1
|
||||
if( !db->mallocFailed ){
|
||||
extern int sqlite3Fts1Init(sqlite3*);
|
||||
rc = sqlite3Fts1Init(db);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_FTS2
|
||||
if( !db->mallocFailed && rc==SQLITE_OK ){
|
||||
extern int sqlite3Fts2Init(sqlite3*);
|
||||
rc = sqlite3Fts2Init(db);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_FTS3 /* automatically defined by SQLITE_ENABLE_FTS4 */
|
||||
if( !db->mallocFailed && rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts3Init(db);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
|
||||
if( !db->mallocFailed && rc==SQLITE_OK ){
|
||||
rc = sqlite3IcuInit(db);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_RTREE
|
||||
if( !db->mallocFailed && rc==SQLITE_OK){
|
||||
rc = sqlite3RtreeInit(db);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_DBPAGE_VTAB
|
||||
if( !db->mallocFailed && rc==SQLITE_OK){
|
||||
rc = sqlite3DbpageRegister(db);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_DBSTAT_VTAB
|
||||
if( !db->mallocFailed && rc==SQLITE_OK){
|
||||
rc = sqlite3DbstatRegister(db);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_JSON1
|
||||
if( !db->mallocFailed && rc==SQLITE_OK){
|
||||
rc = sqlite3Json1Init(db);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_STMTVTAB
|
||||
if( !db->mallocFailed && rc==SQLITE_OK){
|
||||
rc = sqlite3StmtVtabInit(db);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_BYTECODE_VTAB
|
||||
if( !db->mallocFailed && rc==SQLITE_OK){
|
||||
rc = sqlite3VdbeBytecodeVtabInit(db);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_INTERNAL_FUNCTIONS
|
||||
/* Testing use only!!! The -DSQLITE_ENABLE_INTERNAL_FUNCTIONS=1 compile-time
|
||||
** option gives access to internal functions by default.
|
||||
@@ -3852,7 +3817,7 @@ int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
|
||||
}else if( op==SQLITE_FCNTL_RESERVE_BYTES ){
|
||||
int iNew = *(int*)pArg;
|
||||
*(int*)pArg = sqlite3BtreeGetRequestedReserve(pBtree);
|
||||
if( iNew>=0 && iNew<=254 ){
|
||||
if( iNew>=0 && iNew<=255 ){
|
||||
sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0);
|
||||
}
|
||||
rc = SQLITE_OK;
|
||||
@@ -4124,7 +4089,7 @@ 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.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS: {
|
||||
|
||||
+3
-1
@@ -482,10 +482,12 @@ void *sqlite3Realloc(void *pOld, u64 nBytes){
|
||||
sqlite3MallocAlarm(nDiff);
|
||||
}
|
||||
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
|
||||
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
if( pNew==0 && mem0.alarmThreshold>0 ){
|
||||
sqlite3MallocAlarm((int)nBytes);
|
||||
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
|
||||
}
|
||||
#endif
|
||||
if( pNew ){
|
||||
nNew = sqlite3MallocSize(pNew);
|
||||
sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nNew-nOld);
|
||||
@@ -670,7 +672,7 @@ static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){
|
||||
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
|
||||
assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
|
||||
pNew = sqlite3_realloc64(p, n);
|
||||
pNew = sqlite3Realloc(p, n);
|
||||
if( !pNew ){
|
||||
sqlite3OomFault(db);
|
||||
}
|
||||
|
||||
+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);
|
||||
|
||||
+7
-6
@@ -166,7 +166,7 @@ static int memdbEnlarge(MemFile *p, sqlite3_int64 newSz){
|
||||
}
|
||||
newSz *= 2;
|
||||
if( newSz>p->szMax ) newSz = p->szMax;
|
||||
pNew = sqlite3_realloc64(p->aData, newSz);
|
||||
pNew = sqlite3Realloc(p->aData, newSz);
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
p->aData = pNew;
|
||||
p->szAlloc = newSz;
|
||||
@@ -344,7 +344,7 @@ static int memdbOpen(
|
||||
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,
|
||||
@@ -613,10 +613,11 @@ int sqlite3MemdbInit(void){
|
||||
sqlite3_vfs *pLower = sqlite3_vfs_find(0);
|
||||
int sz = pLower->szOsFile;
|
||||
memdb_vfs.pAppData = pLower;
|
||||
/* In all known configurations of SQLite, the size of a default
|
||||
** sqlite3_file is greater than the size of a memdb sqlite3_file.
|
||||
** Should that ever change, remove the following NEVER() */
|
||||
if( NEVER(sz<sizeof(MemFile)) ) sz = sizeof(MemFile);
|
||||
/* The following conditional can only be true when compiled for
|
||||
** Windows x86 and SQLITE_MAX_MMAP_SIZE=0. We always leave
|
||||
** it in, to be safe, but it is marked as NO_TEST since there
|
||||
** is no way to reach it under most builds. */
|
||||
if( sz<sizeof(MemFile) ) sz = sizeof(MemFile); /*NO_TEST*/
|
||||
memdb_vfs.szOsFile = sz;
|
||||
return sqlite3_vfs_register(&memdb_vfs, 0);
|
||||
}
|
||||
|
||||
+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);
|
||||
|
||||
+41
-23
@@ -1565,8 +1565,9 @@ static int osSetPosixAdvisoryLock(
|
||||
struct flock *pLock, /* The description of the lock */
|
||||
unixFile *pFile /* Structure holding timeout value */
|
||||
){
|
||||
int tm = pFile->iBusyTimeout;
|
||||
int rc = osFcntl(h,F_SETLK,pLock);
|
||||
while( rc<0 && pFile->iBusyTimeout>0 ){
|
||||
while( rc<0 && tm>0 ){
|
||||
/* On systems that support some kind of blocking file lock with a timeout,
|
||||
** make appropriate changes here to invoke that blocking file lock. On
|
||||
** generic posix, however, there is no such API. So we simply try the
|
||||
@@ -1574,7 +1575,7 @@ static int osSetPosixAdvisoryLock(
|
||||
** the lock is obtained. */
|
||||
usleep(1000);
|
||||
rc = osFcntl(h,F_SETLK,pLock);
|
||||
pFile->iBusyTimeout--;
|
||||
tm--;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -3339,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
|
||||
@@ -3452,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
|
||||
@@ -3996,7 +3997,13 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
case SQLITE_FCNTL_LOCK_TIMEOUT: {
|
||||
int iOld = pFile->iBusyTimeout;
|
||||
#if SQLITE_ENABLE_SETLK_TIMEOUT==1
|
||||
pFile->iBusyTimeout = *(int*)pArg;
|
||||
#elif SQLITE_ENABLE_SETLK_TIMEOUT==2
|
||||
pFile->iBusyTimeout = !!(*(int*)pArg);
|
||||
#else
|
||||
# error "SQLITE_ENABLE_SETLK_TIMEOUT must be set to 1 or 2"
|
||||
#endif
|
||||
*(int*)pArg = iOld;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -4316,13 +4323,20 @@ static int unixShmSystemLock(
|
||||
assert( n>=1 && n<=SQLITE_SHM_NLOCK );
|
||||
|
||||
if( pShmNode->hShm>=0 ){
|
||||
int res;
|
||||
/* Initialize the locking parameters */
|
||||
f.l_type = lockType;
|
||||
f.l_whence = SEEK_SET;
|
||||
f.l_start = ofst;
|
||||
f.l_len = n;
|
||||
rc = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile);
|
||||
rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
|
||||
res = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile);
|
||||
if( res==-1 ){
|
||||
#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) && SQLITE_ENABLE_SETLK_TIMEOUT==1
|
||||
rc = (pFile->iBusyTimeout ? SQLITE_BUSY_TIMEOUT : SQLITE_BUSY);
|
||||
#else
|
||||
rc = SQLITE_BUSY;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the global lock state and do debug tracing */
|
||||
@@ -4819,22 +4833,26 @@ static int unixShmLock(
|
||||
assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 );
|
||||
assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 );
|
||||
|
||||
/* Check that, if this to be a blocking lock, that locks have been
|
||||
** obtained in the following order.
|
||||
/* Check that, if this to be a blocking lock, no locks that occur later
|
||||
** in the following list than the lock being obtained are already held:
|
||||
**
|
||||
** 1. Checkpointer lock (ofst==1).
|
||||
** 2. Recover lock (ofst==2).
|
||||
** 2. Write lock (ofst==0).
|
||||
** 3. Read locks (ofst>=3 && ofst<SQLITE_SHM_NLOCK).
|
||||
** 4. Write lock (ofst==0).
|
||||
**
|
||||
** 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( pDbFd->iBusyTimeout==0
|
||||
|| (flags & SQLITE_SHM_UNLOCK) || ofst==0
|
||||
|| ((p->exclMask|p->sharedMask)&~((1<<ofst)-2))==0
|
||||
);
|
||||
assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
|
||||
(ofst!=2) /* not RECOVER */
|
||||
&& (ofst!=1 || (p->exclMask|p->sharedMask)==0)
|
||||
&& (ofst!=0 || (p->exclMask|p->sharedMask)<3)
|
||||
&& (ofst<3 || (p->exclMask|p->sharedMask)<(1<<ofst))
|
||||
));
|
||||
#endif
|
||||
|
||||
mask = (1<<(ofst+n)) - (1<<ofst);
|
||||
@@ -5761,7 +5779,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.
|
||||
**
|
||||
@@ -5895,7 +5913,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--;
|
||||
@@ -5968,12 +5986,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
|
||||
));
|
||||
@@ -5996,17 +6014,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
|
||||
);
|
||||
|
||||
@@ -6199,7 +6217,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);
|
||||
|
||||
|
||||
+28
-13
@@ -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 */
|
||||
@@ -3502,6 +3502,7 @@ static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){
|
||||
/* Forward references to VFS helper methods used for temporary files */
|
||||
static int winGetTempname(sqlite3_vfs *, char **);
|
||||
static int winIsDir(const void *);
|
||||
static BOOL winIsLongPathPrefix(const char *);
|
||||
static BOOL winIsDriveLetterAndColon(const char *);
|
||||
|
||||
/*
|
||||
@@ -5022,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
|
||||
));
|
||||
@@ -5043,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
|
||||
);
|
||||
|
||||
@@ -5271,7 +5272,9 @@ static int winOpen(
|
||||
if( isReadonly ){
|
||||
pFile->ctrlFlags |= WINFILE_RDONLY;
|
||||
}
|
||||
if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){
|
||||
if( (flags & SQLITE_OPEN_MAIN_DB)
|
||||
&& sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE)
|
||||
){
|
||||
pFile->ctrlFlags |= WINFILE_PSOW;
|
||||
}
|
||||
pFile->lastErrno = NO_ERROR;
|
||||
@@ -5481,6 +5484,17 @@ static int winAccess(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Returns non-zero if the specified path name starts with the "long path"
|
||||
** prefix.
|
||||
*/
|
||||
static BOOL winIsLongPathPrefix(
|
||||
const char *zPathname
|
||||
){
|
||||
return ( zPathname[0]=='\\' && zPathname[1]=='\\'
|
||||
&& zPathname[2]=='?' && zPathname[3]=='\\' );
|
||||
}
|
||||
|
||||
/*
|
||||
** Returns non-zero if the specified path name starts with a drive letter
|
||||
** followed by a colon character.
|
||||
@@ -5545,10 +5559,11 @@ static int winFullPathname(
|
||||
char *zOut;
|
||||
#endif
|
||||
|
||||
/* If this path name begins with "/X:", where "X" is any alphabetic
|
||||
** character, discard the initial "/" from the pathname.
|
||||
/* If this path name begins with "/X:" or "\\?\", where "X" is any
|
||||
** alphabetic character, discard the initial "/" from the pathname.
|
||||
*/
|
||||
if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){
|
||||
if( zRelative[0]=='/' && (winIsDriveLetterAndColon(zRelative+1)
|
||||
|| winIsLongPathPrefix(zRelative+1)) ){
|
||||
zRelative++;
|
||||
}
|
||||
|
||||
|
||||
+197
-182
@@ -70,8 +70,8 @@
|
||||
** (5) All writes to the database file are synced prior to the rollback journal
|
||||
** being deleted, truncated, or zeroed.
|
||||
**
|
||||
** (6) If a master journal file is used, then all writes to the database file
|
||||
** are synced prior to the master journal being deleted.
|
||||
** (6) If a super-journal file is used, then all writes to the database file
|
||||
** are synced prior to the super-journal being deleted.
|
||||
**
|
||||
** Definition: Two databases (or the same database at two points it time)
|
||||
** are said to be "logically equivalent" if they give the same answer to
|
||||
@@ -488,29 +488,29 @@ struct PagerSavepoint {
|
||||
** need only update the change-counter once, for the first transaction
|
||||
** committed.
|
||||
**
|
||||
** setMaster
|
||||
** setSuper
|
||||
**
|
||||
** When PagerCommitPhaseOne() is called to commit a transaction, it may
|
||||
** (or may not) specify a master-journal name to be written into the
|
||||
** (or may not) specify a super-journal name to be written into the
|
||||
** journal file before it is synced to disk.
|
||||
**
|
||||
** Whether or not a journal file contains a master-journal pointer affects
|
||||
** Whether or not a journal file contains a super-journal pointer affects
|
||||
** the way in which the journal file is finalized after the transaction is
|
||||
** committed or rolled back when running in "journal_mode=PERSIST" mode.
|
||||
** If a journal file does not contain a master-journal pointer, it is
|
||||
** If a journal file does not contain a super-journal pointer, it is
|
||||
** finalized by overwriting the first journal header with zeroes. If
|
||||
** it does contain a master-journal pointer the journal file is finalized
|
||||
** it does contain a super-journal pointer the journal file is finalized
|
||||
** by truncating it to zero bytes, just as if the connection were
|
||||
** running in "journal_mode=truncate" mode.
|
||||
**
|
||||
** Journal files that contain master journal pointers cannot be finalized
|
||||
** Journal files that contain super-journal pointers cannot be finalized
|
||||
** simply by overwriting the first journal-header with zeroes, as the
|
||||
** master journal pointer could interfere with hot-journal rollback of any
|
||||
** super-journal pointer could interfere with hot-journal rollback of any
|
||||
** subsequently interrupted transaction that reuses the journal file.
|
||||
**
|
||||
** The flag is cleared as soon as the journal file is finalized (either
|
||||
** by PagerCommitPhaseTwo or PagerRollback). If an IO error prevents the
|
||||
** journal file from being successfully finalized, the setMaster flag
|
||||
** journal file from being successfully finalized, the setSuper flag
|
||||
** is cleared anyway (and the pager will move to ERROR state).
|
||||
**
|
||||
** doNotSpill
|
||||
@@ -642,7 +642,7 @@ struct Pager {
|
||||
u8 eState; /* Pager state (OPEN, READER, WRITER_LOCKED..) */
|
||||
u8 eLock; /* Current lock held on database file */
|
||||
u8 changeCountDone; /* Set after incrementing the change-counter */
|
||||
u8 setMaster; /* True if a m-j name has been written to jrnl */
|
||||
u8 setSuper; /* Super-jrnl name is written into jrnl */
|
||||
u8 doNotSpill; /* Do not spill the cache when non-zero */
|
||||
u8 subjInMemory; /* True to use in-memory sub-journals */
|
||||
u8 bUseFetch; /* True to use xFetch() */
|
||||
@@ -920,7 +920,7 @@ static int assert_pager_state(Pager *p){
|
||||
assert( pPager->dbSize==pPager->dbOrigSize );
|
||||
assert( pPager->dbOrigSize==pPager->dbFileSize );
|
||||
assert( pPager->dbOrigSize==pPager->dbHintSize );
|
||||
assert( pPager->setMaster==0 );
|
||||
assert( pPager->setSuper==0 );
|
||||
break;
|
||||
|
||||
case PAGER_WRITER_CACHEMOD:
|
||||
@@ -1274,66 +1274,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;
|
||||
}
|
||||
@@ -1661,50 +1661,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 ){
|
||||
@@ -1712,25 +1712,25 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
|
||||
}
|
||||
iHdrOff = pPager->journalOff;
|
||||
|
||||
/* Write the master journal data to the end of the journal file. If
|
||||
/* Write the super-journal data to the end of the journal file. If
|
||||
** an error occurs, return the error code to the caller.
|
||||
*/
|
||||
if( (0 != (rc = write32bits(pPager->jfd, iHdrOff, PAGER_MJ_PGNO(pPager))))
|
||||
|| (0 != (rc = sqlite3OsWrite(pPager->jfd, zMaster, nMaster, iHdrOff+4)))
|
||||
|| (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster, nMaster)))
|
||||
|| (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster+4, cksum)))
|
||||
|| (0 != (rc = sqlite3OsWrite(pPager->jfd, zSuper, nSuper, iHdrOff+4)))
|
||||
|| (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nSuper, nSuper)))
|
||||
|| (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nSuper+4, cksum)))
|
||||
|| (0 != (rc = sqlite3OsWrite(pPager->jfd, aJournalMagic, 8,
|
||||
iHdrOff+4+nMaster+8)))
|
||||
iHdrOff+4+nSuper+8)))
|
||||
){
|
||||
return rc;
|
||||
}
|
||||
pPager->journalOff += (nMaster+20);
|
||||
pPager->journalOff += (nSuper+20);
|
||||
|
||||
/* If the pager is in peristent-journal mode, then the physical
|
||||
** journal-file may extend past the end of the master-journal name
|
||||
** journal-file may extend past the end of the super-journal name
|
||||
** and 8 bytes of magic data just written to the file. This is
|
||||
** dangerous because the code to rollback a hot-journal file
|
||||
** will not be able to find the master-journal name to determine
|
||||
** will not be able to find the super-journal name to determine
|
||||
** whether or not the journal is hot.
|
||||
**
|
||||
** Easiest thing to do in this scenario is to truncate the journal
|
||||
@@ -1891,7 +1891,7 @@ static void pager_unlock(Pager *pPager){
|
||||
|
||||
pPager->journalOff = 0;
|
||||
pPager->journalHdr = 0;
|
||||
pPager->setMaster = 0;
|
||||
pPager->setSuper = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2007,7 +2007,7 @@ static int pagerFlushOnCommit(Pager *pPager, int bCommit){
|
||||
** to the first error encountered (the journal finalization one) is
|
||||
** returned.
|
||||
*/
|
||||
static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
|
||||
static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){
|
||||
int rc = SQLITE_OK; /* Error code from journal finalization operation */
|
||||
int rc2 = SQLITE_OK; /* Error code from db file unlock operation */
|
||||
|
||||
@@ -2059,7 +2059,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
|
||||
}else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST
|
||||
|| (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL)
|
||||
){
|
||||
rc = zeroJournalHdr(pPager, hasMaster||pPager->tempFile);
|
||||
rc = zeroJournalHdr(pPager, hasSuper||pPager->tempFile);
|
||||
pPager->journalOff = 0;
|
||||
}else{
|
||||
/* This branch may be executed with Pager.journalMode==MEMORY if
|
||||
@@ -2132,7 +2132,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
|
||||
rc2 = pagerUnlockDb(pPager, SHARED_LOCK);
|
||||
}
|
||||
pPager->eState = PAGER_READER;
|
||||
pPager->setMaster = 0;
|
||||
pPager->setSuper = 0;
|
||||
|
||||
return (rc==SQLITE_OK?rc2:rc);
|
||||
}
|
||||
@@ -2440,36 +2440,36 @@ static int pager_playback_one_page(
|
||||
}
|
||||
|
||||
/*
|
||||
** Parameter zMaster is the name of a master journal file. A single journal
|
||||
** file that referred to the master journal file has just been rolled back.
|
||||
** This routine checks if it is possible to delete the master journal file,
|
||||
** Parameter zSuper is the name of a super-journal file. A single journal
|
||||
** file that referred to the super-journal file has just been rolled back.
|
||||
** This routine checks if it is possible to delete the super-journal file,
|
||||
** and does so if it is.
|
||||
**
|
||||
** Argument zMaster may point to Pager.pTmpSpace. So that buffer is not
|
||||
** Argument zSuper may point to Pager.pTmpSpace. So that buffer is not
|
||||
** available for use within this function.
|
||||
**
|
||||
** When a master journal file is created, it is populated with the names
|
||||
** When a super-journal file is created, it is populated with the names
|
||||
** of all of its child journals, one after another, formatted as utf-8
|
||||
** encoded text. The end of each child journal file is marked with a
|
||||
** nul-terminator byte (0x00). i.e. the entire contents of a master journal
|
||||
** nul-terminator byte (0x00). i.e. the entire contents of a super-journal
|
||||
** file for a transaction involving two databases might be:
|
||||
**
|
||||
** "/home/bill/a.db-journal\x00/home/bill/b.db-journal\x00"
|
||||
**
|
||||
** A master journal file may only be deleted once all of its child
|
||||
** A super-journal file may only be deleted once all of its child
|
||||
** journals have been rolled back.
|
||||
**
|
||||
** This function reads the contents of the master-journal file into
|
||||
** This function reads the contents of the super-journal file into
|
||||
** memory and loops through each of the child journal names. For
|
||||
** each child journal, it checks if:
|
||||
**
|
||||
** * if the child journal exists, and if so
|
||||
** * if the child journal contains a reference to master journal
|
||||
** file zMaster
|
||||
** * if the child journal contains a reference to super-journal
|
||||
** file zSuper
|
||||
**
|
||||
** If a child journal can be found that matches both of the criteria
|
||||
** above, this function returns without doing anything. Otherwise, if
|
||||
** no such child journal can be found, file zMaster is deleted from
|
||||
** no such child journal can be found, file zSuper is deleted from
|
||||
** the file-system using sqlite3OsDelete().
|
||||
**
|
||||
** If an IO error within this function, an error code is returned. This
|
||||
@@ -2478,99 +2478,99 @@ 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);
|
||||
pJournal = (sqlite3_file *)(((u8 *)pSuper) + pVfs->szOsFile);
|
||||
if( !pSuper ){
|
||||
rc = SQLITE_NOMEM_BKPT;
|
||||
}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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -2648,7 +2648,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.
|
||||
**
|
||||
@@ -2747,7 +2747,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;
|
||||
@@ -2761,8 +2761,8 @@ static int pager_playback(Pager *pPager, int isHot){
|
||||
goto end_playback;
|
||||
}
|
||||
|
||||
/* Read the master journal name from the journal, if it is present.
|
||||
** If a master journal file name is specified, but the file is not
|
||||
/* Read the super-journal name from the journal, if it is present.
|
||||
** If a super-journal file name is specified, but the file is not
|
||||
** present on disk, then the journal is not hot and does not need to be
|
||||
** played back.
|
||||
**
|
||||
@@ -2772,12 +2772,12 @@ static int pager_playback(Pager *pPager, int isHot){
|
||||
** mxPathname is 512, which is the same as the minimum allowable value
|
||||
** for pageSize.
|
||||
*/
|
||||
zMaster = pPager->pTmpSpace;
|
||||
rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1);
|
||||
if( rc==SQLITE_OK && zMaster[0] ){
|
||||
rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res);
|
||||
zSuper = pPager->pTmpSpace;
|
||||
rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1);
|
||||
if( rc==SQLITE_OK && zSuper[0] ){
|
||||
rc = sqlite3OsAccess(pVfs, zSuper, SQLITE_ACCESS_EXISTS, &res);
|
||||
}
|
||||
zMaster = 0;
|
||||
zSuper = 0;
|
||||
if( rc!=SQLITE_OK || !res ){
|
||||
goto end_playback;
|
||||
}
|
||||
@@ -2904,8 +2904,8 @@ end_playback:
|
||||
pPager->changeCountDone = pPager->tempFile;
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
zMaster = pPager->pTmpSpace;
|
||||
rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1);
|
||||
zSuper = pPager->pTmpSpace;
|
||||
rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1);
|
||||
testcase( rc!=SQLITE_OK );
|
||||
}
|
||||
if( rc==SQLITE_OK
|
||||
@@ -2914,14 +2914,14 @@ end_playback:
|
||||
rc = sqlite3PagerSync(pPager, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = pager_end_transaction(pPager, zMaster[0]!='\0', 0);
|
||||
rc = pager_end_transaction(pPager, zSuper[0]!='\0', 0);
|
||||
testcase( rc!=SQLITE_OK );
|
||||
}
|
||||
if( rc==SQLITE_OK && zMaster[0] && res ){
|
||||
/* If there was a master journal and this routine will return success,
|
||||
** see if it is possible to delete the master journal.
|
||||
if( rc==SQLITE_OK && zSuper[0] && res ){
|
||||
/* If there was a super-journal and this routine will return success,
|
||||
** see if it is possible to delete the super-journal.
|
||||
*/
|
||||
rc = pager_delmaster(pPager, zMaster);
|
||||
rc = pager_delsuper(pPager, zSuper);
|
||||
testcase( rc!=SQLITE_OK );
|
||||
}
|
||||
if( isHot && nPlayback ){
|
||||
@@ -3300,7 +3300,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.
|
||||
**
|
||||
@@ -5040,8 +5040,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
|
||||
@@ -5705,7 +5705,6 @@ void sqlite3PagerUnrefPageOne(DbPage *pPg){
|
||||
assert( pPg->pgno==1 );
|
||||
assert( (pPg->flags & PGHDR_MMAP)==0 ); /* Page1 is never memory mapped */
|
||||
pPager = pPg->pPager;
|
||||
sqlite3PagerResetLockTimeout(pPager);
|
||||
sqlite3PcacheRelease(pPg);
|
||||
pagerUnlockIfUnused(pPager);
|
||||
}
|
||||
@@ -5787,7 +5786,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);
|
||||
}
|
||||
@@ -6299,9 +6298,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 ){
|
||||
@@ -6339,10 +6338,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:
|
||||
**
|
||||
@@ -6354,9 +6353,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
|
||||
@@ -6366,7 +6365,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 */
|
||||
@@ -6384,8 +6383,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;
|
||||
@@ -6424,7 +6423,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);
|
||||
@@ -6462,7 +6461,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)
|
||||
@@ -6483,7 +6482,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 );
|
||||
@@ -6493,11 +6492,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.
|
||||
@@ -6565,7 +6564,7 @@ int sqlite3PagerCommitPhaseOne(
|
||||
|
||||
/* Finally, sync the database file. */
|
||||
if( !noSync ){
|
||||
rc = sqlite3PagerSync(pPager, zMaster);
|
||||
rc = sqlite3PagerSync(pPager, zSuper);
|
||||
}
|
||||
IOTRACE(("DBSYNC %p\n", pPager))
|
||||
}
|
||||
@@ -6630,7 +6629,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);
|
||||
}
|
||||
|
||||
@@ -6675,7 +6674,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;
|
||||
@@ -6998,16 +6997,6 @@ sqlite3_file *sqlite3PagerFile(Pager *pPager){
|
||||
return pPager->fd;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
/*
|
||||
** Reset the lock timeout for pager.
|
||||
*/
|
||||
void sqlite3PagerResetLockTimeout(Pager *pPager){
|
||||
int x = 0;
|
||||
sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_LOCK_TIMEOUT, &x);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Return the file handle for the journal file (if it exists).
|
||||
** This will be either the rollback journal or the WAL file.
|
||||
@@ -7421,7 +7410,6 @@ int sqlite3PagerCheckpoint(
|
||||
pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
|
||||
pnLog, pnCkpt
|
||||
);
|
||||
sqlite3PagerResetLockTimeout(pPager);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -7586,7 +7574,31 @@ int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
/*
|
||||
** If pager pPager is a wal-mode database not in exclusive locking mode,
|
||||
** invoke the sqlite3WalWriteLock() function on the associated Wal object
|
||||
** with the same db and bLock parameters as were passed to this function.
|
||||
** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise.
|
||||
*/
|
||||
int sqlite3PagerWalWriteLock(Pager *pPager, int bLock){
|
||||
int rc = SQLITE_OK;
|
||||
if( pagerUseWal(pPager) && pPager->exclusiveMode==0 ){
|
||||
rc = sqlite3WalWriteLock(pPager->pWal, bLock);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the database handle used by the wal layer to determine if
|
||||
** blocking locks are required.
|
||||
*/
|
||||
void sqlite3PagerWalDb(Pager *pPager, sqlite3 *db){
|
||||
if( pagerUseWal(pPager) ){
|
||||
sqlite3WalDb(pPager->pWal, db);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_SNAPSHOT
|
||||
/*
|
||||
@@ -7606,7 +7618,10 @@ int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot){
|
||||
** read transaction is opened, attempt to read from the snapshot it
|
||||
** identifies. If this is not a WAL database, return an error.
|
||||
*/
|
||||
int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot){
|
||||
int sqlite3PagerSnapshotOpen(
|
||||
Pager *pPager,
|
||||
sqlite3_snapshot *pSnapshot
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
if( pPager->pWal ){
|
||||
sqlite3WalSnapshotOpen(pPager->pWal, pSnapshot);
|
||||
|
||||
+14
-11
@@ -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))
|
||||
@@ -161,9 +161,9 @@ void *sqlite3PagerGetExtra(DbPage *);
|
||||
/* Functions used to manage pager transactions and savepoints. */
|
||||
void sqlite3PagerPagecount(Pager*, int*);
|
||||
int sqlite3PagerBegin(Pager*, int exFlag, int);
|
||||
int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, int);
|
||||
int sqlite3PagerCommitPhaseOne(Pager*,const char *zSuper, int);
|
||||
int sqlite3PagerExclusiveLock(Pager*);
|
||||
int sqlite3PagerSync(Pager *pPager, const char *zMaster);
|
||||
int sqlite3PagerSync(Pager *pPager, const char *zSuper);
|
||||
int sqlite3PagerCommitPhaseTwo(Pager*);
|
||||
int sqlite3PagerRollback(Pager*);
|
||||
int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
|
||||
@@ -177,14 +177,22 @@ int sqlite3PagerSharedLock(Pager *pPager);
|
||||
int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
|
||||
int sqlite3PagerCloseWal(Pager *pPager, sqlite3*);
|
||||
# ifdef SQLITE_ENABLE_SNAPSHOT
|
||||
int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot);
|
||||
int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot);
|
||||
int sqlite3PagerSnapshotGet(Pager*, sqlite3_snapshot **ppSnapshot);
|
||||
int sqlite3PagerSnapshotOpen(Pager*, sqlite3_snapshot *pSnapshot);
|
||||
int sqlite3PagerSnapshotRecover(Pager *pPager);
|
||||
int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot);
|
||||
void sqlite3PagerSnapshotUnlock(Pager *pPager);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(SQLITE_OMIT_WAL) && defined(SQLITE_ENABLE_SETLK_TIMEOUT)
|
||||
int sqlite3PagerWalWriteLock(Pager*, int);
|
||||
void sqlite3PagerWalDb(Pager*, sqlite3*);
|
||||
#else
|
||||
# define sqlite3PagerWalWriteLock(y,z) SQLITE_OK
|
||||
# define sqlite3PagerWalDb(x,y)
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_DIRECT_OVERFLOW_READ
|
||||
int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno);
|
||||
#endif
|
||||
@@ -210,11 +218,6 @@ int sqlite3PagerIsMemdb(Pager*);
|
||||
void sqlite3PagerCacheStat(Pager *, int, int, int *);
|
||||
void sqlite3PagerClearCache(Pager*);
|
||||
int sqlite3SectorSize(sqlite3_file *);
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
void sqlite3PagerResetLockTimeout(Pager *pPager);
|
||||
#else
|
||||
# define sqlite3PagerResetLockTimeout(X)
|
||||
#endif
|
||||
|
||||
/* Functions used to truncate the database file. */
|
||||
void sqlite3PagerTruncateImage(Pager*,Pgno);
|
||||
|
||||
+1
-1
@@ -1315,7 +1315,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.
|
||||
|
||||
+20
-3
@@ -555,7 +555,7 @@ void sqlite3Pragma(
|
||||
** buffer that the pager module resizes using sqlite3_realloc().
|
||||
*/
|
||||
db->nextPagesize = sqlite3Atoi(zRight);
|
||||
if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,-1,0) ){
|
||||
if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,0,0) ){
|
||||
sqlite3OomFault(db);
|
||||
}
|
||||
}
|
||||
@@ -1729,7 +1729,6 @@ void sqlite3Pragma(
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, loopTop-1);
|
||||
#ifndef SQLITE_OMIT_BTREECOUNT
|
||||
if( !isQuick ){
|
||||
sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
@@ -1743,7 +1742,6 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_OMIT_BTREECOUNT */
|
||||
}
|
||||
}
|
||||
{
|
||||
@@ -2178,6 +2176,25 @@ void sqlite3Pragma(
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** PRAGMA analysis_limit
|
||||
** PRAGMA analysis_limit = N
|
||||
**
|
||||
** Configure the maximum number of rows that ANALYZE will examine
|
||||
** in each index that it looks at. Return the new limit.
|
||||
*/
|
||||
case PragTyp_ANALYSIS_LIMIT: {
|
||||
sqlite3_int64 N;
|
||||
if( zRight
|
||||
&& sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK
|
||||
&& N>=0
|
||||
){
|
||||
db->nAnalysisLimit = (int)(N&0x7fffffff);
|
||||
}
|
||||
returnSingleInt(v, db->nAnalysisLimit);
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
/*
|
||||
** Report the current state of file logs for all databases
|
||||
|
||||
+50
-44
@@ -6,49 +6,50 @@
|
||||
|
||||
/* The various pragma types */
|
||||
#define PragTyp_ACTIVATE_EXTENSIONS 0
|
||||
#define PragTyp_HEADER_VALUE 1
|
||||
#define PragTyp_AUTO_VACUUM 2
|
||||
#define PragTyp_FLAG 3
|
||||
#define PragTyp_BUSY_TIMEOUT 4
|
||||
#define PragTyp_CACHE_SIZE 5
|
||||
#define PragTyp_CACHE_SPILL 6
|
||||
#define PragTyp_CASE_SENSITIVE_LIKE 7
|
||||
#define PragTyp_COLLATION_LIST 8
|
||||
#define PragTyp_COMPILE_OPTIONS 9
|
||||
#define PragTyp_DATA_STORE_DIRECTORY 10
|
||||
#define PragTyp_DATABASE_LIST 11
|
||||
#define PragTyp_DEFAULT_CACHE_SIZE 12
|
||||
#define PragTyp_ENCODING 13
|
||||
#define PragTyp_FOREIGN_KEY_CHECK 14
|
||||
#define PragTyp_FOREIGN_KEY_LIST 15
|
||||
#define PragTyp_FUNCTION_LIST 16
|
||||
#define PragTyp_HARD_HEAP_LIMIT 17
|
||||
#define PragTyp_INCREMENTAL_VACUUM 18
|
||||
#define PragTyp_INDEX_INFO 19
|
||||
#define PragTyp_INDEX_LIST 20
|
||||
#define PragTyp_INTEGRITY_CHECK 21
|
||||
#define PragTyp_JOURNAL_MODE 22
|
||||
#define PragTyp_JOURNAL_SIZE_LIMIT 23
|
||||
#define PragTyp_LOCK_PROXY_FILE 24
|
||||
#define PragTyp_LOCKING_MODE 25
|
||||
#define PragTyp_PAGE_COUNT 26
|
||||
#define PragTyp_MMAP_SIZE 27
|
||||
#define PragTyp_MODULE_LIST 28
|
||||
#define PragTyp_OPTIMIZE 29
|
||||
#define PragTyp_PAGE_SIZE 30
|
||||
#define PragTyp_PRAGMA_LIST 31
|
||||
#define PragTyp_SECURE_DELETE 32
|
||||
#define PragTyp_SHRINK_MEMORY 33
|
||||
#define PragTyp_SOFT_HEAP_LIMIT 34
|
||||
#define PragTyp_SYNCHRONOUS 35
|
||||
#define PragTyp_TABLE_INFO 36
|
||||
#define PragTyp_TEMP_STORE 37
|
||||
#define PragTyp_TEMP_STORE_DIRECTORY 38
|
||||
#define PragTyp_THREADS 39
|
||||
#define PragTyp_WAL_AUTOCHECKPOINT 40
|
||||
#define PragTyp_WAL_CHECKPOINT 41
|
||||
#define PragTyp_LOCK_STATUS 42
|
||||
#define PragTyp_STATS 43
|
||||
#define PragTyp_ANALYSIS_LIMIT 1
|
||||
#define PragTyp_HEADER_VALUE 2
|
||||
#define PragTyp_AUTO_VACUUM 3
|
||||
#define PragTyp_FLAG 4
|
||||
#define PragTyp_BUSY_TIMEOUT 5
|
||||
#define PragTyp_CACHE_SIZE 6
|
||||
#define PragTyp_CACHE_SPILL 7
|
||||
#define PragTyp_CASE_SENSITIVE_LIKE 8
|
||||
#define PragTyp_COLLATION_LIST 9
|
||||
#define PragTyp_COMPILE_OPTIONS 10
|
||||
#define PragTyp_DATA_STORE_DIRECTORY 11
|
||||
#define PragTyp_DATABASE_LIST 12
|
||||
#define PragTyp_DEFAULT_CACHE_SIZE 13
|
||||
#define PragTyp_ENCODING 14
|
||||
#define PragTyp_FOREIGN_KEY_CHECK 15
|
||||
#define PragTyp_FOREIGN_KEY_LIST 16
|
||||
#define PragTyp_FUNCTION_LIST 17
|
||||
#define PragTyp_HARD_HEAP_LIMIT 18
|
||||
#define PragTyp_INCREMENTAL_VACUUM 19
|
||||
#define PragTyp_INDEX_INFO 20
|
||||
#define PragTyp_INDEX_LIST 21
|
||||
#define PragTyp_INTEGRITY_CHECK 22
|
||||
#define PragTyp_JOURNAL_MODE 23
|
||||
#define PragTyp_JOURNAL_SIZE_LIMIT 24
|
||||
#define PragTyp_LOCK_PROXY_FILE 25
|
||||
#define PragTyp_LOCKING_MODE 26
|
||||
#define PragTyp_PAGE_COUNT 27
|
||||
#define PragTyp_MMAP_SIZE 28
|
||||
#define PragTyp_MODULE_LIST 29
|
||||
#define PragTyp_OPTIMIZE 30
|
||||
#define PragTyp_PAGE_SIZE 31
|
||||
#define PragTyp_PRAGMA_LIST 32
|
||||
#define PragTyp_SECURE_DELETE 33
|
||||
#define PragTyp_SHRINK_MEMORY 34
|
||||
#define PragTyp_SOFT_HEAP_LIMIT 35
|
||||
#define PragTyp_SYNCHRONOUS 36
|
||||
#define PragTyp_TABLE_INFO 37
|
||||
#define PragTyp_TEMP_STORE 38
|
||||
#define PragTyp_TEMP_STORE_DIRECTORY 39
|
||||
#define PragTyp_THREADS 40
|
||||
#define PragTyp_WAL_AUTOCHECKPOINT 41
|
||||
#define PragTyp_WAL_CHECKPOINT 42
|
||||
#define PragTyp_LOCK_STATUS 43
|
||||
#define PragTyp_STATS 44
|
||||
|
||||
/* Property flags associated with various pragma. */
|
||||
#define PragFlg_NeedSchema 0x01 /* Force schema load before running */
|
||||
@@ -139,6 +140,11 @@ static const PragmaName aPragmaName[] = {
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
{/* zName: */ "analysis_limit",
|
||||
/* ePragTyp: */ PragTyp_ANALYSIS_LIMIT,
|
||||
/* ePragFlg: */ PragFlg_Result0,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ 0 },
|
||||
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
|
||||
{/* zName: */ "application_id",
|
||||
/* ePragTyp: */ PragTyp_HEADER_VALUE,
|
||||
@@ -639,4 +645,4 @@ static const PragmaName aPragmaName[] = {
|
||||
/* iArg: */ SQLITE_WriteSchema|SQLITE_NoSchemaError },
|
||||
#endif
|
||||
};
|
||||
/* Number of pragmas: 66 on by default, 76 total. */
|
||||
/* Number of pragmas: 67 on by default, 77 total. */
|
||||
|
||||
+28
-12
@@ -177,7 +177,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 +189,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,"
|
||||
@@ -333,7 +333,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
|
||||
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 +363,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 +504,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 ){
|
||||
@@ -529,11 +530,26 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
** Deallocate a single AggInfo object
|
||||
*/
|
||||
static void agginfoFree(sqlite3 *db, AggInfo *p){
|
||||
sqlite3DbFree(db, p->aCol);
|
||||
sqlite3DbFree(db, p->aFunc);
|
||||
sqlite3DbFree(db, p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Free all memory allocations in the pParse object
|
||||
*/
|
||||
void sqlite3ParserReset(Parse *pParse){
|
||||
sqlite3 *db = pParse->db;
|
||||
AggInfo *pThis = pParse->pAggList;
|
||||
while( pThis ){
|
||||
AggInfo *pNext = pThis->pNext;
|
||||
agginfoFree(db, pThis);
|
||||
pThis = pNext;
|
||||
}
|
||||
sqlite3DbFree(db, pParse->aLabel);
|
||||
sqlite3ExprListDelete(db, pParse->pConstExpr);
|
||||
if( db ){
|
||||
@@ -727,7 +743,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){
|
||||
|
||||
+17
-3
@@ -194,6 +194,13 @@ static char *printfTempBuf(sqlite3_str *pAccum, sqlite3_int64 n){
|
||||
#endif
|
||||
#define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */
|
||||
|
||||
/*
|
||||
** Hard limit on the precision of floating-point conversions.
|
||||
*/
|
||||
#ifndef SQLITE_PRINTF_PRECISION_LIMIT
|
||||
# define SQLITE_FP_PRECISION_LIMIT 100000000
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Render a string given by "fmt" into the StrAccum object.
|
||||
*/
|
||||
@@ -394,6 +401,8 @@ void sqlite3_str_vappendf(
|
||||
** xtype The class of the conversion.
|
||||
** infop Pointer to the appropriate info struct.
|
||||
*/
|
||||
assert( width>=0 );
|
||||
assert( precision>=(-1) );
|
||||
switch( xtype ){
|
||||
case etPOINTER:
|
||||
flag_long = sizeof(char*)==sizeof(i64) ? 2 :
|
||||
@@ -515,6 +524,11 @@ void sqlite3_str_vappendf(
|
||||
length = 0;
|
||||
#else
|
||||
if( precision<0 ) precision = 6; /* Set default precision */
|
||||
#ifdef SQLITE_FP_PRECISION_LIMIT
|
||||
if( precision>SQLITE_FP_PRECISION_LIMIT ){
|
||||
precision = SQLITE_FP_PRECISION_LIMIT;
|
||||
}
|
||||
#endif
|
||||
if( realvalue<0.0 ){
|
||||
realvalue = -realvalue;
|
||||
prefix = '-';
|
||||
@@ -797,7 +811,7 @@ void sqlite3_str_vappendf(
|
||||
}
|
||||
isnull = escarg==0;
|
||||
if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
|
||||
/* For %q, %Q, and %w, the precision is the number of byte (or
|
||||
/* For %q, %Q, and %w, the precision is the number of bytes (or
|
||||
** characters if the ! flags is present) to use from the input.
|
||||
** Because of the extra quoting characters inserted, the number
|
||||
** of output characters may be larger than the precision.
|
||||
@@ -924,7 +938,7 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
|
||||
if( p->db ){
|
||||
zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
|
||||
}else{
|
||||
zNew = sqlite3_realloc64(zOld, p->nAlloc);
|
||||
zNew = sqlite3Realloc(zOld, p->nAlloc);
|
||||
}
|
||||
if( zNew ){
|
||||
assert( p->zText!=0 || p->nChar==0 );
|
||||
@@ -1266,7 +1280,7 @@ void sqlite3_log(int iErrCode, const char *zFormat, ...){
|
||||
void sqlite3DebugPrintf(const char *zFormat, ...){
|
||||
va_list ap;
|
||||
StrAccum acc;
|
||||
char zBuf[500];
|
||||
char zBuf[SQLITE_PRINT_BUF_SIZE*10];
|
||||
sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
|
||||
va_start(ap,zFormat);
|
||||
sqlite3_str_vappendf(&acc, zFormat, ap);
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
**
|
||||
** incrAggFunctionDepth(pExpr,n) is the main routine. incrAggDepth(..)
|
||||
** is a helper function - a callback for the tree walker.
|
||||
**
|
||||
** See also the sqlite3WindowExtraAggFuncDepth() routine in window.c
|
||||
*/
|
||||
static int incrAggDepth(Walker *pWalker, Expr *pExpr){
|
||||
if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.n;
|
||||
|
||||
+132
-119
@@ -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
|
||||
@@ -138,9 +124,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 +160,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -2717,9 +2702,7 @@ static int multiSelect(
|
||||
selectOpName(p->op)));
|
||||
rc = sqlite3Select(pParse, p, &uniondest);
|
||||
testcase( rc!=SQLITE_OK );
|
||||
/* Query flattening in sqlite3Select() might refill p->pOrderBy.
|
||||
** Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */
|
||||
sqlite3ExprListDelete(db, p->pOrderBy);
|
||||
assert( p->pOrderBy==0 );
|
||||
pDelete = p->pPrior;
|
||||
p->pPrior = pPrior;
|
||||
p->pOrderBy = 0;
|
||||
@@ -3792,6 +3775,7 @@ static int flattenSubquery(
|
||||
Expr *pWhere; /* The WHERE clause */
|
||||
struct SrcList_item *pSubitem; /* The subquery */
|
||||
sqlite3 *db = pParse->db;
|
||||
Walker w; /* Walker to persist agginfo data */
|
||||
|
||||
/* Check to see if flattening is permitted. Return 0 if not.
|
||||
*/
|
||||
@@ -4105,7 +4089,7 @@ static int flattenSubquery(
|
||||
** We look at every expression in the outer query and every place we see
|
||||
** "a" we substitute "x*3" and every place we see "b" we substitute "y+10".
|
||||
*/
|
||||
if( pSub->pOrderBy ){
|
||||
if( pSub->pOrderBy && (pParent->selFlags & SF_NoopOrderBy)==0 ){
|
||||
/* At this point, any non-zero iOrderByCol values indicate that the
|
||||
** ORDER BY column expression is identical to the iOrderByCol'th
|
||||
** expression returned by SELECT statement pSub. Since these values
|
||||
@@ -4129,7 +4113,13 @@ static int flattenSubquery(
|
||||
if( isLeftJoin>0 ){
|
||||
sqlite3SetJoinExpr(pWhere, iNewParent);
|
||||
}
|
||||
pParent->pWhere = sqlite3ExprAnd(pParse, pWhere, pParent->pWhere);
|
||||
if( pWhere ){
|
||||
if( pParent->pWhere ){
|
||||
pParent->pWhere = sqlite3PExpr(pParse, TK_AND, pWhere, pParent->pWhere);
|
||||
}else{
|
||||
pParent->pWhere = pWhere;
|
||||
}
|
||||
}
|
||||
if( db->mallocFailed==0 ){
|
||||
SubstContext x;
|
||||
x.pParse = pParse;
|
||||
@@ -4166,6 +4156,8 @@ static int flattenSubquery(
|
||||
/* Finially, delete what is left of the subquery and return
|
||||
** success.
|
||||
*/
|
||||
sqlite3AggInfoPersistWalkerInit(&w, pParse);
|
||||
sqlite3WalkSelect(&w,pSub1);
|
||||
sqlite3SelectDelete(db, pSub1);
|
||||
|
||||
#if SELECTTRACE_ENABLED
|
||||
@@ -4426,11 +4418,14 @@ static int pushDownWhereTerms(
|
||||
){
|
||||
Expr *pNew;
|
||||
int nChng = 0;
|
||||
Select *pSel;
|
||||
if( pWhere==0 ) return 0;
|
||||
if( pSubq->selFlags & SF_Recursive ) return 0; /* restriction (2) */
|
||||
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( pSubq->pWin ) return 0; /* restriction (6) */
|
||||
for(pSel=pSubq; pSel; pSel=pSel->pPrior){
|
||||
if( pSel->pWin ) return 0; /* restriction (6) */
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
@@ -4630,6 +4625,14 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
|
||||
for(pX=p; pX && (pX->op==TK_ALL || pX->op==TK_SELECT); pX=pX->pPrior){}
|
||||
if( pX==0 ) return WRC_Continue;
|
||||
a = p->pOrderBy->a;
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
/* If iOrderByCol is already non-zero, then it has already been matched
|
||||
** to a result column of the SELECT statement. This occurs when the
|
||||
** SELECT is rewritten for window-functions processing and then passed
|
||||
** to sqlite3SelectPrep() and similar a second time. The rewriting done
|
||||
** by this function is not required in this case. */
|
||||
if( a[0].u.x.iOrderByCol ) return WRC_Continue;
|
||||
#endif
|
||||
for(i=p->pOrderBy->nExpr-1; i>=0; i--){
|
||||
if( a[i].pExpr->flags & EP_Collate ) break;
|
||||
}
|
||||
@@ -5229,29 +5232,6 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
/*
|
||||
** No-op routine for the parse-tree walker.
|
||||
**
|
||||
** When this routine is the Walker.xExprCallback then expression trees
|
||||
** are walked without any actions being taken at each node. Presumably,
|
||||
** when this routine is used for Walker.xExprCallback then
|
||||
** Walker.xSelectCallback is set to do something useful for every
|
||||
** subquery in the parser tree.
|
||||
*/
|
||||
int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
|
||||
UNUSED_PARAMETER2(NotUsed, NotUsed2);
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
/*
|
||||
** No-op routine for the parse-tree walker for SELECT statements.
|
||||
** subquery in the parser tree.
|
||||
*/
|
||||
int sqlite3SelectWalkNoop(Walker *NotUsed, Select *NotUsed2){
|
||||
UNUSED_PARAMETER2(NotUsed, NotUsed2);
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
#if SQLITE_DEBUG
|
||||
/*
|
||||
** Always assert. This xSelectCallback2 implementation proves that the
|
||||
@@ -5393,7 +5373,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 */
|
||||
@@ -5410,7 +5390,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 "
|
||||
@@ -5434,8 +5414,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);
|
||||
}
|
||||
@@ -5464,11 +5444,11 @@ 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)
|
||||
){
|
||||
@@ -5530,7 +5510,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;
|
||||
@@ -5773,10 +5753,10 @@ int sqlite3Select(
|
||||
Expr *pWhere; /* The WHERE clause. May be NULL */
|
||||
ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
|
||||
Expr *pHaving; /* The HAVING clause. May be NULL */
|
||||
AggInfo *pAggInfo = 0; /* Aggregate information */
|
||||
int rc = 1; /* Value to return from this function */
|
||||
DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */
|
||||
SortCtx sSort; /* Info on how to code the ORDER BY clause */
|
||||
AggInfo sAggInfo; /* Information used by aggregate queries */
|
||||
int iEnd; /* Address of the end of the query */
|
||||
sqlite3 *db; /* The database connection */
|
||||
ExprList *pMinMaxOrderBy = 0; /* Added ORDER BY for min/max queries */
|
||||
@@ -5788,7 +5768,6 @@ int sqlite3Select(
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
|
||||
memset(&sAggInfo, 0, sizeof(sAggInfo));
|
||||
#if SELECTTRACE_ENABLED
|
||||
SELECTTRACE(1,pParse,p, ("begin processing:\n", pParse->addrExplain));
|
||||
if( sqlite3SelectTrace & 0x100 ){
|
||||
@@ -5810,6 +5789,7 @@ int sqlite3Select(
|
||||
sqlite3ExprListDelete(db, p->pOrderBy);
|
||||
p->pOrderBy = 0;
|
||||
p->selFlags &= ~SF_Distinct;
|
||||
p->selFlags |= SF_NoopOrderBy;
|
||||
}
|
||||
sqlite3SelectPrep(pParse, p, 0);
|
||||
if( pParse->nErr || db->mallocFailed ){
|
||||
@@ -5845,7 +5825,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)
|
||||
@@ -5854,6 +5834,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.
|
||||
*/
|
||||
@@ -6245,7 +6230,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);
|
||||
}
|
||||
@@ -6378,14 +6363,21 @@ int sqlite3Select(
|
||||
** sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the
|
||||
** SELECT statement.
|
||||
*/
|
||||
pAggInfo = sqlite3DbMallocZero(db, sizeof(*pAggInfo) );
|
||||
if( pAggInfo==0 ){
|
||||
goto select_end;
|
||||
}
|
||||
pAggInfo->pNext = pParse->pAggList;
|
||||
pParse->pAggList = pAggInfo;
|
||||
pAggInfo->selId = p->selId;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = pParse;
|
||||
sNC.pSrcList = pTabList;
|
||||
sNC.uNC.pAggInfo = &sAggInfo;
|
||||
sNC.uNC.pAggInfo = pAggInfo;
|
||||
VVA_ONLY( sNC.ncFlags = NC_UAggInfo; )
|
||||
sAggInfo.mnReg = pParse->nMem+1;
|
||||
sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0;
|
||||
sAggInfo.pGroupBy = pGroupBy;
|
||||
pAggInfo->mnReg = pParse->nMem+1;
|
||||
pAggInfo->nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0;
|
||||
pAggInfo->pGroupBy = pGroupBy;
|
||||
sqlite3ExprAnalyzeAggList(&sNC, pEList);
|
||||
sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy);
|
||||
if( pHaving ){
|
||||
@@ -6398,14 +6390,14 @@ int sqlite3Select(
|
||||
}
|
||||
sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
|
||||
}
|
||||
sAggInfo.nAccumulator = sAggInfo.nColumn;
|
||||
if( p->pGroupBy==0 && p->pHaving==0 && sAggInfo.nFunc==1 ){
|
||||
minMaxFlag = minMaxQuery(db, sAggInfo.aFunc[0].pExpr, &pMinMaxOrderBy);
|
||||
pAggInfo->nAccumulator = pAggInfo->nColumn;
|
||||
if( p->pGroupBy==0 && p->pHaving==0 && pAggInfo->nFunc==1 ){
|
||||
minMaxFlag = minMaxQuery(db, pAggInfo->aFunc[0].pFExpr, &pMinMaxOrderBy);
|
||||
}else{
|
||||
minMaxFlag = WHERE_ORDERBY_NORMAL;
|
||||
}
|
||||
for(i=0; i<sAggInfo.nFunc; i++){
|
||||
Expr *pExpr = sAggInfo.aFunc[i].pExpr;
|
||||
for(i=0; i<pAggInfo->nFunc; i++){
|
||||
Expr *pExpr = pAggInfo->aFunc[i].pFExpr;
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
sNC.ncFlags |= NC_InAggFunc;
|
||||
sqlite3ExprAnalyzeAggList(&sNC, pExpr->x.pList);
|
||||
@@ -6417,22 +6409,22 @@ int sqlite3Select(
|
||||
#endif
|
||||
sNC.ncFlags &= ~NC_InAggFunc;
|
||||
}
|
||||
sAggInfo.mxReg = pParse->nMem;
|
||||
pAggInfo->mxReg = pParse->nMem;
|
||||
if( db->mallocFailed ) goto select_end;
|
||||
#if SELECTTRACE_ENABLED
|
||||
if( sqlite3SelectTrace & 0x400 ){
|
||||
int ii;
|
||||
SELECTTRACE(0x400,pParse,p,("After aggregate analysis:\n"));
|
||||
SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", pAggInfo));
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
for(ii=0; ii<sAggInfo.nColumn; ii++){
|
||||
for(ii=0; ii<pAggInfo->nColumn; ii++){
|
||||
sqlite3DebugPrintf("agg-column[%d] iMem=%d\n",
|
||||
ii, sAggInfo.aCol[ii].iMem);
|
||||
sqlite3TreeViewExpr(0, sAggInfo.aCol[ii].pExpr, 0);
|
||||
ii, pAggInfo->aCol[ii].iMem);
|
||||
sqlite3TreeViewExpr(0, pAggInfo->aCol[ii].pCExpr, 0);
|
||||
}
|
||||
for(ii=0; ii<sAggInfo.nFunc; ii++){
|
||||
for(ii=0; ii<pAggInfo->nFunc; ii++){
|
||||
sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n",
|
||||
ii, sAggInfo.aFunc[ii].iMem);
|
||||
sqlite3TreeViewExpr(0, sAggInfo.aFunc[ii].pExpr, 0);
|
||||
ii, pAggInfo->aFunc[ii].iMem);
|
||||
sqlite3TreeViewExpr(0, pAggInfo->aFunc[ii].pFExpr, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -6457,10 +6449,11 @@ int sqlite3Select(
|
||||
** that we do not need it after all, the OP_SorterOpen instruction
|
||||
** will be converted into a Noop.
|
||||
*/
|
||||
sAggInfo.sortingIdx = pParse->nTab++;
|
||||
pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pGroupBy,0,sAggInfo.nColumn);
|
||||
pAggInfo->sortingIdx = pParse->nTab++;
|
||||
pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pGroupBy,
|
||||
0, pAggInfo->nColumn);
|
||||
addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
|
||||
sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
|
||||
pAggInfo->sortingIdx, pAggInfo->nSortingColumn,
|
||||
0, (char*)pKeyInfo, P4_KEYINFO);
|
||||
|
||||
/* Initialize memory locations used by GROUP BY aggregate processing
|
||||
@@ -6515,8 +6508,8 @@ int sqlite3Select(
|
||||
nGroupBy = pGroupBy->nExpr;
|
||||
nCol = nGroupBy;
|
||||
j = nGroupBy;
|
||||
for(i=0; i<sAggInfo.nColumn; i++){
|
||||
if( sAggInfo.aCol[i].iSorterColumn>=j ){
|
||||
for(i=0; i<pAggInfo->nColumn; i++){
|
||||
if( pAggInfo->aCol[i].iSorterColumn>=j ){
|
||||
nCol++;
|
||||
j++;
|
||||
}
|
||||
@@ -6524,8 +6517,8 @@ int sqlite3Select(
|
||||
regBase = sqlite3GetTempRange(pParse, nCol);
|
||||
sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0);
|
||||
j = nGroupBy;
|
||||
for(i=0; i<sAggInfo.nColumn; i++){
|
||||
struct AggInfo_col *pCol = &sAggInfo.aCol[i];
|
||||
for(i=0; i<pAggInfo->nColumn; i++){
|
||||
struct AggInfo_col *pCol = &pAggInfo->aCol[i];
|
||||
if( pCol->iSorterColumn>=j ){
|
||||
int r1 = j + regBase;
|
||||
sqlite3ExprCodeGetColumnOfTable(v,
|
||||
@@ -6535,16 +6528,16 @@ int sqlite3Select(
|
||||
}
|
||||
regRecord = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord);
|
||||
sqlite3VdbeAddOp2(v, OP_SorterInsert, sAggInfo.sortingIdx, regRecord);
|
||||
sqlite3VdbeAddOp2(v, OP_SorterInsert, pAggInfo->sortingIdx, regRecord);
|
||||
sqlite3ReleaseTempReg(pParse, regRecord);
|
||||
sqlite3ReleaseTempRange(pParse, regBase, nCol);
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
sAggInfo.sortingIdxPTab = sortPTab = pParse->nTab++;
|
||||
pAggInfo->sortingIdxPTab = sortPTab = pParse->nTab++;
|
||||
sortOut = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_OpenPseudo, sortPTab, sortOut, nCol);
|
||||
sqlite3VdbeAddOp2(v, OP_SorterSort, sAggInfo.sortingIdx, addrEnd);
|
||||
sqlite3VdbeAddOp2(v, OP_SorterSort, pAggInfo->sortingIdx, addrEnd);
|
||||
VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v);
|
||||
sAggInfo.useSortingIdx = 1;
|
||||
pAggInfo->useSortingIdx = 1;
|
||||
}
|
||||
|
||||
/* If the index or temporary table used by the GROUP BY sort
|
||||
@@ -6568,14 +6561,14 @@ int sqlite3Select(
|
||||
*/
|
||||
addrTopOfLoop = sqlite3VdbeCurrentAddr(v);
|
||||
if( groupBySort ){
|
||||
sqlite3VdbeAddOp3(v, OP_SorterData, sAggInfo.sortingIdx,
|
||||
sqlite3VdbeAddOp3(v, OP_SorterData, pAggInfo->sortingIdx,
|
||||
sortOut, sortPTab);
|
||||
}
|
||||
for(j=0; j<pGroupBy->nExpr; j++){
|
||||
if( groupBySort ){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j);
|
||||
}else{
|
||||
sAggInfo.directMode = 1;
|
||||
pAggInfo->directMode = 1;
|
||||
sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j);
|
||||
}
|
||||
}
|
||||
@@ -6605,14 +6598,14 @@ int sqlite3Select(
|
||||
** the current row
|
||||
*/
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
updateAccumulator(pParse, iUseFlag, &sAggInfo);
|
||||
updateAccumulator(pParse, iUseFlag, pAggInfo);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag);
|
||||
VdbeComment((v, "indicate data in accumulator"));
|
||||
|
||||
/* End of the loop
|
||||
*/
|
||||
if( groupBySort ){
|
||||
sqlite3VdbeAddOp2(v, OP_SorterNext, sAggInfo.sortingIdx, addrTopOfLoop);
|
||||
sqlite3VdbeAddOp2(v, OP_SorterNext, pAggInfo->sortingIdx, addrTopOfLoop);
|
||||
VdbeCoverage(v);
|
||||
}else{
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
@@ -6645,7 +6638,7 @@ int sqlite3Select(
|
||||
VdbeCoverage(v);
|
||||
VdbeComment((v, "Groupby result generator entry point"));
|
||||
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
|
||||
finalizeAggFunctions(pParse, &sAggInfo);
|
||||
finalizeAggFunctions(pParse, pAggInfo);
|
||||
sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
|
||||
selectInnerLoop(pParse, p, -1, &sSort,
|
||||
&sDistinct, pDest,
|
||||
@@ -6656,16 +6649,15 @@ int sqlite3Select(
|
||||
/* Generate a subroutine that will reset the group-by accumulator
|
||||
*/
|
||||
sqlite3VdbeResolveLabel(v, addrReset);
|
||||
resetAccumulator(pParse, &sAggInfo);
|
||||
resetAccumulator(pParse, pAggInfo);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag);
|
||||
VdbeComment((v, "indicate accumulator empty"));
|
||||
sqlite3VdbeAddOp1(v, OP_Return, regReset);
|
||||
|
||||
} /* endif pGroupBy. Begin aggregate queries without GROUP BY: */
|
||||
else {
|
||||
#ifndef SQLITE_OMIT_BTREECOUNT
|
||||
Table *pTab;
|
||||
if( (pTab = isSimpleCount(p, &sAggInfo))!=0 ){
|
||||
if( (pTab = isSimpleCount(p, pAggInfo))!=0 ){
|
||||
/* If isSimpleCount() returns a pointer to a Table structure, then
|
||||
** the SQL statement is of the form:
|
||||
**
|
||||
@@ -6699,13 +6691,15 @@ int sqlite3Select(
|
||||
** passed to keep OP_OpenRead happy.
|
||||
*/
|
||||
if( !HasRowid(pTab) ) pBest = sqlite3PrimaryKeyIndex(pTab);
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( pIdx->bUnordered==0
|
||||
&& pIdx->szIdxRow<pTab->szTabRow
|
||||
&& pIdx->pPartIdxWhere==0
|
||||
&& (!pBest || pIdx->szIdxRow<pBest->szIdxRow)
|
||||
){
|
||||
pBest = pIdx;
|
||||
if( !p->pSrc->a[0].fg.notIndexed ){
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( pIdx->bUnordered==0
|
||||
&& pIdx->szIdxRow<pTab->szTabRow
|
||||
&& pIdx->pPartIdxWhere==0
|
||||
&& (!pBest || pIdx->szIdxRow<pBest->szIdxRow)
|
||||
){
|
||||
pBest = pIdx;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( pBest ){
|
||||
@@ -6718,12 +6712,10 @@ int sqlite3Select(
|
||||
if( pKeyInfo ){
|
||||
sqlite3VdbeChangeP4(v, -1, (char *)pKeyInfo, P4_KEYINFO);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Count, iCsr, sAggInfo.aFunc[0].iMem);
|
||||
sqlite3VdbeAddOp2(v, OP_Count, iCsr, pAggInfo->aFunc[0].iMem);
|
||||
sqlite3VdbeAddOp1(v, OP_Close, iCsr);
|
||||
explainSimpleCount(pParse, pTab, pBest);
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_BTREECOUNT */
|
||||
{
|
||||
}else{
|
||||
int regAcc = 0; /* "populate accumulators" flag */
|
||||
|
||||
/* If there are accumulator registers but no min() or max() functions
|
||||
@@ -6735,12 +6727,16 @@ int sqlite3Select(
|
||||
** first row visited by the aggregate, so that they are updated at
|
||||
** least once even if the FILTER clause means the min() or max()
|
||||
** function visits zero rows. */
|
||||
if( sAggInfo.nAccumulator ){
|
||||
for(i=0; i<sAggInfo.nFunc; i++){
|
||||
if( ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_WinFunc) ) continue;
|
||||
if( sAggInfo.aFunc[i].pFunc->funcFlags&SQLITE_FUNC_NEEDCOLL ) break;
|
||||
if( pAggInfo->nAccumulator ){
|
||||
for(i=0; i<pAggInfo->nFunc; i++){
|
||||
if( ExprHasProperty(pAggInfo->aFunc[i].pFExpr, EP_WinFunc) ){
|
||||
continue;
|
||||
}
|
||||
if( pAggInfo->aFunc[i].pFunc->funcFlags&SQLITE_FUNC_NEEDCOLL ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( i==sAggInfo.nFunc ){
|
||||
if( i==pAggInfo->nFunc ){
|
||||
regAcc = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regAcc);
|
||||
}
|
||||
@@ -6751,7 +6747,7 @@ int sqlite3Select(
|
||||
** of output.
|
||||
*/
|
||||
assert( p->pGroupBy==0 );
|
||||
resetAccumulator(pParse, &sAggInfo);
|
||||
resetAccumulator(pParse, pAggInfo);
|
||||
|
||||
/* If this query is a candidate for the min/max optimization, then
|
||||
** minMaxFlag will have been previously set to either
|
||||
@@ -6767,7 +6763,7 @@ int sqlite3Select(
|
||||
if( pWInfo==0 ){
|
||||
goto select_end;
|
||||
}
|
||||
updateAccumulator(pParse, regAcc, &sAggInfo);
|
||||
updateAccumulator(pParse, regAcc, pAggInfo);
|
||||
if( regAcc ) sqlite3VdbeAddOp2(v, OP_Integer, 1, regAcc);
|
||||
if( sqlite3WhereIsOrdered(pWInfo)>0 ){
|
||||
sqlite3VdbeGoto(v, sqlite3WhereBreakLabel(pWInfo));
|
||||
@@ -6775,7 +6771,7 @@ int sqlite3Select(
|
||||
(minMaxFlag==WHERE_ORDERBY_MIN?"min":"max")));
|
||||
}
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
finalizeAggFunctions(pParse, &sAggInfo);
|
||||
finalizeAggFunctions(pParse, pAggInfo);
|
||||
}
|
||||
|
||||
sSort.pOrderBy = 0;
|
||||
@@ -6814,8 +6810,25 @@ int sqlite3Select(
|
||||
*/
|
||||
select_end:
|
||||
sqlite3ExprListDelete(db, pMinMaxOrderBy);
|
||||
sqlite3DbFree(db, sAggInfo.aCol);
|
||||
sqlite3DbFree(db, sAggInfo.aFunc);
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( pAggInfo && !db->mallocFailed ){
|
||||
for(i=0; i<pAggInfo->nColumn; i++){
|
||||
Expr *pExpr = pAggInfo->aCol[i].pCExpr;
|
||||
assert( pExpr!=0 || db->mallocFailed );
|
||||
if( pExpr==0 ) continue;
|
||||
assert( pExpr->pAggInfo==pAggInfo );
|
||||
assert( pExpr->iAgg==i );
|
||||
}
|
||||
for(i=0; i<pAggInfo->nFunc; i++){
|
||||
Expr *pExpr = pAggInfo->aFunc[i].pFExpr;
|
||||
assert( pExpr!=0 || db->mallocFailed );
|
||||
if( pExpr==0 ) continue;
|
||||
assert( pExpr->pAggInfo==pAggInfo );
|
||||
assert( pExpr->iAgg==i );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SELECTTRACE_ENABLED
|
||||
SELECTTRACE(0x1,pParse,p,("end processing\n"));
|
||||
if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
|
||||
|
||||
+486
-147
File diff suppressed because it is too large
Load Diff
+25
-11
@@ -508,6 +508,7 @@ int sqlite3_exec(
|
||||
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
|
||||
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
|
||||
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
|
||||
#define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8))
|
||||
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
|
||||
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
|
||||
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
|
||||
@@ -516,6 +517,7 @@ int sqlite3_exec(
|
||||
#define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6<<8))
|
||||
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
|
||||
#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8))
|
||||
#define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3<<8))
|
||||
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
|
||||
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
|
||||
#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
|
||||
@@ -562,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() */
|
||||
@@ -571,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
|
||||
@@ -868,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.
|
||||
@@ -1111,6 +1116,11 @@ struct sqlite3_io_methods {
|
||||
** happen either internally or externally and that are associated with
|
||||
** a particular attached database.
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_CKPT_START]]
|
||||
** The [SQLITE_FCNTL_CKPT_START] opcode is invoked from within a checkpoint
|
||||
** in wal mode before the client starts to copy pages from the wal
|
||||
** file to the database file.
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_CKPT_DONE]]
|
||||
** The [SQLITE_FCNTL_CKPT_DONE] opcode is invoked from within a checkpoint
|
||||
** in wal mode after the client has finished copying pages from the wal
|
||||
@@ -1155,6 +1165,7 @@ struct sqlite3_io_methods {
|
||||
#define SQLITE_FCNTL_SIZE_LIMIT 36
|
||||
#define SQLITE_FCNTL_CKPT_DONE 37
|
||||
#define SQLITE_FCNTL_RESERVE_BYTES 38
|
||||
#define SQLITE_FCNTL_CKPT_START 39
|
||||
|
||||
/* deprecated names */
|
||||
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
|
||||
@@ -1259,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>)^
|
||||
**
|
||||
@@ -1637,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
|
||||
@@ -2275,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:
|
||||
@@ -5487,7 +5497,7 @@ void sqlite3_value_free(sqlite3_value*);
|
||||
**
|
||||
** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
|
||||
** determined by the N parameter on first successful call. Changing the
|
||||
** value of N in any subsequents call to sqlite3_aggregate_context() within
|
||||
** value of N in any subsequent call to sqlite3_aggregate_context() within
|
||||
** the same aggregate function instance will not resize the memory
|
||||
** allocation.)^ Within the xFinal callback, it is customary to set
|
||||
** N=0 in calls to sqlite3_aggregate_context(C,N) so that no
|
||||
@@ -6266,7 +6276,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
|
||||
@@ -7368,7 +7378,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
|
||||
@@ -7570,7 +7580,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() */
|
||||
@@ -7585,6 +7595,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
|
||||
@@ -9380,7 +9394,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.
|
||||
|
||||
+57
-28
@@ -190,10 +190,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
|
||||
@@ -979,6 +979,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(sqlite3SelectTrace&(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
|
||||
@@ -994,26 +1004,27 @@ struct BusyHandler {
|
||||
int (*xBusyHandler)(void *,int); /* The busy callback */
|
||||
void *pBusyArg; /* First arg to busy callback */
|
||||
int nBusy; /* Incremented with each busy call */
|
||||
u8 bExtraFileArg; /* Include sqlite3_file as callback arg */
|
||||
};
|
||||
|
||||
/*
|
||||
** 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
|
||||
@@ -1539,6 +1550,7 @@ struct sqlite3 {
|
||||
BusyHandler busyHandler; /* Busy callback */
|
||||
Db aDbStatic[2]; /* Static space for the 2 default backends */
|
||||
Savepoint *pSavepoint; /* List of active savepoints */
|
||||
int nAnalysisLimit; /* Number of index rows to ANALYZE */
|
||||
int busyTimeout; /* Busy handler timeout, in msec */
|
||||
int nSavepoint; /* Number of non-transaction savepoints */
|
||||
int nStatement; /* Number of nested statement-transactions */
|
||||
@@ -1546,7 +1558,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 +1600,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 */
|
||||
@@ -1764,7 +1776,7 @@ struct FuncDestructor {
|
||||
#define SQLITE_FUNC_LENGTH 0x0040 /* Built-in length() function */
|
||||
#define SQLITE_FUNC_TYPEOF 0x0080 /* Built-in typeof() function */
|
||||
#define SQLITE_FUNC_COUNT 0x0100 /* Built-in count(*) aggregate */
|
||||
#define SQLITE_FUNC_COALESCE 0x0200 /* Built-in coalesce() or ifnull() */
|
||||
/* 0x0200 -- available for reuse */
|
||||
#define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */
|
||||
#define SQLITE_FUNC_CONSTANT 0x0800 /* Constant inputs give a constant output */
|
||||
#define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */
|
||||
@@ -1785,6 +1797,7 @@ struct FuncDestructor {
|
||||
#define INLINEFUNC_expr_implies_expr 2
|
||||
#define INLINEFUNC_expr_compare 3
|
||||
#define INLINEFUNC_affinity 4
|
||||
#define INLINEFUNC_iif 5
|
||||
#define INLINEFUNC_unlikely 99 /* Default case */
|
||||
|
||||
/*
|
||||
@@ -2381,7 +2394,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
|
||||
@@ -2485,7 +2498,7 @@ struct Token {
|
||||
** code for a SELECT that contains aggregate functions.
|
||||
**
|
||||
** If Expr.op==TK_AGG_COLUMN or TK_AGG_FUNCTION then Expr.pAggInfo is a
|
||||
** pointer to this structure. The Expr.iColumn field is the index in
|
||||
** pointer to this structure. The Expr.iAgg field is the index in
|
||||
** AggInfo.aCol[] or AggInfo.aFunc[] of information needed to generate
|
||||
** code for that node.
|
||||
**
|
||||
@@ -2505,25 +2518,32 @@ struct AggInfo {
|
||||
ExprList *pGroupBy; /* The group by clause */
|
||||
struct AggInfo_col { /* For each column used in source tables */
|
||||
Table *pTab; /* Source table */
|
||||
Expr *pCExpr; /* The original expression */
|
||||
int iTable; /* Cursor number of the source table */
|
||||
int iColumn; /* Column number within the source table */
|
||||
int iSorterColumn; /* Column number in the sorting index */
|
||||
int iMem; /* Memory location that acts as accumulator */
|
||||
Expr *pExpr; /* The original expression */
|
||||
i16 iColumn; /* Column number within the source table */
|
||||
i16 iSorterColumn; /* Column number in the sorting index */
|
||||
} *aCol;
|
||||
int nColumn; /* Number of used entries in aCol[] */
|
||||
int nAccumulator; /* Number of columns that show through to the output.
|
||||
** Additional columns are used only as parameters to
|
||||
** aggregate functions */
|
||||
struct AggInfo_func { /* For each aggregate function */
|
||||
Expr *pExpr; /* Expression encoding the function */
|
||||
Expr *pFExpr; /* Expression encoding the function */
|
||||
FuncDef *pFunc; /* The aggregate function implementation */
|
||||
int iMem; /* Memory location that acts as accumulator */
|
||||
int iDistinct; /* Ephemeral table used to enforce DISTINCT */
|
||||
} *aFunc;
|
||||
int nFunc; /* Number of entries in aFunc[] */
|
||||
u32 selId; /* Select to which this AggInfo belongs */
|
||||
AggInfo *pNext; /* Next in list of them all */
|
||||
};
|
||||
|
||||
/*
|
||||
** Value for AggInfo.iAggMagic when the structure is valid
|
||||
*/
|
||||
#define AggInfoMagic 0x2059e99e
|
||||
|
||||
/*
|
||||
** The datatype ynVar is a signed integer, either 16-bit or 32-bit.
|
||||
** Usually it is 16-bits. But if SQLITE_MAX_VARIABLE_NUMBER is greater
|
||||
@@ -2700,7 +2720,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 */
|
||||
|
||||
/*
|
||||
@@ -2880,7 +2900,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 */
|
||||
@@ -3001,7 +3021,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
|
||||
@@ -3104,6 +3124,7 @@ struct Select {
|
||||
#define SF_WhereBegin 0x0080000 /* Really a WhereBegin() call. Debug Only */
|
||||
#define SF_WinRewrite 0x0100000 /* Window function rewrite accomplished */
|
||||
#define SF_View 0x0200000 /* SELECT statement is a view */
|
||||
#define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */
|
||||
|
||||
/*
|
||||
** The results of a SELECT can be distributed in several ways, as defined
|
||||
@@ -3320,6 +3341,7 @@ struct Parse {
|
||||
Parse *pToplevel; /* Parse structure for main program (or NULL) */
|
||||
Table *pTriggerTab; /* Table triggers are being coded for */
|
||||
Parse *pParentParse; /* Parent parser if this parser is nested */
|
||||
AggInfo *pAggList; /* List of all AggInfo objects */
|
||||
int addrCrTab; /* Address of OP_CreateBtree opcode on CREATE TABLE */
|
||||
u32 nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
|
||||
u32 oldmask; /* Mask of old.* columns referenced */
|
||||
@@ -3724,6 +3746,9 @@ int sqlite3WalkSelectFrom(Walker*, Select*);
|
||||
int sqlite3ExprWalkNoop(Walker*, Expr*);
|
||||
int sqlite3SelectWalkNoop(Walker*, Select*);
|
||||
int sqlite3SelectWalkFail(Walker*, Select*);
|
||||
int sqlite3WalkerDepthIncrease(Walker*,Select*);
|
||||
void sqlite3WalkerDepthDecrease(Walker*,Select*);
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
void sqlite3SelectWalkAssert2(Walker*, Select*);
|
||||
#endif
|
||||
@@ -4121,7 +4146,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
|
||||
@@ -4283,6 +4308,7 @@ int sqlite3ExprCompareSkip(Expr*, Expr*, int);
|
||||
int sqlite3ExprListCompare(ExprList*, ExprList*, int);
|
||||
int sqlite3ExprImpliesExpr(Parse*,Expr*, Expr*, int);
|
||||
int sqlite3ExprImpliesNonNullRow(Expr*,int);
|
||||
void sqlite3AggInfoPersistWalkerInit(Walker*,Parse*);
|
||||
void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
|
||||
void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
|
||||
int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx);
|
||||
@@ -4542,10 +4568,11 @@ extern const unsigned char sqlite3UpperToLower[];
|
||||
extern const unsigned char sqlite3CtypeMap[];
|
||||
extern SQLITE_WSD struct Sqlite3Config sqlite3Config;
|
||||
extern FuncDefHash sqlite3BuiltinFunctions;
|
||||
extern u32 sqlite3SelectTrace;
|
||||
#ifndef SQLITE_OMIT_WSD
|
||||
extern int sqlite3PendingByte;
|
||||
#endif
|
||||
#endif
|
||||
#endif /* SQLITE_AMALGAMATION */
|
||||
#ifdef VDBE_PROFILE
|
||||
extern sqlite3_uint64 sqlite3NProfileCnt;
|
||||
#endif
|
||||
@@ -4584,7 +4611,7 @@ void sqlite3RenameExprlistUnmap(Parse*, ExprList*);
|
||||
CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
|
||||
char sqlite3AffinityType(const char*, Column*);
|
||||
void sqlite3Analyze(Parse*, Token*, Token*);
|
||||
int sqlite3InvokeBusyHandler(BusyHandler*, sqlite3_file*);
|
||||
int sqlite3InvokeBusyHandler(BusyHandler*);
|
||||
int sqlite3FindDb(sqlite3*, Token*);
|
||||
int sqlite3FindDbName(sqlite3 *, const char *);
|
||||
int sqlite3AnalysisLoad(sqlite3*,int iDB);
|
||||
@@ -4709,8 +4736,10 @@ void sqlite3AutoLoadExtensions(sqlite3*);
|
||||
int sqlite3ReadOnlyShadowTables(sqlite3 *db);
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
int sqlite3ShadowTableName(sqlite3 *db, const char *zName);
|
||||
int sqlite3IsShadowTableOf(sqlite3*,Table*,const char*);
|
||||
#else
|
||||
# define sqlite3ShadowTableName(A,B) 0
|
||||
# define sqlite3IsShadowTableOf(A,B,C) 0
|
||||
#endif
|
||||
int sqlite3VtabEponymousTableInit(Parse*,Module*);
|
||||
void sqlite3VtabEponymousTableClear(sqlite3*,Module*);
|
||||
|
||||
+2
-2
@@ -56,7 +56,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
|
||||
if( p->nData + need > p->nAlloc ){
|
||||
char **azNew;
|
||||
p->nAlloc = p->nAlloc*2 + need;
|
||||
azNew = sqlite3_realloc64( p->azResult, sizeof(char*)*p->nAlloc );
|
||||
azNew = sqlite3Realloc( p->azResult, sizeof(char*)*p->nAlloc );
|
||||
if( azNew==0 ) goto malloc_failed;
|
||||
p->azResult = azNew;
|
||||
}
|
||||
@@ -165,7 +165,7 @@ int sqlite3_get_table(
|
||||
}
|
||||
if( res.nAlloc>res.nData ){
|
||||
char **azNew;
|
||||
azNew = sqlite3_realloc64( res.azResult, sizeof(char*)*res.nData );
|
||||
azNew = sqlite3Realloc( res.azResult, sizeof(char*)*res.nData );
|
||||
if( azNew==0 ){
|
||||
sqlite3_free_table(&res.azResult[1]);
|
||||
db->errCode = SQLITE_NOMEM;
|
||||
|
||||
+11
-2
@@ -3699,6 +3699,7 @@ static int SQLITE_TCLAPI DbMain(
|
||||
const char *zFile = 0;
|
||||
const char *zVfs = 0;
|
||||
int flags;
|
||||
int bTranslateFileName = 1;
|
||||
Tcl_DString translatedFilename;
|
||||
int rc;
|
||||
|
||||
@@ -3796,6 +3797,10 @@ static int SQLITE_TCLAPI DbMain(
|
||||
}else{
|
||||
flags &= ~SQLITE_OPEN_URI;
|
||||
}
|
||||
}else if( strcmp(zArg, "-translatefilename")==0 ){
|
||||
if( Tcl_GetBooleanFromObj(interp, objv[i], &bTranslateFileName) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
}else{
|
||||
Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0);
|
||||
return TCL_ERROR;
|
||||
@@ -3805,9 +3810,13 @@ static int SQLITE_TCLAPI DbMain(
|
||||
p = (SqliteDb*)Tcl_Alloc( sizeof(*p) );
|
||||
memset(p, 0, sizeof(*p));
|
||||
if( zFile==0 ) zFile = "";
|
||||
zFile = Tcl_TranslateFileName(interp, zFile, &translatedFilename);
|
||||
if( bTranslateFileName ){
|
||||
zFile = Tcl_TranslateFileName(interp, zFile, &translatedFilename);
|
||||
}
|
||||
rc = sqlite3_open_v2(zFile, &p->db, flags, zVfs);
|
||||
Tcl_DStringFree(&translatedFilename);
|
||||
if( bTranslateFileName ){
|
||||
Tcl_DStringFree(&translatedFilename);
|
||||
}
|
||||
if( p->db ){
|
||||
if( SQLITE_OK!=sqlite3_errcode(p->db) ){
|
||||
zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db));
|
||||
|
||||
+4
-2
@@ -4630,7 +4630,7 @@ static int SQLITE_TCLAPI test_open_v2(
|
||||
{ "SQLITE_OPEN_MAIN_JOURNAL", SQLITE_OPEN_MAIN_JOURNAL },
|
||||
{ "SQLITE_OPEN_TEMP_JOURNAL", SQLITE_OPEN_TEMP_JOURNAL },
|
||||
{ "SQLITE_OPEN_SUBJOURNAL", SQLITE_OPEN_SUBJOURNAL },
|
||||
{ "SQLITE_OPEN_MASTER_JOURNAL", SQLITE_OPEN_MASTER_JOURNAL },
|
||||
{ "SQLITE_OPEN_SUPER_JOURNAL", SQLITE_OPEN_SUPER_JOURNAL },
|
||||
{ "SQLITE_OPEN_NOMUTEX", SQLITE_OPEN_NOMUTEX },
|
||||
{ "SQLITE_OPEN_FULLMUTEX", SQLITE_OPEN_FULLMUTEX },
|
||||
{ "SQLITE_OPEN_SHAREDCACHE", SQLITE_OPEN_SHAREDCACHE },
|
||||
@@ -7257,6 +7257,7 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
|
||||
extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_explain_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_decimal_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
@@ -7282,6 +7283,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 },
|
||||
@@ -8164,7 +8166,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
#endif
|
||||
#endif
|
||||
#if defined(SQLITE_ENABLE_SELECTTRACE)
|
||||
extern int sqlite3SelectTrace;
|
||||
extern u32 sqlite3SelectTrace;
|
||||
#endif
|
||||
|
||||
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
|
||||
|
||||
+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);
|
||||
|
||||
@@ -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 ){
|
||||
|
||||
+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 ){
|
||||
|
||||
+5
-3
@@ -582,8 +582,10 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
#endif
|
||||
}
|
||||
if( pExpr->op==TK_AGG_FUNCTION ){
|
||||
sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s",
|
||||
pExpr->op2, pExpr->u.zToken, zFlgs);
|
||||
sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s agg=%d[%d]/%p",
|
||||
pExpr->op2, pExpr->u.zToken, zFlgs,
|
||||
pExpr->pAggInfo ? pExpr->pAggInfo->selId : 0,
|
||||
pExpr->iAgg, pExpr->pAggInfo);
|
||||
}else if( pExpr->op2!=0 ){
|
||||
const char *zOp2;
|
||||
char zBuf[8];
|
||||
@@ -615,7 +617,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
break;
|
||||
}
|
||||
case TK_SELECT: {
|
||||
sqlite3TreeViewLine(pView, "SELECT-expr flags=0x%x", pExpr->flags);
|
||||
sqlite3TreeViewLine(pView, "subquery-expr flags=0x%x", pExpr->flags);
|
||||
sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
+8
-7
@@ -128,7 +128,7 @@ void sqlite3BeginTrigger(
|
||||
** ^^^^^^^^
|
||||
**
|
||||
** To maintain backwards compatibility, ignore the database
|
||||
** name on pTableName if we are reparsing out of SQLITE_MASTER.
|
||||
** name on pTableName if we are reparsing out of the schema table
|
||||
*/
|
||||
if( db->init.busy && iDb!=1 ){
|
||||
sqlite3DbFree(db, pTableName->a[0].zDatabase);
|
||||
@@ -318,21 +318,22 @@ void sqlite3FinishTrigger(
|
||||
#endif
|
||||
|
||||
/* if we are not initializing,
|
||||
** build the sqlite_master entry
|
||||
** build the sqlite_schema entry
|
||||
*/
|
||||
if( !db->init.busy ){
|
||||
Vdbe *v;
|
||||
char *z;
|
||||
|
||||
/* Make an entry in the sqlite_master table */
|
||||
/* Make an entry in the sqlite_schema table */
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) goto triggerfinish_cleanup;
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n);
|
||||
testcase( z==0 );
|
||||
sqlite3NestedParse(pParse,
|
||||
"INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
|
||||
db->aDb[iDb].zDbSName, MASTER_NAME, zName,
|
||||
"INSERT INTO %Q." DFLT_SCHEMA_TABLE
|
||||
" VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
|
||||
db->aDb[iDb].zDbSName, zName,
|
||||
pTrig->table, z);
|
||||
sqlite3DbFree(db, z);
|
||||
sqlite3ChangeCookie(pParse, iDb);
|
||||
@@ -639,8 +640,8 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
|
||||
*/
|
||||
if( (v = sqlite3GetVdbe(pParse))!=0 ){
|
||||
sqlite3NestedParse(pParse,
|
||||
"DELETE FROM %Q.%s WHERE name=%Q AND type='trigger'",
|
||||
db->aDb[iDb].zDbSName, MASTER_NAME, pTrigger->zName
|
||||
"DELETE FROM %Q." DFLT_SCHEMA_TABLE " WHERE name=%Q AND type='trigger'",
|
||||
db->aDb[iDb].zDbSName, pTrigger->zName
|
||||
);
|
||||
sqlite3ChangeCookie(pParse, iDb);
|
||||
sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->zName, 0);
|
||||
|
||||
+6
-6
@@ -46,17 +46,17 @@ static void updateVirtualTable(
|
||||
** literal default values specified: a number, null or a string. (If a more
|
||||
** complicated default expression value was provided, it is evaluated
|
||||
** when the ALTER TABLE is executed and one of the literal values written
|
||||
** into the sqlite_master table.)
|
||||
** into the sqlite_schema table.)
|
||||
**
|
||||
** Therefore, the P4 parameter is only required if the default value for
|
||||
** the column is a literal number, string or null. The sqlite3ValueFromExpr()
|
||||
** function is capable of transforming these types of expressions into
|
||||
** sqlite3_value objects.
|
||||
**
|
||||
** If parameter iReg is not negative, code an OP_RealAffinity instruction
|
||||
** on register iReg. This is used when an equivalent integer value is
|
||||
** stored in place of an 8-byte floating point value in order to save
|
||||
** space.
|
||||
** If column as REAL affinity and the table is an ordinary b-tree table
|
||||
** (not a virtual table) then the value might have been stored as an
|
||||
** integer. In that case, add an OP_RealAffinity opcode to make sure
|
||||
** it has been converted into REAL.
|
||||
*/
|
||||
void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
|
||||
assert( pTab!=0 );
|
||||
@@ -73,7 +73,7 @@ void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
|
||||
if( pTab->aCol[i].affinity==SQLITE_AFF_REAL && !IsVirtual(pTab) ){
|
||||
sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
|
||||
}
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user