Compare commits

..

4 Commits

Author SHA1 Message Date
drh 27de99df79 Add the EXPLAIN TABLES syntax that uses SQLITE_STMTMODE_TABLELIST. Seems
to work, but not well-tested.

FossilOrigin-Name: e7343ce7514f61eb1aeba22ab83da5b05779080db394332e2e90b4d54cabe123
2020-03-20 20:00:10 +00:00
drh 3041bf593b Further simplification of the EXPLAIN logic. Fix the test errors from
the previous check-in.

FossilOrigin-Name: 5eaba9af1c35ea7b7c08cad7d0d9b5a4b63b11b3177bb84a570ce1cea44b9f57
2020-03-20 17:49:37 +00:00
drh cc6408ffa3 Revamp the EXPLAIN infrastructure to facilitate sqlite3_stmt_mode(). The
currently code mostly works, but there are test failures.  This is an
incremental check-in.

FossilOrigin-Name: e9e17e2125dbbafd5da4adb3bd2893735fa4d0aaa5f3daee75f866cb32231a8d
2020-03-20 16:13:41 +00:00
drh 8e8c2f1498 Initial code for a proposed new sqlite3_stmt_mode() API.
This is an incomplete snapshot of a work-in-progress.

FossilOrigin-Name: 3cf7537b5e14e218218b18b3c0c668c950a71fcddc68a5faf0f197519718a6c2
2020-03-19 21:17:11 +00:00
346 changed files with 5744 additions and 22021 deletions
+5 -35
View File
@@ -190,8 +190,7 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
table.lo threads.lo tokenize.lo treeview.lo trigger.lo \
update.lo userauth.lo upsert.lo util.lo vacuum.lo \
vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \
vdbetrace.lo vdbevtab.lo \
wal.lo walker.lo where.lo wherecode.lo whereexpr.lo \
vdbetrace.lo wal.lo walker.lo where.lo wherecode.lo whereexpr.lo \
window.lo utf.lo vtab.lo
# Object files for the amalgamation.
@@ -297,7 +296,6 @@ SRC = \
$(TOP)/src/vdbemem.c \
$(TOP)/src/vdbesort.c \
$(TOP)/src/vdbetrace.c \
$(TOP)/src/vdbevtab.c \
$(TOP)/src/vdbeInt.h \
$(TOP)/src/vtab.c \
$(TOP)/src/vxworks.h \
@@ -441,10 +439,8 @@ TESTSRC += \
$(TOP)/ext/expert/test_expert.c \
$(TOP)/ext/misc/amatch.c \
$(TOP)/ext/misc/carray.c \
$(TOP)/ext/misc/cksumvfs.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 \
@@ -506,7 +502,6 @@ TESTSRC2 = \
$(TOP)/src/vdbe.c \
$(TOP)/src/vdbemem.c \
$(TOP)/src/vdbetrace.c \
$(TOP)/src/vdbevtab.c \
$(TOP)/src/where.c \
$(TOP)/src/wherecode.c \
$(TOP)/src/whereexpr.c \
@@ -612,7 +607,6 @@ SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
SHELL_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB
SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC
SHELL_OPT += -DSQLITE_ENABLE_DESERIALIZE
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
@@ -621,12 +615,10 @@ 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
FUZZCHECK_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
FUZZCHECK_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB
FUZZCHECK_SRC = $(TOP)/test/fuzzcheck.c $(TOP)/test/ossfuzz.c
DBFUZZ_OPT =
@@ -696,7 +688,6 @@ DBFUZZ2_OPTS = \
-DSQLITE_ENABLE_DESERIALIZE \
-DSQLITE_DEBUG \
-DSQLITE_ENABLE_DBSTAT_VTAB \
-DSQLITE_ENABLE_BYTECODE_VTAB \
-DSQLITE_ENABLE_RTREE \
-DSQLITE_ENABLE_FTS4 \
-DSQLITE_ENABLE_FTS5
@@ -1013,9 +1004,6 @@ vdbesort.lo: $(TOP)/src/vdbesort.c $(HDR)
vdbetrace.lo: $(TOP)/src/vdbetrace.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbetrace.c
vdbevtab.lo: $(TOP)/src/vdbevtab.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbevtab.c
vtab.lo: $(TOP)/src/vtab.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vtab.c
@@ -1069,12 +1057,6 @@ 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
@@ -1083,14 +1065,10 @@ keywordhash.h: $(TOP)/tool/mkkeywordhash.c
SHELL_SRC = \
$(TOP)/src/shell.c.in \
$(TOP)/ext/misc/appendvfs.c \
$(TOP)/ext/misc/completion.c \
$(TOP)/ext/misc/decimal.c \
$(TOP)/ext/misc/fileio.c \
$(TOP)/ext/misc/ieee754.c \
$(TOP)/ext/misc/series.c \
$(TOP)/ext/misc/shathree.c \
$(TOP)/ext/misc/fileio.c \
$(TOP)/ext/misc/completion.c \
$(TOP)/ext/misc/sqlar.c \
$(TOP)/ext/misc/uint.c \
$(TOP)/ext/expert/sqlite3expert.c \
$(TOP)/ext/expert/sqlite3expert.h \
$(TOP)/ext/misc/zipfile.c \
@@ -1232,9 +1210,7 @@ TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_BYTECODE_VTAB
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DESERIALIZE
TESTFIXTURE_FLAGS += -DSQLITE_CKSUMVFS_STATIC
TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlite3.la
TESTFIXTURE_SRC1 = sqlite3.c
@@ -1298,9 +1274,6 @@ 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
@@ -1378,9 +1351,6 @@ wordcount$(TEXE): $(TOP)/test/wordcount.c sqlite3.lo
speedtest1$(TEXE): $(TOP)/test/speedtest1.c sqlite3.c
$(LTLINK) $(ST_OPT) -o $@ $(TOP)/test/speedtest1.c sqlite3.c $(TLIBS)
startup$(TEXE): $(TOP)/test/startup.c sqlite3.c
$(CC) -Os -g -DSQLITE_THREADSAFE=0 -o $@ $(TOP)/test/startup.c sqlite3.c $(TLIBS)
KV_OPT += -DSQLITE_DIRECT_OVERFLOW_READ
kvtest$(TEXE): $(TOP)/test/kvtest.c sqlite3.c
@@ -1406,10 +1376,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 sqlite3rc.h
amalgamation-tarball: sqlite3.c
TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --normal
snapshot-tarball: sqlite3.c sqlite3rc.h
snapshot-tarball: sqlite3.c
TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --snapshot
# The next two rules are used to support the "threadtest" target. Building
+12 -53
View File
@@ -234,15 +234,6 @@ 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.
@@ -366,7 +357,6 @@ 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
@@ -380,9 +370,6 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SESSION=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK=1
!ENDIF
# Always enable math functions on Windows
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MATH_FUNCTIONS
# Should the rbu extension be enabled? If so, add compilation options
# to enable it.
#
@@ -788,7 +775,7 @@ MKSQLITE3C_TOOL = $(TOP)\tool\mksqlite3c.tcl
!ENDIF
!IFNDEF MKSQLITE3C_ARGS
!IF $(DEBUG)>1 && $(NO_LINEMACROS)==0
!IF $(DEBUG)>1
MKSQLITE3C_ARGS = --linemacros
!ELSE
MKSQLITE3C_ARGS =
@@ -1259,8 +1246,7 @@ 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 vdbevtab.lo wal.lo walker.lo where.lo wherecode.lo \
whereexpr.lo \
vdbetrace.lo wal.lo walker.lo where.lo wherecode.lo whereexpr.lo \
window.lo utf.lo vtab.lo
# <</mark>>
@@ -1367,7 +1353,6 @@ SRC01 = \
$(TOP)\src\vdbemem.c \
$(TOP)\src\vdbesort.c \
$(TOP)\src\vdbetrace.c \
$(TOP)\src\vdbevtab.c \
$(TOP)\src\vtab.c \
$(TOP)\src\wal.c \
$(TOP)\src\walker.c \
@@ -1498,7 +1483,7 @@ SRC12 =
# All source code files.
#
SRC = $(SRC00) $(SRC01) $(SRC03) $(SRC04) $(SRC05) $(SRC06) $(SRC07) $(SRC08) $(SRC09) $(SRC10) $(SRC11) $(SRC12)
SRC = $(SRC00) $(SRC01) $(SRC03) $(SRC04) $(SRC05) $(SRC06) $(SRC07) $(SRC08) $(SRC09) $(SRC10) $(SRC11)
# Source code to the test files.
#
@@ -1561,10 +1546,8 @@ TESTEXT = \
$(TOP)\ext\expert\test_expert.c \
$(TOP)\ext\misc\amatch.c \
$(TOP)\ext\misc\carray.c \
$(TOP)\ext\misc\cksumvfs.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 \
@@ -1701,7 +1684,6 @@ FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_FTS4
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_RTREE
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_GEOPOLY
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_DBSTAT_VTAB
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_BYTECODE_VTAB
FUZZCHECK_SRC = $(TOP)\test\fuzzcheck.c $(TOP)\test\ossfuzz.c
OSSSHELL_SRC = $(TOP)\test\ossshell.c $(TOP)\test\ossfuzz.c
@@ -1851,16 +1833,15 @@ 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 sqlite3session.h $(MKSQLITE3C_TOOL)
sqlite3.c: .target_source sqlite3ext.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
@@ -1875,8 +1856,7 @@ sqlite3.lo: $(SQLITE3C)
# Rules to build the LEMON compiler generator
#
lempar.c: $(TOP)\tool\lempar.c
copy /Y $(TOP)\tool\lempar.c .
copy /B lempar.c +,,
copy $(TOP)\tool\lempar.c .
lemon.exe: $(TOP)\tool\lemon.c lempar.c
$(BCC) $(NO_WARN) -Daccess=_access \
@@ -2129,9 +2109,6 @@ vdbesort.lo: $(TOP)\src\vdbesort.c $(HDR)
vdbetrace.lo: $(TOP)\src\vdbetrace.c $(HDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vdbetrace.c
vdbevtab.lo: $(TOP)\src\vdbevtab.c $(HDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vdbevtab.c
vtab.lo: $(TOP)\src\vtab.c $(HDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vtab.c
@@ -2176,8 +2153,7 @@ parse.h: parse.c
parse.c: $(TOP)\src\parse.y lemon.exe
del /Q parse.y parse.h parse.h.temp 2>NUL
copy /Y $(TOP)\src\parse.y .
copy /B parse.y +,,
copy $(TOP)\src\parse.y .
.\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) -S parse.y
$(SQLITE3H): $(TOP)\src\sqlite.h.in $(TOP)\manifest mksourceid.exe $(TOP)\VERSION
@@ -2190,13 +2166,8 @@ 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)
@@ -2208,13 +2179,9 @@ keywordhash.h: $(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe
SHELL_SRC = \
$(TOP)\src\shell.c.in \
$(TOP)\ext\misc\appendvfs.c \
$(TOP)\ext\misc\completion.c \
$(TOP)\ext\misc\decimal.c \
$(TOP)\ext\misc\fileio.c \
$(TOP)\ext\misc\ieee754.c \
$(TOP)\ext\misc\series.c \
$(TOP)\ext\misc\shathree.c \
$(TOP)\ext\misc\uint.c \
$(TOP)\ext\misc\fileio.c \
$(TOP)\ext\misc\completion.c \
$(TOP)\ext\expert\sqlite3expert.c \
$(TOP)\ext\expert\sqlite3expert.h \
$(TOP)\ext\misc\memtrace.c \
@@ -2345,8 +2312,7 @@ LSM1_SRC = \
$(TOP)\ext\lsm1\lsm_win32.c
fts5parse.c: $(TOP)\ext\fts5\fts5parse.y lemon.exe
copy /Y $(TOP)\ext\fts5\fts5parse.y .
copy /B fts5parse.y +,,
copy $(TOP)\ext\fts5\fts5parse.y .
del /Q fts5parse.h 2>NUL
.\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) -S fts5parse.y
@@ -2354,13 +2320,11 @@ fts5parse.h: fts5parse.c
fts5.c: $(FTS5_SRC)
$(TCLSH_CMD) $(TOP)\ext\fts5\tool\mkfts5c.tcl
copy /Y $(TOP)\ext\fts5\fts5.h .
copy /B fts5.h +,,
copy $(TOP)\ext\fts5\fts5.h .
lsm1.c: $(LSM1_SRC)
$(TCLSH_CMD) $(TOP)\ext\lsm1\tool\mklsm1c.tcl
copy /Y $(TOP)\ext\lsm1\lsm.h .
copy /B lsm.h +,,
copy $(TOP)\ext\lsm1\lsm.h .
fts5.lo: fts5.c $(HDR) $(EXTHDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c fts5.c
@@ -2388,10 +2352,8 @@ TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_DEFAULT_PAGE_SIZE=1024
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_JSON1=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DESERIALIZE=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_CKSUMVFS_STATIC=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) $(TEST_CCONV_OPTS)
TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2)
@@ -2472,9 +2434,6 @@ 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 > $@
+1 -1
View File
@@ -1 +1 @@
3.35.0
3.32.0
+1 -1
View File
@@ -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 sqlite3rc.h README.txt Replace.cs Makefile.fallback
EXTRA_DIST = sqlite3.1 tea Makefile.msc sqlite3.rc README.txt Replace.cs Makefile.fallback
pkgconfigdir = ${libdir}/pkgconfig
pkgconfig_DATA = sqlite3.pc
-2
View File
@@ -196,7 +196,6 @@ 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.
@@ -289,7 +288,6 @@ 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 -3
View File
@@ -87,9 +87,7 @@ AC_SUBST(READLINE_LIBS)
AC_ARG_ENABLE(threadsafe, [AS_HELP_STRING(
[--enable-threadsafe], [build a thread-safe library [default=yes]])],
[], [enable_threadsafe=yes])
if test x"$enable_threadsafe" == "xno"; then
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_THREADSAFE=0"
else
if test x"$enable_threadsafe" != "xno"; then
BUILD_CFLAGS="$BUILD_CFLAGS -D_REENTRANT=1 -DSQLITE_THREADSAFE=1"
AC_SEARCH_LIBS(pthread_create, pthread)
AC_SEARCH_LIBS(pthread_mutexattr_init, pthread)
+1 -1
View File
@@ -153,7 +153,7 @@ Please `cd` to its location first.
#
#-------------------------------------------------------------------------
PROJECT = sqlite3
PROJECT = tclsqlite3
!include "rules.vc"
# nmakehelp -V <file> <tag> will search the file for tag, skips until a
Vendored
+34 -106
View File
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for sqlite 3.35.0.
# Generated by GNU Autoconf 2.69 for sqlite 3.32.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.35.0'
PACKAGE_STRING='sqlite 3.35.0'
PACKAGE_VERSION='3.32.0'
PACKAGE_STRING='sqlite 3.32.0'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -799,6 +799,7 @@ TEMP_STORE
ALLOWRELEASE
SQLITE_THREADSAFE
BUILD_CC
VERSION_NUMBER
RELEASE
VERSION
program_prefix
@@ -903,7 +904,6 @@ with_readline_inc
enable_debug
enable_amalgamation
enable_load_extension
enable_math
enable_memsys5
enable_memsys3
enable_all
@@ -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.35.0 to adapt to many kinds of systems.
\`configure' configures sqlite 3.32.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.35.0:";;
short | recursive ) echo "Configuration of sqlite 3.32.0:";;
esac
cat <<\_ACEOF
@@ -1558,7 +1558,6 @@ Optional Features:
separately
--disable-load-extension
Disable loading of external extensions
--disable-math Disable math functions
--enable-memsys5 Enable MEMSYS5
--enable-memsys3 Enable MEMSYS3
--enable-all Enable FTS4, FTS5, Geopoly, JSON, RTree, Sessions
@@ -1660,7 +1659,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
sqlite configure 3.35.0
sqlite configure 3.32.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2079,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.35.0, which was
It was created by sqlite $as_me 3.32.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -3937,13 +3936,13 @@ if ${lt_cv_nm_interface+:} false; then :
else
lt_cv_nm_interface="BSD nm"
echo "int some_variable = 0;" > conftest.$ac_ext
(eval echo "\"\$as_me:3940: $ac_compile\"" >&5)
(eval echo "\"\$as_me:3939: $ac_compile\"" >&5)
(eval "$ac_compile" 2>conftest.err)
cat conftest.err >&5
(eval echo "\"\$as_me:3943: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval echo "\"\$as_me:3942: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
cat conftest.err >&5
(eval echo "\"\$as_me:3946: output\"" >&5)
(eval echo "\"\$as_me:3945: output\"" >&5)
cat conftest.out >&5
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
lt_cv_nm_interface="MS dumpbin"
@@ -5149,7 +5148,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
echo '#line 5152 "configure"' > conftest.$ac_ext
echo '#line 5151 "configure"' > conftest.$ac_ext
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -6674,11 +6673,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:6677: $lt_compile\"" >&5)
(eval echo "\"\$as_me:6676: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:6681: \$? = $ac_status" >&5
echo "$as_me:6680: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -7013,11 +7012,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:7016: $lt_compile\"" >&5)
(eval echo "\"\$as_me:7015: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:7020: \$? = $ac_status" >&5
echo "$as_me:7019: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -7118,11 +7117,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:7121: $lt_compile\"" >&5)
(eval echo "\"\$as_me:7120: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:7125: \$? = $ac_status" >&5
echo "$as_me:7124: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -7173,11 +7172,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:7176: $lt_compile\"" >&5)
(eval echo "\"\$as_me:7175: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:7180: \$? = $ac_status" >&5
echo "$as_me:7179: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -9553,7 +9552,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 9556 "configure"
#line 9555 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -9649,7 +9648,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 9652 "configure"
#line 9651 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -10366,10 +10365,8 @@ fi
if test "x${TCLLIBDIR+set}" != "xset" ; then
TCLLIBDIR='$(libdir)'
for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}` ; do
if test -d $i ; then
TCLLIBDIR=$i
break
fi
TCLLIBDIR=$i
break
done
TCLLIBDIR="${TCLLIBDIR}/sqlite3"
fi
@@ -10391,6 +10388,12 @@ RELEASE=`cat $srcdir/VERSION`
{ $as_echo "$as_me:${as_lineno-$LINENO}: Release set to $RELEASE" >&5
$as_echo "$as_me: Release set to $RELEASE" >&6;}
VERSION_NUMBER=`cat $srcdir/VERSION \
| sed 's/[^0-9]/ /g' \
| awk '{printf "%d%03d%03d",$1,$2,$3}'`
{ $as_echo "$as_me:${as_lineno-$LINENO}: Version number set to $VERSION_NUMBER" >&5
$as_echo "$as_me: Version number set to $VERSION_NUMBER" >&6;}
#########
# Locate a compiler for the build machine. This compiler should
@@ -11265,7 +11268,7 @@ if test "${enable_amalgamation+set}" = set; then :
enableval=$enable_amalgamation;
fi
if test "${enable_amalgamation}" = "no" ; then
if test "${enable_amalgamation}" == "no" ; then
USE_AMALGAMATION=0
fi
@@ -11415,81 +11418,6 @@ else
OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1"
fi
##########
# Do we want to support math functions
#
# Check whether --enable-math was given.
if test "${enable_math+set}" = set; then :
enableval=$enable_math;
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support math functions" >&5
$as_echo_n "checking whether to support math functions... " >&6; }
if test "$enable_math" = "no"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_MATH_FUNCTIONS"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing ceil" >&5
$as_echo_n "checking for library containing ceil... " >&6; }
if ${ac_cv_search_ceil+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char ceil ();
int
main ()
{
return ceil ();
;
return 0;
}
_ACEOF
for ac_lib in '' m; do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_search_ceil=$ac_res
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
if ${ac_cv_search_ceil+:} false; then :
break
fi
done
if ${ac_cv_search_ceil+:} false; then :
else
ac_cv_search_ceil=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_ceil" >&5
$as_echo "$ac_cv_search_ceil" >&6; }
ac_res=$ac_cv_search_ceil
if test "$ac_res" != no; then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
fi
fi
##########
# Do we want to support memsys3 and/or memsys5
#
@@ -11691,7 +11619,7 @@ if test "${enable_update_limit+set}" = set; then :
enableval=$enable_update_limit;
fi
if test "${enable_update_limit}" = "yes" ; then
if test "${enable_udlimit}" = "yes" ; then
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT"
fi
@@ -12315,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.35.0, which was
This file was extended by sqlite $as_me 3.32.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -12381,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.35.0
sqlite config.status 3.32.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
+9 -20
View File
@@ -134,10 +134,8 @@ AC_ARG_VAR([TCLLIBDIR], [Where to install tcl plugin])
if test "x${TCLLIBDIR+set}" != "xset" ; then
TCLLIBDIR='$(libdir)'
for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}` ; do
if test -d $i ; then
TCLLIBDIR=$i
break
fi
TCLLIBDIR=$i
break
done
TCLLIBDIR="${TCLLIBDIR}/sqlite3"
fi
@@ -157,6 +155,11 @@ AC_SUBST(VERSION)
RELEASE=`cat $srcdir/VERSION`
AC_MSG_NOTICE(Release set to $RELEASE)
AC_SUBST(RELEASE)
VERSION_NUMBER=[`cat $srcdir/VERSION \
| sed 's/[^0-9]/ /g' \
| awk '{printf "%d%03d%03d",$1,$2,$3}'`]
AC_MSG_NOTICE(Version number set to $VERSION_NUMBER)
AC_SUBST(VERSION_NUMBER)
#########
# Locate a compiler for the build machine. This compiler should
@@ -566,7 +569,7 @@ AC_SUBST(TARGET_DEBUG)
# See whether we should use the amalgamation to build
AC_ARG_ENABLE(amalgamation, AC_HELP_STRING([--disable-amalgamation],
[Disable the amalgamation and instead build all files separately]))
if test "${enable_amalgamation}" = "no" ; then
if test "${enable_amalgamation}" == "no" ; then
USE_AMALGAMATION=0
fi
AC_SUBST(USE_AMALGAMATION)
@@ -588,20 +591,6 @@ else
OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1"
fi
##########
# Do we want to support math functions
#
AC_ARG_ENABLE(math,
AC_HELP_STRING([--disable-math],[Disable math functions]))
AC_MSG_CHECKING([whether to support math functions])
if test "$enable_math" = "no"; then
AC_MSG_RESULT([no])
else
AC_MSG_RESULT([yes])
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_MATH_FUNCTIONS"
AC_SEARCH_LIBS(ceil, m)
fi
##########
# Do we want to support memsys3 and/or memsys5
#
@@ -662,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_update_limit}" = "yes" ; then
if test "${enable_udlimit}" = "yes" ; then
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT"
fi
+179 -355
View File
File diff suppressed because it is too large Load Diff
-49
View File
@@ -1,49 +0,0 @@
20-11-2020
# Memory Allocation In vdbesort.c
Memory allocation is slightly different depending on:
* whether or not SQLITE_CONFIG_SMALL_MALLOC is set, and
* whether or not worker threads are enabled.
## SQLITE_CONFIG_SMALL_MALLOC=0
Assuming SQLITE_CONFIG_SMALL_MALLOC is not set, keys passed to the sorter are
added to an in-memory buffer. This buffer is grown using sqlite3Realloc() as
required it reaches the size configured for the main pager cache using "PRAGMA
cache_size". i.e. if the user has executed "PRAGMA main.cache_size = -2048",
then this buffer is allowed to grow up to 2MB in size.
Once the buffer has grown to its threshold, keys are sorted and written to
a temp file. If worker threads are not enabled, this is the only significant
allocation the sorter module makes. After keys are sorted and flushed out to
the temp file, the buffer is reused to accumulate the next batch of keys.
If worker threads are available, then the buffer is passed to a worker thread
to sort and flush once it is full, and a new buffer allocated to allow the
main thread to continue to accumulate keys. Buffers are reused once they
have been flushed, so in this case at most (nWorker+1) buffers are allocated
and used, where nWorker is the number of configured worker threads.
There are no other significant users of heap memory in the sorter module.
Once sorted buffers of keys have been flushed to disk, they are read back
either by mapping the file (via sqlite3_file.xFetch()) or else read back
in one page at a time.
All buffers are allocated by the main thread. A sorter object is associated
with a single database connection, to which it holds a pointer.
## SQLITE_CONFIG_SMALL_MALLOC=1
This case is similar to the above, except that instead of accumulating
multiple keys in a single large buffer, sqlite3VdbeSorterWrite() stores
keys in a regular heap-memory linked list (one allocation per element).
List elements are freed as they are flushed to disk, either by the main
thread or by a worker thread.
Each time a key is added the sorter (and an allocation made),
sqlite3HeapNearlyFull() is called. If it returns true, the current
list of keys is flushed to a temporary file, even if it has not yet
reached the size threshold.
-88
View File
@@ -1,88 +0,0 @@
# 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.
+1
View File
@@ -1704,3 +1704,4 @@ int sqlite3async_control(int op, ...){
}
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ASYNCIO) */
+1
View File
@@ -220,3 +220,4 @@ int sqlite3async_control(int op, ...);
} /* End of the 'extern "C"' block */
#endif
#endif /* ifndef __SQLITEASYNC_H_ */
+5 -77
View File
@@ -28,7 +28,6 @@ if {[info commands sqlite3_expert_new]==""} {
return
}
set CLI [test_binary_name sqlite3]
set CMD [test_binary_name sqlite3_expert]
@@ -38,9 +37,6 @@ proc squish {txt} {
proc do_setup_rec_test {tn setup sql res} {
reset_db
if {[info exists ::set_main_db_name]} {
dbconfig_maindbname_icecube db
}
db eval $setup
uplevel [list do_rec_test $tn $sql $res]
}
@@ -80,10 +76,6 @@ foreach {tn setup} {
}
}
3 {
if {[info commands sqlite3_expert_new]==""} { continue }
set ::set_main_db_name 1
}
4 {
if {![file executable $CLI]} { continue }
proc do_rec_test {tn sql res} {
@@ -327,70 +319,6 @@ do_setup_rec_test $tn.16 {
SCAN TABLE t1
}
do_setup_rec_test $tn.17.1 {
CREATE TABLE example (A INTEGER, B INTEGER, C INTEGER, PRIMARY KEY (A,B));
} {
SELECT * FROM example WHERE a=?
} {
(no new indexes)
SEARCH TABLE example USING INDEX sqlite_autoindex_example_1 (A=?)
}
do_setup_rec_test $tn.17.2 {
CREATE TABLE example (A INTEGER, B INTEGER, C INTEGER, PRIMARY KEY (A,B));
} {
SELECT * FROM example WHERE b=?
} {
CREATE INDEX example_idx_00000042 ON example(B);
SEARCH TABLE example USING INDEX example_idx_00000042 (B=?)
}
do_setup_rec_test $tn.17.3 {
CREATE TABLE example (A INTEGER, B INTEGER, C INTEGER, PRIMARY KEY (A,B));
} {
SELECT * FROM example WHERE a=? AND b=?
} {
(no new indexes)
SEARCH TABLE example USING INDEX sqlite_autoindex_example_1 (A=? AND B=?)
}
do_setup_rec_test $tn.17.4 {
CREATE TABLE example (A INTEGER, B INTEGER, C INTEGER, PRIMARY KEY (A,B));
} {
SELECT * FROM example WHERE a=? AND b>?
} {
(no new indexes)
SEARCH TABLE example USING INDEX sqlite_autoindex_example_1 (A=? AND B>?)
}
do_setup_rec_test $tn.17.5 {
CREATE TABLE example (A INTEGER, B INTEGER, C INTEGER, PRIMARY KEY (A,B));
} {
SELECT * FROM example WHERE a>? AND b=?
} {
CREATE INDEX example_idx_0000cb3f ON example(B, A);
SEARCH TABLE example USING INDEX example_idx_0000cb3f (B=? AND A>?)
}
do_setup_rec_test $tn.18.0 {
CREATE TABLE SomeObject (
a INTEGER PRIMARY KEY,
x TEXT GENERATED ALWAYS AS(HEX(a)) VIRTUAL
);
} {
SELECT x FROM SomeObject;
} {
(no new indexes)
SCAN TABLE SomeObject
}
do_setup_rec_test $tn.18.1 {
CREATE TABLE SomeObject (
a INTEGER PRIMARY KEY,
x TEXT GENERATED ALWAYS AS(HEX(a)) VIRTUAL
);
} {
SELECT * FROM SomeObject WHERE x=?;
} {
CREATE INDEX SomeObject_idx_00000078 ON SomeObject(x);
SEARCH TABLE SomeObject USING COVERING INDEX SomeObject_idx_00000078 (x=?)
}
}
proc do_candidates_test {tn sql res} {
@@ -408,7 +336,7 @@ proc do_candidates_test {tn sql res} {
reset_db
do_execsql_test 5.0 {
do_execsql_test 4.0 {
CREATE TABLE t1(a, b);
CREATE TABLE t2(c, d);
@@ -418,7 +346,7 @@ do_execsql_test 5.0 {
WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100)
INSERT INTO t2 SELECT (i-1)/20, (i-1)/5 FROM s;
}
do_candidates_test 5.1 {
do_candidates_test 4.1 {
SELECT * FROM t1,t2 WHERE (b=? OR a=?) AND (c=? OR d=?)
} {
CREATE INDEX t1_idx_00000062 ON t1(b); -- stat1: 100 20
@@ -427,14 +355,14 @@ do_candidates_test 5.1 {
CREATE INDEX t2_idx_00000064 ON t2(d); -- stat1: 100 5
}
do_candidates_test 5.2 {
do_candidates_test 4.2 {
SELECT * FROM t1,t2 WHERE a=? AND b=? AND c=? AND d=?
} {
CREATE INDEX t1_idx_000123a7 ON t1(a, b); -- stat1: 100 50 17
CREATE INDEX t2_idx_0001295b ON t2(c, d); -- stat1: 100 20 5
}
do_execsql_test 5.3 {
do_execsql_test 4.3 {
CREATE INDEX t1_idx_00000061 ON t1(a); -- stat1: 100 50
CREATE INDEX t1_idx_00000062 ON t1(b); -- stat1: 100 20
CREATE INDEX t1_idx_000123a7 ON t1(a, b); -- stat1: 100 50 16
@@ -454,5 +382,5 @@ do_execsql_test 5.3 {
t2 t2_idx_0001295b {100 20 5}
}
finish_test
finish_test
+17 -26
View File
@@ -685,9 +685,8 @@ static int idxGetTableInfo(
IdxTable *pNew = 0;
int rc, rc2;
char *pCsr = 0;
int nPk = 0;
rc = idxPrintfPrepareStmt(db, &p1, pzErrmsg, "PRAGMA table_xinfo=%Q", zTab);
rc = idxPrintfPrepareStmt(db, &p1, pzErrmsg, "PRAGMA table_info=%Q", zTab);
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){
const char *zCol = (const char*)sqlite3_column_text(p1, 1);
nByte += 1 + STRLEN(zCol);
@@ -696,7 +695,6 @@ static int idxGetTableInfo(
);
nByte += 1 + STRLEN(zCol);
nCol++;
nPk += (sqlite3_column_int(p1, 5)>0);
}
rc2 = sqlite3_reset(p1);
if( rc==SQLITE_OK ) rc = rc2;
@@ -716,7 +714,7 @@ static int idxGetTableInfo(
const char *zCol = (const char*)sqlite3_column_text(p1, 1);
int nCopy = STRLEN(zCol) + 1;
pNew->aCol[nCol].zName = pCsr;
pNew->aCol[nCol].iPk = (sqlite3_column_int(p1, 5)==1 && nPk==1);
pNew->aCol[nCol].iPk = sqlite3_column_int(p1, 5);
memcpy(pCsr, zCol, nCopy);
pCsr += nCopy;
@@ -1130,19 +1128,14 @@ 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;
int nDetail = STRLEN(zDetail);
int i;
if( !zDetail ) continue;
nDetail = STRLEN(zDetail);
for(i=0; i<nDetail; i++){
const char *zIdx = 0;
if( i+13<nDetail && memcmp(&zDetail[i], " USING INDEX ", 13)==0 ){
if( memcmp(&zDetail[i], " USING INDEX ", 13)==0 ){
zIdx = &zDetail[i+13];
}else if( i+22<nDetail
&& memcmp(&zDetail[i], " USING COVERING INDEX ", 22)==0
){
}else if( memcmp(&zDetail[i], " USING COVERING INDEX ", 22)==0 ){
zIdx = &zDetail[i+22];
}
if( zIdx ){
@@ -1225,7 +1218,7 @@ static int idxProcessOneTrigger(
IdxTable *pTab = pWrite->pTab;
const char *zTab = pTab->zName;
const char *zSql =
"SELECT 'CREATE TEMP' || substr(sql, 7) FROM sqlite_schema "
"SELECT 'CREATE TEMP' || substr(sql, 7) FROM sqlite_master "
"WHERE tbl_name = %Q AND type IN ('table', 'trigger') "
"ORDER BY type;";
sqlite3_stmt *pSelect = 0;
@@ -1325,12 +1318,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_schema "
"SELECT type, name, sql, 1 FROM sqlite_master "
"WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%%' "
" UNION ALL "
"SELECT type, name, sql, 2 FROM sqlite_schema "
"SELECT type, name, sql, 2 FROM sqlite_master "
"WHERE type = 'trigger'"
" AND tbl_name IN(SELECT name FROM sqlite_schema WHERE type = 'view') "
" AND tbl_name IN(SELECT name FROM sqlite_master WHERE type = 'view') "
"ORDER BY 4, 1"
);
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSchema) ){
@@ -1500,7 +1493,7 @@ static int idxLargestIndex(sqlite3 *db, int *pnMax, char **pzErr){
int rc = SQLITE_OK;
const char *zMax =
"SELECT max(i.seqno) FROM "
" sqlite_schema AS s, "
" sqlite_master AS s, "
" pragma_index_list(s.name) AS l, "
" pragma_index_info(l.name) AS i "
"WHERE s.type = 'table'";
@@ -1653,7 +1646,7 @@ static int idxPopulateStat1(sqlite3expert *p, char **pzErr){
const char *zAllIndex =
"SELECT s.rowid, s.name, l.name FROM "
" sqlite_schema AS s, "
" sqlite_master AS s, "
" pragma_index_list(s.name) AS l "
"WHERE s.type = 'table'";
const char *zIndexXInfo =
@@ -1721,15 +1714,13 @@ static int idxPopulateStat1(sqlite3expert *p, char **pzErr){
idxFinalize(&rc, pIndexXInfo);
idxFinalize(&rc, pWrite);
if( pCtx ){
for(i=0; i<pCtx->nSlot; i++){
sqlite3_free(pCtx->aSlot[i].z);
}
sqlite3_free(pCtx);
for(i=0; i<pCtx->nSlot; i++){
sqlite3_free(pCtx->aSlot[i].z);
}
sqlite3_free(pCtx);
if( rc==SQLITE_OK ){
rc = sqlite3_exec(p->dbm, "ANALYZE sqlite_schema", 0, 0, 0);
rc = sqlite3_exec(p->dbm, "ANALYZE sqlite_master", 0, 0, 0);
}
sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp."UNIQUE_TABLE_NAME,0,0,0);
@@ -1768,7 +1759,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_schema WHERE name NOT LIKE 'sqlite_%%'"
"SELECT sql FROM sqlite_master WHERE name NOT LIKE 'sqlite_%%'"
" AND sql NOT LIKE 'CREATE VIRTUAL %%'"
);
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
@@ -1959,4 +1950,4 @@ void sqlite3_expert_destroy(sqlite3expert *p){
}
}
#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
#endif /* ifndef SQLITE_OMIT_VIRTUAL_TABLE */
+2
View File
@@ -174,3 +174,5 @@ 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.
+22 -52
View File
@@ -962,22 +962,6 @@ static char *fts3WriteExprList(Fts3Table *p, const char *zFunc, int *pRc){
return zRet;
}
/*
** Buffer z contains a positive integer value encoded as utf-8 text.
** Decode this value and store it in *pnOut, returning the number of bytes
** consumed. If an overflow error occurs return a negative value.
*/
int sqlite3Fts3ReadInt(const char *z, int *pnOut){
u64 iVal = 0;
int i;
for(i=0; z[i]>='0' && z[i]<='9'; i++){
iVal = iVal*10 + (z[i] - '0');
if( iVal>0x7FFFFFFF ) return -1;
}
*pnOut = (int)iVal;
return i;
}
/*
** This function interprets the string at (*pp) as a non-negative integer
** value. It reads the integer and sets *pnOut to the value read, then
@@ -993,17 +977,19 @@ int sqlite3Fts3ReadInt(const char *z, int *pnOut){
*/
static int fts3GobbleInt(const char **pp, int *pnOut){
const int MAX_NPREFIX = 10000000;
const char *p; /* Iterator pointer */
int nInt = 0; /* Output value */
int nByte;
nByte = sqlite3Fts3ReadInt(*pp, &nInt);
if( nInt>MAX_NPREFIX ){
nInt = 0;
}
if( nByte==0 ){
return SQLITE_ERROR;
for(p=*pp; p[0]>='0' && p[0]<='9'; p++){
nInt = nInt * 10 + (p[0] - '0');
if( nInt>MAX_NPREFIX ){
nInt = 0;
break;
}
}
if( p==*pp ) return SQLITE_ERROR;
*pnOut = nInt;
*pp += nByte;
*pp = p;
return SQLITE_OK;
}
@@ -2068,7 +2054,7 @@ static void fts3PutDeltaVarint(
sqlite3_int64 *piPrev, /* IN/OUT: Previous value written to list */
sqlite3_int64 iVal /* Write this value to the list */
){
assert_fts3_nc( iVal-*piPrev > 0 || (*piPrev==0 && iVal==0) );
assert( iVal-*piPrev > 0 || (*piPrev==0 && iVal==0) );
*pp += sqlite3Fts3PutVarint(*pp, iVal-*piPrev);
*piPrev = iVal;
}
@@ -2185,9 +2171,7 @@ static void fts3ReadNextPos(
sqlite3_int64 *pi /* IN/OUT: Value read from position-list */
){
if( (**pp)&0xFE ){
int iVal;
*pp += fts3GetVarint32((*pp), &iVal);
*pi += iVal;
fts3GetDeltaVarint(pp, pi);
*pi -= 2;
}else{
*pi = POSITION_LIST_END;
@@ -2267,9 +2251,6 @@ 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;
@@ -2338,7 +2319,7 @@ static int fts3PoslistPhraseMerge(
/* Never set both isSaveLeft and isExact for the same invocation. */
assert( isSaveLeft==0 || isExact==0 );
assert_fts3_nc( p!=0 && *p1!=0 && *p2!=0 );
assert( p!=0 && *p1!=0 && *p2!=0 );
if( *p1==POS_COLUMN ){
p1++;
p1 += fts3GetVarint32(p1, &iCol1);
@@ -3479,7 +3460,7 @@ static int fts3ColumnMethod(
break;
}else{
iCol = p->nColumn;
/* no break */ deliberate_fall_through
/* fall-through */
}
default:
@@ -3722,13 +3703,9 @@ static void fts3SnippetFunc(
switch( nVal ){
case 6: nToken = sqlite3_value_int(apVal[5]);
/* no break */ deliberate_fall_through
case 5: iCol = sqlite3_value_int(apVal[4]);
/* no break */ deliberate_fall_through
case 4: zEllipsis = (const char*)sqlite3_value_text(apVal[3]);
/* no break */ deliberate_fall_through
case 3: zEnd = (const char*)sqlite3_value_text(apVal[2]);
/* no break */ deliberate_fall_through
case 2: zStart = (const char*)sqlite3_value_text(apVal[1]);
}
if( !zEllipsis || !zEnd || !zStart ){
@@ -4527,7 +4504,7 @@ void sqlite3Fts3DoclistNext(
assert( nDoclist>0 );
assert( *pbEof==0 );
assert_fts3_nc( p || *piDocid==0 );
assert( p || *piDocid==0 );
assert( !p || (p>=aDoclist && p<=&aDoclist[nDoclist]) );
if( p==0 ){
@@ -5177,7 +5154,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".
@@ -5212,12 +5189,10 @@ static int fts3EvalNearTrim(
);
if( res ){
nNew = (int)(pOut - pPhrase->doclist.pList) - 1;
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;
}
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;
}
@@ -5326,7 +5301,6 @@ static void fts3EvalNextRow(
fts3EvalNextRow(pCsr, pLeft, pRc);
}
}
pRight->bEof = pLeft->bEof = 1;
}
}
break;
@@ -5569,10 +5543,7 @@ static int fts3EvalTestExpr(
}else
#endif
{
bHit = (
pExpr->bEof==0 && pExpr->iDocid==pCsr->iPrevId
&& pExpr->pPhrase->doclist.nList>0
);
bHit = (pExpr->bEof==0 && pExpr->iDocid==pCsr->iPrevId);
}
break;
}
@@ -5835,8 +5806,7 @@ static int fts3EvalGatherStats(
fts3EvalRestart(pCsr, pRoot, &rc);
do {
fts3EvalNextRow(pCsr, pRoot, &rc);
assert_fts3_nc( pRoot->bEof==0 );
if( pRoot->bEof ) rc = FTS_CORRUPT_VTAB;
assert( pRoot->bEof==0 );
}while( pRoot->iDocid!=iDocid && rc==SQLITE_OK );
}
}
-3
View File
@@ -199,8 +199,6 @@ typedef sqlite3_int64 i64; /* 8-byte signed integer */
#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
#define deliberate_fall_through
#endif /* SQLITE_AMALGAMATION */
#ifdef SQLITE_DEBUG
@@ -593,7 +591,6 @@ int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *);
int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *);
void sqlite3Fts3CreateStatTable(int*, Fts3Table*);
int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc);
int sqlite3Fts3ReadInt(const char *z, int *pnOut);
/* fts3_tokenizer.c */
const char *sqlite3Fts3NextToken(const char *, int *);
+4 -1
View File
@@ -446,7 +446,10 @@ static int getNextNode(
if( pKey->eType==FTSQUERY_NEAR ){
assert( nKey==4 );
if( zInput[4]=='/' && zInput[5]>='0' && zInput[5]<='9' ){
nKey += 1+sqlite3Fts3ReadInt(&zInput[nKey+1], &nNear);
nNear = 0;
for(nKey=5; zInput[nKey]>='0' && zInput[nKey]<='9'; nKey++){
nNear = nNear * 10 + (zInput[nKey] - '0');
}
}
}
+1 -1
View File
@@ -876,7 +876,7 @@ static int fts3ExprLHits(
iStart = pExpr->iPhrase * ((p->nCol + 31) / 32);
}
if( pIter ) while( 1 ){
while( 1 ){
int nHit = fts3ColumnlistCount(&pIter);
if( (pPhrase->iColumn>=pTab->nColumn || pPhrase->iColumn==iCol) ){
if( p->flag==FTS3_MATCHINFO_LHITS ){
+1 -2
View File
@@ -188,8 +188,7 @@ static int fts3tokConnectMethod(
assert( (rc==SQLITE_OK)==(pMod!=0) );
if( rc==SQLITE_OK ){
const char * const *azArg = 0;
if( nDequote>1 ) azArg = (const char * const *)&azDequote[1];
const char * const *azArg = (const char * const *)&azDequote[1];
rc = pMod->xCreate((nDequote>1 ? nDequote-1 : 0), azArg, &pTok);
}
+14 -33
View File
@@ -341,9 +341,7 @@ 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 (SELECT * FROM %Q.'%q_segdir' "
" WHERE level = ? ORDER BY idx ASC LIMIT ?"
" )",
" FROM %Q.'%q_segdir' WHERE level = ? AND idx < ?",
/* SQL_DELETE_SEGDIR_ENTRY
** Delete the %_segdir entry on absolute level :1 with index :2. */
@@ -1417,7 +1415,6 @@ static int fts3SegReaderNext(
*/
if( pReader->nDoclist > pReader->nNode-(pReader->aDoclist-pReader->aNode)
|| (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1])
|| pReader->nDoclist==0
){
return FTS_CORRUPT_VTAB;
}
@@ -2855,19 +2852,6 @@ int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr){
return SQLITE_OK;
}
static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, int nReq){
if( nReq>pCsr->nBuffer ){
char *aNew;
pCsr->nBuffer = nReq*2;
aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer);
if( !aNew ){
return SQLITE_NOMEM;
}
pCsr->aBuffer = aNew;
}
return SQLITE_OK;
}
int sqlite3Fts3SegReaderStep(
Fts3Table *p, /* Virtual table handle */
@@ -3002,9 +2986,15 @@ int sqlite3Fts3SegReaderStep(
}
nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0);
rc = fts3GrowSegReaderBuffer(pCsr, nByte+nDoclist);
if( rc ) return rc;
if( nDoclist+nByte>pCsr->nBuffer ){
char *aNew;
pCsr->nBuffer = (nDoclist+nByte)*2;
aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer);
if( !aNew ){
return SQLITE_NOMEM;
}
pCsr->aBuffer = aNew;
}
if( isFirst ){
char *a = &pCsr->aBuffer[nDoclist];
@@ -3029,9 +3019,6 @@ int sqlite3Fts3SegReaderStep(
fts3SegReaderSort(apSegment, nMerge, j, xCmp);
}
if( nDoclist>0 ){
rc = fts3GrowSegReaderBuffer(pCsr, nDoclist+FTS3_NODE_PADDING);
if( rc ) return rc;
memset(&pCsr->aBuffer[nDoclist], 0, FTS3_NODE_PADDING);
pCsr->aDoclist = pCsr->aBuffer;
pCsr->nDoclist = nDoclist;
rc = SQLITE_ROW;
@@ -3081,11 +3068,11 @@ static void fts3ReadEndBlockField(
if( zText ){
int i;
int iMul = 1;
u64 iVal = 0;
i64 iVal = 0;
for(i=0; zText[i]>='0' && zText[i]<='9'; i++){
iVal = iVal*10 + (zText[i] - '0');
}
*piEndBlock = (i64)iVal;
*piEndBlock = iVal;
while( zText[i]==' ' ) i++;
iVal = 0;
if( zText[i]=='-' ){
@@ -3095,7 +3082,7 @@ static void fts3ReadEndBlockField(
for(/* no-op */; zText[i]>='0' && zText[i]<='9'; i++){
iVal = iVal*10 + (zText[i] - '0');
}
*pnByte = ((i64)iVal * (i64)iMul);
*pnByte = (iVal * (i64)iMul);
}
}
@@ -4300,7 +4287,7 @@ static int fts3IncrmergeLoad(
int i;
int nHeight = (int)aRoot[0];
NodeWriter *pNode;
if( nHeight<1 || nHeight>=FTS_MAX_APPENDABLE_HEIGHT ){
if( nHeight<1 || nHeight>FTS_MAX_APPENDABLE_HEIGHT ){
sqlite3_reset(pSelect);
return FTS_CORRUPT_VTAB;
}
@@ -4966,12 +4953,6 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
** Exit early in this case. */
if( nSeg<=0 ) break;
assert( nMod<=0x7FFFFFFF );
if( iAbsLevel<0 || iAbsLevel>(nMod<<32) ){
rc = FTS_CORRUPT_VTAB;
break;
}
/* Open a cursor to iterate through the contents of the oldest nSeg
** indexes of absolute level iAbsLevel. If this cursor is opened using
** the 'hint' parameters, it is possible that there are less than nSeg
+2 -2
View File
@@ -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_schema"
"SELECT sql FROM sqlite_master"
" 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_schema a, sqlite_schema b"
" FROM sqlite_master a, sqlite_master b"
" WHERE a.name GLOB '*_segdir'"
" AND b.name=substr(a.name,1,length(a.name)-7)"
" ORDER BY 1");
-1
View File
@@ -742,7 +742,6 @@ proc print_categories {lMap} {
}
iTbl++;
}
aAscii[0] = 0; /* 0x00 is never a token character */
}
}]
}
+9 -23
View File
@@ -184,7 +184,6 @@ struct Fts5Config {
Fts5Tokenizer *pTok;
fts5_tokenizer *pTokApi;
int bLock; /* True when table is preparing statement */
int ePattern; /* FTS_PATTERN_XXX constant */
/* Values loaded from the %_config table */
int iCookie; /* Incremented when %_config is modified */
@@ -205,19 +204,17 @@ struct Fts5Config {
};
/* Current expected value of %_config table 'version' field */
#define FTS5_CURRENT_VERSION 4
#define FTS5_CURRENT_VERSION 4
#define FTS5_CONTENT_NORMAL 0
#define FTS5_CONTENT_NONE 1
#define FTS5_CONTENT_EXTERNAL 2
#define FTS5_DETAIL_FULL 0
#define FTS5_DETAIL_NONE 1
#define FTS5_DETAIL_COLUMNS 2
#define FTS5_DETAIL_FULL 0
#define FTS5_DETAIL_NONE 1
#define FTS5_DETAIL_COLUMNS 2
#define FTS5_PATTERN_NONE 0
#define FTS5_PATTERN_LIKE 65 /* matches SQLITE_INDEX_CONSTRAINT_LIKE */
#define FTS5_PATTERN_GLOB 66 /* matches SQLITE_INDEX_CONSTRAINT_GLOB */
int sqlite3Fts5ConfigParse(
Fts5Global*, sqlite3*, int, const char **, Fts5Config**, char**
@@ -487,7 +484,7 @@ int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8*, int);
/*
** Functions called by the storage module as part of integrity-check.
*/
int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum, int bUseCksum);
int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum);
/*
** Called during virtual module initialization to register UDF
@@ -557,7 +554,8 @@ int sqlite3Fts5GetTokenizer(
Fts5Global*,
const char **azArg,
int nArg,
Fts5Config*,
Fts5Tokenizer**,
fts5_tokenizer**,
char **pzErr
);
@@ -641,7 +639,7 @@ int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**);
int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*);
int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64);
int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg);
int sqlite3Fts5StorageIntegrity(Fts5Storage *p);
int sqlite3Fts5StorageStmt(Fts5Storage *p, int eStmt, sqlite3_stmt**, char**);
void sqlite3Fts5StorageStmtRelease(Fts5Storage *p, int eStmt, sqlite3_stmt*);
@@ -686,19 +684,11 @@ struct Fts5Token {
/* Parse a MATCH expression. */
int sqlite3Fts5ExprNew(
Fts5Config *pConfig,
int bPhraseToAnd,
int iCol, /* Column on LHS of MATCH operator */
const char *zExpr,
Fts5Expr **ppNew,
char **pzErr
);
int sqlite3Fts5ExprPattern(
Fts5Config *pConfig,
int bGlob,
int iCol,
const char *zText,
Fts5Expr **pp
);
/*
** for(rc = sqlite3Fts5ExprFirst(pExpr, pIdx, bDesc);
@@ -807,10 +797,6 @@ int sqlite3Fts5AuxInit(fts5_api*);
*/
int sqlite3Fts5TokenizerInit(fts5_api*);
int sqlite3Fts5TokenizerPattern(
int (*xCreate)(void*, const char**, int, Fts5Tokenizer**),
Fts5Tokenizer *pTok
);
/*
** End of interface to code in fts5_tokenizer.c.
**************************************************************************/
+12 -10
View File
@@ -566,7 +566,7 @@ static int fts5Bm25GetData(
int rc = SQLITE_OK; /* Return code */
Fts5Bm25Data *p; /* Object to return */
p = (Fts5Bm25Data*)pApi->xGetAuxdata(pFts, 0);
p = pApi->xGetAuxdata(pFts, 0);
if( p==0 ){
int nPhrase; /* Number of phrases in query */
sqlite3_int64 nRow = 0; /* Number of rows in table */
@@ -640,7 +640,7 @@ static void fts5Bm25Function(
){
const double k1 = 1.2; /* Constant "k1" from BM25 formula */
const double b = 0.75; /* Constant "b" from BM25 formula */
int rc; /* Error code */
int rc = SQLITE_OK; /* Error code */
double score = 0.0; /* SQL function return value */
Fts5Bm25Data *pData; /* Values allocated/calculated once only */
int i; /* Iterator variable */
@@ -672,15 +672,17 @@ static void fts5Bm25Function(
D = (double)nTok;
}
/* Determine and return the BM25 score for the current row. Or, if an
** error has occurred, throw an exception. */
/* Determine the BM25 score for the current row. */
for(i=0; rc==SQLITE_OK && i<pData->nPhrase; i++){
score += pData->aIDF[i] * (
( aFreq[i] * (k1 + 1.0) ) /
( aFreq[i] + k1 * (1 - b + b * D / pData->avgdl) )
);
}
/* If no error has occurred, return the calculated score. Otherwise,
** throw an SQL exception. */
if( rc==SQLITE_OK ){
for(i=0; i<pData->nPhrase; i++){
score += pData->aIDF[i] * (
( aFreq[i] * (k1 + 1.0) ) /
( aFreq[i] + k1 * (1 - b + b * D / pData->avgdl) )
);
}
sqlite3_result_double(pCtx, -1.0 * score);
}else{
sqlite3_result_error_code(pCtx, rc);
+4 -2
View File
@@ -325,7 +325,7 @@ static int fts5ConfigParseSpecial(
rc = SQLITE_ERROR;
}else{
rc = sqlite3Fts5GetTokenizer(pGlobal,
(const char**)azArg, (int)nArg, pConfig,
(const char**)azArg, (int)nArg, &pConfig->pTok, &pConfig->pTokApi,
pzErr
);
}
@@ -397,7 +397,9 @@ static int fts5ConfigParseSpecial(
*/
static int fts5ConfigDefaultTokenizer(Fts5Global *pGlobal, Fts5Config *pConfig){
assert( pConfig->pTok==0 && pConfig->pTokApi==0 );
return sqlite3Fts5GetTokenizer(pGlobal, 0, 0, pConfig, 0);
return sqlite3Fts5GetTokenizer(
pGlobal, 0, 0, &pConfig->pTok, &pConfig->pTokApi, 0
);
}
/*
+56 -219
View File
@@ -128,7 +128,6 @@ struct Fts5Parse {
int nPhrase; /* Size of apPhrase array */
Fts5ExprPhrase **apPhrase; /* Array of all phrases */
Fts5ExprNode *pExpr; /* Result of a successful parse */
int bPhraseToAnd; /* Convert "a+b" to "a AND b" */
};
void sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...){
@@ -217,7 +216,6 @@ static void fts5ParseFree(void *p){ sqlite3_free(p); }
int sqlite3Fts5ExprNew(
Fts5Config *pConfig, /* FTS5 Configuration */
int bPhraseToAnd,
int iCol,
const char *zExpr, /* Expression text */
Fts5Expr **ppNew,
@@ -233,7 +231,6 @@ int sqlite3Fts5ExprNew(
*ppNew = 0;
*pzErr = 0;
memset(&sParse, 0, sizeof(sParse));
sParse.bPhraseToAnd = bPhraseToAnd;
pEngine = sqlite3Fts5ParserAlloc(fts5ParseAlloc);
if( pEngine==0 ){ return SQLITE_NOMEM; }
sParse.pConfig = pConfig;
@@ -276,7 +273,6 @@ int sqlite3Fts5ExprNew(
pNew->pConfig = pConfig;
pNew->apExprPhrase = sParse.apPhrase;
pNew->nPhrase = sParse.nPhrase;
pNew->bDesc = 0;
sParse.apPhrase = 0;
}
}else{
@@ -288,81 +284,6 @@ int sqlite3Fts5ExprNew(
return sParse.rc;
}
/*
** This function is only called when using the special 'trigram' tokenizer.
** Argument zText contains the text of a LIKE or GLOB pattern matched
** against column iCol. This function creates and compiles an FTS5 MATCH
** expression that will match a superset of the rows matched by the LIKE or
** GLOB. If successful, SQLITE_OK is returned. Otherwise, an SQLite error
** code.
*/
int sqlite3Fts5ExprPattern(
Fts5Config *pConfig, int bGlob, int iCol, const char *zText, Fts5Expr **pp
){
i64 nText = strlen(zText);
char *zExpr = (char*)sqlite3_malloc64(nText*4 + 1);
int rc = SQLITE_OK;
if( zExpr==0 ){
rc = SQLITE_NOMEM;
}else{
char aSpec[3];
int iOut = 0;
int i = 0;
int iFirst = 0;
if( bGlob==0 ){
aSpec[0] = '_';
aSpec[1] = '%';
aSpec[2] = 0;
}else{
aSpec[0] = '*';
aSpec[1] = '?';
aSpec[2] = '[';
}
while( i<=nText ){
if( i==nText
|| zText[i]==aSpec[0] || zText[i]==aSpec[1] || zText[i]==aSpec[2]
){
if( i-iFirst>=3 ){
int jj;
zExpr[iOut++] = '"';
for(jj=iFirst; jj<i; jj++){
zExpr[iOut++] = zText[jj];
if( zText[jj]=='"' ) zExpr[iOut++] = '"';
}
zExpr[iOut++] = '"';
zExpr[iOut++] = ' ';
}
if( zText[i]==aSpec[2] ){
i += 2;
if( zText[i-1]=='^' ) i++;
while( i<nText && zText[i]!=']' ) i++;
}
iFirst = i+1;
}
i++;
}
if( iOut>0 ){
int bAnd = 0;
if( pConfig->eDetail!=FTS5_DETAIL_FULL ){
bAnd = 1;
if( pConfig->eDetail==FTS5_DETAIL_NONE ){
iCol = pConfig->nCol;
}
}
zExpr[iOut] = '\0';
rc = sqlite3Fts5ExprNew(pConfig, bAnd, iCol, zExpr, pp,pConfig->pzErrmsg);
}else{
*pp = 0;
}
sqlite3_free(zExpr);
}
return rc;
}
/*
** Free the expression node object passed as the only argument.
*/
@@ -1500,8 +1421,8 @@ int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bDesc){
}
/* If the iterator is not at a real match, skip forward until it is. */
while( pRoot->bNomatch && rc==SQLITE_OK ){
assert( pRoot->bEof==0 );
while( pRoot->bNomatch ){
assert( pRoot->bEof==0 && rc==SQLITE_OK );
rc = fts5ExprNodeNext(p, pRoot, 0, 0);
}
return rc;
@@ -1740,20 +1661,6 @@ void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p){
pParse->pExpr = p;
}
static int parseGrowPhraseArray(Fts5Parse *pParse){
if( (pParse->nPhrase % 8)==0 ){
sqlite3_int64 nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8);
Fts5ExprPhrase **apNew;
apNew = (Fts5ExprPhrase**)sqlite3_realloc64(pParse->apPhrase, nByte);
if( apNew==0 ){
pParse->rc = SQLITE_NOMEM;
return SQLITE_NOMEM;
}
pParse->apPhrase = apNew;
}
return SQLITE_OK;
}
/*
** This function is called by the parser to process a string token. The
** string may or may not be quoted. In any case it is tokenized and a
@@ -1789,9 +1696,16 @@ Fts5ExprPhrase *sqlite3Fts5ParseTerm(
}else{
if( pAppend==0 ){
if( parseGrowPhraseArray(pParse) ){
fts5ExprPhraseFree(sCtx.pPhrase);
return 0;
if( (pParse->nPhrase % 8)==0 ){
sqlite3_int64 nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8);
Fts5ExprPhrase **apNew;
apNew = (Fts5ExprPhrase**)sqlite3_realloc64(pParse->apPhrase, nByte);
if( apNew==0 ){
pParse->rc = SQLITE_NOMEM;
fts5ExprPhraseFree(sCtx.pPhrase);
return 0;
}
pParse->apPhrase = apNew;
}
pParse->nPhrase++;
}
@@ -2198,67 +2112,6 @@ static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){
}
}
/*
** This function is used when parsing LIKE or GLOB patterns against
** trigram indexes that specify either detail=column or detail=none.
** It converts a phrase:
**
** abc + def + ghi
**
** into an AND tree:
**
** abc AND def AND ghi
*/
static Fts5ExprNode *fts5ParsePhraseToAnd(
Fts5Parse *pParse,
Fts5ExprNearset *pNear
){
int nTerm = pNear->apPhrase[0]->nTerm;
int ii;
int nByte;
Fts5ExprNode *pRet;
assert( pNear->nPhrase==1 );
assert( pParse->bPhraseToAnd );
nByte = sizeof(Fts5ExprNode) + nTerm*sizeof(Fts5ExprNode*);
pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte);
if( pRet ){
pRet->eType = FTS5_AND;
pRet->nChild = nTerm;
fts5ExprAssignXNext(pRet);
pParse->nPhrase--;
for(ii=0; ii<nTerm; ii++){
Fts5ExprPhrase *pPhrase = (Fts5ExprPhrase*)sqlite3Fts5MallocZero(
&pParse->rc, sizeof(Fts5ExprPhrase)
);
if( pPhrase ){
if( parseGrowPhraseArray(pParse) ){
fts5ExprPhraseFree(pPhrase);
}else{
pParse->apPhrase[pParse->nPhrase++] = pPhrase;
pPhrase->nTerm = 1;
pPhrase->aTerm[0].zTerm = sqlite3Fts5Strndup(
&pParse->rc, pNear->apPhrase[0]->aTerm[ii].zTerm, -1
);
pRet->apChild[ii] = sqlite3Fts5ParseNode(pParse, FTS5_STRING,
0, 0, sqlite3Fts5ParseNearset(pParse, 0, pPhrase)
);
}
}
}
if( pParse->rc ){
sqlite3Fts5ParseNodeFree(pRet);
pRet = 0;
}else{
sqlite3Fts5ParseNearsetFree(pNear);
}
}
return pRet;
}
/*
** Allocate and return a new expression object. If anything goes wrong (i.e.
** OOM error), leave an error code in pParse and return NULL.
@@ -2283,58 +2136,51 @@ Fts5ExprNode *sqlite3Fts5ParseNode(
if( eType!=FTS5_STRING && pLeft==0 ) return pRight;
if( eType!=FTS5_STRING && pRight==0 ) return pLeft;
if( eType==FTS5_STRING
&& pParse->bPhraseToAnd
&& pNear->apPhrase[0]->nTerm>1
){
pRet = fts5ParsePhraseToAnd(pParse, pNear);
}else{
if( eType==FTS5_NOT ){
nChild = 2;
}else if( eType==FTS5_AND || eType==FTS5_OR ){
nChild = 2;
if( pLeft->eType==eType ) nChild += pLeft->nChild-1;
if( pRight->eType==eType ) nChild += pRight->nChild-1;
}
if( eType==FTS5_NOT ){
nChild = 2;
}else if( eType==FTS5_AND || eType==FTS5_OR ){
nChild = 2;
if( pLeft->eType==eType ) nChild += pLeft->nChild-1;
if( pRight->eType==eType ) nChild += pRight->nChild-1;
}
nByte = sizeof(Fts5ExprNode) + sizeof(Fts5ExprNode*)*(nChild-1);
pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte);
nByte = sizeof(Fts5ExprNode) + sizeof(Fts5ExprNode*)*(nChild-1);
pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte);
if( pRet ){
pRet->eType = eType;
pRet->pNear = pNear;
fts5ExprAssignXNext(pRet);
if( eType==FTS5_STRING ){
int iPhrase;
for(iPhrase=0; iPhrase<pNear->nPhrase; iPhrase++){
pNear->apPhrase[iPhrase]->pNode = pRet;
if( pNear->apPhrase[iPhrase]->nTerm==0 ){
pRet->xNext = 0;
pRet->eType = FTS5_EOF;
}
if( pRet ){
pRet->eType = eType;
pRet->pNear = pNear;
fts5ExprAssignXNext(pRet);
if( eType==FTS5_STRING ){
int iPhrase;
for(iPhrase=0; iPhrase<pNear->nPhrase; iPhrase++){
pNear->apPhrase[iPhrase]->pNode = pRet;
if( pNear->apPhrase[iPhrase]->nTerm==0 ){
pRet->xNext = 0;
pRet->eType = FTS5_EOF;
}
if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL ){
Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
if( pNear->nPhrase!=1
|| pPhrase->nTerm>1
|| (pPhrase->nTerm>0 && pPhrase->aTerm[0].bFirst)
){
assert( pParse->rc==SQLITE_OK );
pParse->rc = SQLITE_ERROR;
assert( pParse->zErr==0 );
pParse->zErr = sqlite3_mprintf(
"fts5: %s queries are not supported (detail!=full)",
pNear->nPhrase==1 ? "phrase": "NEAR"
);
sqlite3_free(pRet);
pRet = 0;
}
}
}else{
fts5ExprAddChildren(pRet, pLeft);
fts5ExprAddChildren(pRet, pRight);
}
if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL ){
Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
if( pNear->nPhrase!=1
|| pPhrase->nTerm>1
|| (pPhrase->nTerm>0 && pPhrase->aTerm[0].bFirst)
){
assert( pParse->rc==SQLITE_OK );
pParse->rc = SQLITE_ERROR;
assert( pParse->zErr==0 );
pParse->zErr = sqlite3_mprintf(
"fts5: %s queries are not supported (detail!=full)",
pNear->nPhrase==1 ? "phrase": "NEAR"
);
sqlite3_free(pRet);
pRet = 0;
}
}
}else{
fts5ExprAddChildren(pRet, pLeft);
fts5ExprAddChildren(pRet, pRight);
}
}
}
@@ -2555,17 +2401,8 @@ static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){
int iTerm;
if( pNear->pColset ){
int ii;
Fts5Colset *pColset = pNear->pColset;
if( pColset->nCol>1 ) zRet = fts5PrintfAppend(zRet, "{");
for(ii=0; ii<pColset->nCol; ii++){
zRet = fts5PrintfAppend(zRet, "%s%s",
pConfig->azCol[pColset->aiCol[ii]], ii==pColset->nCol-1 ? "" : " "
);
}
if( zRet ){
zRet = fts5PrintfAppend(zRet, "%s : ", pColset->nCol>1 ? "}" : "");
}
int iCol = pNear->pColset->aiCol[0];
zRet = fts5PrintfAppend(zRet, "%s : ", pConfig->azCol[iCol]);
if( zRet==0 ) return 0;
}
@@ -2688,7 +2525,7 @@ static void fts5ExprFunction(
rc = sqlite3Fts5ConfigParse(pGlobal, db, nConfig, azConfig, &pConfig, &zErr);
if( rc==SQLITE_OK ){
rc = sqlite3Fts5ExprNew(pConfig, 0, pConfig->nCol, zExpr, &pExpr, &zErr);
rc = sqlite3Fts5ExprNew(pConfig, pConfig->nCol, zExpr, &pExpr, &zErr);
}
if( rc==SQLITE_OK ){
char *zText;
+2 -2
View File
@@ -306,6 +306,7 @@ int sqlite3Fts5HashWrite(
p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1);
}
nIncr += p->nData;
}else{
/* Appending to an existing hash-entry. Check that there is enough
@@ -338,9 +339,8 @@ int sqlite3Fts5HashWrite(
/* If this is a new rowid, append the 4-byte size field for the previous
** entry, and the new rowid for this entry. */
if( iRowid!=p->iRowid ){
u64 iDiff = (u64)iRowid - (u64)p->iRowid;
fts5HashAddPoslistSize(pHash, p, 0);
p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iDiff);
p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid);
p->iRowid = iRowid;
bNew = 1;
p->iSzPoslist = p->nData;
+227 -301
View File
@@ -1754,7 +1754,7 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
ASSERT_SZLEAF_OK(pIter->pLeaf);
while( 1 ){
u64 iDelta = 0;
i64 iDelta = 0;
if( eDetail==FTS5_DETAIL_NONE ){
/* todo */
@@ -1769,7 +1769,7 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
i += nPos;
}
if( i>=n ) break;
i += fts5GetVarint(&a[i], &iDelta);
i += fts5GetVarint(&a[i], (u64*)&iDelta);
pIter->iRowid += iDelta;
/* If necessary, grow the pIter->aRowidOffset[] array. */
@@ -1868,7 +1868,7 @@ static void fts5SegIterNext_Reverse(
if( pIter->iRowidOffset>0 ){
u8 *a = pIter->pLeaf->p;
int iOff;
u64 iDelta;
i64 iDelta;
pIter->iRowidOffset--;
pIter->iLeafOffset = pIter->aRowidOffset[pIter->iRowidOffset];
@@ -1877,7 +1877,7 @@ static void fts5SegIterNext_Reverse(
if( p->pConfig->eDetail!=FTS5_DETAIL_NONE ){
iOff += pIter->nPos;
}
fts5GetVarint(&a[iOff], &iDelta);
fts5GetVarint(&a[iOff], (u64*)&iDelta);
pIter->iRowid -= iDelta;
}else{
fts5SegIterReverseNewPage(p, pIter);
@@ -2070,10 +2070,14 @@ static void fts5SegIterNext(
}else{
/* The following could be done by calling fts5SegIterLoadNPos(). But
** this block is particularly performance critical, so equivalent
** code is inlined. */
** code is inlined.
**
** Later: Switched back to fts5SegIterLoadNPos() because it supports
** detail=none mode. Not ideal.
*/
int nSz;
assert( p->rc==SQLITE_OK );
assert_nc( pIter->iLeafOffset<=pIter->pLeaf->nn );
assert( pIter->iLeafOffset<=pIter->pLeaf->nn );
fts5FastGetVarint32(pIter->pLeaf->p, pIter->iLeafOffset, nSz);
pIter->bDel = (nSz & 0x0001);
pIter->nPos = nSz>>1;
@@ -2317,11 +2321,11 @@ static void fts5LeafSeek(
}
search_success:
if( (i64)iOff+nNew>n || nNew<1 ){
pIter->iLeafOffset = iOff + nNew;
if( pIter->iLeafOffset>n || nNew<1 ){
p->rc = FTS5_CORRUPT;
return;
}
pIter->iLeafOffset = iOff + nNew;
pIter->iTermLeafOffset = pIter->iLeafOffset;
pIter->iTermLeafPgno = pIter->iLeafPgno;
@@ -3065,7 +3069,7 @@ static void fts5ChunkIterate(
int pgno = pSeg->iLeafPgno;
int pgnoSave = 0;
/* This function does not work with detail=none databases. */
/* This function does notmwork with detail=none databases. */
assert( p->pConfig->eDetail!=FTS5_DETAIL_NONE );
if( (pSeg->flags & FTS5_SEGITER_REVERSE)==0 ){
@@ -3078,9 +3082,6 @@ static void fts5ChunkIterate(
fts5DataRelease(pData);
if( nRem<=0 ){
break;
}else if( pSeg->pSeg==0 ){
p->rc = FTS5_CORRUPT;
return;
}else{
pgno++;
pData = fts5LeafRead(p, FTS5_SEGMENT_ROWID(pSeg->pSeg->iSegid, pgno));
@@ -3132,72 +3133,66 @@ static void fts5SegiterPoslist(
}
/*
** Parameter pPos points to a buffer containing a position list, size nPos.
** This function filters it according to pColset (which must be non-NULL)
** and sets pIter->base.pData/nData to point to the new position list.
** If memory is required for the new position list, use buffer pIter->poslist.
** Or, if the new position list is a contiguous subset of the input, set
** pIter->base.pData/nData to point directly to it.
**
** This function is a no-op if *pRc is other than SQLITE_OK when it is
** called. If an OOM error is encountered, *pRc is set to SQLITE_NOMEM
** before returning.
** IN/OUT parameter (*pa) points to a position list n bytes in size. If
** the position list contains entries for column iCol, then (*pa) is set
** to point to the sub-position-list for that column and the number of
** bytes in it returned. Or, if the argument position list does not
** contain any entries for column iCol, return 0.
*/
static int fts5IndexExtractCol(
const u8 **pa, /* IN/OUT: Pointer to poslist */
int n, /* IN: Size of poslist in bytes */
int iCol /* Column to extract from poslist */
){
int iCurrent = 0; /* Anything before the first 0x01 is col 0 */
const u8 *p = *pa;
const u8 *pEnd = &p[n]; /* One byte past end of position list */
while( iCol>iCurrent ){
/* Advance pointer p until it points to pEnd or an 0x01 byte that is
** not part of a varint. Note that it is not possible for a negative
** or extremely large varint to occur within an uncorrupted position
** list. So the last byte of each varint may be assumed to have a clear
** 0x80 bit. */
while( *p!=0x01 ){
while( *p++ & 0x80 );
if( p>=pEnd ) return 0;
}
*pa = p++;
iCurrent = *p++;
if( iCurrent & 0x80 ){
p--;
p += fts5GetVarint32(p, iCurrent);
}
}
if( iCol!=iCurrent ) return 0;
/* Advance pointer p until it points to pEnd or an 0x01 byte that is
** not part of a varint */
while( p<pEnd && *p!=0x01 ){
while( *p++ & 0x80 );
}
return p - (*pa);
}
static void fts5IndexExtractColset(
int *pRc,
Fts5Colset *pColset, /* Colset to filter on */
const u8 *pPos, int nPos, /* Position list */
Fts5Iter *pIter
Fts5Buffer *pBuf /* Output buffer */
){
if( *pRc==SQLITE_OK ){
const u8 *p = pPos;
const u8 *aCopy = p;
const u8 *pEnd = &p[nPos]; /* One byte past end of position list */
int i = 0;
int iCurrent = 0;
if( pColset->nCol>1 && sqlite3Fts5BufferSize(pRc, &pIter->poslist, nPos) ){
return;
}
while( 1 ){
while( pColset->aiCol[i]<iCurrent ){
i++;
if( i==pColset->nCol ){
pIter->base.pData = pIter->poslist.p;
pIter->base.nData = pIter->poslist.n;
return;
}
}
/* Advance pointer p until it points to pEnd or an 0x01 byte that is
** not part of a varint */
while( p<pEnd && *p!=0x01 ){
while( *p++ & 0x80 );
}
if( pColset->aiCol[i]==iCurrent ){
if( pColset->nCol==1 ){
pIter->base.pData = aCopy;
pIter->base.nData = p-aCopy;
return;
}
fts5BufferSafeAppendBlob(&pIter->poslist, aCopy, p-aCopy);
}
if( p==pEnd ){
pIter->base.pData = pIter->poslist.p;
pIter->base.nData = pIter->poslist.n;
return;
}
aCopy = p++;
iCurrent = *p++;
if( iCurrent & 0x80 ){
p--;
p += fts5GetVarint32(p, iCurrent);
int i;
fts5BufferZero(pBuf);
for(i=0; i<pColset->nCol; i++){
const u8 *pSub = pPos;
int nSub = fts5IndexExtractCol(&pSub, nPos, pColset->aiCol[i]);
if( nSub ){
fts5BufferAppendBlob(pRc, pBuf, nSub, pSub);
}
}
}
}
/*
@@ -3317,9 +3312,16 @@ static void fts5IterSetOutputs_Full(Fts5Iter *pIter, Fts5SegIter *pSeg){
/* All data is stored on the current page. Populate the output
** variables to point into the body of the page object. */
const u8 *a = &pSeg->pLeaf->p[pSeg->iLeafOffset];
int *pRc = &pIter->pIndex->rc;
fts5BufferZero(&pIter->poslist);
fts5IndexExtractColset(pRc, pColset, a, pSeg->nPos, pIter);
if( pColset->nCol==1 ){
pIter->base.nData = fts5IndexExtractCol(&a, pSeg->nPos,pColset->aiCol[0]);
pIter->base.pData = a;
}else{
int *pRc = &pIter->pIndex->rc;
fts5BufferZero(&pIter->poslist);
fts5IndexExtractColset(pRc, pColset, a, pSeg->nPos, &pIter->poslist);
pIter->base.pData = pIter->poslist.p;
pIter->base.nData = pIter->poslist.n;
}
}else{
/* The data is distributed over two or more pages. Copy it into the
** Fts5Iter.poslist buffer and then set the output pointer to point
@@ -4802,7 +4804,7 @@ static void fts5AppendPoslist(
static void fts5DoclistIterNext(Fts5DoclistIter *pIter){
u8 *p = pIter->aPoslist + pIter->nSize + pIter->nPoslist;
assert( pIter->aPoslist || (p==0 && pIter->aPoslist==0) );
assert( pIter->aPoslist );
if( p>=pIter->aEof ){
pIter->aPoslist = 0;
}else{
@@ -4886,20 +4888,16 @@ static void fts5NextRowid(Fts5Buffer *pBuf, int *piOff, i64 *piRowid){
static void fts5MergeRowidLists(
Fts5Index *p, /* FTS5 backend object */
Fts5Buffer *p1, /* First list to merge */
int nBuf, /* Number of entries in apBuf[] */
Fts5Buffer *aBuf /* Array of other lists to merge into p1 */
Fts5Buffer *p2 /* Second list to merge */
){
int i1 = 0;
int i2 = 0;
i64 iRowid1 = 0;
i64 iRowid2 = 0;
i64 iOut = 0;
Fts5Buffer *p2 = &aBuf[0];
Fts5Buffer out;
(void)nBuf;
Fts5Buffer out;
memset(&out, 0, sizeof(out));
assert( nBuf==1 );
sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n);
if( p->rc ) return;
@@ -4926,213 +4924,177 @@ static void fts5MergeRowidLists(
fts5BufferFree(&out);
}
typedef struct PrefixMerger PrefixMerger;
struct PrefixMerger {
Fts5DoclistIter iter; /* Doclist iterator */
i64 iPos; /* For iterating through a position list */
int iOff;
u8 *aPos;
PrefixMerger *pNext; /* Next in docid/poslist order */
};
static void fts5PrefixMergerInsertByRowid(
PrefixMerger **ppHead,
PrefixMerger *p
){
if( p->iter.aPoslist ){
PrefixMerger **pp = ppHead;
while( *pp && p->iter.iRowid>(*pp)->iter.iRowid ){
pp = &(*pp)->pNext;
}
p->pNext = *pp;
*pp = p;
}
}
static void fts5PrefixMergerInsertByPosition(
PrefixMerger **ppHead,
PrefixMerger *p
){
if( p->iPos>=0 ){
PrefixMerger **pp = ppHead;
while( *pp && p->iPos>(*pp)->iPos ){
pp = &(*pp)->pNext;
}
p->pNext = *pp;
*pp = p;
}
}
/*
** Array aBuf[] contains nBuf doclists. These are all merged in with the
** doclist in buffer p1.
** Buffers p1 and p2 contain doclists. This function merges the content
** of the two doclists together and sets buffer p1 to the result before
** returning.
**
** If an error occurs, an error code is left in p->rc. If an error has
** already occurred, this function is a no-op.
*/
static void fts5MergePrefixLists(
Fts5Index *p, /* FTS5 backend object */
Fts5Buffer *p1, /* First list to merge */
int nBuf, /* Number of buffers in array aBuf[] */
Fts5Buffer *aBuf /* Other lists to merge in */
Fts5Buffer *p2 /* Second list to merge */
){
#define fts5PrefixMergerNextPosition(p) \
sqlite3Fts5PoslistNext64((p)->aPos,(p)->iter.nPoslist,&(p)->iOff,&(p)->iPos);
#define FTS5_MERGE_NLIST 16
PrefixMerger aMerger[FTS5_MERGE_NLIST];
PrefixMerger *pHead = 0;
int i;
int nOut = 0;
Fts5Buffer out = {0, 0, 0};
Fts5Buffer tmp = {0, 0, 0};
i64 iLastRowid = 0;
if( p2->n ){
i64 iLastRowid = 0;
Fts5DoclistIter i1;
Fts5DoclistIter i2;
Fts5Buffer out = {0, 0, 0};
Fts5Buffer tmp = {0, 0, 0};
/* Initialize a doclist-iterator for each input buffer. Arrange them in
** a linked-list starting at pHead in ascending order of rowid. Avoid
** linking any iterators already at EOF into the linked list at all. */
assert( nBuf+1<=sizeof(aMerger)/sizeof(aMerger[0]) );
memset(aMerger, 0, sizeof(PrefixMerger)*(nBuf+1));
pHead = &aMerger[nBuf];
fts5DoclistIterInit(p1, &pHead->iter);
for(i=0; i<nBuf; i++){
fts5DoclistIterInit(&aBuf[i], &aMerger[i].iter);
fts5PrefixMergerInsertByRowid(&pHead, &aMerger[i]);
nOut += aBuf[i].n;
}
if( nOut==0 ) return;
nOut += p1->n + 9 + 10*nBuf;
/* The maximum size of the output is equal to the sum of the two
** input sizes + 1 varint (9 bytes). The extra varint is because if the
** first rowid in one input is a large negative number, and the first in
** the other a non-negative number, the delta for the non-negative
** number will be larger on disk than the literal integer value
** was.
**
** Or, if the input position-lists are corrupt, then the output might
** include up to 2 extra 10-byte positions created by interpreting -1
** (the value PoslistNext64() uses for EOF) as a position and appending
** it to the output. This can happen at most once for each input
** position-list, hence two 10 byte paddings. */
if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n + 9+10+10) ) return;
fts5DoclistIterInit(p1, &i1);
fts5DoclistIterInit(p2, &i2);
/* The maximum size of the output is equal to the sum of the
** input sizes + 1 varint (9 bytes). The extra varint is because if the
** first rowid in one input is a large negative number, and the first in
** the other a non-negative number, the delta for the non-negative
** number will be larger on disk than the literal integer value
** was.
**
** Or, if the input position-lists are corrupt, then the output might
** include up to (nBuf+1) extra 10-byte positions created by interpreting -1
** (the value PoslistNext64() uses for EOF) as a position and appending
** it to the output. This can happen at most once for each input
** position-list, hence (nBuf+1) 10 byte paddings. */
if( sqlite3Fts5BufferSize(&p->rc, &out, nOut) ) return;
while( pHead ){
fts5MergeAppendDocid(&out, iLastRowid, pHead->iter.iRowid);
if( pHead->pNext && iLastRowid==pHead->pNext->iter.iRowid ){
/* Merge data from two or more poslists */
i64 iPrev = 0;
int nTmp = FTS5_DATA_ZERO_PADDING;
int nMerge = 0;
PrefixMerger *pSave = pHead;
PrefixMerger *pThis = 0;
int nTail = 0;
pHead = 0;
while( pSave && pSave->iter.iRowid==iLastRowid ){
PrefixMerger *pNext = pSave->pNext;
pSave->iOff = 0;
pSave->iPos = 0;
pSave->aPos = &pSave->iter.aPoslist[pSave->iter.nSize];
fts5PrefixMergerNextPosition(pSave);
nTmp += pSave->iter.nPoslist + 10;
nMerge++;
fts5PrefixMergerInsertByPosition(&pHead, pSave);
pSave = pNext;
while( 1 ){
if( i1.iRowid<i2.iRowid ){
/* Copy entry from i1 */
fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid);
fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.nPoslist+i1.nSize);
fts5DoclistIterNext(&i1);
if( i1.aPoslist==0 ) break;
assert( out.n<=((i1.aPoslist-p1->p) + (i2.aPoslist-p2->p)+9+10+10) );
}
if( pHead==0 || pHead->pNext==0 ){
p->rc = FTS5_CORRUPT;
break;
else if( i2.iRowid!=i1.iRowid ){
/* Copy entry from i2 */
fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.nPoslist+i2.nSize);
fts5DoclistIterNext(&i2);
if( i2.aPoslist==0 ) break;
assert( out.n<=((i1.aPoslist-p1->p) + (i2.aPoslist-p2->p)+9+10+10) );
}
else{
/* Merge the two position lists. */
i64 iPos1 = 0;
i64 iPos2 = 0;
int iOff1 = 0;
int iOff2 = 0;
u8 *a1 = &i1.aPoslist[i1.nSize];
u8 *a2 = &i2.aPoslist[i2.nSize];
int nCopy;
u8 *aCopy;
/* See the earlier comment in this function for an explanation of why
** corrupt input position lists might cause the output to consume
** at most nMerge*10 bytes of unexpected space. */
if( sqlite3Fts5BufferSize(&p->rc, &tmp, nTmp+nMerge*10) ){
break;
}
fts5BufferZero(&tmp);
i64 iPrev = 0;
Fts5PoslistWriter writer;
memset(&writer, 0, sizeof(writer));
pThis = pHead;
pHead = pThis->pNext;
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, pThis->iPos);
fts5PrefixMergerNextPosition(pThis);
fts5PrefixMergerInsertByPosition(&pHead, pThis);
/* See the earlier comment in this function for an explanation of why
** corrupt input position lists might cause the output to consume
** at most 20 bytes of unexpected space. */
fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
fts5BufferZero(&tmp);
sqlite3Fts5BufferSize(&p->rc, &tmp, i1.nPoslist + i2.nPoslist + 10 + 10);
if( p->rc ) break;
while( pHead->pNext ){
pThis = pHead;
if( pThis->iPos!=iPrev ){
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, pThis->iPos);
sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
assert_nc( iPos1>=0 && iPos2>=0 );
if( iPos1<iPos2 ){
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
}else{
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
}
fts5PrefixMergerNextPosition(pThis);
pHead = pThis->pNext;
fts5PrefixMergerInsertByPosition(&pHead, pThis);
}
if( pHead->iPos!=iPrev ){
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, pHead->iPos);
}
nTail = pHead->iter.nPoslist - pHead->iOff;
/* WRITEPOSLISTSIZE */
assert( tmp.n+nTail<=nTmp );
if( tmp.n+nTail>nTmp-FTS5_DATA_ZERO_PADDING ){
if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT;
break;
}
fts5BufferSafeAppendVarint(&out, (tmp.n+nTail) * 2);
fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n);
if( nTail>0 ){
fts5BufferSafeAppendBlob(&out, &pHead->aPos[pHead->iOff], nTail);
}
pHead = pSave;
for(i=0; i<nBuf+1; i++){
PrefixMerger *pX = &aMerger[i];
if( pX->iter.aPoslist && pX->iter.iRowid==iLastRowid ){
fts5DoclistIterNext(&pX->iter);
fts5PrefixMergerInsertByRowid(&pHead, pX);
if( iPos1>=0 && iPos2>=0 ){
while( 1 ){
if( iPos1<iPos2 ){
if( iPos1!=iPrev ){
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
}
sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
if( iPos1<0 ) break;
}else{
assert_nc( iPos2!=iPrev );
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
if( iPos2<0 ) break;
}
}
}
}
}else{
/* Copy poslist from pHead to output */
PrefixMerger *pThis = pHead;
Fts5DoclistIter *pI = &pThis->iter;
fts5BufferSafeAppendBlob(&out, pI->aPoslist, pI->nPoslist+pI->nSize);
fts5DoclistIterNext(pI);
pHead = pThis->pNext;
fts5PrefixMergerInsertByRowid(&pHead, pThis);
if( iPos1>=0 ){
if( iPos1!=iPrev ){
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
}
aCopy = &a1[iOff1];
nCopy = i1.nPoslist - iOff1;
}else{
assert_nc( iPos2>=0 && iPos2!=iPrev );
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
aCopy = &a2[iOff2];
nCopy = i2.nPoslist - iOff2;
}
if( nCopy>0 ){
fts5BufferSafeAppendBlob(&tmp, aCopy, nCopy);
}
/* WRITEPOSLISTSIZE */
assert_nc( tmp.n<=i1.nPoslist+i2.nPoslist );
assert( tmp.n<=i1.nPoslist+i2.nPoslist+10+10 );
if( tmp.n>i1.nPoslist+i2.nPoslist ){
if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT;
break;
}
fts5BufferSafeAppendVarint(&out, tmp.n * 2);
fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n);
fts5DoclistIterNext(&i1);
fts5DoclistIterNext(&i2);
assert_nc( out.n<=(p1->n+p2->n+9) );
if( i1.aPoslist==0 || i2.aPoslist==0 ) break;
assert( out.n<=((i1.aPoslist-p1->p) + (i2.aPoslist-p2->p)+9+10+10) );
}
}
}
fts5BufferFree(p1);
fts5BufferFree(&tmp);
memset(&out.p[out.n], 0, FTS5_DATA_ZERO_PADDING);
*p1 = out;
if( i1.aPoslist ){
fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid);
fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.aEof - i1.aPoslist);
}
else if( i2.aPoslist ){
fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.aEof - i2.aPoslist);
}
assert_nc( out.n<=(p1->n+p2->n+9) );
fts5BufferSet(&p->rc, p1, out.n, out.p);
fts5BufferFree(&tmp);
fts5BufferFree(&out);
}
}
static void fts5SetupPrefixIter(
Fts5Index *p, /* Index to read from */
int bDesc, /* True for "ORDER BY rowid DESC" */
int iIdx, /* Index to scan for data */
u8 *pToken, /* Buffer containing prefix to match */
const u8 *pToken, /* Buffer containing prefix to match */
int nToken, /* Size of buffer pToken in bytes */
Fts5Colset *pColset, /* Restrict matches to these columns */
Fts5Iter **ppIter /* OUT: New iterator */
){
Fts5Structure *pStruct;
Fts5Buffer *aBuf;
int nBuf = 32;
int nMerge = 1;
const int nBuf = 32;
void (*xMerge)(Fts5Index*, Fts5Buffer*, int, Fts5Buffer*);
void (*xMerge)(Fts5Index*, Fts5Buffer*, Fts5Buffer*);
void (*xAppend)(Fts5Index*, i64, Fts5Iter*, Fts5Buffer*);
if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
xMerge = fts5MergeRowidLists;
xAppend = fts5AppendRowid;
}else{
nMerge = FTS5_MERGE_NLIST-1;
nBuf = nMerge*8; /* Sufficient to merge (16^8)==(2^32) lists */
xMerge = fts5MergePrefixLists;
xAppend = fts5AppendPoslist;
}
@@ -5152,27 +5114,6 @@ static void fts5SetupPrefixIter(
int bNewTerm = 1;
memset(&doclist, 0, sizeof(doclist));
if( iIdx!=0 ){
int dummy = 0;
const int f2 = FTS5INDEX_QUERY_SKIPEMPTY|FTS5INDEX_QUERY_NOOUTPUT;
pToken[0] = FTS5_MAIN_PREFIX;
fts5MultiIterNew(p, pStruct, f2, pColset, pToken, nToken, -1, 0, &p1);
fts5IterSetOutputCb(&p->rc, p1);
for(;
fts5MultiIterEof(p, p1)==0;
fts5MultiIterNext2(p, p1, &dummy)
){
Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
p1->xSetOutputs(p1, pSeg);
if( p1->base.nData ){
xAppend(p, p1->base.iRowid-iLastRowid, p1, &doclist);
iLastRowid = p1->base.iRowid;
}
}
fts5MultiIterFree(p1);
}
pToken[0] = FTS5_MAIN_PREFIX + iIdx;
fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1);
fts5IterSetOutputCb(&p->rc, p1);
for( /* no-op */ ;
@@ -5193,21 +5134,13 @@ static void fts5SetupPrefixIter(
if( p1->base.iRowid<=iLastRowid && doclist.n>0 ){
for(i=0; p->rc==SQLITE_OK && doclist.n; i++){
int i1 = i*nMerge;
int iStore;
assert( i1+nMerge<=nBuf );
for(iStore=i1; iStore<i1+nMerge; iStore++){
if( aBuf[iStore].n==0 ){
fts5BufferSwap(&doclist, &aBuf[iStore]);
fts5BufferZero(&doclist);
break;
}
}
if( iStore==i1+nMerge ){
xMerge(p, &doclist, nMerge, &aBuf[i1]);
for(iStore=i1; iStore<i1+nMerge; iStore++){
fts5BufferZero(&aBuf[iStore]);
}
assert( i<nBuf );
if( aBuf[i].n==0 ){
fts5BufferSwap(&doclist, &aBuf[i]);
fts5BufferZero(&doclist);
}else{
xMerge(p, &doclist, &aBuf[i]);
fts5BufferZero(&aBuf[i]);
}
}
iLastRowid = 0;
@@ -5217,15 +5150,11 @@ static void fts5SetupPrefixIter(
iLastRowid = p1->base.iRowid;
}
assert( (nBuf%nMerge)==0 );
for(i=0; i<nBuf; i+=nMerge){
int iFree;
for(i=0; i<nBuf; i++){
if( p->rc==SQLITE_OK ){
xMerge(p, &doclist, nMerge, &aBuf[i]);
}
for(iFree=i; iFree<i+nMerge; iFree++){
fts5BufferFree(&aBuf[iFree]);
xMerge(p, &doclist, &aBuf[i]);
}
fts5BufferFree(&aBuf[i]);
}
fts5MultiIterFree(p1);
@@ -5480,7 +5409,6 @@ int sqlite3Fts5IndexQuery(
if( sqlite3Fts5BufferSize(&p->rc, &buf, nToken+1)==0 ){
int iIdx = 0; /* Index to search */
int iPrefixIdx = 0; /* +1 prefix index */
if( nToken ) memcpy(&buf.p[1], pToken, nToken);
/* Figure out which index to search and set iIdx accordingly. If this
@@ -5502,9 +5430,7 @@ int sqlite3Fts5IndexQuery(
if( flags & FTS5INDEX_QUERY_PREFIX ){
int nChar = fts5IndexCharlen(pToken, nToken);
for(iIdx=1; iIdx<=pConfig->nPrefix; iIdx++){
int nIdxChar = pConfig->aPrefix[iIdx-1];
if( nIdxChar==nChar ) break;
if( nIdxChar==nChar+1 ) iPrefixIdx = iIdx;
if( pConfig->aPrefix[iIdx-1]==nChar ) break;
}
}
@@ -5521,7 +5447,8 @@ int sqlite3Fts5IndexQuery(
}else{
/* Scan multiple terms in the main index */
int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0;
fts5SetupPrefixIter(p, bDesc, iPrefixIdx, buf.p, nToken+1, pColset,&pRet);
buf.p[0] = FTS5_MAIN_PREFIX;
fts5SetupPrefixIter(p, bDesc, buf.p, nToken+1, pColset, &pRet);
assert( p->rc!=SQLITE_OK || pRet->pColset==0 );
fts5IterSetOutputCb(&p->rc, pRet);
if( p->rc==SQLITE_OK ){
@@ -6132,7 +6059,7 @@ static void fts5IndexIntegrityCheckSegment(
** error, or some other SQLite error code if another error (e.g. OOM)
** occurs.
*/
int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum){
int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
int eDetail = p->pConfig->eDetail;
u64 cksum2 = 0; /* Checksum based on contents of indexes */
Fts5Buffer poslist = {0,0,0}; /* Buffer used to hold a poslist */
@@ -6193,7 +6120,6 @@ int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum){
}else{
poslist.n = 0;
fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst], 0, &poslist);
fts5BufferAppendBlob(&p->rc, &poslist, 4, (const u8*)"\0\0\0\0");
while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){
int iCol = FTS5_POS2COLUMN(iPos);
int iTokOff = FTS5_POS2OFFSET(iPos);
@@ -6204,7 +6130,7 @@ int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum){
fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3);
fts5MultiIterFree(pIter);
if( p->rc==SQLITE_OK && bUseCksum && cksum!=cksum2 ) p->rc = FTS5_CORRUPT;
if( p->rc==SQLITE_OK && cksum!=cksum2 ) p->rc = FTS5_CORRUPT;
fts5StructureRelease(pStruct);
#ifdef SQLITE_DEBUG
+37 -80
View File
@@ -464,23 +464,6 @@ static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){
#endif
}
static int fts5UsePatternMatch(
Fts5Config *pConfig,
struct sqlite3_index_constraint *p
){
assert( FTS5_PATTERN_GLOB==SQLITE_INDEX_CONSTRAINT_GLOB );
assert( FTS5_PATTERN_LIKE==SQLITE_INDEX_CONSTRAINT_LIKE );
if( pConfig->ePattern==FTS5_PATTERN_GLOB && p->op==FTS5_PATTERN_GLOB ){
return 1;
}
if( pConfig->ePattern==FTS5_PATTERN_LIKE
&& (p->op==FTS5_PATTERN_LIKE || p->op==FTS5_PATTERN_GLOB)
){
return 1;
}
return 0;
}
/*
** Implementation of the xBestIndex method for FTS5 tables. Within the
** WHERE constraint, it searches for the following:
@@ -510,9 +493,7 @@ static int fts5UsePatternMatch(
**
** Match against table column: "m"
** Match against rank column: "r"
** Match against other column: "M<column-number>"
** LIKE against other column: "L<column-number>"
** GLOB against other column: "G<column-number>"
** Match against other column: "<column-number>"
** Equality constraint against the rowid: "="
** A < or <= against the rowid: "<"
** A > or >= against the rowid: ">"
@@ -573,7 +554,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
return SQLITE_ERROR;
}
idxStr = (char*)sqlite3_malloc(pInfo->nConstraint * 8 + 1);
idxStr = (char*)sqlite3_malloc(pInfo->nConstraint * 6 + 1);
if( idxStr==0 ) return SQLITE_NOMEM;
pInfo->idxStr = idxStr;
pInfo->needToFreeIdxStr = 1;
@@ -597,29 +578,25 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
if( bSeenRank ) continue;
idxStr[iIdxStr++] = 'r';
bSeenRank = 1;
}else if( iCol>=0 ){
}else{
bSeenMatch = 1;
idxStr[iIdxStr++] = 'M';
sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol);
idxStr += strlen(&idxStr[iIdxStr]);
assert( idxStr[iIdxStr]=='\0' );
idxStr[iIdxStr++] = 'm';
if( iCol<nCol ){
sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol);
idxStr += strlen(&idxStr[iIdxStr]);
assert( idxStr[iIdxStr]=='\0' );
}
}
pInfo->aConstraintUsage[i].argvIndex = ++iCons;
pInfo->aConstraintUsage[i].omit = 1;
}
}else if( p->usable ){
if( iCol>=0 && iCol<nCol && fts5UsePatternMatch(pConfig, p) ){
assert( p->op==FTS5_PATTERN_LIKE || p->op==FTS5_PATTERN_GLOB );
idxStr[iIdxStr++] = p->op==FTS5_PATTERN_LIKE ? 'L' : 'G';
sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol);
idxStr += strlen(&idxStr[iIdxStr]);
pInfo->aConstraintUsage[i].argvIndex = ++iCons;
assert( idxStr[iIdxStr]=='\0' );
}else if( bSeenEq==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol<0 ){
idxStr[iIdxStr++] = '=';
bSeenEq = 1;
pInfo->aConstraintUsage[i].argvIndex = ++iCons;
}
}
else if( p->usable && bSeenEq==0
&& p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol<0
){
idxStr[iIdxStr++] = '=';
bSeenEq = 1;
pInfo->aConstraintUsage[i].argvIndex = ++iCons;
}
}
@@ -1252,14 +1229,19 @@ static int fts5FilterMethod(
case 'r':
pRank = apVal[i];
break;
case 'M': {
case 'm': {
const char *zText = (const char*)sqlite3_value_text(apVal[i]);
if( zText==0 ) zText = "";
iCol = 0;
do{
iCol = iCol*10 + (idxStr[iIdxStr]-'0');
iIdxStr++;
}while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' );
if( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' ){
iCol = 0;
do{
iCol = iCol*10 + (idxStr[iIdxStr]-'0');
iIdxStr++;
}while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' );
}else{
iCol = pConfig->nCol;
}
if( zText[0]=='*' ){
/* The user has issued a query of the form "MATCH '*...'". This
@@ -1269,7 +1251,7 @@ static int fts5FilterMethod(
goto filter_out;
}else{
char **pzErr = &pTab->p.base.zErrMsg;
rc = sqlite3Fts5ExprNew(pConfig, 0, iCol, zText, &pExpr, pzErr);
rc = sqlite3Fts5ExprNew(pConfig, iCol, zText, &pExpr, pzErr);
if( rc==SQLITE_OK ){
rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr);
pExpr = 0;
@@ -1279,25 +1261,6 @@ static int fts5FilterMethod(
break;
}
case 'L':
case 'G': {
int bGlob = (idxStr[iIdxStr-1]=='G');
const char *zText = (const char*)sqlite3_value_text(apVal[i]);
iCol = 0;
do{
iCol = iCol*10 + (idxStr[iIdxStr]-'0');
iIdxStr++;
}while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' );
if( zText ){
rc = sqlite3Fts5ExprPattern(pConfig, bGlob, iCol, zText, &pExpr);
}
if( rc==SQLITE_OK ){
rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr);
pExpr = 0;
}
if( rc!=SQLITE_OK ) goto filter_out;
break;
}
case '=':
pRowidEq = apVal[i];
break;
@@ -1545,8 +1508,7 @@ static int fts5SpecialInsert(
int nMerge = sqlite3_value_int(pVal);
rc = sqlite3Fts5StorageMerge(pTab->pStorage, nMerge);
}else if( 0==sqlite3_stricmp("integrity-check", zCmd) ){
int iArg = sqlite3_value_int(pVal);
rc = sqlite3Fts5StorageIntegrity(pTab->pStorage, iArg);
rc = sqlite3Fts5StorageIntegrity(pTab->pStorage);
#ifdef SQLITE_DEBUG
}else if( 0==sqlite3_stricmp("prefix-index", zCmd) ){
pConfig->bPrefixIndex = sqlite3_value_int(pVal);
@@ -2709,7 +2671,8 @@ int sqlite3Fts5GetTokenizer(
Fts5Global *pGlobal,
const char **azArg,
int nArg,
Fts5Config *pConfig,
Fts5Tokenizer **ppTok,
fts5_tokenizer **ppTokApi,
char **pzErr
){
Fts5TokenizerModule *pMod;
@@ -2721,22 +2684,16 @@ int sqlite3Fts5GetTokenizer(
rc = SQLITE_ERROR;
*pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]);
}else{
rc = pMod->x.xCreate(
pMod->pUserData, &azArg[1], (nArg?nArg-1:0), &pConfig->pTok
);
pConfig->pTokApi = &pMod->x;
if( rc!=SQLITE_OK ){
if( pzErr ) *pzErr = sqlite3_mprintf("error in tokenizer constructor");
}else{
pConfig->ePattern = sqlite3Fts5TokenizerPattern(
pMod->x.xCreate, pConfig->pTok
);
rc = pMod->x.xCreate(pMod->pUserData, &azArg[1], (nArg?nArg-1:0), ppTok);
*ppTokApi = &pMod->x;
if( rc!=SQLITE_OK && pzErr ){
*pzErr = sqlite3_mprintf("error in tokenizer constructor");
}
}
if( rc!=SQLITE_OK ){
pConfig->pTokApi = 0;
pConfig->pTok = 0;
*ppTokApi = 0;
*ppTok = 0;
}
return rc;
+65 -78
View File
@@ -429,16 +429,9 @@ static int fts5StorageDeleteFromIndex(
zText, nText, (void*)&ctx, fts5StorageInsertCallback
);
p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
if( p->aTotalSize[iCol-1]<0 ){
rc = FTS5_CORRUPT;
}
}
}
if( rc==SQLITE_OK && p->nTotalRow<1 ){
rc = FTS5_CORRUPT;
}else{
p->nTotalRow--;
}
p->nTotalRow--;
rc2 = sqlite3_reset(pSeek);
if( rc==SQLITE_OK ) rc = rc2;
@@ -881,14 +874,13 @@ static int fts5StorageIntegrityCallback(
** some other SQLite error code if an error occurs while attempting to
** determine this.
*/
int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg){
int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
Fts5Config *pConfig = p->pConfig;
int rc = SQLITE_OK; /* Return code */
int rc; /* Return code */
int *aColSize; /* Array of size pConfig->nCol */
i64 *aTotalSize; /* Array of size pConfig->nCol */
Fts5IntegrityCtx ctx;
sqlite3_stmt *pScan;
int bUseCksum;
memset(&ctx, 0, sizeof(Fts5IntegrityCtx));
ctx.pConfig = p->pConfig;
@@ -897,88 +889,83 @@ int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg){
aColSize = (int*)&aTotalSize[pConfig->nCol];
memset(aTotalSize, 0, sizeof(i64) * pConfig->nCol);
bUseCksum = (pConfig->eContent==FTS5_CONTENT_NORMAL
|| (pConfig->eContent==FTS5_CONTENT_EXTERNAL && iArg)
);
if( bUseCksum ){
/* Generate the expected index checksum based on the contents of the
** %_content table. This block stores the checksum in ctx.cksum. */
rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0);
if( rc==SQLITE_OK ){
int rc2;
while( SQLITE_ROW==sqlite3_step(pScan) ){
int i;
ctx.iRowid = sqlite3_column_int64(pScan, 0);
/* Generate the expected index checksum based on the contents of the
** %_content table. This block stores the checksum in ctx.cksum. */
rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0);
if( rc==SQLITE_OK ){
int rc2;
while( SQLITE_ROW==sqlite3_step(pScan) ){
int i;
ctx.iRowid = sqlite3_column_int64(pScan, 0);
ctx.szCol = 0;
if( pConfig->bColumnsize ){
rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize);
}
if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){
rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
}
for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
if( pConfig->abUnindexed[i] ) continue;
ctx.iCol = i;
ctx.szCol = 0;
if( pConfig->bColumnsize ){
rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize);
}
if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){
if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
}
for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
if( pConfig->abUnindexed[i] ) continue;
ctx.iCol = i;
ctx.szCol = 0;
if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
}
if( rc==SQLITE_OK ){
const char *zText = (const char*)sqlite3_column_text(pScan, i+1);
int nText = sqlite3_column_bytes(pScan, i+1);
rc = sqlite3Fts5Tokenize(pConfig,
FTS5_TOKENIZE_DOCUMENT,
zText, nText,
(void*)&ctx,
fts5StorageIntegrityCallback
);
}
if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
rc = FTS5_CORRUPT;
}
aTotalSize[i] += ctx.szCol;
if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
sqlite3Fts5TermsetFree(ctx.pTermset);
ctx.pTermset = 0;
}
if( rc==SQLITE_OK ){
const char *zText = (const char*)sqlite3_column_text(pScan, i+1);
int nText = sqlite3_column_bytes(pScan, i+1);
rc = sqlite3Fts5Tokenize(pConfig,
FTS5_TOKENIZE_DOCUMENT,
zText, nText,
(void*)&ctx,
fts5StorageIntegrityCallback
);
}
if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
rc = FTS5_CORRUPT;
}
aTotalSize[i] += ctx.szCol;
if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
sqlite3Fts5TermsetFree(ctx.pTermset);
ctx.pTermset = 0;
}
sqlite3Fts5TermsetFree(ctx.pTermset);
ctx.pTermset = 0;
if( rc!=SQLITE_OK ) break;
}
rc2 = sqlite3_reset(pScan);
if( rc==SQLITE_OK ) rc = rc2;
}
sqlite3Fts5TermsetFree(ctx.pTermset);
ctx.pTermset = 0;
/* Test that the "totals" (sometimes called "averages") record looks Ok */
if( rc==SQLITE_OK ){
int i;
rc = fts5StorageLoadTotals(p, 0);
for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
if( p->aTotalSize[i]!=aTotalSize[i] ) rc = FTS5_CORRUPT;
}
if( rc!=SQLITE_OK ) break;
}
rc2 = sqlite3_reset(pScan);
if( rc==SQLITE_OK ) rc = rc2;
}
/* Check that the %_docsize and %_content tables contain the expected
** number of rows. */
if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
i64 nRow = 0;
rc = fts5StorageCount(p, "content", &nRow);
if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT;
}
if( rc==SQLITE_OK && pConfig->bColumnsize ){
i64 nRow = 0;
rc = fts5StorageCount(p, "docsize", &nRow);
if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT;
/* Test that the "totals" (sometimes called "averages") record looks Ok */
if( rc==SQLITE_OK ){
int i;
rc = fts5StorageLoadTotals(p, 0);
for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
if( p->aTotalSize[i]!=aTotalSize[i] ) rc = FTS5_CORRUPT;
}
}
/* Check that the %_docsize and %_content tables contain the expected
** number of rows. */
if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
i64 nRow = 0;
rc = fts5StorageCount(p, "content", &nRow);
if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT;
}
if( rc==SQLITE_OK && pConfig->bColumnsize ){
i64 nRow = 0;
rc = fts5StorageCount(p, "docsize", &nRow);
if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT;
}
/* Pass the expected checksum down to the FTS index module. It will
** verify, amongst other things, that it matches the checksum generated by
** inspecting the index itself. */
if( rc==SQLITE_OK ){
rc = sqlite3Fts5IndexIntegrityCheck(p->pIndex, ctx.cksum, bUseCksum);
rc = sqlite3Fts5IndexIntegrityCheck(p->pIndex, ctx.cksum);
}
sqlite3_free(aTotalSize);
-128
View File
@@ -1258,133 +1258,6 @@ static int fts5PorterTokenize(
);
}
/**************************************************************************
** Start of trigram implementation.
*/
typedef struct TrigramTokenizer TrigramTokenizer;
struct TrigramTokenizer {
int bFold; /* True to fold to lower-case */
};
/*
** Free a trigram tokenizer.
*/
static void fts5TriDelete(Fts5Tokenizer *p){
sqlite3_free(p);
}
/*
** Allocate a trigram tokenizer.
*/
static int fts5TriCreate(
void *pUnused,
const char **azArg,
int nArg,
Fts5Tokenizer **ppOut
){
int rc = SQLITE_OK;
TrigramTokenizer *pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew));
UNUSED_PARAM(pUnused);
if( pNew==0 ){
rc = SQLITE_NOMEM;
}else{
int i;
pNew->bFold = 1;
for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
const char *zArg = azArg[i+1];
if( 0==sqlite3_stricmp(azArg[i], "case_sensitive") ){
if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){
rc = SQLITE_ERROR;
}else{
pNew->bFold = (zArg[0]=='0');
}
}else{
rc = SQLITE_ERROR;
}
}
if( rc!=SQLITE_OK ){
fts5TriDelete((Fts5Tokenizer*)pNew);
pNew = 0;
}
}
*ppOut = (Fts5Tokenizer*)pNew;
return rc;
}
/*
** Trigram tokenizer tokenize routine.
*/
static int fts5TriTokenize(
Fts5Tokenizer *pTok,
void *pCtx,
int unusedFlags,
const char *pText, int nText,
int (*xToken)(void*, int, const char*, int, int, int)
){
TrigramTokenizer *p = (TrigramTokenizer*)pTok;
int rc = SQLITE_OK;
char aBuf[32];
const unsigned char *zIn = (const unsigned char*)pText;
const unsigned char *zEof = &zIn[nText];
u32 iCode;
UNUSED_PARAM(unusedFlags);
while( 1 ){
char *zOut = aBuf;
int iStart = zIn - (const unsigned char*)pText;
const unsigned char *zNext;
READ_UTF8(zIn, zEof, iCode);
if( iCode==0 ) break;
zNext = zIn;
if( zIn<zEof ){
if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
WRITE_UTF8(zOut, iCode);
READ_UTF8(zIn, zEof, iCode);
if( iCode==0 ) break;
}else{
break;
}
if( zIn<zEof ){
if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
WRITE_UTF8(zOut, iCode);
READ_UTF8(zIn, zEof, iCode);
if( iCode==0 ) break;
if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
WRITE_UTF8(zOut, iCode);
}else{
break;
}
rc = xToken(pCtx, 0, aBuf, zOut-aBuf, iStart, iStart + zOut-aBuf);
if( rc!=SQLITE_OK ) break;
zIn = zNext;
}
return rc;
}
/*
** Argument xCreate is a pointer to a constructor function for a tokenizer.
** pTok is a tokenizer previously created using the same method. This function
** returns one of FTS5_PATTERN_NONE, FTS5_PATTERN_LIKE or FTS5_PATTERN_GLOB
** indicating the style of pattern matching that the tokenizer can support.
** In practice, this is:
**
** "trigram" tokenizer, case_sensitive=1 - FTS5_PATTERN_GLOB
** "trigram" tokenizer, case_sensitive=0 (the default) - FTS5_PATTERN_LIKE
** all other tokenizers - FTS5_PATTERN_NONE
*/
int sqlite3Fts5TokenizerPattern(
int (*xCreate)(void*, const char**, int, Fts5Tokenizer**),
Fts5Tokenizer *pTok
){
if( xCreate==fts5TriCreate ){
TrigramTokenizer *p = (TrigramTokenizer*)pTok;
return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB;
}
return FTS5_PATTERN_NONE;
}
/*
** Register all built-in tokenizers with FTS5.
*/
@@ -1396,7 +1269,6 @@ int sqlite3Fts5TokenizerInit(fts5_api *pApi){
{ "unicode61", {fts5UnicodeCreate, fts5UnicodeDelete, fts5UnicodeTokenize}},
{ "ascii", {fts5AsciiCreate, fts5AsciiDelete, fts5AsciiTokenize }},
{ "porter", {fts5PorterCreate, fts5PorterDelete, fts5PorterTokenize }},
{ "trigram", {fts5TriCreate, fts5TriDelete, fts5TriTokenize}},
};
int rc = SQLITE_OK; /* Return code */
-2
View File
@@ -773,6 +773,4 @@ void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){
}
iTbl++;
}
aAscii[0] = 0; /* 0x00 is never a token character */
}
-19
View File
@@ -82,24 +82,5 @@ foreach_detail_mode $::testprefix {
} {1 {unable to use function MATCH in the requested context}}
}
#-------------------------------------------------------------------------
# Confirm that the expression parser creates the same expression tree
# for:
#
# {a b} : (abc AND def)
# -{c d} : (abc AND def)
#
# Assuming that the table columns are (a, b, c, d).
#
do_execsql_test 5.1 {
SELECT fts5_expr('abcd AND cdef');
} {{"abcd" AND "cdef"}}
do_execsql_test 5.2 {
SELECT fts5_expr('{a b} : (abcd AND cdef)', 'a', 'b', 'c', 'd');
} {{{a b} : "abcd" AND {a b} : "cdef"}}
do_execsql_test 5.3 {
SELECT fts5_expr('-{c d} : (abcd AND cdef)', 'a', 'b', 'c', 'd');
} {{{a b} : "abcd" AND {a b} : "cdef"}}
finish_test
+2 -657
View File
@@ -8346,7 +8346,6 @@ do_catchsql_test 58.1 {
#-------------------------------------------------------------------------
do_test 59.0 {
sqlite3 db {}
sqlite3_fts5_register_matchinfo db
db deserialize [decode_hexdb {
.open --hexdb
| size 32768 pagesize 4096 filename crash-96b136358d01ec.db
@@ -8545,12 +8544,11 @@ do_test 59.0 {
do_catchsql_test 59.1 {
SELECT (matchinfo(591,t1)) FROM t1 WHERE t1 MATCH 'e*eŸ'
} {0 {}}
} {1 {database disk image is malformed}}
#-------------------------------------------------------------------------
do_test 60.0 {
sqlite3 db {}
sqlite3_fts5_register_matchinfo db
db deserialize [decode_hexdb {
.open --hexdb
| size 32768 pagesize 4096 filename crash-c77b90b929dc92.db
@@ -9693,7 +9691,7 @@ do_test 65.0 {
do_catchsql_test 65.1 {
SELECT ( MATCH (t1,591)) FROM t1 WHERE t1 MATCH 'e*eŸ'
} {1 {malformed database schema (t2) - invalid rootpage}}
} {1 {database disk image is malformed}}
#-------------------------------------------------------------------------
#
@@ -10110,659 +10108,6 @@ do_catchsql_test 68.1 {
INSERT INTO t1(t1) SELECT x FROM t2;
} {1 {database disk image is malformed}}
#-------------------------------------------------------------------------
reset_db
do_test 69.0 {
sqlite3 db {}
db deserialize [decode_hexdb {
.open --hexdb
| size 32768 pagesize 4096 filename crash-31c462b8b665d0.db
| page 1 offset 0
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 08 .....@ ........
| 32: 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 ................
| 96: 00 00 00 00 0d 0f c7 00 07 0d 92 00 0f 8d 0f 36 ...............6
| 112: 0e cb 0e 6b 0e 0e 0d b6 0d 92 00 00 00 00 00 00 ...k............
| 3472: 00 00 22 08 06 17 11 11 01 31 74 61 62 6c 65 74 .........1tablet
| 3488: 32 74 32 08 43 52 45 41 54 45 20 54 41 42 4c 45 2t2.CREATE TABLE
| 3504: 20 74 32 28 78 29 56 07 06 17 1f 1f 01 7d 74 61 t2(x)V.......ta
| 3520: 62 6c 65 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 blet1_configt1_c
| 3536: 6f 6e 66 69 67 07 43 52 45 41 54 45 20 54 41 42 onfig.CREATE TAB
| 3552: 4c 45 20 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b LE 't1_config'(k
| 3568: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 PRIMARY KEY, v)
| 3584: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5b 06 WITHOUT ROWID[.
| 3600: 07 17 21 21 01 81 01 74 61 62 6c 65 74 31 5f 64 ..!!...tablet1_d
| 3616: 6f 63 73 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 ocsizet1_docsize
| 3632: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 .CREATE TABLE 't
| 3648: 31 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 1_docsize'(id IN
| 3664: 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 TEGER PRIMARY KE
| 3680: 59 2c 20 73 7a 20 42 4c 4f 42 29 5e 05 07 17 21 Y, sz BLOB)^...!
| 3696: 21 01 81 07 74 61 62 6c 65 74 31 5f 63 6f 6e 74 !...tablet1_cont
| 3712: 65 6e 74 74 31 5f 63 6f 6e 74 65 6e 74 05 43 52 entt1_content.CR
| 3728: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 EATE TABLE 't1_c
| 3744: 6f 6e 74 65 6e 74 27 28 69 64 20 49 4e 54 45 47 ontent'(id INTEG
| 3760: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY,
| 3776: 63 39 2c 20 63 31 2c 20 63 32 29 69 04 07 17 19 c9, c1, c2)i....
| 3792: 19 01 81 2d 74 61 62 6c 65 74 31 5f 69 64 78 74 ...-tablet1_idxt
| 3808: 31 5f 69 64 78 04 43 52 45 41 54 45 20 54 41 42 1_idx.CREATE TAB
| 3824: 4c 45 20 27 74 31 5f 69 64 78 27 28 73 65 67 69 LE 't1_idx'(segi
| 3840: 64 2c 20 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 50 d, term, pgno, P
| 3856: 52 49 4d 41 52 59 20 4b 45 59 28 73 65 67 69 64 RIMARY KEY(segid
| 3872: 2c 20 74 65 72 6d 29 29 20 57 49 54 48 4f 55 54 , term)) WITHOUT
| 3888: 20 52 4f 57 49 44 55 03 07 17 1b 1b 01 81 01 74 ROWIDU........t
| 3904: 61 62 6c 65 74 31 5f 64 61 74 61 74 31 5f 64 61 ablet1_datat1_da
| 3920: 74 61 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 ta.CREATE TABLE
| 3936: 27 74 31 5f 64 61 74 61 27 28 69 64 20 49 4e 54 't1_data'(id INT
| 3952: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY
| 3968: 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 38 02 06 , block BLOB)8..
| 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR
| 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB
| 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 35 LE t1 USING fts5
| 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c).........
| page 3 offset 8192
| 0: 0d 00 00 00 03 0c 94 00 0f e6 0f ef 0c 94 00 00 ................
| 3216: 00 00 00 00 86 4a 84 80 80 80 80 01 04 00 8d 18 .....J..........
| 3232: 00 00 03 2b 02 30 30 01 02 06 01 02 06 01 02 06 ...+.00.........
| 3248: 1f 02 03 01 02 03 01 02 03 01 08 32 30 31 36 30 ...........20160
| 3264: 36 30 39 01 02 07 01 02 07 01 02 07 01 01 34 01 609...........4.
| 3280: 02 05 01 02 05 01 02 05 01 01 35 01 02 04 01 02 ..........5.....
| 3296: 04 01 02 04 02 07 30 30 30 30 30 30 30 1c 02 04 ......0000000...
| 3312: 01 02 04 01 02 04 01 06 62 69 6e 61 72 79 03 06 ........binary..
| 3328: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
| 3344: 02 02 03 06 00 02 02 03 06 01 02 02 03 06 01 02 ................
| 3360: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
| 3376: 03 06 01 02 02 03 06 01 02 02 01 08 63 6f 6d 70 ............comp
| 3392: 69 6c 65 72 01 02 02 01 02 02 01 02 02 01 06 64 iler...........d
| 3408: 62 73 74 61 74 07 02 03 01 02 03 01 02 03 02 04 bstat...........
| 3424: 65 62 75 67 04 02 02 01 02 02 01 02 02 01 06 65 ebug...........e
| 3440: 6e 61 62 6c 65 07 02 02 01 02 02 01 02 02 01 02 nable...........
| 3456: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
| 3472: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
| 3488: 01 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
| 3504: 02 01 02 02 02 08 78 74 65 6e 73 69 6f 6e 1f 02 ......xtension..
| 3520: 04 01 02 04 01 02 04 01 04 66 74 73 34 1a 02 03 .........fts4...
| 3536: 01 02 03 01 02 03 04 01 35 0d 02 03 01 02 03 01 ........5.......
| 3552: 02 03 01 03 67 63 63 01 aa 03 01 02 03 01 02 03 ....gcc.........
| 3568: 02 06 65 6f 70 6f 6c 79 10 02 03 02 02 03 01 02 ..eopoly........
| 3584: 03 01 05 6a 73 6f 6e 31 13 02 03 01 02 03 01 02 ...json1........
| 3600: 03 01 04 6c 6f 61 64 1f 02 03 01 02 03 01 02 03 ...load.........
| 3616: 01 03 6d 61 78 1c 02 02 01 02 02 01 02 02 02 05 ..max...........
| 3632: 65 6d 6f 72 79 1c 02 03 01 02 03 01 02 03 04 04 emory...........
| 3648: 73 79 73 35 16 02 03 01 02 03 01 02 03 01 06 6e sys5...........n
| 3664: 6f 63 61 73 65 02 06 01 02 02 03 06 01 02 02 03 ocase...........
| 3680: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
| 3696: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
| 3712: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
| 3728: 02 01 04 6f 6d 69 74 1f 02 02 01 02 02 01 02 01 ...omit.........
| 3744: ff ff ff ff ff ff ff ff f0 00 00 00 00 00 01 02 ................
| 3760: 58 81 96 4d 01 06 01 02 02 03 06 01 02 02 03 06 X..M............
| 3776: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
| 3792: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
| 3808: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
| 3824: 01 0a 74 68 72 65 61 64 73 61 66 65 22 02 02 01 ..threadsafe....
| 3840: 02 02 01 02 02 01 04 76 74 61 62 07 02 04 01 02 .......vtab.....
| 3856: 04 01 02 04 01 01 78 01 06 01 01 02 01 06 01 01 ......x.........
| 3872: 02 01 06 01 1e 02 01 06 01 01 02 01 06 01 01 02 ................
| 3888: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
| 3904: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
| 3920: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
| 3936: 00 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
| 3952: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
| 3968: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
| 3984: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
| 4000: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
| 4016: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
| 4032: 02 01 06 01 01 02 01 06 01 01 02 04 15 13 0c 0c ................
| 4048: 12 44 13 11 0f 47 13 0f 0b 0e 11 10 0f 0e 10 0f .D...G..........
| 4064: 44 0f 10 40 15 0f 07 01 03 00 14 24 5a 24 24 0f D..@.......$Z$$.
| 4080: 0a 03 00 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............
| page 4 offset 12288
| 0: 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................
| page 5 offset 16384
| 0: 0d 00 00 00 24 0c 0a 00 0f d8 0f af 0f 86 0f 74 ....$..........t
| 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./..........
| 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$......
| 48: 0d bb 0d a0 0d 84 0d 68 0d 4f 0d 00 00 00 00 00 .......h.O......
| 3072: 00 00 00 00 00 00 00 00 00 00 18 24 05 00 25 0f ...........$..%.
| 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI
| 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA
| 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE..
| 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 45 3d ..%..THREADSAFE=
| 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM
| 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO
| 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 d3 19 4f NXBINARY. ..3..O
| 3200: 4d 49 54 28 2c 4f 41 44 b2 04 55 85 44 54 e5 34 MIT(,OAD..U.DT.4
| 3216: 94 f4 e5 84 e4 f4 34 15 34 51 e1 f0 50 03 30 f1 ......4.4Q..P.0.
| 3232: 74 f4 d4 95 42 04 c4 f4 14 42 04 55 85 44 54 e5 t...B....B.U.DT.
| 3248: 34 94 f4 e5 85 25 45 24 94 d1 f1 e0 50 03 30 f1 4....%E$....P.0.
| 3264: 94 d4 15 82 04 d4 54 d4 f5 25 93 d3 53 03 03 03 ......T..%..S...
| 3280: 03 03 03 05 84 24 94 e4 15 25 91 f1 d0 50 03 30 .....$...%...P.0
| 3296: f1 94 d4 15 82 04 d4 54 d4 f5 25 93 d3 53 03 03 .......T..%..S..
| 3312: 03 03 03 03 05 84 e4 f4 34 15 34 51 e1 c0 50 03 ........4.4Q..P.
| 3328: 30 f1 74 d4 15 82 04 d4 54 d4 f5 25 93 d3 53 03 0.t.....T..%..S.
| 3344: 03 03 03 03 03 05 85 25 45 24 94 d1 81 b0 50 02 .......%E$....P.
| 3360: 50 f1 94 54 e4 14 24 c4 52 05 25 45 24 54 55 84 P..T..$.R.%E$TU.
| 3376: 24 94 e4 15 25 91 81 a0 50 02 50 f1 94 54 e4 14 $...%...P.P..T..
| 3392: 24 c4 52 05 25 45 24 54 55 84 e4 f4 34 15 34 51 $.R.%E$TU...4.4Q
| 3408: 71 90 50 02 50 f1 74 54 e4 14 24 c4 52 05 25 45 q.P.P.tT..$.R.%E
| 3424: 24 54 55 85 25 45 24 94 d1 a1 80 50 02 90 f1 94 $TU.%E$....P....
| 3440: 54 e4 14 24 c4 52 04 d4 54 d5 35 95 33 55 84 24 T..$.R..T.5.3U.$
| 3456: 94 e4 15 25 91 a1 70 50 02 90 f1 94 54 e4 14 24 ...%..pP....T..$
| 3472: c4 52 04 d4 54 d5 35 95 33 55 84 e4 f4 34 15 34 .R..T.5.3U...4.4
| 3488: 51 91 60 50 02 90 f1 74 54 e4 14 24 c4 52 04 d4 Q.`P...tT..$.R..
| 3504: 54 d5 35 95 33 55 85 25 45 24 94 d1 81 50 50 02 T.5.3U.%E$...PP.
| 3520: 50 f1 94 54 e4 14 24 c4 52 04 a5 34 f4 e3 15 84 P..T..$.R..4....
| 3536: 24 94 e4 15 25 91 81 40 50 02 50 f1 94 54 e4 14 $...%..@P.P..T..
| 3552: 24 c4 52 04 a5 34 f4 e3 15 84 e4 f4 34 15 34 51 $.R..4......4.4Q
| 3568: 71 30 50 02 4f f1 74 54 e4 14 24 c4 52 04 a5 34 q0P.O.tT..$.R..4
| 3584: f4 e3 15 85 25 45 24 94 d1 a1 20 50 02 90 f1 94 ....%E$... P....
| 3600: 54 e4 14 24 c4 52 04 74 54 f5 04 f4 c5 95 84 24 T..$.R.tT......$
| 3616: 94 e4 15 25 91 a1 10 50 02 90 f1 94 54 e4 14 24 ...%...P....T..$
| 3632: c4 52 04 74 54 f5 04 f4 c5 95 84 e4 f4 34 15 34 .R.tT........4.4
| 3648: 51 91 00 50 02 90 f1 74 54 e4 14 24 c4 51 f4 74 Q..P...tT..$.Q.t
| 3664: 54 f5 04 f4 c5 95 85 25 45 24 94 d1 70 f0 50 02 T......%E$..p.P.
| 3680: 30 f1 94 54 e4 14 24 c5 20 46 54 53 35 58 42 49 0..T..$. FTS5XBI
| 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL
| 3712: 45 20 46 54 53 35 58 4f 4f 43 41 53 45 16 0d 05 E FTS5XOOCASE...
| 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X
| 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB
| 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 97 0b LE FTS4XBINARY..
| 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34 ..#..ENABLE FTS4
| 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN
| 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM.
| 3824: 09 05 00 3e 5f 19 45 4e 41 42 4c 45 20 44 42 53 ...>_.ENABLE DBS
| 3840: 44 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e DAT VTABXBINARY.
| 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
| 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 4d e3 45 1d TAT VTABXNOCM.E.
| 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
| 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM..
| 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR
| 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO
| 3952: 43 41 53 45 10 02 02 50 08 5f 17 44 45 42 55 47 CASE...P._.DEBUG
| 3968: 58 52 54 52 49 4d 27 03 05 00 44 0f 19 43 4f 4d XRTRIM'...D..COM
| 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0
| 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY'
| 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g
| 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060
| 4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 c9 17 43 9XNOCASE&...C..C
| 4064: 4f 4d 50 49 4c 47 02 3d 67 63 63 2d 35 2e 34 2e OMPILG.=gcc-5.4.
| 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM
| page 6 offset 20480
| 0: 0d 00 00 00 24 0e e0 00 0f f8 0f f0 0f e8 0f e0 ....$...........
| 16: 0f d8 0f d0 0f c8 0f c0 0f b8 0f b0 0f a8 0f a0 ................
| 32: 0f 98 0f 90 0f 88 0f 80 0f 78 0f 70 0f 68 0f 60 .........x.p.h.`
| 48: 0f 58 0f 50 0f 48 0f 40 0f 38 00 00 00 00 00 00 .X.P.H.@.8......
| 3808: 06 24 03 00 12 02 01 01 06 23 03 00 12 02 01 01 .$.......#......
| 3824: 06 22 03 00 12 02 01 01 06 21 03 00 12 03 01 01 .........!......
| 3840: 06 20 03 00 12 03 01 01 06 1f 03 00 12 03 01 01 . ..............
| 3856: 06 1e 03 00 12 03 01 01 06 1d 03 00 12 03 01 01 ................
| 3872: 06 1c 03 00 12 03 01 01 06 1b 03 00 12 02 01 01 ................
| 3888: 06 1a 03 00 12 02 01 01 06 19 03 00 12 02 01 01 ................
| 3904: 06 18 03 00 12 02 01 01 06 17 03 00 12 02 01 01 ................
| 3920: 06 16 03 00 12 02 01 01 06 15 03 00 12 02 01 01 ................
| 3936: 06 14 03 00 12 02 01 01 06 13 03 00 12 02 01 01 ................
| 3952: 06 12 03 00 12 02 01 01 06 11 03 00 12 02 01 01 ................
| 3968: 06 10 03 00 12 02 01 01 06 1f 03 00 12 02 01 01 ................
| 3984: 06 0e 03 00 12 02 01 01 06 0d 03 00 12 02 01 01 ................
| 4000: 06 0c 03 00 12 02 01 01 06 0b 03 00 12 02 01 01 ................
| 4016: 06 0a 03 00 12 02 01 01 06 09 03 00 12 03 01 01 ................
| 4032: 06 08 03 00 12 03 01 01 06 07 03 00 12 03 01 01 ................
| 4048: 06 06 03 00 12 01 01 01 06 05 03 00 12 01 01 01 ................
| 4064: 06 04 03 00 12 01 01 01 06 03 03 00 12 06 01 01 ................
| 4080: 06 02 03 00 12 06 01 01 06 01 03 00 12 06 01 01 ................
| page 7 offset 24576
| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
| page 8 offset 28672
| 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
| 4048: 00 00 00 00 00 00 11 03 02 2b 69 6e 74 65 67 72 .........+integr
| 4064: 69 74 79 2d 63 68 65 63 6b 09 00 00 00 00 00 00 ity-check.......
| end crash-31c462b8b665d0.db
}]} {}
do_catchsql_test 69.2 {
SELECT * FROM t1 WHERE a MATCH 'fx*'
} {1 {database disk image is malformed}}
#-------------------------------------------------------------------------
reset_db
do_test 70.0 {
sqlite3 db {}
db deserialize [decode_hexdb {
.open --hexdb
| size 24576 pagesize 4096 filename sql022250.txt.db
| page 1 offset 0
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 00 .....@ ........
| 96: 00 00 00 00 0d 00 00 00 06 0d e2 00 0f c4 0f 6a ...............j
| 112: 0e fc 0e 9d 0e 3d 0d e2 00 00 00 00 00 00 00 00 .....=..........
| 3552: 00 00 59 06 06 17 21 21 01 7f 74 61 62 6c 65 74 ..Y...!!..tablet
| 3568: 74 74 5f 63 6f 6e 66 69 67 74 74 74 5f 63 6f 6e tt_configttt_con
| 3584: 66 69 67 06 43 52 45 41 54 45 20 54 41 42 4c 45 fig.CREATE TABLE
| 3600: 20 27 74 74 74 5f 63 6f 6e 66 69 67 27 28 6b 20 'ttt_config'(k
| 3616: 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 20 PRIMARY KEY, v)
| 3632: 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5e 15 07 WITHOUT ROWID^..
| 3648: 17 23 23 01 81 03 74 61 62 6c 65 74 74 74 5f 64 .##...tablettt_d
| 3664: 6f 63 73 69 7a 65 74 74 74 5f 64 6f 63 73 69 7a ocsizettt_docsiz
| 3680: 65 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 e.CREATE TABLE '
| 3696: 74 74 74 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 ttt_docsize'(id
| 3712: 49 4d 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 IMTEGER PRIMARY
| 3728: 4b 45 59 2c 20 73 7a 20 42 4c 4f 20 29 5d 04 07 KEY, sz BLO )]..
| 3744: 17 23 23 01 81 01 74 61 62 6c 65 74 74 74 5f 63 .##...tablettt_c
| 3760: 6f 6e 74 65 6e 74 74 74 74 5f 63 6f 6e 74 65 6e ontentttt_conten
| 3776: 74 04 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 t.CREATE TABLE '
| 3792: 74 74 74 5f 63 6f 6e 74 65 6e 74 27 28 69 64 20 ttt_content'(id
| 3808: 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 INTEGER PRIMARY
| 3824: 4b 45 59 2c 20 63 30 2c 20 63 31 29 6c 03 07 17 KEY, c0, c1)l...
| 3840: 1b 1b 01 81 2f 74 61 62 6c 65 74 74 74 5f 69 64 ..../tablettt_id
| 3856: 78 74 74 74 5f 69 64 78 03 43 52 45 41 54 45 20 xttt_idx.CREATE
| 3872: 54 41 42 4c 45 20 27 74 74 74 5f 69 64 78 27 28 TABLE 'ttt_idx'(
| 3888: 73 65 67 69 64 2c 20 74 65 72 6d 2c 20 70 67 6e segid, term, pgn
| 3904: 6f 2c 20 50 52 49 4d 41 52 59 20 4b 45 59 28 73 o, PRIMARY KEY(s
| 3920: 65 67 69 64 2c 20 74 65 72 6d 29 29 20 57 49 54 egid, term)) WIT
| 3936: 48 4f 55 54 20 52 4f 57 49 44 58 02 07 17 1d 1d HOUT ROWIDX.....
| 3952: 01 81 03 74 61 62 6c 65 74 74 74 5f 64 61 74 61 ...tablettt_data
| 3968: 74 74 74 5f 64 61 74 61 02 43 52 45 41 54 45 20 ttt_data.CREATE
| 3984: 54 41 42 4c 45 20 27 74 74 74 5f 64 61 74 61 27 TABLE 'ttt_data'
| 4000: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d (id INTEGER PRIM
| 4016: 41 52 59 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 ARY KEY, block B
| 4032: 4c 4f 42 29 3a 01 06 17 13 13 08 5f 74 61 62 6c LOB):......_tabl
| 4048: 65 74 74 74 74 74 74 43 52 45 41 54 45 20 56 49 ettttttCREATE VI
| 4064: 52 54 55 41 4c 20 54 41 42 4c 45 20 74 74 74 20 RTUAL TABLE ttt
| 4080: 55 53 49 4e 47 20 66 74 73 35 28 61 2c 20 62 29 USING fts5(a, b)
| page 2 offset 4096
| 0: 0d 0f 54 00 05 0e 81 00 0f e7 0e 81 0f af 0f 58 ..T............X
| 16: 0e 98 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
| 3712: 00 15 0a 03 00 30 00 00 00 00 01 03 03 00 03 01 .....0..........
| 3728: 01 01 02 01 01 03 01 01 81 24 8c 80 80 80 80 01 .........$......
| 3744: 04 00 82 4c 00 00 00 9b 02 30 65 03 1a 02 05 05 ...L.....0e.....
| 3760: 07 05 01 01 04 03 03 08 03 03 01 2e 02 05 05 07 ................
| 3776: 05 07 05 07 05 01 01 14 03 03 08 03 03 08 03 bf ................
| 3792: 07 f2 f3 02 01 65 03 1e 03 05 05 04 05 05 01 01 .....e..........
| 3808: 03 06 04 04 06 04 03 01 36 03 05 05 04 05 05 04 ........6.......
| 3824: 05 15 04 05 05 01 01 03 06 04 04 06 04 04 a1 04 ................
| 3840: 04 06 04 03 03 01 65 03 14 04 05 07 05 05 01 01 ......e.........
| 3856: 02 09 0a 01 20 04 05 07 05 07 05 07 05 05 01 01 .... ...........
| 3872: 02 0f da 0a 0a 04 01 64 f3 02 0a 01 06 0a 0a 0a .......d........
| 3888: 05 01 65 03 06 01 01 0a 01 0a 01 01 0a 0a 0a 04 ..e.............
| 3904: 2b 31 21 0b 0f ef 00 14 2a 00 00 00 00 01 02 02 +1!.....*.......
| 3920: 00 02 01 01 01 02 01 01 50 88 80 80 80 80 01 04 ........P.......
| 3936: 00 81 24 00 00 00 47 01 30 65 02 1a 02 05 05 07 ..$...G.0e......
| 3952: 05 01 01 04 03 03 08 03 03 02 01 65 02 1d f3 05 ...........e....
| 3968: 05 04 05 05 01 01 04 06 04 04 06 04 03 03 01 65 ...............e
| 3984: 02 14 04 05 07 05 05 01 01 02 08 0a 04 01 65 02 ..............e.
| 4000: 02 0a 05 01 65 02 06 01 01 0a 04 12 14 0f 06 31 ....e..........1
| 4016: 84 80 80 80 80 01 03 00 68 00 00 00 2b 02 30 65 ........h...+.0e
| 4032: 01 10 02 05 05 01 01 04 03 03 02 01 66 01 12 03 ............f...
| 4048: 05 05 01 01 03 06 04 03 03 01 65 01 0e 04 05 05 ..........e.....
| 4064: 01 01 02 08 04 0d 0e 06 01 03 00 12 04 4c 4c 00 .............LL.
| 4080: 00 00 11 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............
| page 3 offset 8192
| 0: 0a 2f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ./..............
| page 4 offset 12288
| 3344: 00 00 00 00 00 00 00 00 00 00 81 52 04 06 10 81 ...........R....
| 3360: 5d 81 55 65 20 65 65 20 65 65 65 20 65 20 65 65 ].Ue ee eee e ee
| 3376: 20 65 65 65 20 65 20 65 65 20 65 65 65 65 20 65 eee e ee eeee e
| 3392: 65 20 65 65 65 24 a5 20 65 65 20 65 65 65 20 65 e eee$. ee eee e
| 3408: 24 05 65 20 65 65 65 65 20 65 65 20 65 65 65 20 $.e eeee ee eee
| 3424: 65 20 65 65 20 65 65 65 20 65 20 65 65 20 65 65 e ee eee e ee ee
| 3440: 65 65 20 65 65 20 65 65 65 20 65 20 65 65 10 65 ee ee eee e ee.e
| 3456: 65 65 20 65 20 65 65 20 65 65 65 65 65 65 20 65 ee e ee eeeeee e
| 3472: 65 20 65 20 65 20 65 20 65 65 20 65 65 65 20 65 e e e e ee eee e
| 3488: 1f 20 65 65 66 65 65 20 65 65 20 65 20 65 20 2d . eefee ee e e -
| page 5 offset 16384
| 4064: 00 00 00 00 05 04 d0 00 10 21 21 05 03 03 00 10 .........!!.....
| 4080: 11 11 05 02 03 00 10 11 10 05 01 03 00 10 09 09 ................
| page 6 offset 20480
| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
| end sql022250.txt.db
}]} {}
do_catchsql_test 70.1 {
SELECT snippet(ttt, -1, '', '','','>')FROM ttt('e* NOT ee*e* NOT ee*');
} {1 {database disk image is malformed}}
do_catchsql_test 70.2 {
SELECT snippet(ttt, -1, '', '','',13)FROM ttt('e* NOT ee*e* NOT ee*')
} {1 {database disk image is malformed}}
#-------------------------------------------------------------------------
reset_db
do_test 71.0 {
sqlite3 db {}
db deserialize [decode_hexdb {
.open --hexdb
| size 28672 pagesize 4096 filename sql025294.txt.db
| page 1 offset 0
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
| 16: 10 00 00 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........
| 96: 00 00 00 00 0d 00 00 00 07 0d d2 00 0f c4 0f 6d ...............m
| 112: 0f 02 0e ab 0e 4e 0d f6 0d d2 00 00 00 00 00 00 .....N..........
| 3536: 00 00 22 07 06 17 11 11 01 31 74 61 62 6c 65 74 .........1tablet
| 3552: 32 74 32 07 43 52 45 41 54 45 20 54 41 42 4c 45 2t2.CREATE TABLE
| 3568: 20 74 32 28 78 29 56 06 06 17 1f 1f 01 7d 74 61 t2(x)V.......ta
| 3584: 62 6c 65 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 blet1_configt1_c
| 3600: 6f 6e 66 69 67 06 43 52 45 41 54 45 20 54 41 42 onfig.CREATE TAB
| 3616: 4c 45 20 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b LE 't1_config'(k
| 3632: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 PRIMARY KEY, v)
| 3648: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5b 05 WITHOUT ROWID[.
| 3664: 07 17 21 21 01 81 01 74 61 62 6c 65 74 31 5f 64 ..!!...tablet1_d
| 3680: 6f 63 73 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 ocsizet1_docsize
| 3696: 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 .CREATE TABLE 't
| 3712: 31 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 1_docsize'(id IN
| 3728: 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 TEGER PRIMARY KE
| 3744: 59 2c 20 73 7a 20 42 4c 4f 42 29 55 04 06 17 21 Y, sz BLOB)U...!
| 3760: 21 01 77 74 61 62 6c 65 74 31 5f 63 6f 6e 74 65 !.wtablet1_conte
| 3776: 6e 74 74 31 5f 63 6f 6e 74 65 6e 74 04 43 52 45 ntt1_content.CRE
| 3792: 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 6f ATE TABLE 't1_co
| 3808: 6e 74 65 6e 74 27 28 69 64 20 49 4e 54 45 47 45 ntent'(id INTEGE
| 3824: 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 63 R PRIMARY KEY, c
| 3840: 30 29 69 03 07 17 19 19 01 81 2d 74 61 62 6c 65 0)i.......-table
| 3856: 74 31 5f 69 64 78 74 31 5f 69 64 78 03 43 52 45 t1_idxt1_idx.CRE
| 3872: 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 69 64 ATE TABLE 't1_id
| 3888: 78 27 28 73 65 67 69 64 2c 20 74 65 72 6d 2c 20 x'(segid, term,
| 3904: 70 67 6e 6f 2c 20 50 52 49 4d 41 52 59 20 4b 45 pgno, PRIMARY KE
| 3920: 59 28 73 65 67 69 64 2c 20 74 65 72 6d 29 29 20 Y(segid, term))
| 3936: 57 49 54 48 4f 55 54 20 52 4f 57 49 44 55 02 07 WITHOUT ROWIDU..
| 3952: 17 1b 1b 01 81 01 74 61 62 6c 65 74 31 5f 64 61 ......tablet1_da
| 3968: 74 61 74 31 5f 64 61 74 61 02 43 52 45 41 54 45 tat1_data.CREATE
| 3984: 20 54 41 42 4c 45 20 27 74 31 5f 64 61 74 61 27 TABLE 't1_data'
| 4000: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d (id INTEGER PRIM
| 4016: 41 52 58 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 ARX KEY, block B
| 4032: 4c 4f 42 29 3a 01 06 17 11 11 08 63 74 61 62 6c LOB):......ctabl
| 4048: 65 74 31 74 31 43 52 45 41 54 45 20 56 49 52 54 et1t1CREATE VIRT
| 4064: 55 41 4c 20 54 41 42 4c 45 20 74 31 20 55 53 49 UAL TABLE t1 USI
| 4080: 4e 47 20 66 74 73 35 28 63 6f 6e 74 65 6e 74 29 NG fts5(content)
| page 2 offset 4096
| 0: 0d 00 00 00 03 0f bd 00 0f e8 0f ef 0f bd 00 00 ................
| 4016: 00 00 00 00 00 00 00 00 00 00 00 00 00 24 84 80 .............$..
| 4032: 80 80 80 01 03 00 4e 00 00 00 1e 06 30 61 62 61 ......N.....0aba
| 4048: 60 eb 01 02 02 04 01 66 74 02 02 02 04 04 6e 64 `......ft.....nd
| 4064: 6f 6e 03 01 f2 04 1a 07 05 01 03 00 10 03 03 0f on..............
| 4080: 0a 03 00 24 00 00 00 00 01 01 4b 00 01 01 01 01 ...$......K.....
| page 3 offset 8192
| 0: 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................
| page 4 offset 12288
| 0: 0d 00 00 00 03 0f e0 00 0f f6 0f ec 0f e0 00 00 ................
| 4064: 0a 03 03 00 1b 61 62 61 6e 64 6f 6e 08 02 03 00 .....abandon....
| 4080: 17 61 62 61 66 74 08 01 03 00 17 61 62 61 63 6b .abaft.....aback
| page 5 offset 16384
| 0: 0d 00 00 00 03 0f ee 00 0f fa 0f f4 0f ee 00 00 ................
| 4064: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 03 ................
| 4080: 03 00 0e 01 04 02 03 00 0e 01 04 01 03 00 0e 01 ................
| page 6 offset 20480
| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
| page 7 offset 24576
| 0: 0d 00 00 00 03 0f d6 00 0f f4 0f e1 00 00 00 00 ................
| 4048: 00 00 00 00 00 00 09 03 02 1b 72 65 62 75 69 6c ..........rebuil
| 4064: 64 11 02 02 2b 69 6e 74 65 67 72 69 74 79 2d 63 d...+integrity-c
| 4080: 68 65 63 6b 0a 01 02 1d 6f 70 74 69 6d 69 7a 65 heck....optimize
| end sql025294.txt.db
}]} {}
do_catchsql_test 71.2 {
INSERT INTO t1(t1) VALUES('integrity-check');
} {1 {database disk image is malformed}}
#-------------------------------------------------------------------------
reset_db
do_test 72.0 {
sqlite3 db {}
db deserialize [decode_hexdb {
.open --hexdb
| size 24576 pagesize 4096 filename crash-77b86d070d0ac6.db
| page 1 offset 0
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 06 .....@ ........
| 32: 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 04 ................
| 96: 00 00 00 00 0d 00 00 00 06 0d e2 00 0f c4 0f 6a ...............j
| 112: 0e fc 0e 9d 0e 3d 0d e2 00 00 00 00 00 00 00 00 .....=..........
| 3552: 00 00 59 06 06 17 21 21 01 7f 74 61 62 6c 65 74 ..Y...!!..tablet
| 3568: 74 74 5f 63 6f 6e 66 69 67 74 74 74 5f 63 6f 6e tt_configttt_con
| 3584: 66 69 67 06 43 52 45 41 54 45 20 54 41 42 4c 45 fig.CREATE TABLE
| 3600: 20 27 74 74 74 5f 63 6f 6e 66 69 67 27 28 6b 20 'ttt_config'(k
| 3616: 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 20 PRIMARY KEY, v)
| 3632: 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5e 05 07 WITHOUT ROWID^..
| 3648: 17 23 23 01 81 03 74 61 62 6c 65 74 74 74 5f 64 .##...tablettt_d
| 3664: 6f 63 73 69 7a 65 74 74 74 5f 64 6f 63 73 69 7a ocsizettt_docsiz
| 3680: 65 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 e.CREATE TABLE '
| 3696: 74 74 74 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 ttt_docsize'(id
| 3712: 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 INTEGER PRIMARY
| 3728: 4b 45 59 2c 20 73 7a 20 42 4c 4f 42 29 5d 04 07 KEY, sz BLOB)]..
| 3744: 17 23 23 01 81 01 74 61 62 6c 65 74 74 74 5f 63 .##...tablettt_c
| 3760: 6f 6e 74 65 6e 74 74 74 74 5f 63 6f 6e 74 65 6e ontentttt_conten
| 3776: 74 04 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 t.CREATE TABLE '
| 3792: 74 74 74 5f 63 6f 6e 74 65 6e 74 27 28 69 64 20 ttt_content'(id
| 3808: 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 INTEGER PRIMARY
| 3824: 4b 45 59 2c 20 63 30 2c 20 63 31 29 6c 03 07 17 KEY, c0, c1)l...
| 3840: 1b 1b 01 81 2f 74 61 62 6c 65 74 74 74 5f 69 64 ..../tablettt_id
| 3856: 78 74 74 74 5f 69 64 78 03 43 52 45 41 54 45 20 xttt_idx.CREATE
| 3872: 54 41 42 4c 45 20 27 74 74 74 5f 69 64 78 27 28 TABLE 'ttt_idx'(
| 3888: 73 65 67 69 64 2c 20 74 65 72 6d 2c 20 70 67 6e segid, term, pgn
| 3904: 6f 2c 20 50 52 49 4d 41 52 59 20 4b 45 59 28 73 o, PRIMARY KEY(s
| 3920: 65 67 69 64 2c 20 74 65 72 6d 29 29 20 57 49 54 egid, term)) WIT
| 3936: 48 4f 55 54 20 52 4f 57 49 44 58 02 07 17 1d 1d HOUT ROWIDX.....
| 3952: 01 81 03 74 61 62 6c 65 74 74 74 5f 64 61 74 61 ...tablettt_data
| 3968: 74 74 74 5f 64 61 74 61 02 43 52 45 41 54 45 20 ttt_data.CREATE
| 3984: 54 41 42 4c 45 20 27 74 74 74 5f 64 61 74 61 27 TABLE 'ttt_data'
| 4000: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d (id INTEGER PRIM
| 4016: 41 52 59 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 ARY KEY, block B
| 4032: 4c 4f 42 29 3a 01 06 17 13 13 08 5f 74 61 62 6c LOB):......_tabl
| 4048: 65 74 74 74 74 74 74 43 52 45 41 54 45 20 56 49 ettttttCREATE VI
| 4064: 52 54 55 41 4c 20 54 41 42 4c 45 20 74 74 74 20 RTUAL TABLE ttt
| 4080: 55 53 49 4e 47 20 66 74 73 35 28 61 2c 20 62 29 USING fts5(a, b)
| page 2 offset 4096
| 0: 0d 0f 44 00 05 0e 81 00 0f e7 0e 81 0f af 0f 58 ..D............X
| 16: 0e 98 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
| 3712: 00 15 0a 03 00 30 00 00 00 00 01 03 03 00 03 01 .....0..........
| 3728: 01 01 02 01 01 03 01 01 81 24 8c 80 80 80 80 01 .........$......
| 3744: 04 00 82 4c 00 00 00 9b 02 30 65 03 1a 02 05 05 ...L.....0e.....
| 3760: 07 05 01 01 04 03 03 08 03 03 01 2e 02 05 05 07 ................
| 3776: 05 07 05 07 05 01 01 04 03 03 08 03 03 08 03 03 ................
| 3792: 08 03 03 02 01 65 03 1e 03 05 05 04 05 05 01 01 .....e..........
| 3808: 03 06 04 04 06 04 03 01 36 03 05 05 04 05 05 04 ........6.......
| 3824: 05 05 04 05 05 01 01 03 06 04 04 06 04 04 06 04 ................
| 3840: 04 06 04 03 03 01 65 03 14 04 05 07 05 05 01 01 ......e.........
| 3856: 02 08 0a 01 20 04 05 07 05 07 05 07 05 05 01 01 .... ...........
| 3872: 02 08 0a 09 fa 04 01 65 03 02 0a 01 06 0a 1a 0a .......e........
| 3888: 05 01 65 03 06 01 01 0a 01 0a 01 01 0a 0a 0a 04 ..e.............
| 3904: 2b 31 21 0b 0f ef 00 14 2a 00 00 00 00 01 02 02 +1!.....*.......
| 3920: 00 02 01 01 01 02 01 01 50 88 80 80 80 80 01 04 ........P.......
| 3936: 00 81 24 00 00 00 47 02 30 65 02 1a 02 05 05 07 ..$...G.0e......
| 3952: 05 01 01 04 03 03 08 03 03 02 01 65 02 1e 03 05 ...........e....
| 3968: 05 04 05 05 01 01 03 06 04 04 06 04 03 03 01 65 ...............e
| 3984: 02 14 04 05 07 05 05 01 01 02 08 0a 04 01 65 02 ..............e.
| 4000: 02 0a 05 01 65 02 06 01 01 0a 04 12 14 0f 06 31 ....e..........1
| 4016: 84 80 80 80 80 01 03 00 68 00 00 00 2b 02 30 65 ........h...+.0e
| 4032: 01 10 02 05 05 01 01 04 03 9f 02 01 65 01 12 03 ............e...
| 4048: 05 05 01 01 03 06 04 03 03 01 65 01 0e 14 05 05 ..........e.....
| 4064: 01 01 02 08 04 0d 0e 06 01 03 00 12 04 4c 4c 00 .............LL.
| 4080: 00 00 11 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............
| page 3 offset 8192
| 0: 0a 00 00 00 03 0f 00 00 00 00 00 00 00 00 00 00 ................
| 4064: 00 00 00 00 00 00 00 00 00 00 00 00 06 04 01 0c ................
| 4080: 01 03 02 06 04 01 0c 01 02 02 05 04 09 0c 01 02 ................
| page 4 offset 12288
| 0: 0d 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 ................
| 3600: 00 00 00 00 00 00 00 00 00 00 81 52 04 06 00 81 ...........R....
| 3616: 5d 81 55 65 20 65 65 20 65 65 65 20 65 20 65 65 ].Ue ee eee e ee
| 3632: 20 65 65 65 20 65 20 65 65 20 65 65 65 65 20 65 eee e ee eeee e
| 3648: 65 20 65 65 65 20 65 20 65 65 20 65 65 65 20 65 e eee e ee eee e
| 3664: 20 65 65 20 65 65 55 65 20 65 65 20 65 65 65 20 ee eeUe ee eee
| 3680: 65 20 65 65 20 65 65 65 20 65 20 65 65 20 65 65 e ee eee e ee ee
| 3696: 65 65 20 65 65 20 65 65 65 20 65 20 65 65 20 65 ee ee eee e ee e
| 3712: 65 65 20 65 20 65 65 20 65 65 65 65 65 65 20 65 ee e ee eeeeee e
| 3728: 65 20 65 20 65 20 65 20 65 65 20 65 85 65 20 65 e e e e ee e.e e
| 3744: 65 20 65 65 65 65 65 20 65 65 20 65 20 65 20 65 e eeeee ee e e e
| 3760: 20 65 65 20 65 65 65 20 65 65 20 65 65 65 65 65 ee eee ee eeeee
| 3776: 20 65 65 20 65 20 65 20 65 20 65 65 20 65 65 65 ee e e e ee eee
| 3792: 20 65 65 20 65 65 65 65 65 20 65 65 20 65 20 65 ee eeeee ee e e
| 3808: 20 65 20 65 65 20 65 65 65 20 65 65 20 65 65 6a e ee eee ee eej
| 3824: 03 04 00 75 71 65 20 65 65 20 65 65 65 20 65 20 ...uqe ee eee e
| 3840: 65 65 20 65 65 65 20 65 20 65 65 20 65 65 65 65 ee eee e ee eeee
| 3856: 20 65 65 20 65 65 65 20 65 20 65 65 20 65 65 65 ee eee e ee eee
| 3872: 20 65 20 65 65 20 65 65 65 65 65 65 20 65 65 20 e ee eeeeee ee
| 3888: 65 20 65 20 65 20 65 64 20 65 65 65 20 65 65 20 e e e ed eee ee
| 3904: 65 65 65 65 65 20 65 65 20 65 20 65 20 65 10 65 eeeee ee e e e.e
| 3920: 65 20 65 65 65 10 65 65 20 65 65 6a 02 04 00 75 e eee.ee eej...u
| 3936: 71 65 20 65 65 20 65 65 65 20 65 20 65 65 20 65 qe ee eee e ee e
| 3952: 65 65 20 65 20 65 65 20 65 65 65 65 20 65 65 20 ee e ee eeee ee
| 3968: 65 65 65 20 65 20 65 65 20 65 65 65 20 65 20 65 eee e ee eee e e
| 3984: 65 20 65 65 65 66 65 65 20 65 65 20 65 20 65 20 e eeefee ee e e
| 4000: 65 88 65 65 20 65 65 65 30 65 65 20 65 65 65 65 e.ee eee0ee eeee
| 4016: 65 20 65 65 20 65 20 65 20 65 20 65 65 20 65 65 e ee e e e ee ee
| 4032: 65 20 65 65 20 65 65 37 01 04 00 41 3f 65 20 65 e ee ee7...A?e e
| 4048: 65 20 65 65 65 20 65 20 65 65 20 65 65 65 20 65 e eee e ee eee e
| 4064: 20 65 65 20 65 65 65 65 65 65 20 65 65 20 65 20 ee eeeeee ee e
| 4080: 65 20 65 20 65 65 20 65 65 65 20 65 65 20 65 65 e e ee eee ee ee
| page 5 offset 16384
| 0: 0d 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 ................
| 4064: 00 00 00 00 05 04 03 00 10 21 21 05 03 03 00 10 .........!!.....
| 4080: 11 11 05 02 03 00 10 11 11 05 01 03 00 10 09 09 ................
| page 6 offset 20480
| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
| end crash-77b86d070d0ac6.db
}]} {}
do_catchsql_test 72.1 {
INSERT INTO ttt(ttt) VALUES('integrity-check');
} {1 {database disk image is malformed}}
do_catchsql_test 72.1 {
SELECT 1 FROM ttt('e* NOT ee*');
} {1 {database disk image is malformed}}
#-------------------------------------------------------------------------
reset_db
do_test 73.0 {
sqlite3 db {}
db deserialize [decode_hexdb {
.open --hexdb
| size 24576 pagesize 4096 filename crash-b02ca2cc4d7dda.db
| page 1 offset 0
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 06 .....@ ........
| 32: 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 04 ................
| 96: 00 00 00 00 0d 00 00 00 06 0d e2 00 0f c4 0f 6a ...............j
| 112: 0e fc 0e 9d 0e 3d 0d e2 00 00 00 00 00 00 00 00 .....=..........
| 3552: 00 00 59 06 06 17 21 21 01 7f 74 61 62 6c 65 74 ..Y...!!..tablet
| 3568: 74 74 5f 63 6f 6e 66 69 67 74 74 74 5f 63 6f 6e tt_configttt_con
| 3584: 66 69 67 06 43 52 45 41 54 45 20 54 41 42 4c 45 fig.CREATE TABLE
| 3600: 20 27 74 74 74 5f 63 6f 6e 66 69 67 27 28 6b 20 'ttt_config'(k
| 3616: 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 20 PRIMARY KEY, v)
| 3632: 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5e 05 07 WITHOUT ROWID^..
| 3648: 17 23 23 01 81 03 74 61 62 6c 65 74 74 74 5f 64 .##...tablettt_d
| 3664: 6f 63 73 69 7a 65 74 74 74 5f 64 6f 63 73 69 7a ocsizettt_docsiz
| 3680: 65 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 e.CREATE TABLE '
| 3696: 74 74 74 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 ttt_docsize'(id
| 3712: 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 INTEGER PRIMARY
| 3728: 4b 45 59 2c 20 73 7a 20 42 4c 4f 42 29 5d 04 07 KEY, sz BLOB)]..
| 3744: 17 23 23 01 81 01 74 61 62 6c 65 74 74 74 5f 63 .##...tablettt_c
| 3760: 6f 6e 74 65 6e 74 74 74 74 5f 63 6f 6e 74 65 6e ontentttt_conten
| 3776: 74 04 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 t.CREATE TABLE '
| 3792: 74 74 74 5f 63 6f 6e 74 65 6e 74 27 28 69 64 20 ttt_content'(id
| 3808: 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 INTEGER PRIMARY
| 3824: 4b 45 59 2c 20 63 30 2c 20 63 31 29 6c 03 07 17 KEY, c0, c1)l...
| 3840: 1b 1b 01 81 2f 74 61 62 6c 65 74 74 74 5f 69 64 ..../tablettt_id
| 3856: 78 74 74 74 5f 69 64 78 03 43 52 45 41 54 45 20 xttt_idx.CREATE
| 3872: 54 41 42 4c 45 20 27 74 74 74 5f 69 64 78 27 28 TABLE 'ttt_idx'(
| 3888: 73 65 67 69 64 2c 20 74 65 72 6d 2c 20 70 67 6e segid, term, pgn
| 3904: 6f 2c 20 50 52 49 4d 41 52 59 20 4b 45 59 28 73 o, PRIMARY KEY(s
| 3920: 65 67 69 64 2c 20 74 65 72 6d 29 29 20 57 49 54 egid, term)) WIT
| 3936: 48 4f 55 54 20 52 4f 57 49 44 58 02 07 17 1d 1d HOUT ROWIDX.....
| 3952: 01 81 03 74 61 62 6c 65 74 74 74 5f 64 61 74 61 ...tablettt_data
| 3968: 74 74 74 5f 64 61 74 61 02 43 52 45 41 54 45 20 ttt_data.CREATE
| 3984: 54 41 42 4c 45 20 27 74 74 74 5f 64 61 74 61 27 TABLE 'ttt_data'
| 4000: 28 69 65 20 49 4e 54 45 47 45 52 20 50 52 49 4d (ie INTEGER PRIM
| 4016: 41 52 59 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 ARY KEY, block B
| 4032: 4c 4f 42 29 3a 01 06 17 13 13 08 5f 74 61 62 6c LOB):......_tabl
| 4048: 65 74 74 74 74 74 74 43 52 45 41 54 45 20 56 49 ettttttCREATE VI
| 4064: 52 54 55 41 4c 20 54 41 42 4c 45 20 74 74 74 20 RTUAL TABLE ttt
| 4080: 55 53 49 4e 47 20 66 74 73 35 28 61 2c 20 62 29 USING fts5(a, b)
| page 2 offset 4096
| 0: 0d 0f 44 00 05 0e 81 00 0f e7 0e 81 0f af 0f 58 ..D............X
| 16: 0e 98 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
| 3712: 00 15 0a 03 00 30 00 00 00 00 01 03 03 00 03 01 .....0..........
| 3728: 01 01 02 01 01 03 01 01 81 24 8c 80 80 80 80 01 .........$......
| 3744: 04 00 82 4c 00 00 00 9b 02 30 65 03 1a 02 05 05 ...L.....0e.....
| 3760: 07 05 01 01 04 03 03 08 03 03 01 2e 02 05 05 07 ................
| 3776: 05 07 05 07 05 01 01 04 03 03 08 03 03 08 03 03 ................
| 3792: 08 03 03 02 01 65 03 1e 03 05 05 04 05 05 01 01 .....e..........
| 3808: 03 06 04 04 06 04 03 01 36 03 05 05 04 05 05 04 ........6.......
| 3824: 05 04 f4 04 05 01 01 03 06 04 04 06 04 04 06 04 ................
| 3840: 04 06 04 db 03 01 65 03 14 04 05 07 05 05 01 01 ......e.........
| 3856: 02 08 0a 01 20 04 05 07 05 07 05 07 05 05 01 01 .... ...........
| 3872: 02 08 0a 0a 0a 04 01 65 03 02 0a 01 06 0a 0a 0a .......e........
| 3888: 05 01 65 03 06 01 01 0a 01 0a 01 01 0a 0a 0a 04 ..e.............
| 3904: 2b 31 21 0b 0f ef 00 14 2a 00 00 00 00 01 02 02 +1!.....*.......
| 3920: 00 02 01 01 01 02 01 01 50 88 80 80 80 80 01 04 ........P.......
| 3936: 00 81 24 00 00 00 47 02 30 65 02 1a 02 05 05 07 ..$...G.0e......
| 3952: 05 01 01 04 03 03 08 03 03 02 01 65 02 1e 03 05 ...........e....
| 3968: 05 04 05 05 01 01 03 06 09 14 06 04 03 03 01 65 ...............e
| 3984: 02 14 04 05 07 05 05 01 01 02 08 ed 04 01 65 02 ..............e.
| 4000: 02 0a 05 01 65 02 06 01 01 0a 04 12 14 0f 06 31 ....e..........1
| 4016: 84 80 80 80 80 01 03 00 68 00 00 00 2b 02 30 65 ........h...+.0e
| 4032: 01 10 02 05 05 01 01 04 03 03 02 01 55 01 12 03 ............U...
| 4048: 05 05 01 01 03 06 05 03 03 01 65 01 0e 04 05 05 ..........e.....
| 4064: 01 01 02 08 04 0d 0e 06 01 03 00 12 04 4c 4c 00 .............LL.
| 4080: 00 00 11 24 00 00 00 00 01 0f c1 00 01 01 01 01 ...$............
| page 3 offset 8192
| 0: 0a 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 ................
| 4064: 00 00 00 00 00 00 00 00 00 00 00 00 06 04 01 0c ................
| 4080: 01 03 02 06 04 01 0c 01 02 02 05 04 09 0c 01 02 ................
| page 4 offset 12288
| 0: 0d 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 ................
| 3600: 00 00 00 00 00 00 00 00 00 00 81 52 04 06 00 81 ...........R....
| 3616: 5d 81 55 65 20 65 65 20 65 65 65 20 65 20 65 65 ].Ue ee eee e ee
| 3632: 20 65 65 65 20 65 20 65 65 20 65 65 65 65 20 65 eee e ee eeee e
| 3648: 65 20 65 65 65 20 65 20 65 65 20 65 65 65 20 65 e eee e ee eee e
| 3664: 20 65 65 20 65 65 65 65 20 65 65 20 65 65 65 20 ee eeee ee eee
| 3680: 65 20 65 65 20 65 65 65 20 65 20 65 65 20 65 65 e ee eee e ee ee
| 3696: 65 65 20 65 65 20 65 65 65 20 65 20 65 65 20 65 ee ee eee e ee e
| 3712: 65 65 20 65 20 65 65 20 65 65 65 65 65 65 20 65 ee e ee eeeeee e
| 3728: 65 20 65 20 65 20 65 20 65 65 20 65 65 65 20 65 e e e e ee eee e
| 3744: 65 20 65 65 65 65 65 20 65 65 20 65 20 65 20 65 e eeeee ee e e e
| 3760: 20 65 65 20 65 62 d5 20 65 65 20 65 65 65 65 65 ee eb. ee eeeee
| 3776: 20 65 65 20 65 20 65 20 65 20 65 65 20 65 65 65 ee e e e ee eee
| 3792: 20 65 65 20 65 65 65 65 65 20 65 65 20 65 21 65 ee eeeee ee e!e
| 3808: 20 65 20 65 65 20 65 65 65 20 65 65 20 65 65 6a e ee eee ee eej
| 3824: 03 04 00 75 71 65 20 65 65 10 65 65 65 20 65 20 ...uqe ee.eee e
| 3840: 65 65 20 65 65 65 20 65 20 65 65 20 65 65 65 65 ee eee e ee eeee
| 3856: 20 65 65 20 65 65 65 20 65 20 65 65 20 65 65 65 ee eee e ee eee
| 3872: 20 65 20 65 65 20 65 65 65 65 65 65 20 65 65 20 e ee eeeeee ee
| 3888: 65 20 65 20 65 20 65 65 20 65 65 65 20 62 55 20 e e e ee eee bU
| 3904: 65 65 65 65 65 20 65 65 20 65 20 65 20 65 20 65 eeeee ee e e e e
| 3920: 65 20 65 65 65 20 55 65 20 65 65 6a 02 04 00 75 e eee Ue eej...u
| 3936: 71 65 20 65 65 20 65 65 65 20 65 10 65 65 20 65 qe ee eee e.ee e
| 3952: 65 65 20 65 20 65 65 20 65 65 65 65 20 65 65 20 ee e ee eeee ee
| 3968: 65 65 65 20 65 20 65 65 20 65 65 65 20 65 20 65 eee e ee eee e e
| 3984: 65 20 65 65 65 65 65 65 20 65 65 20 65 20 65 20 e eeeeee ee e e
| 4000: 65 20 65 65 20 65 65 65 20 65 65 20 65 65 65 65 e ee eee ee eeee
| 4016: 65 20 65 65 20 65 20 65 20 65 20 65 65 20 65 65 e ee e e e ee ee
| 4032: 65 20 65 65 21 65 65 37 0a 04 00 41 3f 65 20 65 e ee!ee7...A?e e
| 4048: 65 20 65 65 65 20 65 20 65 65 20 65 65 65 20 65 e eee e ee eee e
| 4064: 20 65 65 20 65 65 65 65 65 65 20 65 65 20 65 20 ee eeeeee ee e
| 4080: 65 20 65 20 65 65 20 65 65 65 20 65 65 20 65 65 e e ee eee ee ee
| page 5 offset 16384
| 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
| 4064: 00 00 00 00 05 04 03 00 10 21 21 05 13 03 00 10 .........!!.....
| 4080: 11 11 05 02 03 00 10 11 11 05 01 03 00 10 09 09 ................
| page 6 offset 20480
| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
| end crash-b02ca2cc4d7dda.db
}]} {}
do_catchsql_test 73.1 {
SELECT snippet(ttt,ttt, NOT 54 ),
* FROM ttt('e* NOT ee*e* NOT ee* NOT ee*e* NOT e*') ;
} {1 {database disk image is malformed}}
sqlite3_fts5_may_be_corrupt 0
finish_test
-2
View File
@@ -29,8 +29,6 @@ do_execsql_test 1.0 {
INSERT INTO ttt SELECT a||a, b||b FROM ttt;
}
expr srand(1)
proc mutate {blob i} {
set o [expr {$i % [string length $blob]}]
set a [string range $blob 0 $o-1]
-64
View File
@@ -50,68 +50,4 @@ do_test 1.2 {
}
} {}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 2.0 {
CREATE TABLE test (
id INTEGER PRIMARY KEY,
name TEXT,
value TEXT
);
CREATE VIRTUAL TABLE test_idx USING fts5(
name, content=test, content_rowid=id
);
}
do_catchsql_test 2.1 {
INSERT INTO test_idx (test_idx, rowid, name) VALUES('delete', 1, 'quick');
} {1 {database disk image is malformed}}
do_catchsql_test 2.2 {
INSERT INTO test_idx(rowid, name) VALUES(123, 'one one one');
INSERT INTO test_idx (test_idx, rowid, name) VALUES('delete', 123, 'one');
INSERT INTO test_idx (test_idx, rowid, name) VALUES('delete', 123, 'one');
} {1 {database disk image is malformed}}
do_execsql_test 2.3 {
DROP TABLE test_idx;
CREATE VIRTUAL TABLE test_idx USING fts5(
name, content=test, content_rowid=id
);
INSERT INTO test_idx(rowid, name) VALUES(123, 'one one one');
INSERT INTO test_idx(rowid, name) VALUES(124, 'two two two');
INSERT INTO test_idx(rowid, name) VALUES(125, 'two two two');
INSERT INTO test_idx (test_idx, rowid, name) VALUES('delete', 123, 'one');
INSERT INTO test_idx (test_idx, rowid, name) VALUES('delete', 123, 'one');
INSERT INTO test_idx (test_idx, rowid, name) VALUES('delete', 123, 'one');
}
do_catchsql_test 2.4 {
SELECT rowid FROM test_idx WHERE test_idx MATCH 'two' ORDER BY rank;
} {1 {database disk image is malformed}}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 3.0 {
CREATE VIRTUAL TABLE tx USING fts5(a, b, c, d, content=);
INSERT INTO tx(rowid, a, c) VALUES(1, 'abc def', 'a b c');
INSERT INTO tx(rowid, a, c) VALUES(5, 'a b c', 'a b d def');
}
do_execsql_test 3.1 {
INSERT INTO tx(tx, rowid, a, b, c, d)
VALUES('delete', 5, 'a b c', NULL, 'a b d def', NULL);
}
do_execsql_test 3.2 {
INSERT INTO tx(tx) VALUES('integrity-check');
}
do_execsql_test 3.3 {
INSERT INTO tx(tx, rowid, a, b, c, d)
VALUES('delete', 1, 'abc def', NULL, 'a b c', NULL);
}
do_execsql_test 3.4 {
INSERT INTO tx(tx) VALUES('integrity-check');
}
finish_test
+1 -1
View File
@@ -14,7 +14,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
source $testdir/malloc_common.tcl
set testprefix fts5faultD
set testprefix fts5faultA
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts5 {
-71
View File
@@ -1,71 +0,0 @@
# 2016 February 2
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#*************************************************************************
#
# This file is focused on OOM errors.
#
source [file join [file dirname [info script]] fts5_common.tcl]
source $testdir/malloc_common.tcl
set testprefix fts5faultE
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
faultsim_save_and_close
do_faultsim_test 1 -prep {
faultsim_restore_and_reopen
} -body {
execsql { CREATE VIRTUAL TABLE t1 USING fts5(x, y, tokenize=trigram) }
} -test {
faultsim_test_result {0 {}} {1 {vtable constructor failed: t1}}
}
reset_db
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE t1 USING fts5(x, y, tokenize=trigram);
}
faultsim_save_and_close
do_faultsim_test 2 -prep {
faultsim_restore_and_reopen
} -body {
execsql {
INSERT INTO t1 VALUES('abcdefghijklmnopqrstuvwxyz', NULL);
SELECT count(*) FROM t1 WHERE x LIKE '%mnop%' AND t1 MATCH 'jkl';
}
} -test {
faultsim_test_result {0 1} {1 {vtable constructor failed: t1}}
}
reset_db
do_execsql_test 3.0 {
CREATE VIRTUAL TABLE t1 USING fts5(x, y, tokenize=trigram, detail=none);
INSERT INTO t1 VALUES('abcdefghijklmnopqrstuvwxyz', NULL);
}
faultsim_save_and_close
do_faultsim_test 3 -prep {
faultsim_restore_and_reopen
} -body {
execsql {
SELECT count(*) FROM t1 WHERE x LIKE '%mnopqrs%' AND t1 MATCH 'abc'
}
} -test {
faultsim_test_result {0 1} {1 {vtable constructor failed: t1}}
}
finish_test
+1 -38
View File
@@ -112,7 +112,7 @@ foreach_detail_mode $testprefix {
# Add a small and very large token with the same hash value to an
# empty table. At one point this would provoke an asan error.
#
do_test 1.5 {
do_test 2.0 {
set big [string repeat 12345 40]
set hash [sqlite3_fts5_token_hash 1024 $big]
while {1} {
@@ -128,41 +128,4 @@ foreach_detail_mode $testprefix {
} ;# foreach_detail_mode
#-------------------------------------------------------------------------
reset_db
do_execsql_test 2.1 {
CREATE VIRTUAL TABLE t1 USING fts5(x);
INSERT INTO t1(t1, rank) VALUES('hashsize', 1024);
INSERT INTO t1(t1, rank) VALUES('automerge', 0);
INSERT INTO t1(t1, rank) VALUES('crisismerge', 1000);
}
do_execsql_test 2.2 {
BEGIN;
INSERT INTO t1 VALUES('abc def ghi');
SELECT count(*) FROM t1_data;
} {2}
do_execsql_test 2.3 {
WITH s(i) AS (
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1024
)
INSERT INTO t1 SELECT 'abc def ghi' FROM s;
SELECT (SELECT count(*) FROM t1_data) > 10;
} {1}
do_execsql_test 2.4 {
COMMIT;
DROP TABLE t1;
CREATE VIRTUAL TABLE t1 USING fts5(x);
INSERT INTO t1(t1, rank) VALUES('hashsize', 1024);
INSERT INTO t1(t1, rank) VALUES('automerge', 0);
INSERT INTO t1(t1, rank) VALUES('crisismerge', 1000);
WITH s(i) AS (
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1024
)
INSERT INTO t1 SELECT 'abc' || i || ' def' || i || ' ghi' || i FROM s;
SELECT (SELECT count(*) FROM t1_data) > 100;
} {1}
finish_test
+1 -36
View File
@@ -273,6 +273,7 @@ do_execsql_test 9.1.2 {
SELECT quote(x'37');
} {X'37'}
breakpoint
do_execsql_test 9.2 {
INSERT INTO vt0 VALUES (SUBSTR(x'37', 0));
-- INSERT INTO vt0 VALUES (x'37');
@@ -281,40 +282,4 @@ do_execsql_test 9.3 {
INSERT INTO vt0(vt0) VALUES('integrity-check');
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 10.0 {
CREATE TABLE t1(i INTEGER PRIMARY KEY, a, b);
CREATE VIRTUAL TABLE vt0 USING fts5(a, b, content=t1);
INSERT INTO vt0(rowid, a, b) VALUES(1, 'abc', 'def');
}
do_catchsql_test 10.1 {
INSERT INTO vt0(vt0) VALUES('integrity-check');
} {0 {}}
do_catchsql_test 10.2 {
INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 0);
} {0 {}}
do_catchsql_test 10.3 {
INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 1);
} {1 {database disk image is malformed}}
do_catchsql_test 10.3 {
INSERT INTO t1 VALUES(1, 'abc', 'def');
INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 1);
} {0 {}}
do_execsql_test 10.4 {
CREATE VIRTUAL TABLE vt1 USING fts5(a, b, content=);
INSERT INTO vt1(rowid, a, b) VALUES(1, 'abc', 'def');
}
do_catchsql_test 10.5.1 {
INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 0);
} {0 {}}
do_catchsql_test 10.5.2 {
INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 1);
} {0 {}}
do_catchsql_test 10.5.3 {
INSERT INTO vt0(vt0) VALUES('integrity-check');
} {0 {}}
finish_test
+2 -2
View File
@@ -31,7 +31,7 @@ do_eqp_test 1.1 {
} {
QUERY PLAN
|--SCAN TABLE t1
`--SCAN TABLE f1 VIRTUAL TABLE INDEX 0:M1
`--SCAN TABLE f1 VIRTUAL TABLE INDEX 0:m
}
do_eqp_test 1.2 {
@@ -46,7 +46,7 @@ do_eqp_test 1.3 {
SELECT * FROM f1 WHERE f1 MATCH ? ORDER BY ff
} {
QUERY PLAN
|--SCAN TABLE f1 VIRTUAL TABLE INDEX 0:M1
|--SCAN TABLE f1 VIRTUAL TABLE INDEX 0:m
`--USE TEMP B-TREE FOR ORDER BY
}
-57
View File
@@ -1,57 +0,0 @@
# 2020 Dec 3
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file contains tests focused on prefix indexes.
#
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5prefix2
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
foreach p {3 2 1} {
reset_db
do_execsql_test 1.$p.0 "
CREATE VIRTUAL TABLE t1 USING fts5(xyz, prefix=$p);
"
do_execsql_test 1.$p.1 {
INSERT INTO t1 VALUES
('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 f.');
}
do_execsql_test 1.$p.2 {
SELECT highlight(t1, 0, '[', ']') FROM t1('f*');
} {
{May you [find] [forgiveness] [for] yourself and [forgive] others.}
{May you share [freely], never taking more than you give [f].}
}
}
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE t2 USING fts5(one, prefix=3);
INSERT INTO t2 VALUES('top');
INSERT INTO t2 VALUES('to');
INSERT INTO t2 VALUES('tommy');
}
do_execsql_test 2.1 {
SELECT * FROM t2('to*');
} {top to tommy}
finish_test
-35
View File
@@ -111,40 +111,5 @@ do_catchsql_test 2.1 {
SELECT * FROM t4;
} {1 {SQL logic error}}
#-------------------------------------------------------------------------
# Embedded 0x00 characters.
#
reset_db
do_execsql_test 3.1.0 {
CREATE VIRTUAL TABLE t1 USING fts5(z);
CREATE VIRTUAL TABLE tt USING fts5vocab(t1, 'instance');
INSERT INTO t1 VALUES('abc' || char(0) || 'def');
SELECT * FROM tt;
} { abc 1 z 0 def 1 z 1 }
do_execsql_test 3.1.1 {
SELECT hex(z) FROM t1;
} {61626300646566}
do_execsql_test 3.1.2 {
INSERT INTO t1(t1) VALUES('integrity-check');
} {}
do_execsql_test 3.2.0 {
CREATE VIRTUAL TABLE t2 USING fts5(z,
tokenize="unicode61 categories 'L* N* Co Cc'"
);
CREATE VIRTUAL TABLE tu USING fts5vocab(t2, 'instance');
INSERT INTO t2 VALUES('abc' || char(0) || 'def');
SELECT * FROM tu;
} { abc 1 z 0 def 1 z 1 }
do_execsql_test 3.2.1 {
SELECT hex(z) FROM t1;
} {61626300646566}
do_execsql_test 3.2.2 {
INSERT INTO t1(t1) VALUES('integrity-check');
} {}
finish_test
-201
View File
@@ -1,201 +0,0 @@
# 2020 September 30
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#*************************************************************************
#
# Tests for the fts5 "trigram" tokenizer.
#
source [file join [file dirname [info script]] fts5_common.tcl]
ifcapable !fts5 { finish_test ; return }
set ::testprefix fts5trigram
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING fts5(y, tokenize=trigram);
INSERT INTO t1 VALUES('abcdefghijklm');
INSERT INTO t1 VALUES('กรุงเทพมหานคร');
}
foreach {tn s res} {
1 abc "(abc)defghijklm"
2 defgh "abc(defgh)ijklm"
3 abcdefghijklm "(abcdefghijklm)"
4 กรุ "(กรุ)งเทพมหานคร"
5 งเทพมห "กรุ(งเทพมห)านคร"
6 กรุงเทพมหานคร "(กรุงเทพมหานคร)"
7 Abc "(abc)defghijklm"
8 deFgh "abc(defgh)ijklm"
9 aBcdefGhijKlm "(abcdefghijklm)"
} {
do_execsql_test 1.1.$tn {
SELECT highlight(t1, 0, '(', ')') FROM t1($s)
} $res
}
do_execsql_test 1.2.0 {
SELECT fts5_expr('ABCD', 'tokenize=trigram')
} {{"abc" + "bcd"}}
do_execsql_test 1.2.1 {
SELECT * FROM t1 WHERE y LIKE ? ESCAPE 'a'
}
foreach {tn like res} {
1 {%cDef%} 1
2 {cDef%} {}
3 {%f%} 1
4 {%f_h%} 1
5 {%f_g%} {}
6 {abc%klm} 1
7 {ABCDEFG%} 1
8 {%รุงเ%} 2
} {
do_execsql_test 1.3.$tn {
SELECT rowid FROM t1 WHERE y LIKE $like
} $res
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE t1 USING fts5(y, tokenize="trigram case_sensitive 1");
INSERT INTO t1 VALUES('abcdefghijklm');
INSERT INTO t1 VALUES('กรุงเทพมหานคร');
}
foreach {tn s res} {
1 abc "(abc)defghijklm"
2 defgh "abc(defgh)ijklm"
3 abcdefghijklm "(abcdefghijklm)"
4 กรุ "(กรุ)งเทพมหานคร"
5 งเทพมห "กรุ(งเทพมห)านคร"
6 กรุงเทพมหานคร "(กรุงเทพมหานคร)"
7 Abc ""
8 deFgh ""
9 aBcdefGhijKlm ""
} {
do_execsql_test 2.1.$tn {
SELECT highlight(t1, 0, '(', ')') FROM t1($s)
} $res
}
foreach {tn like res} {
1 {%cDef%} 1
2 {cDef%} {}
3 {%f%} 1
4 {%f_h%} 1
5 {%f_g%} {}
6 {abc%klm} 1
7 {ABCDEFG%} 1
8 {%รุงเ%} 2
} {
do_execsql_test 2.2.$tn {
SELECT rowid FROM t1 WHERE y LIKE $like
} $res
}
foreach {tn like res} {
1 {*cdef*} 1
2 {cdef*} {}
3 {*f*} 1
4 {*f?h*} 1
5 {*f?g*} {}
6 {abc*klm} 1
7 {abcdefg*} 1
8 {*รุงเ*} 2
9 {abc[d]efg*} 1
10 {abc[]d]efg*} 1
11 {abc[^]d]efg*} {}
12 {abc[^]XYZ]efg*} 1
} {
do_execsql_test 2.3.$tn {
SELECT rowid FROM t1 WHERE y GLOB $like
} $res
}
do_execsql_test 2.3.null.1 {
SELECT rowid FROM t1 WHERE y LIKE NULL
}
#-------------------------------------------------------------------------
reset_db
do_catchsql_test 3.1 {
CREATE VIRTUAL TABLE ttt USING fts5(c, tokenize="trigram case_sensitive 2");
} {1 {error in tokenizer constructor}}
do_catchsql_test 3.2 {
CREATE VIRTUAL TABLE ttt USING fts5(c, tokenize="trigram case_sensitive 11");
} {1 {error in tokenizer constructor}}
do_catchsql_test 3.3 {
CREATE VIRTUAL TABLE ttt USING fts5(c, "tokenize=trigram case_sensitive 1");
} {0 {}}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 4.0 {
CREATE VIRTUAL TABLE t0 USING fts5(b, tokenize = "trigram");
}
do_execsql_test 4.1 {
INSERT INTO t0 VALUES (x'000b01');
}
do_execsql_test 4.2 {
INSERT INTO t0(t0) VALUES('integrity-check');
}
#-------------------------------------------------------------------------
reset_db
foreach_detail_mode $::testprefix {
foreach {ci} {0 1} {
reset_db
do_execsql_test 5.cs=$ci.0.1 "
CREATE VIRTUAL TABLE t1 USING fts5(
y, tokenize=\"trigram case_sensitive $ci\", detail=%DETAIL%
);
"
do_execsql_test 5.cs=$ci.0.2 {
INSERT INTO t1 VALUES('abcdefghijklm');
INSERT INTO t1 VALUES('กรุงเทพมหานคร');
}
foreach {tn like res} {
1 {%cDef%} 1
2 {cDef%} {}
3 {%f%} 1
4 {%f_h%} 1
5 {%f_g%} {}
6 {abc%klm} 1
7 {ABCDEFG%} 1
8 {%รุงเ%} 2
} {
do_execsql_test 5.cs=$ci.1.$tn {
SELECT rowid FROM t1 WHERE y LIKE $like
} $res
}
}
}
do_execsql_test 6.0 {
CREATE VIRTUAL TABLE ci0 USING fts5(x, tokenize="trigram");
CREATE VIRTUAL TABLE ci1 USING fts5(x, tokenize="trigram case_sensitive 1");
}
# LIKE and GLOB both work with case-insensitive tokenizers. Only GLOB works
# with case-sensitive.
do_eqp_test 6.1 {
SELECT * FROM ci0 WHERE x LIKE ?
} {VIRTUAL TABLE INDEX 0:L0}
do_eqp_test 6.2 {
SELECT * FROM ci0 WHERE x GLOB ?
} {VIRTUAL TABLE INDEX 0:G0}
do_eqp_test 6.3 {
SELECT * FROM ci1 WHERE x LIKE ?
} {{SCAN TABLE ci1 VIRTUAL TABLE INDEX 0:}}
do_eqp_test 6.4 {
SELECT * FROM ci1 WHERE x GLOB ?
} {VIRTUAL TABLE INDEX 0:G0}
finish_test
-2
View File
@@ -12,7 +12,6 @@ proc process_cmdline {} {
cmdline::process ::A $::argv {
{fts5 "use fts5 (this is the default)"}
{fts4 "use fts4"}
{trigram "Use tokenize=trigram"}
{colsize "10 10 10" "list of column sizes"}
{tblname "t1" "table name to create"}
{detail "full" "Fts5 detail mode to use"}
@@ -176,7 +175,6 @@ proc create_table {} {
set sql "CREATE VIRTUAL TABLE IF NOT EXISTS $A(tblname) USING $A(fts) ("
append sql [join $cols ,]
if {$A(fts)=="fts5"} { append sql ",detail=$A(detail)" }
if {$A(trigram)} { append sql ",tokenize=trigram" }
append sql ", prefix='$A(prefix)');"
db eval $sql
+1 -2
View File
@@ -116,8 +116,7 @@ SQLite. Documentation follows.
and use it as a dynamically loadable SQLite extension. To do this
using gcc on *nix:
gcc -fPIC -shared icu.c `pkg-config --libs --cflags icu-uc icu-io` \
-o libSqliteIcu.so
gcc -shared icu.c `icu-config --ldflags` -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
+1
View File
@@ -24,3 +24,4 @@ int sqlite3IcuInit(sqlite3 *db);
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
+2
View File
@@ -654,3 +654,5 @@ void test_data_3(
testFree(zName);
}
}
+2
View File
@@ -322,3 +322,5 @@ void do_writer_crash_test(const char *zPattern, int *pRc){
}
}
+3
View File
@@ -138,3 +138,6 @@ void test_data_4(
testFree(zName);
}
}
+4
View File
@@ -69,3 +69,7 @@ int do_bt(int nArg, char **azArg){
sqlite4_buffer_clear(&buf.output);
return 0;
}
+1 -1
View File
@@ -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_schema LIMIT 1;" , 0, 0, 0
"BEGIN; SELECT * FROM sqlite_master LIMIT 1;" , 0, 0, 0
);
if( rc!=0 ) return rc;
pDb->nOpenTrans = 1;
+1
View File
@@ -367,3 +367,4 @@ int test_mdb_scan(
}
#endif /* HAVE_MDB */
+2
View File
@@ -978,3 +978,5 @@ static int bgc_detach(BtDb *pDb){
/*
** End of background checkpointer.
*************************************************************************/
+1 -8
View File
@@ -228,10 +228,6 @@ 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;
}
@@ -417,10 +413,7 @@ 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]==MAP_FAILED ){
p->apShm[iChunk] = 0;
return LSM_IOERR_BKPT;
}
if( p->apShm[iChunk]==0 ) return LSM_IOERR_BKPT;
}
*ppShm = p->apShm[iChunk];
+1 -1
View File
@@ -439,7 +439,7 @@ static int apndOpen(
p = (ApndFile*)pFile;
memset(p, 0, sizeof(*p));
pSubFile = ORIGFILE(pFile);
pFile->pMethods = &apnd_io_methods;
p->base.pMethods = &apnd_io_methods;
rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags);
if( rc ) goto apnd_open_done;
rc = pSubFile->pMethods->xFileSize(pSubFile, &sz);
+6 -6
View File
@@ -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_schema
** sql TEXT, -- SQL for this btree - from sqlite_master
** 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_schema table.
** The first 5 fields are taken directly from the sqlite_master table.
** Considering only the first 5 fields, the only difference between
** this virtual table and the sqlite_schema table is that this virtual
** this virtual table and the sqlite_master 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_schema */
sqlite3_stmt *pStmt; /* Query against sqlite_master */
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_schema','sqlite_schema',1,NULL "
"SELECT 0, 'table','sqlite_master','sqlite_master',1,NULL "
"UNION ALL "
"SELECT rowid, type, name, tbl_name, rootpage, sql"
" FROM \"%w\".sqlite_schema WHERE rootpage>=1",
" FROM \"%w\".sqlite_master WHERE rootpage>=1",
pCsr->zSchema);
sqlite3_finalize(pCsr->pStmt);
pCsr->pStmt = 0;
+38 -153
View File
@@ -57,31 +57,20 @@ SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
/* Allowed values for the mFlags parameter to sqlite3_carray_bind().
** Must exactly match the definitions in carray.h.
*/
#define CARRAY_INT32 0 /* Data is 32-bit signed integers */
#define CARRAY_INT64 1 /* Data is 64-bit signed integers */
#define CARRAY_DOUBLE 2 /* Data is doubles */
#define CARRAY_TEXT 3 /* Data is char* */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Names of allowed datatypes
** Allowed datatypes
*/
static const char *azType[] = { "int32", "int64", "double", "char*" };
#define CARRAY_INT32 0
#define CARRAY_INT64 1
#define CARRAY_DOUBLE 2
#define CARRAY_TEXT 3
/*
** Structure used to hold the sqlite3_carray_bind() information
** Names of types
*/
typedef struct carray_bind carray_bind;
struct carray_bind {
void *aData; /* The data */
int nData; /* Number of elements */
int mFlags; /* Control flags */
void (*xDel)(void*); /* Destructor for aData */
};
static const char *azType[] = { "int32", "int64", "double", "char*" };
/* carray_cursor is a subclass of sqlite3_vtab_cursor which will
@@ -250,39 +239,28 @@ static int carrayFilter(
int argc, sqlite3_value **argv
){
carray_cursor *pCur = (carray_cursor *)pVtabCursor;
pCur->pPtr = 0;
pCur->iCnt = 0;
switch( idxNum ){
case 1: {
carray_bind *pBind = sqlite3_value_pointer(argv[0], "carray-bind");
if( pBind==0 ) break;
pCur->pPtr = pBind->aData;
pCur->iCnt = pBind->nData;
pCur->eType = pBind->mFlags & 0x03;
break;
}
case 2:
case 3: {
pCur->pPtr = sqlite3_value_pointer(argv[0], "carray");
pCur->iCnt = pCur->pPtr ? sqlite3_value_int64(argv[1]) : 0;
if( idxNum<3 ){
pCur->eType = CARRAY_INT32;
}else{
unsigned char i;
const char *zType = (const char*)sqlite3_value_text(argv[2]);
for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
if( sqlite3_stricmp(zType, azType[i])==0 ) break;
}
if( i>=sizeof(azType)/sizeof(azType[0]) ){
pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf(
"unknown datatype: %Q", zType);
return SQLITE_ERROR;
}else{
pCur->eType = i;
}
if( idxNum ){
pCur->pPtr = sqlite3_value_pointer(argv[0], "carray");
pCur->iCnt = pCur->pPtr ? sqlite3_value_int64(argv[1]) : 0;
if( idxNum<3 ){
pCur->eType = CARRAY_INT32;
}else{
unsigned char i;
const char *zType = (const char*)sqlite3_value_text(argv[2]);
for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
if( sqlite3_stricmp(zType, azType[i])==0 ) break;
}
if( i>=sizeof(azType)/sizeof(azType[0]) ){
pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf(
"unknown datatype: %Q", zType);
return SQLITE_ERROR;
}else{
pCur->eType = i;
}
break;
}
}else{
pCur->pPtr = 0;
pCur->iCnt = 0;
}
pCur->iRowid = 1;
return SQLITE_OK;
@@ -297,16 +275,9 @@ static int carrayFilter(
** In this implementation idxNum is used to represent the
** query plan. idxStr is unused.
**
** idxNum is:
**
** 1 If only the pointer= constraint exists. In this case, the
** parameter must be bound using sqlite3_carray_bind().
**
** 2 if the pointer= and count= constraints exist.
**
** 3 if the ctype= constraint also exists.
**
** idxNum is 0 otherwise and carray becomes an empty table.
** idxNum is 2 if the pointer= and count= constraints exist,
** 3 if the ctype= constraint also exists, and is 0 otherwise.
** If idxNum is 0, then carray becomes an empty table.
*/
static int carrayBestIndex(
sqlite3_vtab *tab,
@@ -334,21 +305,18 @@ static int carrayBestIndex(
break;
}
}
if( ptrIdx>=0 ){
if( ptrIdx>=0 && cntIdx>=0 ){
pIdxInfo->aConstraintUsage[ptrIdx].argvIndex = 1;
pIdxInfo->aConstraintUsage[ptrIdx].omit = 1;
pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2;
pIdxInfo->aConstraintUsage[cntIdx].omit = 1;
pIdxInfo->estimatedCost = (double)1;
pIdxInfo->estimatedRows = 100;
pIdxInfo->idxNum = 1;
if( cntIdx>=0 ){
pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2;
pIdxInfo->aConstraintUsage[cntIdx].omit = 1;
pIdxInfo->idxNum = 2;
if( ctypeIdx>=0 ){
pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3;
pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1;
pIdxInfo->idxNum = 3;
}
pIdxInfo->idxNum = 2;
if( ctypeIdx>=0 ){
pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3;
pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1;
pIdxInfo->idxNum = 3;
}
}else{
pIdxInfo->estimatedCost = (double)2147483647;
@@ -385,89 +353,6 @@ static sqlite3_module carrayModule = {
0, /* xRename */
};
/*
** Destructor for the carray_bind object
*/
static void carrayBindDel(void *pPtr){
carray_bind *p = (carray_bind*)pPtr;
if( p->xDel!=SQLITE_STATIC ){
p->xDel(p->aData);
}
sqlite3_free(p);
}
/*
** Invoke this interface in order to bind to the single-argument
** version of CARRAY().
*/
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_carray_bind(
sqlite3_stmt *pStmt,
int idx,
void *aData,
int nData,
int mFlags,
void (*xDestroy)(void*)
){
carray_bind *pNew;
int i;
pNew = sqlite3_malloc64(sizeof(*pNew));
if( pNew==0 ){
if( xDestroy!=SQLITE_STATIC && xDestroy!=SQLITE_TRANSIENT ){
xDestroy(aData);
}
return SQLITE_NOMEM;
}
pNew->nData = nData;
pNew->mFlags = mFlags;
if( xDestroy==SQLITE_TRANSIENT ){
sqlite3_int64 sz = nData;
switch( mFlags & 0x03 ){
case CARRAY_INT32: sz *= 4; break;
case CARRAY_INT64: sz *= 8; break;
case CARRAY_DOUBLE: sz *= 8; break;
case CARRAY_TEXT: sz *= sizeof(char*); break;
}
if( (mFlags & 0x03)==CARRAY_TEXT ){
for(i=0; i<nData; i++){
const char *z = ((char**)aData)[i];
if( z ) sz += strlen(z) + 1;
}
}
pNew->aData = sqlite3_malloc64( sz );
if( pNew->aData==0 ){
sqlite3_free(pNew);
return SQLITE_NOMEM;
}
if( (mFlags & 0x03)==CARRAY_TEXT ){
char **az = (char**)pNew->aData;
char *z = (char*)&az[nData];
for(i=0; i<nData; i++){
const char *zData = ((char**)aData)[i];
sqlite3_int64 n;
if( zData==0 ){
az[i] = 0;
continue;
}
az[i] = z;
n = strlen(zData);
memcpy(z, zData, n+1);
z += n+1;
}
}else{
memcpy(pNew->aData, aData, sz*nData);
}
pNew->xDel = sqlite3_free;
}else{
pNew->aData = aData;
pNew->xDel = xDestroy;
}
return sqlite3_bind_pointer(pStmt, idx, pNew, "carray-bind", carrayBindDel);
}
/*
** For testing purpose in the TCL test harness, we need a method for
** setting the pointer value. The inttoptr(X) SQL function accomplishes
-23
View File
@@ -1,23 +0,0 @@
/*
** Interface definitions for the CARRAY table-valued function
** extension.
*/
/* Use this interface to bind an array to the single-argument version
** of CARRAY().
*/
int sqlite3_carray_bind(
sqlite3_stmt *pStmt, /* Statement to be bound */
int i, /* Parameter index */
void *aData, /* Pointer to array data */
int nData, /* Number of data elements */
int mFlags, /* CARRAY flags */
void (*xDel)(void*) /* Destructgor for aData*/
);
/* Allowed values for the mFlags parameter to sqlite3_carray_bind().
*/
#define CARRAY_INT32 0 /* Data is 32-bit signed integers */
#define CARRAY_INT64 1 /* Data is 64-bit signed integers */
#define CARRAY_DOUBLE 2 /* Data is doubles */
#define CARRAY_TEXT 3 /* Data is char* */
-868
View File
@@ -1,868 +0,0 @@
/*
** 2020-04-20
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** This file implements a VFS shim that writes a checksum on each page
** of an SQLite database file. When reading pages, the checksum is verified
** and an error is raised if the checksum is incorrect.
**
** COMPILING
**
** This extension requires SQLite 3.32.0 or later. It uses the
** sqlite3_database_file_object() interface which was added in
** version 3.32.0, so it will not link with an earlier version of
** SQLite.
**
** To build this extension as a separately loaded shared library or
** DLL, use compiler command-lines similar to the following:
**
** (linux) gcc -fPIC -shared cksumvfs.c -o cksumvfs.so
** (mac) clang -fPIC -dynamiclib cksumvfs.c -o cksumvfs.dylib
** (windows) cl cksumvfs.c -link -dll -out:cksumvfs.dll
**
** You may want to add additional compiler options, of course,
** according to the needs of your project.
**
** If you want to statically link this extension with your product,
** then compile it like any other C-language module but add the
** "-DSQLITE_CKSUMVFS_STATIC" option so that this module knows that
** it is being statically linked rather than dynamically linked
**
** LOADING
**
** To load this extension as a shared library, you first have to
** bring up a dummy SQLite database connection to use as the argument
** to the sqlite3_load_extension() API call. Then you invoke the
** sqlite3_load_extension() API and shutdown the dummy database
** connection. All subsequent database connections that are opened
** will include this extension. For example:
**
** sqlite3 *db;
** sqlite3_open(":memory:", &db);
** sqlite3_load_extention(db, "./cksumvfs");
** sqlite3_close(db);
**
** If this extension is compiled with -DSQLITE_CKSUMVFS_STATIC and
** statically linked against the application, initialize it using
** a single API call as follows:
**
** sqlite3_register_cksumvfs();
**
** Cksumvfs is a VFS Shim. When loaded, "cksmvfs" becomes the new
** default VFS and it uses the prior default VFS as the next VFS
** down in the stack. This is normally what you want. However, in
** complex situations where multiple VFS shims are being loaded,
** it might be important to ensure that cksumvfs is loaded in the
** correct order so that it sequences itself into the default VFS
** Shim stack in the right order.
**
** USING
**
** Open database connections using the sqlite3_open() or
** sqlite3_open_v2() interfaces, as normal. Ordinary database files
** (without a checksum) will operate normally. Databases with
** checksums will return an SQLITE_IOERR_DATA error if a page is
** encountered that contains an invalid checksum.
**
** Checksumming only works on databases that have a reserve-bytes
** value of exactly 8. The default value for reserve-bytes is 0.
** Hence, newly created database files will omit the checksum by
** default. To create a database that includes a checksum, change
** the reserve-bytes value to 8 by runing:
**
** int n = 8;
** sqlite3_file_control(db, 0, SQLITE_FCNTL_RESERVE_BYTES, &n);
**
** If you do this immediately after creating a new database file,
** before anything else has been written into the file, then that
** might be all that you need to do. Otherwise, the API call
** above should be followed by:
**
** sqlite3_exec(db, "VACUUM", 0, 0, 0);
**
** It never hurts to run the VACUUM, even if you don't need it.
** If the database is in WAL mode, you should shutdown and
** reopen all database connections before continuing.
**
** From the CLI, use the ".filectrl reserve_bytes 8" command,
** followed by "VACUUM;".
**
** Note that SQLite allows the number of reserve-bytes to be
** increased but not decreased. So if a database file already
** has a reserve-bytes value greater than 8, there is no way to
** activate checksumming on that database, other than to dump
** and restore the database file. Note also that other extensions
** might also make use of the reserve-bytes. Checksumming will
** be incompatible with those other extensions.
**
** VERIFICATION OF CHECKSUMS
**
** If any checksum is incorrect, the "PRAGMA quick_check" command
** will find it. To verify that checksums are actually enabled
** and running, use the following query:
**
** SELECT count(*), verify_checksum(data)
** FROM sqlite_dbpage
** GROUP BY 2;
**
** There are three possible outputs form the verify_checksum()
** function: 1, 0, and NULL. 1 is returned if the checksum is
** correct. 0 is returned if the checksum is incorrect. NULL
** is returned if the page is unreadable. If checksumming is
** enabled, the read will fail if the checksum is wrong, so the
** usual result from verify_checksum() on a bad checksum is NULL.
**
** If everything is OK, the query above should return a single
** row where the second column is 1. Any other result indicates
** either that there is a checksum error, or checksum validation
** is disabled.
**
** CONTROLLING CHECKSUM VERIFICATION
**
** The cksumvfs extension implements a new PRAGMA statement that can
** be used to disable, re-enable, or query the status of checksum
** verification:
**
** PRAGMA checksum_verification; -- query status
** PRAGMA checksum_verification=OFF; -- disable verification
** PRAGMA checksum_verification=ON; -- re-enable verification
**
** The "checksum_verification" pragma will return "1" (true) or "0"
** (false) if checksum verification is enabled or disabled, respectively.
** "Verification" in this context means the feature that causes
** SQLITE_IOERR_DATA errors if a checksum mismatch is detected while
** reading. Checksums are always kept up-to-date as long as the
** reserve-bytes value of the database is 8, regardless of the setting
** of this pragma. Checksum verification can be disabled (for example)
** to do forensic analysis of a database that has previously reported
** a checksum error.
**
** The "checksum_verification" pragma will always respond with "0" if
** the database file does not have a reserve-bytes value of 8. The
** pragma will return no rows at all if the cksumvfs extension is
** not loaded.
**
** IMPLEMENTATION NOTES
**
** The checksum is stored in the last 8 bytes of each page. This
** module only operates if the "bytes of reserved space on each page"
** value at offset 20 the SQLite database header is exactly 8. If
** the reserved-space value is not 8, this module is a no-op.
*/
#if defined(SQLITE_AMALGAMATION) && !defined(SQLITE_CKSUMVFS_STATIC)
# define SQLITE_CKSUMVFS_STATIC
#endif
#ifdef SQLITE_CKSUMVFS_STATIC
# include "sqlite3.h"
#else
# include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#endif
#include <string.h>
#include <assert.h>
/*
** Forward declaration of objects used by this utility
*/
typedef struct sqlite3_vfs CksmVfs;
typedef struct CksmFile CksmFile;
/*
** Useful datatype abbreviations
*/
#if !defined(SQLITE_AMALGAMATION)
typedef unsigned char u8;
typedef unsigned int u32;
#endif
/* Access to a lower-level VFS that (might) implement dynamic loading,
** access to randomness, etc.
*/
#define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
#define ORIGFILE(p) ((sqlite3_file*)(((CksmFile*)(p))+1))
/* An open file */
struct CksmFile {
sqlite3_file base; /* IO methods */
const char *zFName; /* Original name of the file */
char computeCksm; /* True to compute checksums.
** 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 */
};
/*
** Methods for CksmFile
*/
static int cksmClose(sqlite3_file*);
static int cksmRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
static int cksmWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
static int cksmTruncate(sqlite3_file*, sqlite3_int64 size);
static int cksmSync(sqlite3_file*, int flags);
static int cksmFileSize(sqlite3_file*, sqlite3_int64 *pSize);
static int cksmLock(sqlite3_file*, int);
static int cksmUnlock(sqlite3_file*, int);
static int cksmCheckReservedLock(sqlite3_file*, int *pResOut);
static int cksmFileControl(sqlite3_file*, int op, void *pArg);
static int cksmSectorSize(sqlite3_file*);
static int cksmDeviceCharacteristics(sqlite3_file*);
static int cksmShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
static int cksmShmLock(sqlite3_file*, int offset, int n, int flags);
static void cksmShmBarrier(sqlite3_file*);
static int cksmShmUnmap(sqlite3_file*, int deleteFlag);
static int cksmFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
static int cksmUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);
/*
** Methods for CksmVfs
*/
static int cksmOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
static int cksmDelete(sqlite3_vfs*, const char *zName, int syncDir);
static int cksmAccess(sqlite3_vfs*, const char *zName, int flags, int *);
static int cksmFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
static void *cksmDlOpen(sqlite3_vfs*, const char *zFilename);
static void cksmDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
static void (*cksmDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
static void cksmDlClose(sqlite3_vfs*, void*);
static int cksmRandomness(sqlite3_vfs*, int nByte, char *zOut);
static int cksmSleep(sqlite3_vfs*, int microseconds);
static int cksmCurrentTime(sqlite3_vfs*, double*);
static int cksmGetLastError(sqlite3_vfs*, int, char *);
static int cksmCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
static int cksmSetSystemCall(sqlite3_vfs*, const char*,sqlite3_syscall_ptr);
static sqlite3_syscall_ptr cksmGetSystemCall(sqlite3_vfs*, const char *z);
static const char *cksmNextSystemCall(sqlite3_vfs*, const char *zName);
static sqlite3_vfs cksm_vfs = {
3, /* iVersion (set when registered) */
0, /* szOsFile (set when registered) */
1024, /* mxPathname */
0, /* pNext */
"cksmvfs", /* zName */
0, /* pAppData (set when registered) */
cksmOpen, /* xOpen */
cksmDelete, /* xDelete */
cksmAccess, /* xAccess */
cksmFullPathname, /* xFullPathname */
cksmDlOpen, /* xDlOpen */
cksmDlError, /* xDlError */
cksmDlSym, /* xDlSym */
cksmDlClose, /* xDlClose */
cksmRandomness, /* xRandomness */
cksmSleep, /* xSleep */
cksmCurrentTime, /* xCurrentTime */
cksmGetLastError, /* xGetLastError */
cksmCurrentTimeInt64, /* xCurrentTimeInt64 */
cksmSetSystemCall, /* xSetSystemCall */
cksmGetSystemCall, /* xGetSystemCall */
cksmNextSystemCall /* xNextSystemCall */
};
static const sqlite3_io_methods cksm_io_methods = {
3, /* iVersion */
cksmClose, /* xClose */
cksmRead, /* xRead */
cksmWrite, /* xWrite */
cksmTruncate, /* xTruncate */
cksmSync, /* xSync */
cksmFileSize, /* xFileSize */
cksmLock, /* xLock */
cksmUnlock, /* xUnlock */
cksmCheckReservedLock, /* xCheckReservedLock */
cksmFileControl, /* xFileControl */
cksmSectorSize, /* xSectorSize */
cksmDeviceCharacteristics, /* xDeviceCharacteristics */
cksmShmMap, /* xShmMap */
cksmShmLock, /* xShmLock */
cksmShmBarrier, /* xShmBarrier */
cksmShmUnmap, /* xShmUnmap */
cksmFetch, /* xFetch */
cksmUnfetch /* xUnfetch */
};
/* Do byte swapping on a unsigned 32-bit integer */
#define BYTESWAP32(x) ( \
(((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8) \
+ (((x)&0x00FF0000)>>8) + (((x)&0xFF000000)>>24) \
)
/* Compute a checksum on a buffer */
static void cksmCompute(
u8 *a, /* Content to be checksummed */
int nByte, /* Bytes of content in a[]. Must be a multiple of 8. */
u8 *aOut /* OUT: Final 8-byte checksum value output */
){
u32 s1 = 0, s2 = 0;
u32 *aData = (u32*)a;
u32 *aEnd = (u32*)&a[nByte];
u32 x = 1;
assert( nByte>=8 );
assert( (nByte&0x00000007)==0 );
assert( nByte<=65536 );
if( 1 == *(u8*)&x ){
/* Little-endian */
do {
s1 += *aData++ + s2;
s2 += *aData++ + s1;
}while( aData<aEnd );
}else{
/* Big-endian */
do {
s1 += BYTESWAP32(aData[0]) + s2;
s2 += BYTESWAP32(aData[1]) + s1;
aData += 2;
}while( aData<aEnd );
s1 = BYTESWAP32(s1);
s2 = BYTESWAP32(s2);
}
memcpy(aOut, &s1, 4);
memcpy(aOut+4, &s2, 4);
}
/*
** SQL function: verify_checksum(BLOB)
**
** Return 0 or 1 if the checksum is invalid or valid. Or return
** NULL if the input is not a BLOB that is the right size for a
** database page.
*/
static void cksmVerifyFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
int nByte;
u8 *data;
u8 cksum[8];
data = (u8*)sqlite3_value_blob(argv[0]);
if( data==0 ) return;
if( sqlite3_value_type(argv[0])!=SQLITE_BLOB ) return;
nByte = sqlite3_value_bytes(argv[0]);
if( nByte<512 || nByte>65536 || (nByte & (nByte-1))!=0 ) return;
cksmCompute(data, nByte-8, cksum);
sqlite3_result_int(context, memcmp(data+nByte-8,cksum,8)==0);
}
#ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME
/*
** SQL function: initialize_cksumvfs(SCHEMANAME)
**
** This SQL functions (whose name is actually determined at compile-time
** by the value of the SQLITE_CKSUMVFS_INIT_FUNCNAME macro) invokes:
**
** sqlite3_file_control(db, SCHEMANAME, SQLITE_FCNTL_RESERVE_BYTE, &n);
**
** In order to set the reserve bytes value to 8, so that cksumvfs will
** operation. This feature is provided (if and only if the
** SQLITE_CKSUMVFS_INIT_FUNCNAME compile-time option is set to a string
** which is the name of the SQL function) so as to provide the ability
** to invoke the file-control in programming languages that lack
** direct access to the sqlite3_file_control() interface (ex: Java).
**
** This interface is undocumented, apart from this comment. Usage
** example:
**
** 1. Compile with -DSQLITE_CKSUMVFS_INIT_FUNCNAME="ckvfs_init"
** 2. Run: "SELECT cksum_init('main'); VACUUM;"
*/
static void cksmInitFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
int nByte = 8;
const char *zSchemaName = (const char*)sqlite3_value_text(argv[0]);
sqlite3 *db = sqlite3_context_db_handle(context);
sqlite3_file_control(db, zSchemaName, SQLITE_FCNTL_RESERVE_BYTES, &nByte);
/* Return NULL */
}
#endif /* SQLITE_CKSUMBFS_INIT_FUNCNAME */
/*
** Close a cksm-file.
*/
static int cksmClose(sqlite3_file *pFile){
CksmFile *p = (CksmFile *)pFile;
if( p->pPartner ){
assert( p->pPartner->pPartner==p );
p->pPartner->pPartner = 0;
p->pPartner = 0;
}
pFile = ORIGFILE(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.
*/
static int cksmRead(
sqlite3_file *pFile,
void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
int rc;
CksmFile *p = (CksmFile *)pFile;
pFile = ORIGFILE(pFile);
rc = pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst);
if( rc==SQLITE_OK ){
if( iOfst==0 && iAmt>=100 && (
memcmp(zBuf,"SQLite format 3",16)==0 || memcmp(zBuf,"ZV-",3)==0
)){
u8 *d = (u8*)zBuf;
char hasCorrectReserveSize = (d[20]==8);
cksmSetFlags(p, hasCorrectReserveSize);
}
/* 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->inCkpt /* (3) */
){
u8 cksum[8];
cksmCompute((u8*)zBuf, iAmt-8, cksum);
if( memcmp((u8*)zBuf+iAmt-8, cksum, 8)!=0 ){
sqlite3_log(SQLITE_IOERR_DATA,
"checksum fault offset %lld of \"%s\"",
iOfst, p->zFName);
rc = SQLITE_IOERR_DATA;
}
}
}
return rc;
}
/*
** Write data to a cksm-file.
*/
static int cksmWrite(
sqlite3_file *pFile,
const void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
CksmFile *p = (CksmFile *)pFile;
pFile = ORIGFILE(pFile);
if( iOfst==0 && iAmt>=100 && (
memcmp(zBuf,"SQLite format 3",16)==0 || memcmp(zBuf,"ZV-",3)==0
)){
u8 *d = (u8*)zBuf;
char hasCorrectReserveSize = (d[20]==8);
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
** the checksums. The reserve byte size might have increased, but
** it will never decrease. And because it cannot decrease, the
** checksum will not overwrite anything.
*/
if( iAmt>=512
&& p->computeCksm
&& !p->inCkpt
){
cksmCompute((u8*)zBuf, iAmt-8, ((u8*)zBuf)+iAmt-8);
}
return pFile->pMethods->xWrite(pFile, zBuf, iAmt, iOfst);
}
/*
** Truncate a cksm-file.
*/
static int cksmTruncate(sqlite3_file *pFile, sqlite_int64 size){
pFile = ORIGFILE(pFile);
return pFile->pMethods->xTruncate(pFile, size);
}
/*
** Sync a cksm-file.
*/
static int cksmSync(sqlite3_file *pFile, int flags){
pFile = ORIGFILE(pFile);
return pFile->pMethods->xSync(pFile, flags);
}
/*
** Return the current file-size of a cksm-file.
*/
static int cksmFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
CksmFile *p = (CksmFile *)pFile;
pFile = ORIGFILE(p);
return pFile->pMethods->xFileSize(pFile, pSize);
}
/*
** Lock a cksm-file.
*/
static int cksmLock(sqlite3_file *pFile, int eLock){
pFile = ORIGFILE(pFile);
return pFile->pMethods->xLock(pFile, eLock);
}
/*
** Unlock a cksm-file.
*/
static int cksmUnlock(sqlite3_file *pFile, int eLock){
pFile = ORIGFILE(pFile);
return pFile->pMethods->xUnlock(pFile, eLock);
}
/*
** Check if another file-handle holds a RESERVED lock on a cksm-file.
*/
static int cksmCheckReservedLock(sqlite3_file *pFile, int *pResOut){
pFile = ORIGFILE(pFile);
return pFile->pMethods->xCheckReservedLock(pFile, pResOut);
}
/*
** File control method. For custom operations on a cksm-file.
*/
static int cksmFileControl(sqlite3_file *pFile, int op, void *pArg){
int rc;
CksmFile *p = (CksmFile*)pFile;
pFile = ORIGFILE(pFile);
if( op==SQLITE_FCNTL_PRAGMA ){
char **azArg = (char**)pArg;
assert( azArg[1]!=0 );
if( sqlite3_stricmp(azArg[1],"checksum_verification")==0 ){
char *zArg = azArg[2];
if( zArg!=0 ){
if( (zArg[0]>='1' && zArg[0]<='9')
|| sqlite3_strlike("enable%",zArg,0)==0
|| sqlite3_stricmp("yes",zArg)==0
|| sqlite3_stricmp("on",zArg)==0
){
p->verifyCksm = p->computeCksm;
}else{
p->verifyCksm = 0;
}
if( p->pPartner ) p->pPartner->verifyCksm = p->verifyCksm;
}
azArg[0] = sqlite3_mprintf("%d",p->verifyCksm);
return SQLITE_OK;
}else if( p->computeCksm && azArg[2]!=0
&& sqlite3_stricmp(azArg[1], "page_size")==0 ){
/* 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 ){
*(char**)pArg = sqlite3_mprintf("cksm/%z", *(char**)pArg);
}
return rc;
}
/*
** Return the sector-size in bytes for a cksm-file.
*/
static int cksmSectorSize(sqlite3_file *pFile){
pFile = ORIGFILE(pFile);
return pFile->pMethods->xSectorSize(pFile);
}
/*
** Return the device characteristic flags supported by a cksm-file.
*/
static int cksmDeviceCharacteristics(sqlite3_file *pFile){
pFile = ORIGFILE(pFile);
return pFile->pMethods->xDeviceCharacteristics(pFile);
}
/* Create a shared memory file mapping */
static int cksmShmMap(
sqlite3_file *pFile,
int iPg,
int pgsz,
int bExtend,
void volatile **pp
){
pFile = ORIGFILE(pFile);
return pFile->pMethods->xShmMap(pFile,iPg,pgsz,bExtend,pp);
}
/* Perform locking on a shared-memory segment */
static int cksmShmLock(sqlite3_file *pFile, int offset, int n, int flags){
pFile = ORIGFILE(pFile);
return pFile->pMethods->xShmLock(pFile,offset,n,flags);
}
/* Memory barrier operation on shared memory */
static void cksmShmBarrier(sqlite3_file *pFile){
pFile = ORIGFILE(pFile);
pFile->pMethods->xShmBarrier(pFile);
}
/* Unmap a shared memory segment */
static int cksmShmUnmap(sqlite3_file *pFile, int deleteFlag){
pFile = ORIGFILE(pFile);
return pFile->pMethods->xShmUnmap(pFile,deleteFlag);
}
/* Fetch a page of a memory-mapped file */
static int cksmFetch(
sqlite3_file *pFile,
sqlite3_int64 iOfst,
int iAmt,
void **pp
){
CksmFile *p = (CksmFile *)pFile;
if( p->computeCksm ){
*pp = 0;
return SQLITE_OK;
}
pFile = ORIGFILE(pFile);
if( pFile->pMethods->iVersion>2 && pFile->pMethods->xFetch ){
return pFile->pMethods->xFetch(pFile, iOfst, iAmt, pp);
}
*pp = 0;
return SQLITE_OK;
}
/* Release a memory-mapped page */
static int cksmUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
pFile = ORIGFILE(pFile);
if( pFile->pMethods->iVersion>2 && pFile->pMethods->xUnfetch ){
return pFile->pMethods->xUnfetch(pFile, iOfst, pPage);
}
return SQLITE_OK;
}
/*
** Open a cksm file handle.
*/
static int cksmOpen(
sqlite3_vfs *pVfs,
const char *zName,
sqlite3_file *pFile,
int flags,
int *pOutFlags
){
CksmFile *p;
sqlite3_file *pSubFile;
sqlite3_vfs *pSubVfs;
int rc;
pSubVfs = ORIGVFS(pVfs);
if( (flags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_WAL))==0 ){
return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags);
}
p = (CksmFile*)pFile;
memset(p, 0, sizeof(*p));
pSubFile = ORIGFILE(pFile);
pFile->pMethods = &cksm_io_methods;
rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags);
if( rc ) goto cksm_open_done;
if( flags & SQLITE_OPEN_WAL ){
sqlite3_file *pDb = sqlite3_database_file_object(zName);
p->pPartner = (CksmFile*)pDb;
assert( p->pPartner->pPartner==0 );
p->pPartner->pPartner = p;
p->isWal = 1;
p->computeCksm = p->pPartner->computeCksm;
}else{
p->isWal = 0;
p->computeCksm = 0;
}
p->zFName = zName;
cksm_open_done:
if( rc ) pFile->pMethods = 0;
return rc;
}
/*
** All other VFS methods are pass-thrus.
*/
static int cksmDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync);
}
static int cksmAccess(
sqlite3_vfs *pVfs,
const char *zPath,
int flags,
int *pResOut
){
return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut);
}
static int cksmFullPathname(
sqlite3_vfs *pVfs,
const char *zPath,
int nOut,
char *zOut
){
return ORIGVFS(pVfs)->xFullPathname(ORIGVFS(pVfs),zPath,nOut,zOut);
}
static void *cksmDlOpen(sqlite3_vfs *pVfs, const char *zPath){
return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath);
}
static void cksmDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg);
}
static void (*cksmDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym);
}
static void cksmDlClose(sqlite3_vfs *pVfs, void *pHandle){
ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle);
}
static int cksmRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut);
}
static int cksmSleep(sqlite3_vfs *pVfs, int nMicro){
return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro);
}
static int cksmCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut);
}
static int cksmGetLastError(sqlite3_vfs *pVfs, int a, char *b){
return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b);
}
static int cksmCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
sqlite3_vfs *pOrig = ORIGVFS(pVfs);
int rc;
assert( pOrig->iVersion>=2 );
if( pOrig->xCurrentTimeInt64 ){
rc = pOrig->xCurrentTimeInt64(pOrig, p);
}else{
double r;
rc = pOrig->xCurrentTime(pOrig, &r);
*p = (sqlite3_int64)(r*86400000.0);
}
return rc;
}
static int cksmSetSystemCall(
sqlite3_vfs *pVfs,
const char *zName,
sqlite3_syscall_ptr pCall
){
return ORIGVFS(pVfs)->xSetSystemCall(ORIGVFS(pVfs),zName,pCall);
}
static sqlite3_syscall_ptr cksmGetSystemCall(
sqlite3_vfs *pVfs,
const char *zName
){
return ORIGVFS(pVfs)->xGetSystemCall(ORIGVFS(pVfs),zName);
}
static const char *cksmNextSystemCall(sqlite3_vfs *pVfs, const char *zName){
return ORIGVFS(pVfs)->xNextSystemCall(ORIGVFS(pVfs), zName);
}
/* Register the verify_checksum() SQL function.
*/
static int cksmRegisterFunc(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
int rc;
if( db==0 ) return SQLITE_OK;
rc = sqlite3_create_function(db, "verify_checksum", 1,
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
0, cksmVerifyFunc, 0, 0);
#ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME
(void)sqlite3_create_function(db, SQLITE_CKSUMVFS_INIT_FUNCNAME, 1,
SQLITE_UTF8|SQLITE_DIRECTONLY,
0, cksmInitFunc, 0, 0);
#endif
return rc;
}
/*
** Register the cksum VFS as the default VFS for the system.
** Also make arrangements to automatically register the "verify_checksum()"
** SQL function on each new database connection.
*/
static int cksmRegisterVfs(void){
int rc = SQLITE_OK;
sqlite3_vfs *pOrig;
if( sqlite3_vfs_find("cksmvfs")!=0 ) return SQLITE_OK;
pOrig = sqlite3_vfs_find(0);
cksm_vfs.iVersion = pOrig->iVersion;
cksm_vfs.pAppData = pOrig;
cksm_vfs.szOsFile = pOrig->szOsFile + sizeof(CksmFile);
rc = sqlite3_vfs_register(&cksm_vfs, 1);
if( rc==SQLITE_OK ){
rc = sqlite3_auto_extension((void(*)(void))cksmRegisterFunc);
}
return rc;
}
#if defined(SQLITE_CKSUMVFS_STATIC)
/* This variant of the initializer runs when the extension is
** statically linked.
*/
int sqlite3_register_cksumvfs(const char *NotUsed){
(void)NotUsed;
return cksmRegisterVfs();
}
int sqlite3_unregister_cksumvfs(void){
if( sqlite3_vfs_find("cksmvfs") ){
sqlite3_vfs_unregister(&cksm_vfs);
sqlite3_cancel_auto_extension((void(*)(void))cksmRegisterFunc);
}
return SQLITE_OK;
}
#endif /* defined(SQLITE_CKSUMVFS_STATIC */
#if !defined(SQLITE_CKSUMVFS_STATIC)
/* This variant of the initializer function is used when the
** extension is shared library to be loaded at run-time.
*/
#ifdef _WIN32
__declspec(dllexport)
#endif
/*
** This routine is called by sqlite3_load_extension() when the
** extension is first loaded.
***/
int sqlite3_cksumvfs_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
int rc;
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* not used */
rc = cksmRegisterFunc(db, 0, 0);
if( rc==SQLITE_OK ){
}
if( rc==SQLITE_OK ){
rc = cksmRegisterVfs();
}
if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
return rc;
}
#endif /* !defined(SQLITE_CKSUMVFS_STATIC) */
+2 -2
View File
@@ -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_schema",
"SELECT name FROM \"%w\".sqlite_master",
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_schema AS sm"
"SELECT pti.name FROM \"%w\".sqlite_master AS sm"
" JOIN pragma_table_info(sm.name,%Q) AS pti"
" WHERE sm.type='table'",
zSql, zSep, zDb, zDb
+1 -1
View File
@@ -776,7 +776,7 @@ static int csvtabColumn(
CsvCursor *pCur = (CsvCursor*)cur;
CsvTable *pTab = (CsvTable*)cur->pVtab;
if( i>=0 && i<pTab->nCol && pCur->azVal[i]!=0 ){
sqlite3_result_text(ctx, pCur->azVal[i], -1, SQLITE_TRANSIENT);
sqlite3_result_text(ctx, pCur->azVal[i], -1, SQLITE_STATIC);
}
return SQLITE_OK;
}
+7 -7
View File
@@ -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_schema;\n", p->pArg);
p->xCallback("ANALYZE sqlite_master;\n", p->pArg);
}else if( strncmp(zTable, "sqlite_", 7)==0 ){
return 0;
}else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
@@ -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_schema(type,name,tbl_name,rootpage,sql)"
"INSERT INTO sqlite_master(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_schema "
"SELECT name, type, sql FROM \"%w\".sqlite_master "
"WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'",
zSchema
);
run_schema_dump_query(&x,
"SELECT name, type, sql FROM \"%w\".sqlite_schema "
"SELECT name, type, sql FROM \"%w\".sqlite_master "
"WHERE name=='sqlite_sequence'", zSchema
);
output_sql_from_query(&x,
"SELECT sql FROM sqlite_schema "
"SELECT sql FROM sqlite_master "
"WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0
);
}else{
run_schema_dump_query(&x,
"SELECT name, type, sql FROM \"%w\".sqlite_schema "
"SELECT name, type, sql FROM \"%w\".sqlite_master "
"WHERE tbl_name=%Q COLLATE nocase AND type=='table'"
" AND sql NOT NULL",
zSchema, zTable
);
output_sql_from_query(&x,
"SELECT sql FROM \"%w\".sqlite_schema "
"SELECT sql FROM \"%w\".sqlite_master "
"WHERE sql NOT NULL"
" AND type IN ('index','trigger','view')"
" AND tbl_name=%Q COLLATE nocase",
-634
View File
@@ -1,634 +0,0 @@
/*
** 2020-06-22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** Routines to implement arbitrary-precision decimal math.
**
** The focus here is on simplicity and correctness, not performance.
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
/* Mark a function parameter as unused, to suppress nuisance compiler
** warnings. */
#ifndef UNUSED_PARAMETER
# define UNUSED_PARAMETER(X) (void)(X)
#endif
/* A decimal object */
typedef struct Decimal Decimal;
struct Decimal {
char sign; /* 0 for positive, 1 for negative */
char oom; /* True if an OOM is encountered */
char isNull; /* True if holds a NULL rather than a number */
char isInit; /* True upon initialization */
int nDigit; /* Total number of digits */
int nFrac; /* Number of digits to the right of the decimal point */
signed char *a; /* Array of digits. Most significant first. */
};
/*
** Release memory held by a Decimal, but do not free the object itself.
*/
static void decimal_clear(Decimal *p){
sqlite3_free(p->a);
}
/*
** Destroy a Decimal object
*/
static void decimal_free(Decimal *p){
if( p ){
decimal_clear(p);
sqlite3_free(p);
}
}
/*
** Allocate a new Decimal object. Initialize it to the number given
** by the input string.
*/
static Decimal *decimal_new(
sqlite3_context *pCtx,
sqlite3_value *pIn,
int nAlt,
const unsigned char *zAlt
){
Decimal *p;
int n, i;
const unsigned char *zIn;
int iExp = 0;
p = sqlite3_malloc( sizeof(*p) );
if( p==0 ) goto new_no_mem;
p->sign = 0;
p->oom = 0;
p->isInit = 1;
p->isNull = 0;
p->nDigit = 0;
p->nFrac = 0;
if( zAlt ){
n = nAlt,
zIn = zAlt;
}else{
if( sqlite3_value_type(pIn)==SQLITE_NULL ){
p->a = 0;
p->isNull = 1;
return p;
}
n = sqlite3_value_bytes(pIn);
zIn = sqlite3_value_text(pIn);
}
p->a = sqlite3_malloc64( n+1 );
if( p->a==0 ) goto new_no_mem;
for(i=0; isspace(zIn[i]); i++){}
if( zIn[i]=='-' ){
p->sign = 1;
i++;
}else if( zIn[i]=='+' ){
i++;
}
while( i<n && zIn[i]=='0' ) i++;
while( i<n ){
char c = zIn[i];
if( c>='0' && c<='9' ){
p->a[p->nDigit++] = c - '0';
}else if( c=='.' ){
p->nFrac = p->nDigit + 1;
}else if( c=='e' || c=='E' ){
int j = i+1;
int neg = 0;
if( j>=n ) break;
if( zIn[j]=='-' ){
neg = 1;
j++;
}else if( zIn[j]=='+' ){
j++;
}
while( j<n && iExp<1000000 ){
if( zIn[j]>='0' && zIn[j]<='9' ){
iExp = iExp*10 + zIn[j] - '0';
}
j++;
}
if( neg ) iExp = -iExp;
break;
}
i++;
}
if( p->nFrac ){
p->nFrac = p->nDigit - (p->nFrac - 1);
}
if( iExp>0 ){
if( p->nFrac>0 ){
if( iExp<=p->nFrac ){
p->nFrac -= iExp;
iExp = 0;
}else{
iExp -= p->nFrac;
p->nFrac = 0;
}
}
if( iExp>0 ){
p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 );
if( p->a==0 ) goto new_no_mem;
memset(p->a+p->nDigit, 0, iExp);
p->nDigit += iExp;
}
}else if( iExp<0 ){
int nExtra;
iExp = -iExp;
nExtra = p->nDigit - p->nFrac - 1;
if( nExtra ){
if( nExtra>=iExp ){
p->nFrac += iExp;
iExp = 0;
}else{
iExp -= nExtra;
p->nFrac = p->nDigit - 1;
}
}
if( iExp>0 ){
p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 );
if( p->a==0 ) goto new_no_mem;
memmove(p->a+iExp, p->a, p->nDigit);
memset(p->a, 0, iExp);
p->nDigit += iExp;
p->nFrac += iExp;
}
}
return p;
new_no_mem:
if( pCtx ) sqlite3_result_error_nomem(pCtx);
sqlite3_free(p);
return 0;
}
/*
** Make the given Decimal the result.
*/
static void decimal_result(sqlite3_context *pCtx, Decimal *p){
char *z;
int i, j;
int n;
if( p==0 || p->oom ){
sqlite3_result_error_nomem(pCtx);
return;
}
if( p->isNull ){
sqlite3_result_null(pCtx);
return;
}
z = sqlite3_malloc( p->nDigit+4 );
if( z==0 ){
sqlite3_result_error_nomem(pCtx);
return;
}
i = 0;
if( p->nDigit==0 || (p->nDigit==1 && p->a[0]==0) ){
p->sign = 0;
}
if( p->sign ){
z[0] = '-';
i = 1;
}
n = p->nDigit - p->nFrac;
if( n<=0 ){
z[i++] = '0';
}
j = 0;
while( n>1 && p->a[j]==0 ){
j++;
n--;
}
while( n>0 ){
z[i++] = p->a[j] + '0';
j++;
n--;
}
if( p->nFrac ){
z[i++] = '.';
do{
z[i++] = p->a[j] + '0';
j++;
}while( j<p->nDigit );
}
z[i] = 0;
sqlite3_result_text(pCtx, z, i, sqlite3_free);
}
/*
** SQL Function: decimal(X)
**
** Convert input X into decimal and then back into text
*/
static void decimalFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
Decimal *p = decimal_new(context, argv[0], 0, 0);
UNUSED_PARAMETER(argc);
decimal_result(context, p);
decimal_free(p);
}
/*
** Compare to Decimal objects. Return negative, 0, or positive if the
** first object is less than, equal to, or greater than the second.
**
** Preconditions for this routine:
**
** pA!=0
** pA->isNull==0
** pB!=0
** pB->isNull==0
*/
static int decimal_cmp(const Decimal *pA, const Decimal *pB){
int nASig, nBSig, rc, n;
if( pA->sign!=pB->sign ){
return pA->sign ? -1 : +1;
}
if( pA->sign ){
const Decimal *pTemp = pA;
pA = pB;
pB = pTemp;
}
nASig = pA->nDigit - pA->nFrac;
nBSig = pB->nDigit - pB->nFrac;
if( nASig!=nBSig ){
return nASig - nBSig;
}
n = pA->nDigit;
if( n>pB->nDigit ) n = pB->nDigit;
rc = memcmp(pA->a, pB->a, n);
if( rc==0 ){
rc = pA->nDigit - pB->nDigit;
}
return rc;
}
/*
** SQL Function: decimal_cmp(X, Y)
**
** Return negative, zero, or positive if X is less then, equal to, or
** greater than Y.
*/
static void decimalCmpFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
Decimal *pA = 0, *pB = 0;
int rc;
UNUSED_PARAMETER(argc);
pA = decimal_new(context, argv[0], 0, 0);
if( pA==0 || pA->isNull ) goto cmp_done;
pB = decimal_new(context, argv[1], 0, 0);
if( pB==0 || pB->isNull ) goto cmp_done;
rc = decimal_cmp(pA, pB);
if( rc<0 ) rc = -1;
else if( rc>0 ) rc = +1;
sqlite3_result_int(context, rc);
cmp_done:
decimal_free(pA);
decimal_free(pB);
}
/*
** Expand the Decimal so that it has a least nDigit digits and nFrac
** digits to the right of the decimal point.
*/
static void decimal_expand(Decimal *p, int nDigit, int nFrac){
int nAddSig;
int nAddFrac;
if( p==0 ) return;
nAddFrac = nFrac - p->nFrac;
nAddSig = (nDigit - p->nDigit) - nAddFrac;
if( nAddFrac==0 && nAddSig==0 ) return;
p->a = sqlite3_realloc64(p->a, nDigit+1);
if( p->a==0 ){
p->oom = 1;
return;
}
if( nAddSig ){
memmove(p->a+nAddSig, p->a, p->nDigit);
memset(p->a, 0, nAddSig);
p->nDigit += nAddSig;
}
if( nAddFrac ){
memset(p->a+p->nDigit, 0, nAddFrac);
p->nDigit += nAddFrac;
p->nFrac += nAddFrac;
}
}
/*
** Add the value pB into pA.
**
** Both pA and pB might become denormalized by this routine.
*/
static void decimal_add(Decimal *pA, Decimal *pB){
int nSig, nFrac, nDigit;
int i, rc;
if( pA==0 ){
return;
}
if( pA->oom || pB==0 || pB->oom ){
pA->oom = 1;
return;
}
if( pA->isNull || pB->isNull ){
pA->isNull = 1;
return;
}
nSig = pA->nDigit - pA->nFrac;
if( nSig && pA->a[0]==0 ) nSig--;
if( nSig<pB->nDigit-pB->nFrac ){
nSig = pB->nDigit - pB->nFrac;
}
nFrac = pA->nFrac;
if( nFrac<pB->nFrac ) nFrac = pB->nFrac;
nDigit = nSig + nFrac + 1;
decimal_expand(pA, nDigit, nFrac);
decimal_expand(pB, nDigit, nFrac);
if( pA->oom || pB->oom ){
pA->oom = 1;
}else{
if( pA->sign==pB->sign ){
int carry = 0;
for(i=nDigit-1; i>=0; i--){
int x = pA->a[i] + pB->a[i] + carry;
if( x>=10 ){
carry = 1;
pA->a[i] = x - 10;
}else{
carry = 0;
pA->a[i] = x;
}
}
}else{
signed char *aA, *aB;
int borrow = 0;
rc = memcmp(pA->a, pB->a, nDigit);
if( rc<0 ){
aA = pB->a;
aB = pA->a;
pA->sign = !pA->sign;
}else{
aA = pA->a;
aB = pB->a;
}
for(i=nDigit-1; i>=0; i--){
int x = aA[i] - aB[i] - borrow;
if( x<0 ){
pA->a[i] = x+10;
borrow = 1;
}else{
pA->a[i] = x;
borrow = 0;
}
}
}
}
}
/*
** Compare text in decimal order.
*/
static int decimalCollFunc(
void *notUsed,
int nKey1, const void *pKey1,
int nKey2, const void *pKey2
){
const unsigned char *zA = (const unsigned char*)pKey1;
const unsigned char *zB = (const unsigned char*)pKey2;
Decimal *pA = decimal_new(0, 0, nKey1, zA);
Decimal *pB = decimal_new(0, 0, nKey2, zB);
int rc;
UNUSED_PARAMETER(notUsed);
if( pA==0 || pB==0 ){
rc = 0;
}else{
rc = decimal_cmp(pA, pB);
}
decimal_free(pA);
decimal_free(pB);
return rc;
}
/*
** SQL Function: decimal_add(X, Y)
** decimal_sub(X, Y)
**
** Return the sum or difference of X and Y.
*/
static void decimalAddFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
Decimal *pA = decimal_new(context, argv[0], 0, 0);
Decimal *pB = decimal_new(context, argv[1], 0, 0);
UNUSED_PARAMETER(argc);
decimal_add(pA, pB);
decimal_result(context, pA);
decimal_free(pA);
decimal_free(pB);
}
static void decimalSubFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
Decimal *pA = decimal_new(context, argv[0], 0, 0);
Decimal *pB = decimal_new(context, argv[1], 0, 0);
UNUSED_PARAMETER(argc);
if( pB==0 ) return;
pB->sign = !pB->sign;
decimal_add(pA, pB);
decimal_result(context, pA);
decimal_free(pA);
decimal_free(pB);
}
/* Aggregate funcion: decimal_sum(X)
**
** Works like sum() except that it uses decimal arithmetic for unlimited
** precision.
*/
static void decimalSumStep(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
Decimal *p;
Decimal *pArg;
UNUSED_PARAMETER(argc);
p = sqlite3_aggregate_context(context, sizeof(*p));
if( p==0 ) return;
if( !p->isInit ){
p->isInit = 1;
p->a = sqlite3_malloc(2);
if( p->a==0 ){
p->oom = 1;
}else{
p->a[0] = 0;
}
p->nDigit = 1;
p->nFrac = 0;
}
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
pArg = decimal_new(context, argv[0], 0, 0);
decimal_add(p, pArg);
decimal_free(pArg);
}
static void decimalSumInverse(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
Decimal *p;
Decimal *pArg;
UNUSED_PARAMETER(argc);
p = sqlite3_aggregate_context(context, sizeof(*p));
if( p==0 ) return;
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
pArg = decimal_new(context, argv[0], 0, 0);
if( pArg ) pArg->sign = !pArg->sign;
decimal_add(p, pArg);
decimal_free(pArg);
}
static void decimalSumValue(sqlite3_context *context){
Decimal *p = sqlite3_aggregate_context(context, 0);
if( p==0 ) return;
decimal_result(context, p);
}
static void decimalSumFinalize(sqlite3_context *context){
Decimal *p = sqlite3_aggregate_context(context, 0);
if( p==0 ) return;
decimal_result(context, p);
decimal_clear(p);
}
/*
** SQL Function: decimal_mul(X, Y)
**
** Return the product of X and Y.
**
** All significant digits after the decimal point are retained.
** Trailing zeros after the decimal point are omitted as long as
** the number of digits after the decimal point is no less than
** either the number of digits in either input.
*/
static void decimalMulFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
Decimal *pA = decimal_new(context, argv[0], 0, 0);
Decimal *pB = decimal_new(context, argv[1], 0, 0);
signed char *acc = 0;
int i, j, k;
int minFrac;
UNUSED_PARAMETER(argc);
if( pA==0 || pA->oom || pA->isNull
|| pB==0 || pB->oom || pB->isNull
){
goto mul_end;
}
acc = sqlite3_malloc64( pA->nDigit + pB->nDigit + 2 );
if( acc==0 ){
sqlite3_result_error_nomem(context);
goto mul_end;
}
memset(acc, 0, pA->nDigit + pB->nDigit + 2);
minFrac = pA->nFrac;
if( pB->nFrac<minFrac ) minFrac = pB->nFrac;
for(i=pA->nDigit-1; i>=0; i--){
signed char f = pA->a[i];
int carry = 0, x;
for(j=pB->nDigit-1, k=i+j+3; j>=0; j--, k--){
x = acc[k] + f*pB->a[j] + carry;
acc[k] = x%10;
carry = x/10;
}
x = acc[k] + carry;
acc[k] = x%10;
acc[k-1] += x/10;
}
sqlite3_free(pA->a);
pA->a = acc;
acc = 0;
pA->nDigit += pB->nDigit + 2;
pA->nFrac += pB->nFrac;
pA->sign ^= pB->sign;
while( pA->nFrac>minFrac && pA->a[pA->nDigit-1]==0 ){
pA->nFrac--;
pA->nDigit--;
}
decimal_result(context, pA);
mul_end:
sqlite3_free(acc);
decimal_free(pA);
decimal_free(pB);
}
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_decimal_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
int rc = SQLITE_OK;
static const struct {
const char *zFuncName;
int nArg;
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
} aFunc[] = {
{ "decimal", 1, decimalFunc },
{ "decimal_cmp", 2, decimalCmpFunc },
{ "decimal_add", 2, decimalAddFunc },
{ "decimal_sub", 2, decimalSubFunc },
{ "decimal_mul", 2, decimalMulFunc },
};
unsigned int i;
(void)pzErrMsg; /* Unused parameter */
SQLITE_EXTENSION_INIT2(pApi);
for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
rc = sqlite3_create_function(db, aFunc[i].zFuncName, aFunc[i].nArg,
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
0, aFunc[i].xFunc, 0, 0);
}
if( rc==SQLITE_OK ){
rc = sqlite3_create_window_function(db, "decimal_sum", 1,
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, 0,
decimalSumStep, decimalSumFinalize,
decimalSumValue, decimalSumInverse, 0);
}
if( rc==SQLITE_OK ){
rc = sqlite3_create_collation(db, "decimal", SQLITE_UTF8,
0, decimalCollFunc);
}
return rc;
}
+1 -1
View File
@@ -16,7 +16,7 @@
** Usage example:
**
** .load ./explain
** SELECT p2 FROM explain('SELECT * FROM sqlite_schema')
** SELECT p2 FROM explain('SELECT * FROM sqlite_master')
** WHERE opcode='OpenRead';
**
** This module was originally written to help simplify SQLite testing,
-2
View File
@@ -394,7 +394,6 @@ static int writeFile(
if( mtime>=0 ){
#if defined(_WIN32)
#if !SQLITE_OS_WINRT
/* Windows */
FILETIME lastAccess;
FILETIME lastWrite;
@@ -425,7 +424,6 @@ static int writeFile(
}else{
return 1;
}
#endif
#elif defined(AT_FDCWD) && 0 /* utimensat() is not universally available */
/* Recent unix */
struct timespec times[2];
+21 -169
View File
@@ -26,76 +26,16 @@
**
** Examples:
**
** 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);
**
** ieee754(2.0) -> 'ieee754(2,0)'
** ieee754(45.25) -> 'ieee754(181,-2)'
** ieee754(2, 0) -> 2.0
** ieee754(181, -2) -> 45.25
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
/* Mark a function parameter as unused, to suppress nuisance compiler
** warnings. */
#ifndef UNUSED_PARAMETER
# define UNUSED_PARAMETER(X) (void)(X)
#endif
/*
** Implementation of the ieee754() function
*/
@@ -111,19 +51,8 @@ static void ieee754func(
int isNeg;
char zResult[100];
assert( sizeof(m)==sizeof(r) );
if( sqlite3_value_type(argv[0])==SQLITE_BLOB
&& sqlite3_value_bytes(argv[0])==sizeof(r)
){
const unsigned char *x = sqlite3_value_blob(argv[0]);
unsigned int i;
sqlite3_uint64 v = 0;
for(i=0; i<sizeof(r); i++){
v = (v<<8) | x[i];
}
memcpy(&r, &v, sizeof(r));
}else{
r = sqlite3_value_double(argv[0]);
}
if( sqlite3_value_type(argv[0])!=SQLITE_FLOAT ) return;
r = sqlite3_value_double(argv[0]);
if( r<0.0 ){
isNeg = 1;
r = -r;
@@ -137,31 +66,17 @@ static void ieee754func(
}else{
e = a>>52;
m = a & ((((sqlite3_int64)1)<<52)-1);
if( e==0 ){
m <<= 1;
}else{
m |= ((sqlite3_int64)1)<<52;
}
m |= ((sqlite3_int64)1)<<52;
while( e<1075 && m>0 && (m&1)==0 ){
m >>= 1;
e++;
}
if( isNeg ) m = -m;
}
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_snprintf(sizeof(zResult), zResult, "ieee754(%lld,%d)",
m, e-1075);
sqlite3_result_text(context, zResult, -1, SQLITE_TRANSIENT);
}else if( argc==2 ){
sqlite3_int64 m, e, a;
double r;
int isNeg = 0;
@@ -171,7 +86,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;
}
@@ -184,13 +99,8 @@ static void ieee754func(
e--;
}
e += 1075;
if( e<=0 ){
/* Subnormal */
m >>= 1-e;
e = 0;
}else if( e>0x7ff ){
e = 0x7ff;
}
if( e<0 ) e = m = 0;
if( e>0x7ff ) e = 0x7ff;
a = m & ((((sqlite3_int64)1)<<52)-1);
a |= e<<52;
if( isNeg ) a |= ((sqlite3_uint64)1)<<63;
@@ -199,51 +109,6 @@ static void ieee754func(
}
}
/*
** Functions to convert between blobs and floats.
*/
static void ieee754func_from_blob(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
UNUSED_PARAMETER(argc);
if( sqlite3_value_type(argv[0])==SQLITE_BLOB
&& sqlite3_value_bytes(argv[0])==sizeof(double)
){
double r;
const unsigned char *x = sqlite3_value_blob(argv[0]);
unsigned int i;
sqlite3_uint64 v = 0;
for(i=0; i<sizeof(r); i++){
v = (v<<8) | x[i];
}
memcpy(&r, &v, sizeof(r));
sqlite3_result_double(context, r);
}
}
static void ieee754func_to_blob(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
UNUSED_PARAMETER(argc);
if( sqlite3_value_type(argv[0])==SQLITE_FLOAT
|| sqlite3_value_type(argv[0])==SQLITE_INTEGER
){
double r = sqlite3_value_double(argv[0]);
sqlite3_uint64 v;
unsigned char a[sizeof(r)];
unsigned int i;
memcpy(&v, &r, sizeof(r));
for(i=1; i<=sizeof(r); i++){
a[sizeof(r)-i] = v&0xff;
v >>= 8;
}
sqlite3_result_blob(context, a, sizeof(r), SQLITE_TRANSIENT);
}
}
#ifdef _WIN32
__declspec(dllexport)
@@ -253,29 +118,16 @@ int sqlite3_ieee_init(
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
static const struct {
char *zFName;
int nArg;
int iAux;
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
} aFunc[] = {
{ "ieee754", 1, 0, ieee754func },
{ "ieee754", 2, 0, ieee754func },
{ "ieee754_mantissa", 1, 1, ieee754func },
{ "ieee754_exponent", 1, 2, ieee754func },
{ "ieee754_to_blob", 1, 0, ieee754func_to_blob },
{ "ieee754_from_blob", 1, 0, ieee754func_from_blob },
};
unsigned int i;
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
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);
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);
}
return rc;
}
+2 -8
View File
@@ -42,10 +42,6 @@ SQLITE_EXTENSION_INIT1
# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
#endif
#ifndef deliberate_fall_through
# define deliberate_fall_through
#endif
/*
** Versions of isspace(), isalnum() and isdigit() to which it is safe
** to pass signed char values.
@@ -258,7 +254,6 @@ 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;
@@ -464,7 +459,7 @@ static void jsonRenderNode(
jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
break;
}
/* no break */ deliberate_fall_through
/* Fall through into the next case */
}
case JSON_REAL:
case JSON_INT: {
@@ -605,7 +600,7 @@ static void jsonReturn(
sqlite3_result_int64(pCtx, i);
int_done:
break;
int_as_real: i=0; /* no break */ deliberate_fall_through
int_as_real: /* fall through to real */;
}
case JSON_REAL: {
double r;
@@ -2308,7 +2303,6 @@ static int jsonEachColumn(
}
/* For json_each() path and root are the same so fall through
** into the root case */
/* no break */ deliberate_fall_through
}
default: {
const char *zRoot = p->zRoot;
+1 -1
View File
@@ -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_schema",
zSql = sqlite3_mprintf("BEGIN; SELECT * FROM %s%q%ssqlite_master",
(zDb ? "'" : ""), (zDb ? zDb : ""), (zDb ? "'." : "")
);
if( zSql==0 ) return SQLITE_NOMEM;
-9
View File
@@ -286,13 +286,6 @@ static const unsigned char sqlite3CtypeMap[256] = {
#define TK_VARIABLE TK_LITERAL
#define TK_BLOB TK_LITERAL
/* Disable nuisence warnings about case fall-through */
#if !defined(deliberate_fall_through) && defined(__GCC__) && __GCC__>=7
# define deliberate_fall_through __attribute__((fallthrough));
#else
# define deliberate_fall_through
#endif
/*
** Return the length (in bytes) of the token that begins at z[0].
** Store the token type in *tokenType before returning.
@@ -443,7 +436,6 @@ static int sqlite3GetToken(const unsigned char *z, int *tokenType){
}
/* If the next character is a digit, this is a floating point
** number that begins with ".". Fall thru into the next case */
/* no break */ deliberate_fall_through
}
case CC_DIGIT: {
*tokenType = TK_INTEGER;
@@ -536,7 +528,6 @@ static int sqlite3GetToken(const unsigned char *z, int *tokenType){
}
/* If it is not a BLOB literal, then it must be an ID, since no
** SQL keywords start with the letter 'x'. Fall through */
/* no break */ deliberate_fall_through
}
case CC_ID: {
i = 1;
+2 -2
View File
@@ -166,7 +166,7 @@ static void scrubBackupOpenSrc(ScrubState *p){
sqlite3_errmsg(p->dbSrc));
return;
}
p->rcErr = sqlite3_exec(p->dbSrc, "SELECT 1 FROM sqlite_schema; BEGIN;",
p->rcErr = sqlite3_exec(p->dbSrc, "SELECT 1 FROM sqlite_master; 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_schema WHERE coalesce(rootpage,0)>0");
"SELECT rootpage FROM sqlite_master WHERE coalesce(rootpage,0)>0");
if( pStmt==0 ) goto scrub_abort;
while( sqlite3_step(pStmt)==SQLITE_ROW ){
i = (u32)sqlite3_column_int(pStmt, 0);
+9 -30
View File
@@ -106,10 +106,10 @@ struct series_cursor {
*/
static int seriesConnect(
sqlite3 *db,
void *pUnused,
int argcUnused, const char *const*argvUnused,
void *pAux,
int argc, const char *const*argv,
sqlite3_vtab **ppVtab,
char **pzErrUnused
char **pzErr
){
sqlite3_vtab *pNew;
int rc;
@@ -120,10 +120,6 @@ static int seriesConnect(
#define SERIES_COLUMN_STOP 2
#define SERIES_COLUMN_STEP 3
(void)pUnused;
(void)argcUnused;
(void)argvUnused;
(void)pzErrUnused;
rc = sqlite3_declare_vtab(db,
"CREATE TABLE x(value,start hidden,stop hidden,step hidden)");
if( rc==SQLITE_OK ){
@@ -146,9 +142,8 @@ static int seriesDisconnect(sqlite3_vtab *pVtab){
/*
** Constructor for a new series_cursor object.
*/
static int seriesOpen(sqlite3_vtab *pUnused, sqlite3_vtab_cursor **ppCursor){
static int seriesOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
series_cursor *pCur;
(void)pUnused;
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
@@ -247,8 +242,7 @@ static int seriesEof(sqlite3_vtab_cursor *cur){
** 4: step=VALUE
**
** Also, if bit 8 is set, that means that the series should be output
** in descending order rather than in ascending order. If bit 16 is
** set, then output must appear in ascending order.
** in descending order rather than in ascending order.
**
** This routine should initialize the cursor and position it so that it
** is pointing at the first row, or pointing off the end of the table
@@ -256,12 +250,11 @@ static int seriesEof(sqlite3_vtab_cursor *cur){
*/
static int seriesFilter(
sqlite3_vtab_cursor *pVtabCursor,
int idxNum, const char *idxStrUnused,
int idxNum, const char *idxStr,
int argc, sqlite3_value **argv
){
series_cursor *pCur = (series_cursor *)pVtabCursor;
int i = 0;
(void)idxStrUnused;
if( idxNum & 1 ){
pCur->mnValue = sqlite3_value_int64(argv[i++]);
}else{
@@ -274,12 +267,7 @@ static int seriesFilter(
}
if( idxNum & 4 ){
pCur->iStep = sqlite3_value_int64(argv[i++]);
if( pCur->iStep==0 ){
pCur->iStep = 1;
}else if( pCur->iStep<0 ){
pCur->iStep = -pCur->iStep;
if( (idxNum & 16)==0 ) idxNum |= 8;
}
if( pCur->iStep<1 ) pCur->iStep = 1;
}else{
pCur->iStep = 1;
}
@@ -323,7 +311,7 @@ static int seriesFilter(
** (8) output in descending order
*/
static int seriesBestIndex(
sqlite3_vtab *tabUnused,
sqlite3_vtab *tab,
sqlite3_index_info *pIdxInfo
){
int i, j; /* Loop over constraints */
@@ -337,7 +325,6 @@ static int seriesBestIndex(
** are the last three columns in the virtual table. */
assert( SERIES_COLUMN_STOP == SERIES_COLUMN_START+1 );
assert( SERIES_COLUMN_STEP == SERIES_COLUMN_START+2 );
(void)tabUnused;
aIdx[0] = aIdx[1] = aIdx[2] = -1;
pConstraint = pIdxInfo->aConstraint;
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
@@ -373,11 +360,7 @@ static int seriesBestIndex(
pIdxInfo->estimatedCost = (double)(2 - ((idxNum&4)!=0));
pIdxInfo->estimatedRows = 1000;
if( pIdxInfo->nOrderBy==1 ){
if( pIdxInfo->aOrderBy[0].desc ){
idxNum |= 8;
}else{
idxNum |= 16;
}
if( pIdxInfo->aOrderBy[0].desc ) idxNum |= 8;
pIdxInfo->orderByConsumed = 1;
}
}else{
@@ -415,10 +398,6 @@ static sqlite3_module seriesModule = {
0, /* xRollback */
0, /* xFindMethod */
0, /* xRename */
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
0 /* xShadowName */
};
#endif /* SQLITE_OMIT_VIRTUALTABLE */
+3 -8
View File
@@ -31,10 +31,7 @@ SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
#include <stdarg.h>
#ifndef SQLITE_AMALGAMATION
typedef sqlite3_uint64 u64;
#endif /* SQLITE_AMALGAMATION */
/******************************************************************************
** The Hash Engine
@@ -624,11 +621,9 @@ static void sha3QueryFunc(
}
nCol = sqlite3_column_count(pStmt);
z = sqlite3_sql(pStmt);
if( z ){
n = (int)strlen(z);
hash_step_vformat(&cx,"S%d:",n);
SHA3Update(&cx,(unsigned char*)z,n);
}
n = (int)strlen(z);
hash_step_vformat(&cx,"S%d:",n);
SHA3Update(&cx,(unsigned char*)z,n);
/* Compute a hash over the result of the query */
while( SQLITE_ROW==sqlite3_step(pStmt) ){
-1
View File
@@ -17,7 +17,6 @@
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <zlib.h>
#include <assert.h>
/*
** Implementation of the "sqlar_compress(X)" SQL function.
+1 -2
View File
@@ -168,8 +168,7 @@ static int stmtColumn(
sqlite3_result_int(ctx, sqlite3_stmt_busy(pCur->pStmt));
break;
}
default: {
assert( i==STMT_COLUMN_MEM );
case STMT_COLUMN_MEM: {
i = SQLITE_STMTSTATUS_MEMUSED +
STMT_COLUMN_NSCAN - SQLITE_STMTSTATUS_FULLSCAN_STEP;
/* Fall thru */
-92
View File
@@ -1,92 +0,0 @@
/*
** 2020-04-14
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** This SQLite extension implements the UINT collating sequence.
**
** UINT works like BINARY for text, except that embedded strings
** of digits compare in numeric order.
**
** * Leading zeros are handled properly, in the sense that
** they do not mess of the maginitude comparison of embedded
** strings of digits. "x00123y" is equal to "x123y".
**
** * Only unsigned integers are recognized. Plus and minus
** signs are ignored. Decimal points and exponential notation
** are ignored.
**
** * Embedded integers can be of arbitrary length. Comparison
** is *not* limited integers that can be expressed as a
** 64-bit machine integer.
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
#include <ctype.h>
/*
** Compare text in lexicographic order, except strings of digits
** compare in numeric order.
*/
static int uintCollFunc(
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;
int i=0, j=0, x;
(void)notUsed;
while( i<nKey1 && j<nKey2 ){
x = zA[i] - zB[j];
if( isdigit(zA[i]) ){
int k;
if( !isdigit(zB[j]) ) return x;
while( i<nKey1 && zA[i]=='0' ){ i++; }
while( j<nKey2 && zB[j]=='0' ){ j++; }
k = 0;
while( i+k<nKey1 && isdigit(zA[i+k])
&& j+k<nKey2 && isdigit(zB[j+k]) ){
k++;
}
if( i+k<nKey1 && isdigit(zA[i+k]) ){
return +1;
}else if( j+k<nKey2 && isdigit(zB[j+k]) ){
return -1;
}else{
x = memcmp(zA+i, zB+j, k);
if( x ) return x;
i += k;
j += k;
}
}else if( x ){
return x;
}else{
i++;
j++;
}
}
return (nKey1 - i) - (nKey2 - j);
}
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_uint_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
return sqlite3_create_collation(db, "uint", SQLITE_UTF8, 0, uintCollFunc);
}
+1 -1
View File
@@ -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((void(*)(void))vstatRegister);
rc = sqlite3_auto_extension(vstatRegister);
}
}
if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
+7 -9
View File
@@ -523,16 +523,14 @@ static int zipfileAppendData(
const u8 *aWrite,
int nWrite
){
if( nWrite>0 ){
size_t n = nWrite;
fseek(pTab->pWriteFd, (long)pTab->szCurrent, SEEK_SET);
n = fwrite(aWrite, 1, nWrite, pTab->pWriteFd);
if( (int)n!=nWrite ){
pTab->base.zErrMsg = sqlite3_mprintf("error in fwrite()");
return SQLITE_ERROR;
}
pTab->szCurrent += nWrite;
size_t n;
fseek(pTab->pWriteFd, (long)pTab->szCurrent, SEEK_SET);
n = fwrite(aWrite, 1, nWrite, pTab->pWriteFd);
if( (int)n!=nWrite ){
pTab->base.zErrMsg = sqlite3_mprintf("error in fwrite()");
return SQLITE_ERROR;
}
pTab->szCurrent += nWrite;
return SQLITE_OK;
}
-7
View File
@@ -183,13 +183,6 @@ int main(int argc, char **argv){
break;
}
if( nStatStep>0 ){
sqlite3_int64 nUsed;
sqlite3_int64 nHighwater;
sqlite3_status64(SQLITE_STATUS_MEMORY_USED, &nUsed, &nHighwater, 0);
fprintf(stdout, "memory used=%lld highwater=%lld\n", nUsed, nHighwater);
}
sqlite3_free(zErrmsg);
return (rc==SQLITE_OK || rc==SQLITE_DONE) ? 0 : 1;
}
+18 -18
View File
@@ -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_schema "
"FROM sqlite_master "
"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_schema "
" FROM main.sqlite_master "
" 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_schema ){
** if( no entry exists in sqlite_master ){
** 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_schema ){
** if( the index that is the pk exists in sqlite_master ){
** *piPK = rootpage of that index.
** return RBU_PK_EXTERNAL
** }else{
@@ -1181,9 +1181,9 @@ static void rbuTableType(
int *piPk
){
/*
** 0) SELECT count(*) FROM sqlite_schema where name=%Q AND IsVirtual(%Q)
** 0) SELECT count(*) FROM sqlite_master where name=%Q AND IsVirtual(%Q)
** 1) PRAGMA index_list = ?
** 2) SELECT count(*) FROM sqlite_schema where name=%Q
** 2) SELECT count(*) FROM sqlite_master 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_schema"
" FROM sqlite_master"
" 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_schema WHERE name = %Q", zIdx
"SELECT rootpage FROM sqlite_master 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_schema WHERE rootpage = ?"
"SELECT name FROM sqlite_master 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_schema WHERE type='index' AND name=?"
"SELECT trim(sql) FROM sqlite_master 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_schema"
"SELECT count(*) FROM stat.sqlite_master"
);
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_schema");
rbuMPrintfExec(p, p->dbMain, "SELECT * FROM sqlite_master");
/* 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_schema", 0, 0, 0);
p->rc = sqlite3_exec(p->dbMain, "SELECT * FROM sqlite_master", 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_schema WHERE sql!='' AND rootpage!=0"
"SELECT sql FROM sqlite_master 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_schema WHERE rootpage=0 OR rootpage IS NULL"
"SELECT * FROM sqlite_master WHERE rootpage=0 OR rootpage IS NULL"
);
}
if( p->rc==SQLITE_OK ){
p->rc = prepareAndCollectError(p->dbMain, &pInsert, &p->zErrmsg,
"INSERT INTO sqlite_schema VALUES(?,?,?,?,?)"
"INSERT INTO sqlite_master VALUES(?,?,?,?,?)"
);
}
@@ -3865,7 +3865,7 @@ static void rbuIndexCntFunc(
assert( nVal==1 );
rc = prepareFreeAndCollectError(db, &pStmt, &zErrmsg,
sqlite3_mprintf("SELECT count(*) FROM sqlite_schema "
sqlite3_mprintf("SELECT count(*) FROM sqlite_master "
"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_schema WHERE tbl_name = 'rbu_count'"
"SELECT 1 FROM sqlite_master WHERE tbl_name = 'rbu_count'"
);
}
if( p->rc==SQLITE_OK ){
+1 -1
View File
@@ -473,7 +473,7 @@ static int cidxLookupIndex(
/* Find the table for this index. */
pFindTab = cidxPrepare(&rc, pCsr,
"SELECT tbl_name, sql FROM sqlite_schema WHERE name=%Q AND type='index'",
"SELECT tbl_name, sql FROM sqlite_master WHERE name=%Q AND type='index'",
zIdx
);
if( rc==SQLITE_OK && sqlite3_step(pFindTab)==SQLITE_ROW ){
+1 -3
View File
@@ -683,8 +683,6 @@ static GeoPoly *geopolyBBox(
aCoord[2].f = mnY;
aCoord[3].f = mxY;
}
}else{
memset(aCoord, 0, sizeof(RtreeCoord)*4);
}
return pOut;
}
@@ -1075,7 +1073,7 @@ static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2){
geopolyAddSegments(p, p1, 1);
geopolyAddSegments(p, p2, 2);
pThisEvent = geopolySortEventsByX(p->aEvent, p->nEvent);
rX = pThisEvent && pThisEvent->x==0.0 ? -1.0 : 0.0;
rX = pThisEvent->x==0.0 ? -1.0 : 0.0;
memset(aOverlap, 0, sizeof(aOverlap));
while( pThisEvent ){
if( pThisEvent->x!=rX ){
+1 -19
View File
@@ -82,7 +82,6 @@ typedef unsigned int u32;
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
/* The following macro is used to suppress compiler warnings.
*/
@@ -420,23 +419,6 @@ struct RtreeMatchArg {
# define testcase(X)
#endif
/*
** Make sure that the compiler intrinsics we desire are enabled when
** compiling with an appropriate version of MSVC unless prevented by
** the SQLITE_DISABLE_INTRINSIC define.
*/
#if !defined(SQLITE_DISABLE_INTRINSIC)
# if defined(_MSC_VER) && _MSC_VER>=1400
# if !defined(_WIN32_WCE)
# include <intrin.h>
# pragma intrinsic(_byteswap_ulong)
# pragma intrinsic(_byteswap_uint64)
# else
# include <cmnintrin.h>
# endif
# endif
#endif
/*
** Macros to determine whether the machine is big or little endian,
** and whether or not that determination is run-time or compile-time.
@@ -759,7 +741,7 @@ static int nodeAcquire(
** are the leaves, and so on. If the depth as specified on the root node
** is greater than RTREE_MAX_DEPTH, the r-tree structure must be corrupt.
*/
if( pNode && rc==SQLITE_OK && iNode==1 ){
if( pNode && iNode==1 ){
pRtree->iDepth = readInt16(pNode->zData);
if( pRtree->iDepth>RTREE_MAX_DEPTH ){
rc = SQLITE_CORRUPT_VTAB;
+2 -2
View File
@@ -172,8 +172,8 @@ proc compare_db {db1 db2} {
set data1 [$db1 eval $sql]
set data2 [$db2 eval $sql]
if {$data1 != $data2} {
puts "$db1: $data1"
puts "$db2: $data2"
puts "$data1"
puts "$data2"
error "table $tbl data mismatch"
}
}
-24
View File
@@ -155,29 +155,5 @@ 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
-57
View File
@@ -1,57 +0,0 @@
# 2020 December 23
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for the SQLite sessions module
# Specifically, for the sqlite3session_memory_used() API.
#
if {![info exists testdir]} {
set testdir [file join [file dirname [info script]] .. .. test]
}
source [file join [file dirname [info script]] session_common.tcl]
source $testdir/tester.tcl
ifcapable !session {finish_test; return}
set testprefix sessionmem
do_execsql_test 1.0 {
CREATE TABLE t1(i INTEGER PRIMARY KEY, x, y);
CREATE TABLE t2(i INTEGER, x, y, PRIMARY KEY(x, y));
}
do_test 1.1 {
sqlite3session S db main
S attach *
} {}
foreach {tn sql eRes} {
1 { INSERT INTO t1 VALUES(1, 2, 3) } 1
2 { UPDATE t1 SET x=5 } 0
3 { UPDATE t1 SET i=5 } 1
4 { DELETE FROM t1 } 0
5 { INSERT INTO t1 VALUES(1, 2, 3) } 0
6 { INSERT INTO t1 VALUES(5, 2, 3) } 0
7 { INSERT INTO t2 VALUES('a', 'b', 'c') } 1
8 { INSERT INTO t2 VALUES('d', 'e', 'f') } 1
9 { UPDATE t2 SET i='e' } 0
} {
set mem1 [S memory_used]
do_test 1.2.$tn.(mu=$mem1) {
execsql $sql
set mem2 [S memory_used]
expr {$mem2 > $mem1}
} $eRes
}
do_test 1.3 {
S delete
} {}
finish_test
+25 -72
View File
@@ -48,7 +48,6 @@ struct sqlite3_session {
int rc; /* Non-zero if an error has occurred */
void *pFilterCtx; /* First argument to pass to xTableFilter */
int (*xTableFilter)(void *pCtx, const char *zTab);
i64 nMalloc; /* Number of bytes of data allocated */
sqlite3_value *pZeroBlob; /* Value containing X'' */
sqlite3_session *pNext; /* Next session object on same db. */
SessionTable *pTable; /* List of attached tables */
@@ -432,26 +431,6 @@ static int sessionSerializeValue(
return SQLITE_OK;
}
/*
** Allocate and return a pointer to a buffer nByte bytes in size. If
** pSession is not NULL, increase the sqlite3_session.nMalloc variable
** by the number of bytes allocated.
*/
static void *sessionMalloc64(sqlite3_session *pSession, i64 nByte){
void *pRet = sqlite3_malloc64(nByte);
if( pSession ) pSession->nMalloc += sqlite3_msize(pRet);
return pRet;
}
/*
** Free buffer pFree, which must have been allocated by an earlier
** call to sessionMalloc64(). If pSession is not NULL, decrease the
** sqlite3_session.nMalloc counter by the number of bytes freed.
*/
static void sessionFree(sqlite3_session *pSession, void *pFree){
if( pSession ) pSession->nMalloc -= sqlite3_msize(pFree);
sqlite3_free(pFree);
}
/*
** This macro is used to calculate hash key values for data structures. In
@@ -919,19 +898,13 @@ static int sessionPreupdateEqual(
** Growing the hash table in this case is a performance optimization only,
** it is not required for correct operation.
*/
static int sessionGrowHash(
sqlite3_session *pSession, /* For memory accounting. May be NULL */
int bPatchset,
SessionTable *pTab
){
static int sessionGrowHash(int bPatchset, SessionTable *pTab){
if( pTab->nChange==0 || pTab->nEntry>=(pTab->nChange/2) ){
int i;
SessionChange **apNew;
sqlite3_int64 nNew = 2*(sqlite3_int64)(pTab->nChange ? pTab->nChange : 128);
apNew = (SessionChange**)sessionMalloc64(
pSession, sizeof(SessionChange*) * nNew
);
apNew = (SessionChange **)sqlite3_malloc64(sizeof(SessionChange *) * nNew);
if( apNew==0 ){
if( pTab->nChange==0 ){
return SQLITE_ERROR;
@@ -952,7 +925,7 @@ static int sessionGrowHash(
}
}
sessionFree(pSession, pTab->apChange);
sqlite3_free(pTab->apChange);
pTab->nChange = nNew;
pTab->apChange = apNew;
}
@@ -986,7 +959,6 @@ static int sessionGrowHash(
** be freed using sqlite3_free() by the caller
*/
static int sessionTableInfo(
sqlite3_session *pSession, /* For memory accounting. May be NULL */
sqlite3 *db, /* Database connection */
const char *zDb, /* Name of attached database (e.g. "main") */
const char *zThis, /* Table name */
@@ -1041,7 +1013,7 @@ static int sessionTableInfo(
if( rc==SQLITE_OK ){
nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1);
pAlloc = sessionMalloc64(pSession, nByte);
pAlloc = sqlite3_malloc64(nByte);
if( pAlloc==0 ){
rc = SQLITE_NOMEM;
}
@@ -1084,7 +1056,7 @@ static int sessionTableInfo(
*pabPK = 0;
*pnCol = 0;
if( pzTab ) *pzTab = 0;
sessionFree(pSession, azCol);
sqlite3_free(azCol);
}
sqlite3_finalize(pStmt);
return rc;
@@ -1106,7 +1078,7 @@ static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
if( pTab->nCol==0 ){
u8 *abPK;
assert( pTab->azCol==0 || pTab->abPK==0 );
pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb,
pSession->rc = sessionTableInfo(pSession->db, pSession->zDb,
pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK
);
if( pSession->rc==SQLITE_OK ){
@@ -1197,7 +1169,7 @@ static void sessionPreupdateOneChange(
}
/* Grow the hash table if required */
if( sessionGrowHash(pSession, 0, pTab) ){
if( sessionGrowHash(0, pTab) ){
pSession->rc = SQLITE_NOMEM;
return;
}
@@ -1264,7 +1236,7 @@ static void sessionPreupdateOneChange(
}
/* Allocate the change object */
pChange = (SessionChange *)sessionMalloc64(pSession, nByte);
pChange = (SessionChange *)sqlite3_malloc64(nByte);
if( !pChange ){
rc = SQLITE_NOMEM;
goto error_out;
@@ -1637,7 +1609,7 @@ int sqlite3session_diff(
int nCol; /* Columns in zFrom.zTbl */
u8 *abPK;
const char **azCol = 0;
rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, &abPK);
rc = sessionTableInfo(db, zFrom, zTbl, &nCol, 0, &azCol, &abPK);
if( rc==SQLITE_OK ){
if( pTo->nCol!=nCol ){
bMismatch = 1;
@@ -1735,7 +1707,7 @@ int sqlite3session_create(
** Free the list of table objects passed as the first argument. The contents
** of the changed-rows hash tables are also deleted.
*/
static void sessionDeleteTable(sqlite3_session *pSession, SessionTable *pList){
static void sessionDeleteTable(SessionTable *pList){
SessionTable *pNext;
SessionTable *pTab;
@@ -1747,12 +1719,12 @@ static void sessionDeleteTable(sqlite3_session *pSession, SessionTable *pList){
SessionChange *pNextChange;
for(p=pTab->apChange[i]; p; p=pNextChange){
pNextChange = p->pNext;
sessionFree(pSession, p);
sqlite3_free(p);
}
}
sessionFree(pSession, (char*)pTab->azCol); /* cast works around VC++ bug */
sessionFree(pSession, pTab->apChange);
sessionFree(pSession, pTab);
sqlite3_free((char*)pTab->azCol); /* cast works around VC++ bug */
sqlite3_free(pTab->apChange);
sqlite3_free(pTab);
}
}
@@ -1780,11 +1752,9 @@ void sqlite3session_delete(sqlite3_session *pSession){
/* Delete all attached table objects. And the contents of their
** associated hash-tables. */
sessionDeleteTable(pSession, pSession->pTable);
sessionDeleteTable(pSession->pTable);
/* Assert that all allocations have been freed and then free the
** session object itself. */
assert( pSession->nMalloc==0 );
/* Free the session object itself. */
sqlite3_free(pSession);
}
@@ -1831,8 +1801,7 @@ int sqlite3session_attach(
if( !pTab ){
/* Allocate new SessionTable object. */
int nByte = sizeof(SessionTable) + nName + 1;
pTab = (SessionTable*)sessionMalloc64(pSession, nByte);
pTab = (SessionTable *)sqlite3_malloc64(sizeof(SessionTable) + nName + 1);
if( !pTab ){
rc = SQLITE_NOMEM;
}else{
@@ -2429,7 +2398,7 @@ static int sessionGenerateChangeset(
int nNoop; /* Size of buffer after writing tbl header */
/* Check the table schema is still Ok. */
rc = sessionTableInfo(0, db, pSession->zDb, zName, &nCol, 0,&azCol,&abPK);
rc = sessionTableInfo(db, pSession->zDb, zName, &nCol, 0, &azCol, &abPK);
if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){
rc = SQLITE_SCHEMA;
}
@@ -2604,13 +2573,6 @@ int sqlite3session_isempty(sqlite3_session *pSession){
return (ret==0);
}
/*
** Return the amount of heap memory in use.
*/
sqlite3_int64 sqlite3session_memory_used(sqlite3_session *pSession){
return pSession->nMalloc;
}
/*
** Do the work for either sqlite3changeset_start() or start_strm().
*/
@@ -2994,13 +2956,8 @@ static int sessionChangesetReadTblhdr(sqlite3_changeset_iter *p){
}
p->apValue = (sqlite3_value**)p->tblhdr.aBuf;
if( p->apValue==0 ){
p->abPK = 0;
p->zTab = 0;
}else{
p->abPK = (u8*)&p->apValue[p->nCol*2];
p->zTab = p->abPK ? (char*)&p->abPK[p->nCol] : 0;
}
p->abPK = (u8*)&p->apValue[p->nCol*2];
p->zTab = (char*)&p->abPK[p->nCol];
return (p->rc = rc);
}
@@ -3522,7 +3479,6 @@ 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 */
@@ -4295,9 +4251,7 @@ static int sessionRetryConstraints(
SessionBuffer cons = pApply->constraints;
memset(&pApply->constraints, 0, sizeof(SessionBuffer));
rc = sessionChangesetStart(
&pIter2, 0, 0, cons.nBuf, cons.aBuf, pApply->bInvertConstraints
);
rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf, 0);
if( rc==SQLITE_OK ){
size_t nByte = 2*pApply->nCol*sizeof(sqlite3_value*);
int rc2;
@@ -4364,7 +4318,6 @@ 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);
@@ -4422,7 +4375,7 @@ static int sessionChangesetApply(
int i;
sqlite3changeset_pk(pIter, &abPK, 0);
rc = sessionTableInfo(0,
rc = sessionTableInfo(
db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK
);
if( rc!=SQLITE_OK ) break;
@@ -4901,7 +4854,7 @@ static int sessionChangesetToHash(
}
}
if( sessionGrowHash(0, pIter->bPatchset, pTab) ){
if( sessionGrowHash(pIter->bPatchset, pTab) ){
rc = SQLITE_NOMEM;
break;
}
@@ -5087,7 +5040,7 @@ int sqlite3changegroup_output_strm(
*/
void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){
if( pGrp ){
sessionDeleteTable(0, pGrp->pList);
sessionDeleteTable(pGrp->pList);
sqlite3_free(pGrp);
}
}
@@ -5488,7 +5441,7 @@ int sqlite3rebaser_rebase_strm(
*/
void sqlite3rebaser_delete(sqlite3_rebaser *p){
if( p ){
sessionDeleteTable(0, p->grp.pList);
sessionDeleteTable(p->grp.pList);
sqlite3_free(p);
}
}
-8
View File
@@ -440,14 +440,6 @@ int sqlite3session_patchset(
*/
int sqlite3session_isempty(sqlite3_session *pSession);
/*
** CAPI3REF: Query for the amount of heap memory used by a session object.
**
** This API returns the total amount of heap memory in bytes currently
** used by the session object passed as the only argument.
*/
sqlite3_int64 sqlite3session_memory_used(sqlite3_session *pSession);
/*
** CAPI3REF: Create An Iterator To Traverse A Changeset
** CONSTRUCTOR: sqlite3_changeset_iter
+3 -10
View File
@@ -227,7 +227,7 @@ static int SQLITE_TCLAPI test_session_cmd(
){
TestSession *p = (TestSession*)clientData;
sqlite3_session *pSession = p->pSession;
static struct SessionSubcmd {
struct SessionSubcmd {
const char *zSub;
int nArg;
const char *zMsg;
@@ -242,7 +242,6 @@ static int SQLITE_TCLAPI test_session_cmd(
{ "table_filter", 1, "SCRIPT", }, /* 6 */
{ "patchset", 0, "", }, /* 7 */
{ "diff", 2, "FROMDB TBL", }, /* 8 */
{ "memory_used", 0, "", }, /* 9 */
{ 0 }
};
int iSub;
@@ -348,12 +347,6 @@ static int SQLITE_TCLAPI test_session_cmd(
}
break;
}
case 9: { /* memory_used */
sqlite3_int64 nMalloc = sqlite3session_memory_used(pSession);
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(nMalloc));
break;
}
}
return TCL_OK;
@@ -1138,7 +1131,7 @@ static int SQLITE_TCLAPI test_rebaser_cmd(
int objc,
Tcl_Obj *CONST objv[]
){
static struct RebaseSubcmd {
struct RebaseSubcmd {
const char *zSub;
int nArg;
const char *zMsg;
@@ -1255,7 +1248,7 @@ static int SQLITE_TCLAPI test_sqlite3session_config(
int objc,
Tcl_Obj *CONST objv[]
){
static struct ConfigOpt {
struct ConfigOpt {
const char *zSub;
int op;
} aSub[] = {
+11 -33
View File
@@ -74,8 +74,7 @@ LIBOBJ+= vdbe.o parse.o \
table.o threads.o tokenize.o treeview.o trigger.o \
update.o upsert.o userauth.o util.o vacuum.o \
vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbesort.o \
vdbetrace.o vdbevtab.o \
wal.o walker.o where.o wherecode.o whereexpr.o \
vdbetrace.o wal.o walker.o where.o wherecode.o whereexpr.o \
utf.o vtab.o window.o
LIBOBJ += sqlite3session.o
@@ -174,7 +173,6 @@ SRC = \
$(TOP)/src/vdbemem.c \
$(TOP)/src/vdbesort.c \
$(TOP)/src/vdbetrace.c \
$(TOP)/src/vdbevtab.c \
$(TOP)/src/vdbeInt.h \
$(TOP)/src/vtab.c \
$(TOP)/src/vxworks.h \
@@ -361,10 +359,8 @@ TESTSRC = \
TESTSRC += \
$(TOP)/ext/misc/amatch.c \
$(TOP)/ext/misc/carray.c \
$(TOP)/ext/misc/cksumvfs.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 \
@@ -425,7 +421,6 @@ 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 \
@@ -531,7 +526,6 @@ SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
SHELL_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB
SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5
@@ -542,7 +536,6 @@ FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS4
FUZZCHECK_OPT += -DSQLITE_ENABLE_RTREE
FUZZCHECK_OPT += -DSQLITE_ENABLE_GEOPOLY
FUZZCHECK_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
FUZZCHECK_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB
DBFUZZ_OPT =
KV_OPT = -DSQLITE_THREADSAFE=0 -DSQLITE_DIRECT_OVERFLOW_READ
ST_OPT = -DSQLITE_THREADSAFE=0
@@ -550,13 +543,13 @@ ST_OPT = -DSQLITE_THREADSAFE=0
# This is the default Makefile target. The objects listed here
# are what get build when you type just "make" with no arguments.
#
all: sqlite3.h sqlite3ext.h libsqlite3.a sqlite3$(EXE)
all: sqlite3.h libsqlite3.a sqlite3$(EXE)
libsqlite3.a: sqlite3.h $(LIBOBJ)
libsqlite3.a: $(LIBOBJ)
$(AR) libsqlite3.a $(LIBOBJ)
$(RANLIB) libsqlite3.a
sqlite3$(EXE): sqlite3.h libsqlite3.a shell.c
sqlite3$(EXE): shell.c libsqlite3.a sqlite3.h
$(TCCX) $(READLINE_FLAGS) -o sqlite3$(EXE) $(SHELL_OPT) \
shell.c libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB)
@@ -593,7 +586,6 @@ DBFUZZ2_OPTS = \
-DSQLITE_ENABLE_DESERIALIZE \
-DSQLITE_DEBUG \
-DSQLITE_ENABLE_DBSTAT_VTAB \
-DSQLITE_ENABLE_BYTECODE_VTAB \
-DSQLITE_ENABLE_RTREE \
-DSQLITE_ENABLE_FTS4 \
-DSQLITE_ENABLE_FTS5
@@ -729,12 +721,6 @@ 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
@@ -743,13 +729,10 @@ keywordhash.h: $(TOP)/tool/mkkeywordhash.c
SHELL_SRC = \
$(TOP)/src/shell.c.in \
$(TOP)/ext/misc/appendvfs.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/fileio.c \
$(TOP)/ext/misc/completion.c \
$(TOP)/ext/misc/sqlar.c \
$(TOP)/ext/misc/uint.c \
$(TOP)/ext/expert/sqlite3expert.c \
$(TOP)/ext/expert/sqlite3expert.h \
$(TOP)/ext/misc/zipfile.c \
@@ -824,13 +807,13 @@ fts3_unicode2.o: $(TOP)/ext/fts3/fts3_unicode2.c $(HDR) $(EXTHDR)
fts3_write.o: $(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR)
$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_write.c
fts5.o: fts5.c sqlite3ext.h sqlite3.h
fts5.o: fts5.c
$(TCCX) -DSQLITE_CORE -c fts5.c
json1.o: $(TOP)/ext/misc/json1.c sqlite3ext.h sqlite3.h
json1.o: $(TOP)/ext/misc/json1.c
$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/misc/json1.c
stmt.o: $(TOP)/ext/misc/stmt.c sqlite3ext.h sqlite3.h
stmt.o: $(TOP)/ext/misc/stmt.c
$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/misc/stmt.c
rtree.o: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR)
@@ -911,9 +894,7 @@ TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_BYTECODE_VTAB
TESTFIXTURE_FLAGS += -DTCLSH_INIT_PROC=sqlite3TestInit
TESTFIXTURE_FLAGS += -DSQLITE_CKSUMVFS_STATIC
testfixture$(EXE): $(TESTSRC2) libsqlite3.a $(TESTSRC) $(TOP)/src/tclsqlite.c
$(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \
@@ -986,9 +967,6 @@ 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.
@@ -1090,10 +1068,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 sqlite3rc.h
amalgamation-tarball: sqlite3.c
TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --normal
snapshot-tarball: sqlite3.c sqlite3rc.h
snapshot-tarball: sqlite3.c
TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --snapshot
+312 -353
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1 +1 @@
390cf60a286b13f454429f4652a133f95a7891a75c1ec6d16cd39990590fd3fb
e7343ce7514f61eb1aeba22ab83da5b05779080db394332e2e90b4d54cabe123
+45 -105
View File
@@ -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\"." DFLT_SCHEMA_TABLE " "
"FROM \"%w\".%s "
"WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'"
" AND sql NOT LIKE 'create virtual%%'"
" AND sqlite_rename_test(%Q, sql, type, name, %d)=NULL ",
zDb,
zDb, MASTER_NAME,
zDb, bTemp
);
if( bTemp==0 ){
sqlite3NestedParse(pParse,
"SELECT 1 "
"FROM temp." DFLT_SCHEMA_TABLE " "
"FROM temp.%s "
"WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'"
" AND sql NOT LIKE 'create virtual%%'"
" AND sqlite_rename_test(%Q, sql, type, name, 1)=NULL ",
zDb
MASTER_NAME, zDb
);
}
}
@@ -123,10 +123,7 @@ 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)
|| sqlite3IsShadowTableOf(db, pTab, zName)
){
if( sqlite3FindTable(db, zName, zDb) || sqlite3FindIndex(db, zName, zDb) ){
sqlite3ErrorMsg(pParse,
"there is already another table or index with this name: %s", zName);
goto exit_rename_table;
@@ -185,17 +182,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\"." DFLT_SCHEMA_TABLE " SET "
"UPDATE \"%w\".%s 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, zDb, zTabName, zName, (iDb==1), zTabName
, zDb, MASTER_NAME, zDb, zTabName, zName, (iDb==1), zTabName
);
/* Update the tbl_name and name columns of the sqlite_schema table
/* Update the tbl_name and name columns of the sqlite_master table
** as required. */
sqlite3NestedParse(pParse,
"UPDATE %Q." DFLT_SCHEMA_TABLE " SET "
"UPDATE %Q.%s SET "
"tbl_name = %Q, "
"name = CASE "
"WHEN type='table' THEN %Q "
@@ -205,7 +202,7 @@ void sqlite3AlterRenameTable(
"ELSE name END "
"WHERE tbl_name=%Q COLLATE nocase AND "
"(type='table' OR type='index' OR type='trigger');",
zDb,
zDb, MASTER_NAME,
zName, zName, zName,
nTabName, zTabName
);
@@ -226,7 +223,7 @@ void sqlite3AlterRenameTable(
** as required. */
if( iDb!=1 ){
sqlite3NestedParse(pParse,
"UPDATE sqlite_temp_schema SET "
"UPDATE sqlite_temp_master SET "
"sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, 1), "
"tbl_name = "
"CASE WHEN tbl_name=%Q COLLATE nocase AND "
@@ -258,22 +255,6 @@ 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
@@ -326,8 +307,7 @@ 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 ){
@@ -340,15 +320,16 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
pDflt = 0;
}
if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){
sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
sqlite3ErrorMsg(pParse,
"Cannot add a REFERENCES column with non-NULL default value");
return;
}
if( pCol->notNull && !pDflt ){
sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
sqlite3ErrorMsg(pParse,
"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.)
*/
@@ -362,13 +343,14 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
return;
}
if( !pVal ){
sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
"Cannot add a column with non-constant default");
sqlite3ErrorMsg(pParse,"Cannot add a column with non-constant default");
return;
}
sqlite3ValueFree(pVal);
}
}else if( pCol->colFlags & COLFLAG_STORED ){
sqlite3ErrorIfNotEmpty(pParse, zDb, zTab, "cannot add a STORED column");
sqlite3ErrorMsg(pParse, "cannot add a STORED column");
return;
}
@@ -381,14 +363,11 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
*zEnd-- = '\0';
}
db->mDbFlags |= DBFLAG_PreferBuiltin;
/* substr() operations on characters, but addColOffset is in bytes. So we
** have to use printf() to translate between these units: */
sqlite3NestedParse(pParse,
"UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET "
"sql = printf('%%.%ds, ',sql) || %Q"
" || substr(sql,1+length(printf('%%.%ds',sql))) "
"UPDATE \"%w\".%s SET "
"sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) "
"WHERE type = 'table' AND name = %Q",
zDb, pNew->addColOffset, zCol, pNew->addColOffset,
zDb, MASTER_NAME, pNew->addColOffset, zCol, pNew->addColOffset+1,
zTab
);
sqlite3DbFree(db, zCol);
@@ -490,7 +469,6 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
for(i=0; i<pNew->nCol; i++){
Column *pCol = &pNew->aCol[i];
pCol->zName = sqlite3DbStrDup(db, pCol->zName);
pCol->hName = sqlite3StrIHash(pCol->zName);
pCol->zColl = 0;
pCol->pDflt = 0;
}
@@ -590,7 +568,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_schema table.
** CREATE statement text for the sqlite_master table.
*/
sqlite3MayAbort(pParse);
zNew = sqlite3NameFromToken(db, pNew);
@@ -598,20 +576,21 @@ void sqlite3AlterRenameColumn(
assert( pNew->n>0 );
bQuote = sqlite3Isquote(pNew->z[0]);
sqlite3NestedParse(pParse,
"UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET "
"UPDATE \"%w\".%s 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,
zDb, MASTER_NAME,
zDb, pTab->zName, iCol, zNew, bQuote, iSchema==1,
pTab->zName
);
sqlite3NestedParse(pParse,
"UPDATE temp." DFLT_SCHEMA_TABLE " SET "
"UPDATE temp.%s 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
);
@@ -718,7 +697,7 @@ void *sqlite3RenameTokenMap(Parse *pParse, void *pPtr, Token *pToken){
RenameToken *pNew;
assert( pPtr || pParse->db->mallocFailed );
renameTokenCheckAll(pParse, pPtr);
if( ALWAYS(pParse->eParseMode!=PARSE_MODE_UNMAP) ){
if( pParse->eParseMode!=PARSE_MODE_UNMAP ){
pNew = sqlite3DbMallocZero(pParse->db, sizeof(RenameToken));
if( pNew ){
pNew->p = pPtr;
@@ -776,21 +755,6 @@ static void renameWalkWith(Walker *pWalker, Select *pSelect){
}
}
/*
** Unmap all tokens in the IdList object passed as the second argument.
*/
static void unmapColumnIdlistNames(
Parse *pParse,
IdList *pIdList
){
if( pIdList ){
int ii;
for(ii=0; ii<pIdList->nId; ii++){
sqlite3RenameTokenRemap(pParse, 0, (void*)pIdList->a[ii].zName);
}
}
}
/*
** Walker callback used by sqlite3RenameExprUnmap().
*/
@@ -812,7 +776,6 @@ static int renameUnmapSelectCb(Walker *pWalker, Select *p){
for(i=0; i<pSrc->nSrc; i++){
sqlite3RenameTokenRemap(pParse, 0, (void*)pSrc->a[i].zName);
if( sqlite3WalkExpr(pWalker, pSrc->a[i].pOn) ) return WRC_Abort;
unmapColumnIdlistNames(pParse, pSrc->a[i].pUsing);
}
}
@@ -1021,7 +984,6 @@ static void renameColumnIdlistNames(
}
}
/*
** Parse the SQL statement zSql using Parse object (*p). The Parse object
** is initialized by this function before it is used.
@@ -1163,7 +1125,7 @@ static int renameEditSql(
** successful. Otherwise, return an SQLite error code and leave an error
** message in the Parse object.
*/
static int renameResolveTrigger(Parse *pParse){
static int renameResolveTrigger(Parse *pParse, const char *zDb){
sqlite3 *db = pParse->db;
Trigger *pNew = pParse->pNewTrigger;
TriggerStep *pStep;
@@ -1194,30 +1156,17 @@ static int renameResolveTrigger(Parse *pParse){
if( pParse->nErr ) rc = pParse->rc;
}
if( rc==SQLITE_OK && pStep->zTarget ){
SrcList *pSrc = sqlite3TriggerStepSrc(pParse, pStep);
if( pSrc ){
int i;
for(i=0; i<pSrc->nSrc && rc==SQLITE_OK; i++){
struct SrcList_item *p = &pSrc->a[i];
p->iCursor = pParse->nTab++;
if( p->pSelect ){
sqlite3SelectPrep(pParse, p->pSelect, 0);
sqlite3ExpandSubquery(pParse, p);
assert( i>0 );
assert( pStep->pFrom->a[i-1].pSelect );
sqlite3SelectPrep(pParse, pStep->pFrom->a[i-1].pSelect, 0);
}else{
p->pTab = sqlite3LocateTableItem(pParse, 0, p);
if( p->pTab==0 ){
rc = SQLITE_ERROR;
}else{
p->pTab->nTabRef++;
rc = sqlite3ViewGetColumnNames(pParse, p->pTab);
}
}
}
sNC.pSrcList = pSrc;
if( rc==SQLITE_OK && pStep->pWhere ){
Table *pTarget = sqlite3LocateTable(pParse, 0, pStep->zTarget, zDb);
if( pTarget==0 ){
rc = SQLITE_ERROR;
}else if( SQLITE_OK==(rc = sqlite3ViewGetColumnNames(pParse, pTarget)) ){
SrcList sSrc;
memset(&sSrc, 0, sizeof(sSrc));
sSrc.nSrc = 1;
sSrc.a[0].zName = pStep->zTarget;
sSrc.a[0].pTab = pTarget;
sNC.pSrcList = &sSrc;
if( pStep->pWhere ){
rc = sqlite3ResolveExprNames(&sNC, pStep->pWhere);
}
if( rc==SQLITE_OK ){
@@ -1227,7 +1176,7 @@ static int renameResolveTrigger(Parse *pParse){
if( pStep->pUpsert ){
Upsert *pUpsert = pStep->pUpsert;
assert( rc==SQLITE_OK );
pUpsert->pUpsertSrc = pSrc;
pUpsert->pUpsertSrc = &sSrc;
sNC.uNC.pUpsert = pUpsert;
sNC.ncFlags = NC_UUpsert;
rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);
@@ -1244,9 +1193,6 @@ static int renameResolveTrigger(Parse *pParse){
sNC.ncFlags = 0;
}
sNC.pSrcList = 0;
sqlite3SrcListDelete(db, pSrc);
}else{
rc = SQLITE_NOMEM;
}
}
}
@@ -1275,12 +1221,6 @@ static void renameWalkTrigger(Walker *pWalker, Trigger *pTrigger){
sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere);
sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere);
}
if( pStep->pFrom ){
int i;
for(i=0; i<pStep->pFrom->nSrc; i++){
sqlite3WalkSelect(pWalker, pStep->pFrom->a[i].pSelect);
}
}
}
}
@@ -1439,7 +1379,7 @@ static void renameColumnFunc(
}else{
/* A trigger */
TriggerStep *pStep;
rc = renameResolveTrigger(&sParse);
rc = renameResolveTrigger(&sParse, (bTemp ? 0 : zDb));
if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
for(pStep=sParse.pNewTrigger->step_list; pStep; pStep=pStep->pNext){
@@ -1642,7 +1582,7 @@ static void renameTableFunc(
}
if( isLegacy==0 ){
rc = renameResolveTrigger(&sParse);
rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb);
if( rc==SQLITE_OK ){
renameWalkTrigger(&sWalker, pTrigger);
for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){
@@ -1729,7 +1669,7 @@ static void renameTableTest(
else if( sParse.pNewTrigger ){
if( isLegacy==0 ){
rc = renameResolveTrigger(&sParse);
rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb);
}
if( rc==SQLITE_OK ){
int i1 = sqlite3SchemaToIndex(db, sParse.pNewTrigger->pTabSchema);
+88 -160
View File
@@ -186,13 +186,8 @@ static void openStatTable(
sqlite3 *db = pParse->db;
Db *pDb;
Vdbe *v = sqlite3GetVdbe(pParse);
u32 aRoot[ArraySize(aTable)];
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) );
@@ -205,9 +200,8 @@ 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( i<nToOpen ){
if( aTable[i].zCols ){
/* 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
@@ -215,7 +209,7 @@ static void openStatTable(
sqlite3NestedParse(pParse,
"CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols
);
aRoot[i] = (u32)pParse->regRoot;
aRoot[i] = pParse->regRoot;
aCreateTbl[i] = OPFLAG_P2ISREG;
}
}else{
@@ -223,6 +217,7 @@ 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,
@@ -235,15 +230,15 @@ static void openStatTable(
#endif
}else{
/* The sqlite_stat[134] table already exists. Delete all rows. */
sqlite3VdbeAddOp2(v, OP_Clear, (int)aRoot[i], iDb);
sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb);
}
}
}
/* Open the sqlite_stat[134] tables for writing. */
for(i=0; i<nToOpen; i++){
for(i=0; aTable[i].zCols; i++){
assert( i<ArraySize(aTable) );
sqlite3VdbeAddOp4Int(v, OP_OpenWrite, iStatCur+i, (int)aRoot[i], iDb, 3);
sqlite3VdbeAddOp4Int(v, OP_OpenWrite, iStatCur+i, aRoot[i], iDb, 3);
sqlite3VdbeChangeP5(v, aCreateTbl[i]);
VdbeComment((v, aTable[i].zName));
}
@@ -280,12 +275,9 @@ struct StatSample {
};
struct StatAccum {
sqlite3 *db; /* Database connection, for malloc() */
tRowcnt nEst; /* Estimated number of rows */
tRowcnt nRow; /* Number of rows visited so far */
int nLimit; /* Analysis row-scan limit */
tRowcnt nRow; /* Number of rows in the entire table */
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 */
@@ -365,28 +357,27 @@ static void sampleCopy(StatAccum *p, StatSample *pTo, StatSample *pFrom){
static void statAccumDestructor(void *pOld){
StatAccum *p = (StatAccum*)pOld;
#ifdef SQLITE_ENABLE_STAT4
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);
}
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,L) SQL function. The four parameters
** Implementation of the stat_init(N,K,C) SQL function. The three 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: Estimated number of rows in the index
** L: A limit on the number of rows to scan, or 0 for no-limit
** C: The number of rows in the index (note 2)
**
** 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
@@ -407,10 +398,9 @@ 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 = sqlite3_context_db_handle(context); /* Database connection */
sqlite3 *db; /* Database connection */
#ifdef SQLITE_ENABLE_STAT4
/* Maximum number of samples. 0 if STAT4 data is not collected */
int mxSample = OptimizationEnabled(db,SQLITE_Stat4) ?SQLITE_STAT4_SAMPLES :0;
int mxSample = SQLITE_STAT4_SAMPLES;
#endif
/* Decode the three function arguments */
@@ -425,14 +415,13 @@ 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
if( mxSample ){
n += sizeof(tRowcnt)*nColUp /* StatAccum.anLt */
+ sizeof(StatSample)*(nCol+mxSample) /* StatAccum.aBest[], a[] */
+ sizeof(tRowcnt)*3*nColUp*(nCol+mxSample);
}
+ 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 ){
@@ -441,23 +430,20 @@ 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->nPSample = (tRowcnt)(p->nEst/(mxSample/3+1) + 1);
p->mxSample = mxSample;
p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[2])/(mxSample/3+1) + 1);
p->current.anLt = &p->current.anEq[nColUp];
p->iPrn = 0x689e962d*(u32)nCol ^ 0xd0944565*(u32)sqlite3_value_int(argv[2]);
@@ -485,7 +471,7 @@ static void statInit(
sqlite3_result_blob(context, p, sizeof(*p), statAccumDestructor);
}
static const FuncDef statInitFuncdef = {
4, /* nArg */
2+IsStat4, /* nArg */
SQLITE_UTF8, /* funcFlags */
0, /* pUserData */
0, /* pNext */
@@ -689,13 +675,10 @@ static void samplePushPrevious(StatAccum *p, int iChng){
** R Rowid for the current row. Might be a key record for
** WITHOUT ROWID 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.
** 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 R parameter is only used for STAT4
*/
@@ -721,7 +704,7 @@ static void statPush(
}else{
/* Second and subsequent calls get processed here */
#ifdef SQLITE_ENABLE_STAT4
if( p->mxSample ) samplePushPrevious(p, iChng);
samplePushPrevious(p, iChng);
#endif
/* Update anDLt[], anLt[] and anEq[] to reflect the values that apply
@@ -732,25 +715,26 @@ static void statPush(
for(i=iChng; i<p->nCol; i++){
p->current.anDLt[i]++;
#ifdef SQLITE_ENABLE_STAT4
if( p->mxSample ) p->current.anLt[i] += p->current.anEq[i];
p->current.anLt[i] += p->current.anEq[i];
#endif
p->current.anEq[i] = 1;
}
}
p->nRow++;
#ifdef SQLITE_ENABLE_STAT4
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;
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];
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;
@@ -766,14 +750,9 @@ 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);
}
#endif
}
static const FuncDef statPushFuncdef = {
2+IsStat4, /* nArg */
SQLITE_UTF8, /* funcFlags */
@@ -825,7 +804,6 @@ 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 );
@@ -861,8 +839,7 @@ static void statGet(
return;
}
sqlite3_snprintf(24, zRet, "%llu",
p->nSkipAhead ? (u64)p->nEst : (u64)p->nRow);
sqlite3_snprintf(24, zRet, "%llu", (u64)p->nRow);
z = zRet + sqlite3Strlen30(zRet);
for(i=0; i<p->nKeyCol; i++){
u64 nDistinct = p->current.anDLt[i] + 1;
@@ -938,43 +915,19 @@ static const FuncDef statGetFuncdef = {
{0}
};
static void callStatGet(Parse *pParse, int regStat, int iParam, int regOut){
static void callStatGet(Parse *pParse, int regStat4, int iParam, int regOut){
#ifdef SQLITE_ENABLE_STAT4
sqlite3VdbeAddOp2(pParse->pVdbe, OP_Integer, iParam, regStat+1);
sqlite3VdbeAddOp2(pParse->pVdbe, OP_Integer, iParam, regStat4+1);
#elif SQLITE_DEBUG
assert( iParam==STAT_GET_STAT1 );
#else
UNUSED_PARAMETER( iParam );
#endif
assert( regOut!=regStat && regOut!=regStat+1 );
sqlite3VdbeAddFunctionCall(pParse, 0, regStat, regOut, 1+IsStat4,
assert( regOut!=regStat4 && regOut!=regStat4+1 );
sqlite3VdbeAddFunctionCall(pParse, 0, regStat4, 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.
@@ -997,11 +950,12 @@ 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 regStat = iMem++; /* Register to hold StatAccum object */
int regStat4 = 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 */
@@ -1129,26 +1083,17 @@ 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) estimated number of rows in the index,
** (3) the number of rows in the index,
**
**
** The third argument is only used for STAT4
*/
sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat+1);
assert( regRowid==regStat+2 );
sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regRowid);
#ifdef SQLITE_ENABLE_STAT4
if( OptimizationEnabled(db, SQLITE_Stat4) ){
sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regTemp);
addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
VdbeCoverage(v);
}else
sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+3);
#endif
{
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,
sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1);
sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2);
sqlite3VdbeAddFunctionCall(pParse, 0, regStat4+1, regStat4, 2+IsStat4,
&statInitFuncdef, 0);
/* Implementation of the following:
@@ -1159,6 +1104,8 @@ static void analyzeOneTable(
** goto next_push_0;
**
*/
addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng);
addrNextRow = sqlite3VdbeCurrentAddr(v);
@@ -1191,7 +1138,6 @@ 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);
@@ -1212,7 +1158,6 @@ 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);
@@ -1226,46 +1171,30 @@ static void analyzeOneTable(
** if !eof(csr) goto next_row;
*/
#ifdef SQLITE_ENABLE_STAT4
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);
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));
}
sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid);
sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol);
}
#endif
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);
}
}
assert( regChng==(regStat4+1) );
sqlite3VdbeAddFunctionCall(pParse, 1, regStat4, regTemp, 2+IsStat4,
&statPushFuncdef, 0);
sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
/* Add the entry to the stat1 table. */
callStatGet(pParse, regStat, STAT_GET_STAT1, regStat1);
callStatGet(pParse, regStat4, 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);
@@ -1277,7 +1206,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;
@@ -1291,12 +1220,12 @@ static void analyzeOneTable(
pParse->nMem = MAX(pParse->nMem, regCol+nCol);
addrNext = sqlite3VdbeCurrentAddr(v);
callStatGet(pParse, regStat, STAT_GET_ROWID, regSampleRowid);
callStatGet(pParse, regStat4, STAT_GET_ROWID, regSampleRowid);
addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regSampleRowid);
VdbeCoverage(v);
callStatGet(pParse, regStat, STAT_GET_NEQ, regEq);
callStatGet(pParse, regStat, STAT_GET_NLT, regLt);
callStatGet(pParse, regStat, STAT_GET_NDLT, regDLt);
callStatGet(pParse, regStat4, STAT_GET_NEQ, regEq);
callStatGet(pParse, regStat4, STAT_GET_NLT, regLt);
callStatGet(pParse, regStat4, STAT_GET_NDLT, regDLt);
sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0);
VdbeCoverage(v);
for(i=0; i<nCol; i++){
@@ -1772,7 +1701,6 @@ static int loadStatTbl(
}
pSpace = (tRowcnt*)&pIdx->aSample[nSample];
pIdx->aAvgEq = pSpace; pSpace += nIdxCol;
pIdx->pTable->tabFlags |= TF_HasStat4;
for(i=0; i<nSample; i++){
pIdx->aSample[i].anEq = pSpace; pSpace += nIdxCol;
pIdx->aSample[i].anLt = pSpace; pSpace += nIdxCol;
+115 -101
View File
@@ -45,17 +45,6 @@ static int resolveAttachExpr(NameContext *pName, Expr *pExpr)
return rc;
}
/*
** Return true if zName points to a name that may be used to refer to
** database iDb attached to handle db.
*/
int sqlite3DbIsNamed(sqlite3 *db, int iDb, const char *zName){
return (
sqlite3StrICmp(db->aDb[iDb].zDbSName, zName)==0
|| (iDb==0 && sqlite3StrICmp("main", zName)==0)
);
}
/*
** An SQL user-function registered to do the work of an ATTACH statement. The
** three arguments to the function come directly from an attach statement:
@@ -128,8 +117,9 @@ static void attachFunc(
goto attach_error;
}
for(i=0; i<db->nDb; i++){
assert( zName );
if( sqlite3DbIsNamed(db, i, zName) ){
char *z = db->aDb[i].zDbSName;
assert( z && zName );
if( sqlite3StrICmp(z, zName)==0 ){
zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName);
goto attach_error;
}
@@ -282,7 +272,7 @@ static void detachFunc(
for(i=0; i<db->nDb; i++){
pDb = &db->aDb[i];
if( pDb->pBt==0 ) continue;
if( sqlite3DbIsNamed(db, i, zName) ) break;
if( sqlite3StrICmp(pDb->zDbSName, zName)==0 ) break;
}
if( i>=db->nDb ){
@@ -293,9 +283,7 @@ static void detachFunc(
sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName);
goto detach_error;
}
if( sqlite3BtreeTxnState(pDb->pBt)!=SQLITE_TXN_NONE
|| sqlite3BtreeIsInBackup(pDb->pBt)
){
if( sqlite3BtreeIsInReadTrans(pDb->pBt) || sqlite3BtreeIsInBackup(pDb->pBt) ){
sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName);
goto detach_error;
}
@@ -433,63 +421,6 @@ void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
}
#endif /* SQLITE_OMIT_ATTACH */
/*
** Expression callback used by sqlite3FixAAAA() routines.
*/
static int fixExprCb(Walker *p, Expr *pExpr){
DbFixer *pFix = p->u.pFix;
if( !pFix->bTemp ) ExprSetProperty(pExpr, EP_FromDDL);
if( pExpr->op==TK_VARIABLE ){
if( pFix->pParse->db->init.busy ){
pExpr->op = TK_NULL;
}else{
sqlite3ErrorMsg(pFix->pParse, "%s cannot use variables", pFix->zType);
return WRC_Abort;
}
}
return WRC_Continue;
}
/*
** Select callback used by sqlite3FixAAAA() routines.
*/
static int fixSelectCb(Walker *p, Select *pSelect){
DbFixer *pFix = p->u.pFix;
int i;
struct SrcList_item *pItem;
sqlite3 *db = pFix->pParse->db;
int iDb = sqlite3FindDbName(db, pFix->zDb);
SrcList *pList = pSelect->pSrc;
if( NEVER(pList==0) ) return WRC_Continue;
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
if( pFix->bTemp==0 ){
if( pItem->zDatabase && iDb!=sqlite3FindDbName(db, pItem->zDatabase) ){
sqlite3ErrorMsg(pFix->pParse,
"%s %T cannot reference objects in database %s",
pFix->zType, pFix->pName, pItem->zDatabase);
return WRC_Abort;
}
sqlite3DbFree(db, pItem->zDatabase);
pItem->zDatabase = 0;
pItem->pSchema = pFix->pSchema;
pItem->fg.fromDDL = 1;
}
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
if( sqlite3WalkExpr(&pFix->w, pList->a[i].pOn) ) return WRC_Abort;
#endif
}
if( pSelect->pWith ){
int i;
for(i=0; i<pSelect->pWith->nCte; i++){
if( sqlite3WalkSelect(p, pSelect->pWith->a[i].pSelect) ){
return WRC_Abort;
}
}
}
return WRC_Continue;
}
/*
** Initialize a DbFixer structure. This routine must be called prior
** to passing the structure to one of the sqliteFixAAAA() routines below.
@@ -501,7 +432,9 @@ void sqlite3FixInit(
const char *zType, /* "view", "trigger", or "index" */
const Token *pName /* Name of the view, trigger, or index */
){
sqlite3 *db = pParse->db;
sqlite3 *db;
db = pParse->db;
assert( db->nDb>iDb );
pFix->pParse = pParse;
pFix->zDb = db->aDb[iDb].zDbSName;
@@ -509,13 +442,6 @@ void sqlite3FixInit(
pFix->zType = zType;
pFix->pName = pName;
pFix->bTemp = (iDb==1);
pFix->w.pParse = pParse;
pFix->w.xExprCallback = fixExprCb;
pFix->w.xSelectCallback = fixSelectCb;
pFix->w.xSelectCallback2 = 0;
pFix->w.walkerDepth = 0;
pFix->w.eCode = 0;
pFix->w.u.pFix = pFix;
}
/*
@@ -536,27 +462,114 @@ int sqlite3FixSrcList(
DbFixer *pFix, /* Context of the fixation */
SrcList *pList /* The Source list to check and modify */
){
int res = 0;
if( pList ){
Select s;
memset(&s, 0, sizeof(s));
s.pSrc = pList;
res = sqlite3WalkSelect(&pFix->w, &s);
int i;
const char *zDb;
struct SrcList_item *pItem;
if( NEVER(pList==0) ) return 0;
zDb = pFix->zDb;
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
if( pFix->bTemp==0 ){
if( pItem->zDatabase && sqlite3StrICmp(pItem->zDatabase, zDb) ){
sqlite3ErrorMsg(pFix->pParse,
"%s %T cannot reference objects in database %s",
pFix->zType, pFix->pName, pItem->zDatabase);
return 1;
}
sqlite3DbFree(pFix->pParse->db, pItem->zDatabase);
pItem->zDatabase = 0;
pItem->pSchema = pFix->pSchema;
pItem->fg.fromDDL = 1;
}
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
#endif
if( pItem->fg.isTabFunc && sqlite3FixExprList(pFix, pItem->u1.pFuncArg) ){
return 1;
}
}
return res;
return 0;
}
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
int sqlite3FixSelect(
DbFixer *pFix, /* Context of the fixation */
Select *pSelect /* The SELECT statement to be fixed to one database */
){
return sqlite3WalkSelect(&pFix->w, pSelect);
while( pSelect ){
if( sqlite3FixExprList(pFix, pSelect->pEList) ){
return 1;
}
if( sqlite3FixSrcList(pFix, pSelect->pSrc) ){
return 1;
}
if( sqlite3FixExpr(pFix, pSelect->pWhere) ){
return 1;
}
if( sqlite3FixExprList(pFix, pSelect->pGroupBy) ){
return 1;
}
if( sqlite3FixExpr(pFix, pSelect->pHaving) ){
return 1;
}
if( sqlite3FixExprList(pFix, pSelect->pOrderBy) ){
return 1;
}
if( sqlite3FixExpr(pFix, pSelect->pLimit) ){
return 1;
}
if( pSelect->pWith ){
int i;
for(i=0; i<pSelect->pWith->nCte; i++){
if( sqlite3FixSelect(pFix, pSelect->pWith->a[i].pSelect) ){
return 1;
}
}
}
pSelect = pSelect->pPrior;
}
return 0;
}
int sqlite3FixExpr(
DbFixer *pFix, /* Context of the fixation */
Expr *pExpr /* The expression to be fixed to one database */
){
return sqlite3WalkExpr(&pFix->w, pExpr);
while( pExpr ){
if( !pFix->bTemp ) ExprSetProperty(pExpr, EP_FromDDL);
if( pExpr->op==TK_VARIABLE ){
if( pFix->pParse->db->init.busy ){
pExpr->op = TK_NULL;
}else{
sqlite3ErrorMsg(pFix->pParse, "%s cannot use variables", pFix->zType);
return 1;
}
}
if( ExprHasProperty(pExpr, EP_TokenOnly|EP_Leaf) ) break;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1;
}else{
if( sqlite3FixExprList(pFix, pExpr->x.pList) ) return 1;
}
if( sqlite3FixExpr(pFix, pExpr->pRight) ){
return 1;
}
pExpr = pExpr->pLeft;
}
return 0;
}
int sqlite3FixExprList(
DbFixer *pFix, /* Context of the fixation */
ExprList *pList /* The expression to be fixed to one database */
){
int i;
struct ExprList_item *pItem;
if( pList==0 ) return 0;
for(i=0, pItem=pList->a; i<pList->nExpr; i++, pItem++){
if( sqlite3FixExpr(pFix, pItem->pExpr) ){
return 1;
}
}
return 0;
}
#endif
@@ -566,20 +579,22 @@ int sqlite3FixTriggerStep(
TriggerStep *pStep /* The trigger step be fixed to one database */
){
while( pStep ){
if( sqlite3WalkSelect(&pFix->w, pStep->pSelect)
|| sqlite3WalkExpr(&pFix->w, pStep->pWhere)
|| sqlite3WalkExprList(&pFix->w, pStep->pExprList)
|| sqlite3FixSrcList(pFix, pStep->pFrom)
){
if( sqlite3FixSelect(pFix, pStep->pSelect) ){
return 1;
}
if( sqlite3FixExpr(pFix, pStep->pWhere) ){
return 1;
}
if( sqlite3FixExprList(pFix, pStep->pExprList) ){
return 1;
}
#ifndef SQLITE_OMIT_UPSERT
if( pStep->pUpsert ){
Upsert *pUp = pStep->pUpsert;
if( sqlite3WalkExprList(&pFix->w, pUp->pUpsertTarget)
|| sqlite3WalkExpr(&pFix->w, pUp->pUpsertTargetWhere)
|| sqlite3WalkExprList(&pFix->w, pUp->pUpsertSet)
|| sqlite3WalkExpr(&pFix->w, pUp->pUpsertWhere)
if( sqlite3FixExprList(pFix, pUp->pUpsertTarget)
|| sqlite3FixExpr(pFix, pUp->pUpsertTargetWhere)
|| sqlite3FixExprList(pFix, pUp->pUpsertSet)
|| sqlite3FixExpr(pFix, pUp->pUpsertWhere)
){
return 1;
}
@@ -587,7 +602,6 @@ int sqlite3FixTriggerStep(
#endif
pStep = pStep->pNext;
}
return 0;
}
#endif
+5 -1
View File
@@ -209,7 +209,11 @@ int sqlite3AuthCheck(
** or if the parser is being invoked from within sqlite3_declare_vtab.
*/
assert( !IN_RENAME_OBJECT || db->xAuth==0 );
if( db->xAuth==0 || db->init.busy || IN_SPECIAL_PARSE ){
if( db->init.busy || IN_SPECIAL_PARSE ){
return SQLITE_OK;
}
if( db->xAuth==0 ){
return SQLITE_OK;
}
+5 -5
View File
@@ -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),0,0);
rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),-1,0);
return rc;
}
@@ -123,7 +123,7 @@ static int setDestPgsz(sqlite3_backup *p){
** message in database handle db.
*/
static int checkReadTransaction(sqlite3 *db, Btree *p){
if( sqlite3BtreeTxnState(p)!=SQLITE_TXN_NONE ){
if( sqlite3BtreeIsInReadTrans(p) ){
sqlite3ErrorWithMsg(db, SQLITE_ERROR, "destination database is in use");
return SQLITE_ERROR;
}
@@ -354,7 +354,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
** one now. If a transaction is opened here, then it will be closed
** before this function exits.
*/
if( rc==SQLITE_OK && SQLITE_TXN_NONE==sqlite3BtreeTxnState(p->pSrc) ){
if( rc==SQLITE_OK && 0==sqlite3BtreeIsInReadTrans(p->pSrc) ){
rc = sqlite3BtreeBeginTrans(p->pSrc, 0, 0);
bCloseTrans = 1;
}
@@ -726,7 +726,7 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
sqlite3BtreeEnter(pTo);
sqlite3BtreeEnter(pFrom);
assert( sqlite3BtreeTxnState(pTo)==SQLITE_TXN_WRITE );
assert( sqlite3BtreeIsInTrans(pTo) );
pFd = sqlite3PagerFile(sqlite3BtreePager(pTo));
if( pFd->pMethods ){
i64 nByte = sqlite3BtreeGetPageSize(pFrom)*(i64)sqlite3BtreeLastPage(pFrom);
@@ -762,7 +762,7 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
sqlite3PagerClearCache(sqlite3BtreePager(b.pDest));
}
assert( sqlite3BtreeTxnState(pTo)!=SQLITE_TXN_WRITE );
assert( sqlite3BtreeIsInTrans(pTo)==0 );
copy_finished:
sqlite3BtreeLeave(pFrom);
sqlite3BtreeLeave(pTo);

Some files were not shown because too many files have changed in this diff Show More