Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bdfea5c025 |
@@ -1,6 +0,0 @@
|
||||
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.
|
||||
+25
-53
@@ -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 \
|
||||
@@ -424,7 +422,6 @@ TESTSRC = \
|
||||
$(TOP)/src/test_tclsh.c \
|
||||
$(TOP)/src/test_tclvar.c \
|
||||
$(TOP)/src/test_thread.c \
|
||||
$(TOP)/src/test_vdbecov.c \
|
||||
$(TOP)/src/test_vfs.c \
|
||||
$(TOP)/src/test_windirent.c \
|
||||
$(TOP)/src/test_window.c \
|
||||
@@ -455,7 +452,6 @@ TESTSRC += \
|
||||
$(TOP)/ext/misc/nextchar.c \
|
||||
$(TOP)/ext/misc/normalize.c \
|
||||
$(TOP)/ext/misc/percentile.c \
|
||||
$(TOP)/ext/misc/prefixes.c \
|
||||
$(TOP)/ext/misc/regexp.c \
|
||||
$(TOP)/ext/misc/remember.c \
|
||||
$(TOP)/ext/misc/series.c \
|
||||
@@ -504,7 +500,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 \
|
||||
@@ -593,8 +588,7 @@ FUZZDATA = \
|
||||
$(TOP)/test/fuzzdata4.db \
|
||||
$(TOP)/test/fuzzdata5.db \
|
||||
$(TOP)/test/fuzzdata6.db \
|
||||
$(TOP)/test/fuzzdata7.db \
|
||||
$(TOP)/test/fuzzdata8.db
|
||||
$(TOP)/test/fuzzdata7.db
|
||||
|
||||
# Standard options to testfixture
|
||||
#
|
||||
@@ -610,20 +604,13 @@ 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
|
||||
SHELL_OPT += -DSQLITE_INTROSPECTION_PRAGMAS
|
||||
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
|
||||
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ
|
||||
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_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 =
|
||||
|
||||
@@ -693,29 +680,14 @@ DBFUZZ2_OPTS = \
|
||||
-DSQLITE_ENABLE_DESERIALIZE \
|
||||
-DSQLITE_DEBUG \
|
||||
-DSQLITE_ENABLE_DBSTAT_VTAB \
|
||||
-DSQLITE_ENABLE_BYTECODE_VTAB \
|
||||
-DSQLITE_ENABLE_RTREE \
|
||||
-DSQLITE_ENABLE_FTS4 \
|
||||
-DSQLITE_ENABLE_FTS5
|
||||
-DSQLITE_EANBLE_FTS5
|
||||
|
||||
dbfuzz2$(TEXE): $(TOP)/test/dbfuzz2.c sqlite3.c sqlite3.h
|
||||
$(CC) $(OPT_FEATURE_FLAGS) $(OPTS) -I. -g -O0 \
|
||||
-DSTANDALONE -o dbfuzz2 \
|
||||
$(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c $(TLIBS)
|
||||
mkdir -p dbfuzz2-dir
|
||||
cp $(TOP)/test/dbfuzz2-seed* dbfuzz2-dir
|
||||
|
||||
dbfuzz2-asan: $(TOP)/test/dbfuzz2.c sqlite3.c sqlite3.h
|
||||
dbfuzz2: $(TOP)/test/dbfuzz2.c sqlite3.c sqlite3.h
|
||||
clang-6.0 $(OPT_FEATURE_FLAGS) $(OPTS) -I. -g -O0 \
|
||||
-fsanitize=fuzzer,undefined,address -o dbfuzz2-asan \
|
||||
$(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c $(TLIBS)
|
||||
mkdir -p dbfuzz2-dir
|
||||
cp $(TOP)/test/dbfuzz2-seed* dbfuzz2-dir
|
||||
|
||||
dbfuzz2-msan: $(TOP)/test/dbfuzz2.c sqlite3.c sqlite3.h
|
||||
clang-6.0 $(OPT_FEATURE_FLAGS) $(OPTS) -I. -g -O0 \
|
||||
-fsanitize=fuzzer,undefined,memory -o dbfuzz2-msan \
|
||||
$(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c $(TLIBS)
|
||||
-fsanitize=fuzzer,undefined,address -o dbfuzz2 \
|
||||
$(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c
|
||||
mkdir -p dbfuzz2-dir
|
||||
cp $(TOP)/test/dbfuzz2-seed* dbfuzz2-dir
|
||||
|
||||
@@ -1010,9 +982,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
|
||||
|
||||
@@ -1059,9 +1028,12 @@ opcodes.h: parse.h $(TOP)/src/vdbe.c $(TOP)/tool/mkopcodeh.tcl
|
||||
#
|
||||
parse.h: parse.c
|
||||
|
||||
parse.c: $(TOP)/src/parse.y lemon$(BEXE)
|
||||
parse.c: $(TOP)/src/parse.y lemon$(BEXE) $(TOP)/tool/addopcodes.tcl
|
||||
cp $(TOP)/src/parse.y .
|
||||
./lemon$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) -S parse.y
|
||||
rm -f parse.h
|
||||
./lemon$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) parse.y
|
||||
mv parse.h parse.h.temp
|
||||
$(TCLSH_CMD) $(TOP)/tool/addopcodes.tcl parse.h.temp >parse.h
|
||||
|
||||
sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest mksourceid$(BEXE) $(TOP)/VERSION
|
||||
$(TCLSH_CMD) $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
|
||||
@@ -1078,11 +1050,9 @@ SHELL_SRC = \
|
||||
$(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 \
|
||||
$(TOP)/ext/misc/memtrace.c \
|
||||
$(TOP)/src/test_windirent.c
|
||||
|
||||
shell.c: $(SHELL_SRC) $(TOP)/tool/mkshellc.tcl
|
||||
@@ -1156,10 +1126,10 @@ fts3_write.lo: $(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR)
|
||||
rtree.lo: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/rtree/rtree.c
|
||||
|
||||
userauth.lo: $(TOP)/ext/userauth/userauth.c $(HDR) $(EXTHDR)
|
||||
sqlite3session.lo: $(TOP)/ext/userauth/userauth.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/userauth/userauth.c
|
||||
|
||||
sqlite3session.lo: $(TOP)/ext/session/sqlite3session.c $(HDR) $(EXTHDR)
|
||||
userauth.lo: $(TOP)/ext/session/sqlite3session.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/session/sqlite3session.c
|
||||
|
||||
json1.lo: $(TOP)/ext/misc/json1.c
|
||||
@@ -1187,10 +1157,10 @@ FTS5_SRC = \
|
||||
$(TOP)/ext/fts5/fts5_varint.c \
|
||||
$(TOP)/ext/fts5/fts5_vocab.c \
|
||||
|
||||
fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon$(BEXE)
|
||||
fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon
|
||||
cp $(TOP)/ext/fts5/fts5parse.y .
|
||||
rm -f fts5parse.h
|
||||
./lemon$(BEXE) $(OPTS) -S fts5parse.y
|
||||
./lemon$(BEXE) $(OPTS) fts5parse.y
|
||||
|
||||
fts5parse.h: fts5parse.c
|
||||
|
||||
@@ -1220,7 +1190,6 @@ 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_SRC0 = $(TESTSRC2) libsqlite3.la
|
||||
@@ -1253,6 +1222,10 @@ fuzztest: fuzzcheck$(TEXE) $(FUZZDATA) sessionfuzz$(TEXE) $(TOP)/test/sessionfuz
|
||||
./fuzzcheck$(TEXE) $(FUZZDATA)
|
||||
./sessionfuzz$(TEXE) run $(TOP)/test/sessionfuzz-data1.db
|
||||
|
||||
fastfuzztest: fuzzcheck$(TEXE) $(FUZZDATA) sessionfuzz$(TEXE) $(TOP)/test/sessionfuzz-data1.db
|
||||
./fuzzcheck$(TEXE) --limit-mem 100M $(FUZZDATA)
|
||||
./sessionfuzz$(TEXE) run $(TOP)/test/sessionfuzz-data1.db
|
||||
|
||||
valgrindfuzz: fuzzcheck$(TEXT) $(FUZZDATA) sessionfuzz$(TEXE) $(TOP)/test/sessionfuzz-data1.db
|
||||
valgrind ./fuzzcheck$(TEXE) --cell-size-check --limit-mem 10M --timeout 600 $(FUZZDATA)
|
||||
valgrind ./sessionfuzz$(TEXE) run $(TOP)/test/sessionfuzz-data1.db
|
||||
@@ -1270,7 +1243,7 @@ quicktest: ./testfixture$(TEXE)
|
||||
# This is the common case. Run many tests that do not take too long,
|
||||
# including fuzzcheck, sqlite3_analyzer, and sqldiff tests.
|
||||
#
|
||||
test: fuzztest sourcetest $(TESTPROGS) tcltest
|
||||
test: fastfuzztest sourcetest $(TESTPROGS) tcltest
|
||||
|
||||
# Run a test using valgrind. This can take a really long time
|
||||
# because valgrind is so much slower than a native machine.
|
||||
@@ -1339,7 +1312,7 @@ showshm$(TEXE): $(TOP)/tool/showshm.c
|
||||
$(LTLINK) -o $@ $(TOP)/tool/showshm.c
|
||||
|
||||
index_usage$(TEXE): $(TOP)/tool/index_usage.c sqlite3.lo
|
||||
$(LTLINK) $(SHELL_OPT) -o $@ $(TOP)/tool/index_usage.c sqlite3.lo $(TLIBS)
|
||||
$(LTLINK) -o $@ $(TOP)/tool/index_usage.c sqlite3.lo $(TLIBS)
|
||||
|
||||
changeset$(TEXE): $(TOP)/ext/session/changeset.c sqlite3.lo
|
||||
$(LTLINK) -o $@ $(TOP)/ext/session/changeset.c sqlite3.lo $(TLIBS)
|
||||
@@ -1378,9 +1351,8 @@ loadfts$(EXE): $(TOP)/tool/loadfts.c libsqlite3.la
|
||||
# releasetest.tcl script.
|
||||
#
|
||||
VALIDIDS=' sqlite3(changeset|changegroup|session)?_'
|
||||
checksymbols: sqlite3.o
|
||||
nm -g --defined-only sqlite3.o
|
||||
nm -g --defined-only sqlite3.o | egrep -v $(VALIDIDS); test $$? -ne 0
|
||||
checksymbols: sqlite3.lo
|
||||
nm -g --defined-only sqlite3.lo | egrep -v $(VALIDIDS); test $$? -ne 0
|
||||
echo '0 errors out of 1 tests'
|
||||
|
||||
# Build the amalgamation-autoconf package. The amalamgation-tarball target builds
|
||||
@@ -1429,7 +1401,7 @@ install: sqlite3$(TEXE) lib_install sqlite3.h sqlite3.pc ${HAVE_TCL:1=tcl_instal
|
||||
$(INSTALL) -m 0644 sqlite3.pc $(DESTDIR)$(pkgconfigdir)
|
||||
|
||||
pkgIndex.tcl:
|
||||
echo 'package ifneeded sqlite3 $(RELEASE) [list load [file join $$dir libtclsqlite3[info sharedlibextension]] sqlite3]' > $@
|
||||
echo 'package ifneeded sqlite3 $(RELEASE) [list load $(TCLLIBDIR)/libtclsqlite3$(SHLIB_SUFFIX) sqlite3]' > $@
|
||||
tcl_install: lib_install libtclsqlite3.la pkgIndex.tcl
|
||||
$(INSTALL) -d $(DESTDIR)$(TCLLIBDIR)
|
||||
$(LTINSTALL) libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)
|
||||
|
||||
+17
-9
@@ -19,7 +19,7 @@ TOP = ../sqlite
|
||||
#### C Compiler and options for use in building executables that
|
||||
# will run on the platform that is doing the build.
|
||||
#
|
||||
BCC = gcc -g -O0
|
||||
BCC = gcc -g -O2
|
||||
#BCC = /opt/ancic/bin/c89 -0
|
||||
|
||||
#### If the target operating system supports the "usleep()" system
|
||||
@@ -38,8 +38,8 @@ THREADSAFE = -DTHREADSAFE=0
|
||||
#### Specify any extra linker options needed to make the library
|
||||
# thread safe
|
||||
#
|
||||
THREADLIB = -lpthread -lm -ldl
|
||||
#THREADLIB =
|
||||
#THREADLIB = -lpthread
|
||||
THREADLIB =
|
||||
|
||||
#### Specify any extra libraries needed to access required functions.
|
||||
#
|
||||
@@ -54,9 +54,11 @@ TLIBS =
|
||||
# You can make the library go almost twice as fast if you compile
|
||||
# with -DNDEBUG=1
|
||||
#
|
||||
OPTS += -DSQLITE_DEBUG=1
|
||||
OPTS += -DSQLITE_ENABLE_WHERETRACE
|
||||
OPTS += -DSQLITE_ENABLE_SELECTTRACE
|
||||
#OPTS = -DSQLITE_DEBUG=2
|
||||
#OPTS = -DSQLITE_DEBUG=1
|
||||
#OPTS =
|
||||
OPTS = -DNDEBUG=1
|
||||
OPTS += -DHAVE_FDATASYNC=1
|
||||
|
||||
#### The suffix to add to executable files. ".exe" for windows.
|
||||
# Nothing for unix.
|
||||
@@ -68,7 +70,7 @@ EXE =
|
||||
# will run on the target platform. This is usually the same
|
||||
# as BCC, unless you are cross-compiling.
|
||||
#
|
||||
TCC = gcc -O0
|
||||
TCC = gcc -O6
|
||||
#TCC = gcc -g -O0 -Wall
|
||||
#TCC = gcc -g -O0 -Wall -fprofile-arcs -ftest-coverage
|
||||
#TCC = /opt/mingw/bin/i386-mingw32-gcc -O6
|
||||
@@ -89,12 +91,18 @@ SHPREFIX = lib
|
||||
|
||||
#### Extra compiler options needed for programs that use the TCL library.
|
||||
#
|
||||
TCL_FLAGS = -I/home/drh/tcl/include/tcl8.6
|
||||
#TCL_FLAGS =
|
||||
#TCL_FLAGS = -DSTATIC_BUILD=1
|
||||
TCL_FLAGS = -I/home/drh/tcltk/8.5linux
|
||||
#TCL_FLAGS = -I/home/drh/tcltk/8.5win -DSTATIC_BUILD=1
|
||||
#TCL_FLAGS = -I/home/drh/tcltk/8.3hpux
|
||||
|
||||
#### Linker options needed to link against the TCL library.
|
||||
#
|
||||
#LIBTCL = -ltcl -lm -ldl
|
||||
LIBTCL = /home/drh/tcl/lib/libtcl8.6.a -lm -lpthread -ldl -lz
|
||||
LIBTCL = /home/drh/tcltk/8.5linux/libtcl8.5g.a -lm -ldl
|
||||
#LIBTCL = /home/drh/tcltk/8.5win/libtcl85s.a -lmsvcrt
|
||||
#LIBTCL = /home/drh/tcltk/8.3hpux/libtcl8.3.a -ldld -lm -lc
|
||||
|
||||
#### Additional objects for SQLite library when TCL support is enabled.
|
||||
#TCLOBJ =
|
||||
|
||||
+24
-86
@@ -73,7 +73,7 @@ API_ARMOR = 0
|
||||
!IFNDEF NO_WARN
|
||||
!IF $(USE_FULLWARN)!=0
|
||||
NO_WARN = -wd4054 -wd4055 -wd4100 -wd4127 -wd4130 -wd4152 -wd4189 -wd4206
|
||||
NO_WARN = $(NO_WARN) -wd4210 -wd4232 -wd4244 -wd4305 -wd4306 -wd4702 -wd4706
|
||||
NO_WARN = $(NO_WARN) -wd4210 -wd4232 -wd4305 -wd4306 -wd4702 -wd4706
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
@@ -248,12 +248,6 @@ OPTIMIZATIONS = 2
|
||||
SESSION = 0
|
||||
!ENDIF
|
||||
|
||||
# Set this to non-0 to enable support for the rbu extension.
|
||||
#
|
||||
!IFNDEF RBU
|
||||
RBU = 0
|
||||
!ENDIF
|
||||
|
||||
# Set the source code file to be used by executables and libraries when
|
||||
# they need the amalgamation.
|
||||
#
|
||||
@@ -326,13 +320,6 @@ SQLITETCLH = sqlite_tcl.h
|
||||
SQLITETCLDECLSH = sqlite_tclDecls.h
|
||||
!ENDIF
|
||||
|
||||
# This is the name to use for the dynamic link library (DLL) containing the
|
||||
# Tcl bindings for SQLite.
|
||||
#
|
||||
!IFNDEF SQLITE3TCLDLL
|
||||
SQLITE3TCLDLL = tclsqlite3.dll
|
||||
!ENDIF
|
||||
|
||||
# These are the additional targets that the targets that integrate with the
|
||||
# Tcl library should depend on when compiling, etc.
|
||||
#
|
||||
@@ -357,7 +344,7 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_JSON1=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBSTAT_VTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_INTROSPECTION_PRAGMAS=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DESERIALIZE=1
|
||||
!ENDIF
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
|
||||
@@ -371,13 +358,6 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SESSION=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK=1
|
||||
!ENDIF
|
||||
|
||||
# Should the rbu extension be enabled? If so, add compilation options
|
||||
# to enable it.
|
||||
#
|
||||
!IF $(RBU)!=0
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RBU=1
|
||||
!ENDIF
|
||||
|
||||
# These are the "extended" SQLite compilation options used when compiling for
|
||||
# the Windows 10 platform.
|
||||
#
|
||||
@@ -515,9 +495,9 @@ UCRTLIBPATH = $(UCRTLIBPATH:\\=\)
|
||||
# will run on the platform that is doing the build.
|
||||
#
|
||||
!IF $(USE_FULLWARN)!=0
|
||||
BCC = $(NCC) -nologo -W4 -Fd$*.pdb $(CCOPTS) $(BCCOPTS)
|
||||
BCC = $(NCC) -nologo -W4 $(CCOPTS) $(BCCOPTS)
|
||||
!ELSE
|
||||
BCC = $(NCC) -nologo -W3 -Fd$*.pdb $(CCOPTS) $(BCCOPTS)
|
||||
BCC = $(NCC) -nologo -W3 $(CCOPTS) $(BCCOPTS)
|
||||
!ENDIF
|
||||
|
||||
# Check if assembly code listings should be generated for the source
|
||||
@@ -873,14 +853,6 @@ RCC = $(RCC) -DSQLITE_WIN32_MALLOC_VALIDATE=1
|
||||
# prior to running nmake in order to match the actual installed location and
|
||||
# version on this machine.
|
||||
#
|
||||
!IFNDEF TCLVERSION
|
||||
TCLVERSION = 86
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF TCLSUFFIX
|
||||
TCLSUFFIX =
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF TCLDIR
|
||||
TCLDIR = $(TOP)\compat\tcl
|
||||
!ENDIF
|
||||
@@ -894,11 +866,11 @@ TCLLIBDIR = $(TCLDIR)\lib
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF LIBTCL
|
||||
LIBTCL = tcl$(TCLVERSION)$(TCLSUFFIX).lib
|
||||
LIBTCL = tcl86.lib
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF LIBTCLSTUB
|
||||
LIBTCLSTUB = tclstub$(TCLVERSION)$(TCLSUFFIX).lib
|
||||
LIBTCLSTUB = tclstub86.lib
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF LIBTCLPATH
|
||||
@@ -1091,7 +1063,7 @@ RCC = $(RCC) -I$(ICUINCDIR)
|
||||
# Command line prefixes for compiling code, compiling resources,
|
||||
# linking, etc.
|
||||
#
|
||||
LTCOMPILE = $(TCC) -Fo$@ -Fd$*.pdb
|
||||
LTCOMPILE = $(TCC) -Fo$@
|
||||
LTRCOMPILE = $(RCC) -r
|
||||
LTLIB = lib.exe
|
||||
LTLINK = $(TCC) -Fe$@
|
||||
@@ -1109,11 +1081,6 @@ LTLIBS = $(LTLIBS) rpcrt4.lib
|
||||
!IFDEF PLATFORM
|
||||
LTLINKOPTS = /NOLOGO /MACHINE:$(PLATFORM)
|
||||
LTLIBOPTS = /NOLOGO /MACHINE:$(PLATFORM)
|
||||
!ELSEIF "$(VISUALSTUDIOVERSION)"=="12.0" || \
|
||||
"$(VISUALSTUDIOVERSION)"=="14.0" || \
|
||||
"$(VISUALSTUDIOVERSION)"=="15.0"
|
||||
LTLINKOPTS = /NOLOGO /MACHINE:x86
|
||||
LTLIBOPTS = /NOLOGO /MACHINE:x86
|
||||
!ELSE
|
||||
LTLINKOPTS = /NOLOGO
|
||||
LTLIBOPTS = /NOLOGO
|
||||
@@ -1354,7 +1321,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 \
|
||||
@@ -1531,7 +1497,6 @@ TESTSRC = \
|
||||
$(TOP)\src\test_tclsh.c \
|
||||
$(TOP)\src\test_tclvar.c \
|
||||
$(TOP)\src\test_thread.c \
|
||||
$(TOP)\src\test_vdbecov.c \
|
||||
$(TOP)\src\test_vfs.c \
|
||||
$(TOP)\src\test_windirent.c \
|
||||
$(TOP)\src\test_window.c \
|
||||
@@ -1562,7 +1527,6 @@ TESTEXT = \
|
||||
$(TOP)\ext\misc\nextchar.c \
|
||||
$(TOP)\ext\misc\normalize.c \
|
||||
$(TOP)\ext\misc\percentile.c \
|
||||
$(TOP)\ext\misc\prefixes.c \
|
||||
$(TOP)\ext\misc\regexp.c \
|
||||
$(TOP)\ext\misc\remember.c \
|
||||
$(TOP)\ext\misc\series.c \
|
||||
@@ -1661,8 +1625,7 @@ FUZZDATA = \
|
||||
$(TOP)\test\fuzzdata4.db \
|
||||
$(TOP)\test\fuzzdata5.db \
|
||||
$(TOP)\test\fuzzdata6.db \
|
||||
$(TOP)\test\fuzzdata7.db \
|
||||
$(TOP)\test\fuzzdata8.db
|
||||
$(TOP)\test\fuzzdata7.db
|
||||
# <</mark>>
|
||||
|
||||
# Additional compiler options for the shell. These are only effective
|
||||
@@ -1680,14 +1643,7 @@ SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DESERIALIZE=1
|
||||
#
|
||||
MPTESTER_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5
|
||||
FUZZERSHELL_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1
|
||||
FUZZCHECK_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ -DSQLITE_MAX_MEMORY=50000000 -DSQLITE_PRINTF_PRECISION_LIMIT=1000
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_DESERIALIZE
|
||||
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_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ -DSQLITE_MAX_MEMORY=50000000 -DSQLITE_PRINTF_PRECISION_LIMIT=1000
|
||||
FUZZCHECK_SRC = $(TOP)\test\fuzzcheck.c $(TOP)\test\ossfuzz.c
|
||||
OSSSHELL_SRC = $(TOP)\test\ossshell.c $(TOP)\test\ossfuzz.c
|
||||
DBFUZZ_COMPILE_OPTS = -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION
|
||||
@@ -1701,7 +1657,7 @@ TESTOPTS = --verbose=file --output=test-out.txt
|
||||
# Extra targets for the "all" target that require Tcl.
|
||||
#
|
||||
!IF $(NO_TCL)==0
|
||||
ALL_TCL_TARGETS = $(SQLITE3TCLDLL)
|
||||
ALL_TCL_TARGETS = libtclsqlite3.lib
|
||||
!ELSE
|
||||
ALL_TCL_TARGETS =
|
||||
!ENDIF
|
||||
@@ -1733,22 +1689,7 @@ libsqlite3.lib: $(LIBOBJ)
|
||||
$(LTLIB) $(LTLIBOPTS) /OUT:$@ $(LIBOBJ) $(TLIBS)
|
||||
|
||||
libtclsqlite3.lib: tclsqlite.lo libsqlite3.lib
|
||||
$(LTLIB) $(LTLIBOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) /OUT:$@ tclsqlite.lo libsqlite3.lib $(LIBTCLSTUB) $(TLIBS)
|
||||
|
||||
tclsqlite3.def: tclsqlite.lo
|
||||
echo EXPORTS > tclsqlite3.def
|
||||
dumpbin /all tclsqlite.lo \
|
||||
| $(TCLSH_CMD) $(TOP)\tool\replace.tcl include "^\s+/EXPORT:_?((?:Sqlite3|Tclsqlite3)_[^@]*)(?:@\d+)?$$" \1 \
|
||||
| sort >> tclsqlite3.def
|
||||
|
||||
pkgIndex.tcl: $(TOP)\VERSION
|
||||
for /F %%V in ('type "$(TOP)\VERSION"') do ( \
|
||||
echo package ifneeded sqlite3 @version@ [list load [file join $$dir $(SQLITE3TCLDLL)] sqlite3] \
|
||||
| $(TCLSH_CMD) $(TOP)\tool\replace.tcl exact @version@ %%V > pkgIndex.tcl \
|
||||
)
|
||||
|
||||
$(SQLITE3TCLDLL): libtclsqlite3.lib $(LIBRESOBJS) tclsqlite3.def pkgIndex.tcl
|
||||
$(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL /DEF:tclsqlite3.def /OUT:$@ libtclsqlite3.lib $(LIBRESOBJS) $(LTLIBS) $(TLIBS)
|
||||
$(LTLIB) $(LTLIBOPTS) $(LTLIBPATHS) /OUT:$@ tclsqlite.lo libsqlite3.lib $(LIBTCLSTUB) $(TLIBS)
|
||||
# <</mark>>
|
||||
|
||||
$(SQLITE3DLL): $(LIBOBJ) $(LIBRESOBJS) $(CORE_LINK_DEP)
|
||||
@@ -1758,7 +1699,7 @@ $(SQLITE3DLL): $(LIBOBJ) $(LIBRESOBJS) $(CORE_LINK_DEP)
|
||||
sqlite3.def: libsqlite3.lib
|
||||
echo EXPORTS > sqlite3.def
|
||||
dumpbin /all libsqlite3.lib \
|
||||
| $(TCLSH_CMD) $(TOP)\tool\replace.tcl include "^\s+1 _?(sqlite3(?:session|changeset|changegroup|rebaser|rbu)?_[^@]*)(?:@\d+)?$$" \1 \
|
||||
| $(TCLSH_CMD) $(TOP)\tool\replace.tcl include "^\s+1 _?(sqlite3(?:session|changeset|changegroup|rebaser)?_[^@]*)(?:@\d+)?$$" \1 \
|
||||
| sort >> sqlite3.def
|
||||
# <</block2>>
|
||||
|
||||
@@ -1789,10 +1730,10 @@ dbfuzz.exe: $(TOP)\test\dbfuzz.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) $(DBFUZZ_COMPILE_OPTS) $(TOP)\test\dbfuzz.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
fuzzcheck.exe: $(FUZZCHECK_SRC) $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) $(FUZZCHECK_OPTS) $(FUZZCHECK_SRC) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
$(LTLINK) $(NO_WARN) $(FUZZCHECK_COMPILE_OPTS) $(FUZZCHECK_SRC) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
ossshell.exe: $(OSSSHELL_SRC) $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) $(FUZZCHECK_OPTS) $(OSSSHELL_SRC) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
$(LTLINK) $(NO_WARN) $(FUZZCHECK_COMPILE_OPTS) $(OSSSHELL_SRC) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
sessionfuzz.exe: zlib $(TOP)\test\sessionfuzz.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) -I$(ZLIBINCDIR) $(TOP)\test\sessionfuzz.c /link $(LDFLAGS) $(LTLINKOPTS) /LIBPATH:$(ZLIBLIBDIR) $(ZLIBLIB)
|
||||
@@ -1888,7 +1829,7 @@ opcodes.lo: opcodes.c
|
||||
#
|
||||
!IF $(USE_RC)!=0
|
||||
# <<block1>>
|
||||
$(LIBRESOBJS): $(TOP)\src\sqlite3.rc $(SQLITE3H) $(TOP)\VERSION
|
||||
$(LIBRESOBJS): $(TOP)\src\sqlite3.rc $(SQLITE3H)
|
||||
echo #ifndef SQLITE_RESOURCE_VERSION > sqlite3rc.h
|
||||
for /F %%V in ('type "$(TOP)\VERSION"') do ( \
|
||||
echo #define SQLITE_RESOURCE_VERSION %%V \
|
||||
@@ -2112,9 +2053,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
|
||||
|
||||
@@ -2157,10 +2095,12 @@ opcodes.h: parse.h $(TOP)\src\vdbe.c $(TOP)\tool\mkopcodeh.tcl
|
||||
#
|
||||
parse.h: parse.c
|
||||
|
||||
parse.c: $(TOP)\src\parse.y lemon.exe
|
||||
parse.c: $(TOP)\src\parse.y lemon.exe $(TOP)\tool\addopcodes.tcl
|
||||
del /Q parse.y parse.h parse.h.temp 2>NUL
|
||||
copy $(TOP)\src\parse.y .
|
||||
.\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) -S parse.y
|
||||
.\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) parse.y
|
||||
move parse.h parse.h.temp
|
||||
$(TCLSH_CMD) $(TOP)\tool\addopcodes.tcl parse.h.temp > parse.h
|
||||
|
||||
$(SQLITE3H): $(TOP)\src\sqlite.h.in $(TOP)\manifest mksourceid.exe $(TOP)\VERSION
|
||||
$(TCLSH_CMD) $(TOP)\tool\mksqlite3h.tcl $(TOP:\=/) > $(SQLITE3H) $(MKSQLITE3H_ARGS)
|
||||
@@ -2188,10 +2128,8 @@ SHELL_SRC = \
|
||||
$(TOP)\ext\misc\shathree.c \
|
||||
$(TOP)\ext\misc\fileio.c \
|
||||
$(TOP)\ext\misc\completion.c \
|
||||
$(TOP)\ext\misc\uint.c \
|
||||
$(TOP)\ext\expert\sqlite3expert.c \
|
||||
$(TOP)\ext\expert\sqlite3expert.h \
|
||||
$(TOP)\ext\misc\memtrace.c \
|
||||
$(TOP)\src\test_windirent.c
|
||||
|
||||
# If use of zlib is enabled, add the "zipfile.c" source file.
|
||||
@@ -2321,7 +2259,7 @@ LSM1_SRC = \
|
||||
fts5parse.c: $(TOP)\ext\fts5\fts5parse.y lemon.exe
|
||||
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
|
||||
.\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) fts5parse.y
|
||||
|
||||
fts5parse.h: fts5parse.c
|
||||
|
||||
@@ -2359,7 +2297,6 @@ 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) $(TEST_CCONV_OPTS)
|
||||
@@ -2425,6 +2362,9 @@ queryplantest: testfixture.exe shell
|
||||
fuzztest: fuzzcheck.exe
|
||||
.\fuzzcheck.exe $(FUZZDATA)
|
||||
|
||||
fastfuzztest: fuzzcheck.exe
|
||||
.\fuzzcheck.exe --limit-mem 100M $(FUZZDATA)
|
||||
|
||||
# Minimal testing that runs in less than 3 minutes (on a fast machine)
|
||||
#
|
||||
quicktest: testfixture.exe sourcetest
|
||||
@@ -2434,7 +2374,7 @@ quicktest: testfixture.exe sourcetest
|
||||
# This is the common case. Run many tests that do not take too long,
|
||||
# including fuzzcheck, sqlite3_analyzer, and sqldiff tests.
|
||||
#
|
||||
test: $(TESTPROGS) sourcetest fuzztest
|
||||
test: $(TESTPROGS) sourcetest fastfuzztest
|
||||
@set PATH=$(LIBTCLPATH);$(PATH)
|
||||
.\testfixture.exe $(TOP)\test\veryquick.test $(TESTOPTS)
|
||||
|
||||
@@ -2565,7 +2505,6 @@ clean:
|
||||
del /Q *.bsc *.def *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL
|
||||
del /Q $(SQLITE3EXE) $(SQLITE3DLL) Replace.exe 2>NUL
|
||||
# <<mark>>
|
||||
del /Q $(SQLITE3TCLDLL) pkgIndex.tcl 2>NUL
|
||||
del /Q opcodes.c opcodes.h 2>NUL
|
||||
del /Q lemon.* lempar.c parse.* 2>NUL
|
||||
del /Q mksourceid.* mkkeywordhash.* keywordhash.h 2>NUL
|
||||
@@ -2576,7 +2515,6 @@ clean:
|
||||
del /Q .target_source 2>NUL
|
||||
del /Q tclsqlite3.exe $(SQLITETCLH) $(SQLITETCLDECLSH) 2>NUL
|
||||
del /Q lsm.dll lsmtest.exe 2>NUL
|
||||
del /Q atrc.exe changesetfuzz.exe dbtotxt.exe index_usage.exe 2>NUL
|
||||
del /Q testloadext.dll 2>NUL
|
||||
del /Q testfixture.exe test.db 2>NUL
|
||||
del /Q LogEst.exe fts3view.exe rollback-test.exe showdb.exe dbdump.exe 2>NUL
|
||||
|
||||
@@ -5,28 +5,16 @@ This repository contains the complete source code for the
|
||||
are also included. However, many other test scripts
|
||||
and most of the documentation are managed separately.
|
||||
|
||||
## Version Control
|
||||
|
||||
SQLite sources are managed using the
|
||||
[Fossil](https://www.fossil-scm.org/), a distributed version control system
|
||||
that was specifically designed and written to support SQLite development.
|
||||
The [Fossil repository](https://sqlite.org/src/timeline) contains the urtext.
|
||||
|
||||
If you are reading this on GitHub or some other Git repository or service,
|
||||
then you are looking at a mirror. The names of check-ins and
|
||||
other artifacts in a Git mirror are different from the official
|
||||
names for those objects. The offical names for check-ins are
|
||||
found in a footer on the check-in comment for authorized mirrors.
|
||||
The official check-in name can also be seen in the `manifest.uuid` file
|
||||
in the root of the tree. Always use the official name, not the
|
||||
Git-name, when communicating about an SQLite check-in.
|
||||
|
||||
If you pulled your SQLite source code from a secondary source and want to
|
||||
verify its integrity, there are hints on how to do that in the
|
||||
[Verifying Code Authenticity](#vauth) section below.
|
||||
SQLite [does not use Git](https://sqlite.org/whynotgit.html).
|
||||
If you are reading this on GitHub, then you are looking at an
|
||||
unofficial mirror. See <https://sqlite.org/src> for the official
|
||||
repository.
|
||||
|
||||
## Obtaining The Code
|
||||
|
||||
SQLite sources are managed using the
|
||||
[Fossil](https://www.fossil-scm.org/), a distributed version control system
|
||||
that was specifically designed to support SQLite development.
|
||||
If you do not want to use Fossil, you can download tarballs or ZIP
|
||||
archives or [SQLite archives](https://sqlite.org/cli.html#sqlar) as follows:
|
||||
|
||||
@@ -41,7 +29,7 @@ archives or [SQLite archives](https://sqlite.org/cli.html#sqlar) as follows:
|
||||
[SQLite-archive](https://www.sqlite.org/src/sqlar/sqlite.sqlar?r=release).
|
||||
|
||||
* For other check-ins, substitute an appropriate branch name or
|
||||
tag or hash prefix in place of "release" in the URLs of the previous
|
||||
tag or hash prefix for "release" in the URLs of the previous
|
||||
bullet. Or browse the [timeline](https://www.sqlite.org/src/timeline)
|
||||
to locate the check-in desired, click on its information page link,
|
||||
then click on the "Tarball" or "ZIP Archive" links on the information
|
||||
@@ -175,8 +163,11 @@ the src/parse.y file. The conversion of "parse.y" into "parse.c" is done
|
||||
by the [lemon](./doc/lemon.html) LALR(1) parser generator. The source code
|
||||
for lemon is at tool/lemon.c. Lemon uses the tool/lempar.c file as a
|
||||
template for generating its parser.
|
||||
|
||||
Lemon also generates the **parse.h** header file, at the same time it
|
||||
generates parse.c.
|
||||
generates parse.c. But the parse.h header file is
|
||||
modified further (to add additional symbols) using the ./addopcodes.tcl
|
||||
Tcl script.
|
||||
|
||||
The **opcodes.h** header file contains macros that define the numbers
|
||||
corresponding to opcodes in the "VDBE" virtual machine. The opcodes.h
|
||||
@@ -303,25 +294,10 @@ Key files:
|
||||
There are many other source files. Each has a succinct header comment that
|
||||
describes its purpose and role within the larger system.
|
||||
|
||||
<a name="vauth"></a>
|
||||
## Verifying Code Authenticity
|
||||
|
||||
The `manifest` file at the root directory of the source tree
|
||||
contains either a SHA3-256 hash (for newer files) or a SHA1 hash (for
|
||||
older files) for every source file in the repository.
|
||||
The SHA3-256 hash of the `manifest`
|
||||
file itself is the official name of the version of the source tree that you
|
||||
have. The `manifest.uuid` file should contain the SHA3-256 hash of the
|
||||
`manifest` file. If all of the above hash comparisons are correct, then
|
||||
you can be confident that your source tree is authentic and unadulterated.
|
||||
|
||||
The format of the `manifest` file should be mostly self-explanatory, but
|
||||
if you want details, they are available
|
||||
[here](https://fossil-scm.org/fossil/doc/trunk/www/fileformat.wiki#manifest).
|
||||
|
||||
## Contacts
|
||||
|
||||
The main SQLite website is [http://www.sqlite.org/](http://www.sqlite.org/)
|
||||
The main SQLite webpage is [http://www.sqlite.org/](http://www.sqlite.org/)
|
||||
with geographically distributed backups at
|
||||
[http://www2.sqlite.org/](http://www2.sqlite.org) and
|
||||
[http://www3.sqlite.org/](http://www3.sqlite.org).
|
||||
|
||||
+6
-23
@@ -73,7 +73,7 @@ API_ARMOR = 0
|
||||
!IFNDEF NO_WARN
|
||||
!IF $(USE_FULLWARN)!=0
|
||||
NO_WARN = -wd4054 -wd4055 -wd4100 -wd4127 -wd4130 -wd4152 -wd4189 -wd4206
|
||||
NO_WARN = $(NO_WARN) -wd4210 -wd4232 -wd4244 -wd4305 -wd4306 -wd4702 -wd4706
|
||||
NO_WARN = $(NO_WARN) -wd4210 -wd4232 -wd4305 -wd4306 -wd4702 -wd4706
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
@@ -210,12 +210,6 @@ OPTIMIZATIONS = 2
|
||||
SESSION = 0
|
||||
!ENDIF
|
||||
|
||||
# Set this to non-0 to enable support for the rbu extension.
|
||||
#
|
||||
!IFNDEF RBU
|
||||
RBU = 0
|
||||
!ENDIF
|
||||
|
||||
# Set the source code file to be used by executables and libraries when
|
||||
# they need the amalgamation.
|
||||
#
|
||||
@@ -288,6 +282,7 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_JSON1=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBSTAT_VTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_INTROSPECTION_PRAGMAS=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DESERIALIZE=1
|
||||
!ENDIF
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
|
||||
@@ -301,13 +296,6 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SESSION=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK=1
|
||||
!ENDIF
|
||||
|
||||
# Should the rbu extension be enabled? If so, add compilation options
|
||||
# to enable it.
|
||||
#
|
||||
!IF $(RBU)!=0
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RBU=1
|
||||
!ENDIF
|
||||
|
||||
# These are the "extended" SQLite compilation options used when compiling for
|
||||
# the Windows 10 platform.
|
||||
#
|
||||
@@ -445,9 +433,9 @@ UCRTLIBPATH = $(UCRTLIBPATH:\\=\)
|
||||
# will run on the platform that is doing the build.
|
||||
#
|
||||
!IF $(USE_FULLWARN)!=0
|
||||
BCC = $(NCC) -nologo -W4 -Fd$*.pdb $(CCOPTS) $(BCCOPTS)
|
||||
BCC = $(NCC) -nologo -W4 $(CCOPTS) $(BCCOPTS)
|
||||
!ELSE
|
||||
BCC = $(NCC) -nologo -W3 -Fd$*.pdb $(CCOPTS) $(BCCOPTS)
|
||||
BCC = $(NCC) -nologo -W3 $(CCOPTS) $(BCCOPTS)
|
||||
!ENDIF
|
||||
|
||||
# Check if assembly code listings should be generated for the source
|
||||
@@ -820,7 +808,7 @@ BCC = $(BCC) -Zi
|
||||
# Command line prefixes for compiling code, compiling resources,
|
||||
# linking, etc.
|
||||
#
|
||||
LTCOMPILE = $(TCC) -Fo$@ -Fd$*.pdb
|
||||
LTCOMPILE = $(TCC) -Fo$@
|
||||
LTRCOMPILE = $(RCC) -r
|
||||
LTLIB = lib.exe
|
||||
LTLINK = $(TCC) -Fe$@
|
||||
@@ -838,11 +826,6 @@ LTLIBS = $(LTLIBS) rpcrt4.lib
|
||||
!IFDEF PLATFORM
|
||||
LTLINKOPTS = /NOLOGO /MACHINE:$(PLATFORM)
|
||||
LTLIBOPTS = /NOLOGO /MACHINE:$(PLATFORM)
|
||||
!ELSEIF "$(VISUALSTUDIOVERSION)"=="12.0" || \
|
||||
"$(VISUALSTUDIOVERSION)"=="14.0" || \
|
||||
"$(VISUALSTUDIOVERSION)"=="15.0"
|
||||
LTLINKOPTS = /NOLOGO /MACHINE:x86
|
||||
LTLIBOPTS = /NOLOGO /MACHINE:x86
|
||||
!ELSE
|
||||
LTLINKOPTS = /NOLOGO
|
||||
LTLIBOPTS = /NOLOGO
|
||||
@@ -990,7 +973,7 @@ Replace.exe:
|
||||
sqlite3.def: Replace.exe $(LIBOBJ)
|
||||
echo EXPORTS > sqlite3.def
|
||||
dumpbin /all $(LIBOBJ) \
|
||||
| .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset|changegroup|rebaser|rbu)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \
|
||||
| .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset|changegroup|rebaser)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \
|
||||
| sort >> sqlite3.def
|
||||
|
||||
$(SQLITE3EXE): shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLITE3H)
|
||||
|
||||
@@ -161,7 +161,7 @@ AC_ARG_ENABLE(rtree, [AS_HELP_STRING(
|
||||
[--enable-rtree], [include rtree support [default=yes]])],
|
||||
[], [enable_rtree=yes])
|
||||
if test x"$enable_rtree" = "xyes"; then
|
||||
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_GEOPOLY"
|
||||
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_RTREE"
|
||||
fi
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ dnl to configure the system for the local environment.
|
||||
# so you can encode the package version directly into the source files.
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
AC_INIT([sqlite], [3.32.0])
|
||||
AC_INIT([sqlite], [3.7.4])
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Call TEA_INIT as the first TEA_ macro to set up initial vars.
|
||||
|
||||
@@ -153,7 +153,7 @@ Please `cd` to its location first.
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
PROJECT = tclsqlite3
|
||||
PROJECT = sqlite3
|
||||
!include "rules.vc"
|
||||
|
||||
# nmakehelp -V <file> <tag> will search the file for tag, skips until a
|
||||
@@ -162,15 +162,18 @@ PROJECT = tclsqlite3
|
||||
|
||||
!if [echo REM = This file is generated from Makefile.vc > versions.vc]
|
||||
!endif
|
||||
# get project version from row "AC_INIT([sqlite], [3.x.y])"
|
||||
# get project version from row "AC_INIT([sqlite], [3.7.14])"
|
||||
!if [echo DOTVERSION = \>> versions.vc] \
|
||||
&& [nmakehlp -V ..\configure.ac AC_INIT >> versions.vc]
|
||||
&& [nmakehlp -V ..\configure.in AC_INIT >> versions.vc]
|
||||
!endif
|
||||
!include "versions.vc"
|
||||
|
||||
VERSION = $(DOTVERSION:.=)
|
||||
STUBPREFIX = $(PROJECT)stub
|
||||
|
||||
DLLOBJS = \
|
||||
$(TMP_DIR)\tclsqlite3.obj
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Target names and paths ( shouldn't need changing )
|
||||
#-------------------------------------------------------------------------
|
||||
@@ -179,7 +182,7 @@ BINROOT = .
|
||||
ROOT = ..
|
||||
|
||||
PRJIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib
|
||||
PRJLIBNAME = $(PROJECT).$(EXT)
|
||||
PRJLIBNAME = $(PROJECT)$(VERSION)$(SUFX).$(EXT)
|
||||
PRJLIB = $(OUT_DIR)\$(PRJLIBNAME)
|
||||
|
||||
PRJSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib
|
||||
@@ -201,17 +204,6 @@ DOCDIR = $(ROOT)\doc
|
||||
TOOLSDIR = $(ROOT)\tools
|
||||
COMPATDIR = $(ROOT)\compat
|
||||
|
||||
### Figure out where the primary source code file(s) is/are.
|
||||
!if exist("$(ROOT)\..\..\sqlite3.c") && exist("$(ROOT)\..\..\src\tclsqlite.c")
|
||||
SQL_INCLUDES = -I"$(ROOT)\..\.."
|
||||
SQLITE_SRCDIR = $(ROOT)\..\..
|
||||
TCLSQLITE_SRCDIR = $(ROOT)\..\..\src
|
||||
DLLOBJS = $(TMP_DIR)\sqlite3.obj $(TMP_DIR)\tclsqlite.obj
|
||||
!else
|
||||
TCLSQLITE_SRCDIR = $(ROOT)\generic
|
||||
DLLOBJS = $(TMP_DIR)\tclsqlite3.obj
|
||||
!endif
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# Compile flags
|
||||
#---------------------------------------------------------------------
|
||||
@@ -231,7 +223,7 @@ cdebug = -Z7 -WX -Od -GZ
|
||||
!endif
|
||||
|
||||
### Declarations common to all compiler options
|
||||
cflags = -nologo -c -W3 -D_CRT_SECURE_NO_WARNINGS -YX -Fp$(TMP_DIR)^\
|
||||
cflags = -nologo -c -W3 -YX -Fp$(TMP_DIR)^\
|
||||
|
||||
!if $(MSVCRT)
|
||||
!if $(DEBUG)
|
||||
@@ -247,8 +239,8 @@ crt = -MT
|
||||
!endif
|
||||
!endif
|
||||
|
||||
INCLUDES = $(SQL_INCLUDES) $(TCL_INCLUDES) -I"$(WINDIR)" \
|
||||
-I"$(GENERICDIR)" -I"$(ROOT)\.."
|
||||
INCLUDES = $(TCL_INCLUDES) -I"$(WINDIR)" -I"$(GENERICDIR)" \
|
||||
-I"$(ROOT)\.."
|
||||
BASE_CLFAGS = $(cflags) $(cdebug) $(crt) $(INCLUDES) \
|
||||
-DSQLITE_3_SUFFIX_ONLY=1 -DSQLITE_ENABLE_RTREE=1 \
|
||||
-DSQLITE_ENABLE_FTS3=1 -DSQLITE_OMIT_DEPRECATED=1
|
||||
@@ -349,17 +341,20 @@ $(PRJSTUBLIB): $(PRJSTUBOBJS)
|
||||
# Implicit rules
|
||||
#---------------------------------------------------------------------
|
||||
|
||||
$(TMP_DIR)\sqlite3.obj: $(SQLITE_SRCDIR)\sqlite3.c
|
||||
$(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ \
|
||||
-c $(SQLITE_SRCDIR)\sqlite3.c
|
||||
{$(WINDIR)}.c{$(TMP_DIR)}.obj::
|
||||
$(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<<
|
||||
$<
|
||||
<<
|
||||
|
||||
$(TMP_DIR)\tclsqlite.obj: $(TCLSQLITE_SRCDIR)\tclsqlite.c
|
||||
$(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ \
|
||||
-c $(TCLSQLITE_SRCDIR)\tclsqlite.c
|
||||
{$(GENERICDIR)}.c{$(TMP_DIR)}.obj::
|
||||
$(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<<
|
||||
$<
|
||||
<<
|
||||
|
||||
$(TMP_DIR)\tclsqlite3.obj: $(TCLSQLITE_SRCDIR)\tclsqlite3.c
|
||||
$(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ \
|
||||
-c $(TCLSQLITE_SRCDIR)\tclsqlite3.c
|
||||
{$(COMPATDIR)}.c{$(TMP_DIR)}.obj::
|
||||
$(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<<
|
||||
$<
|
||||
<<
|
||||
|
||||
{$(WINDIR)}.rc{$(TMP_DIR)}.res:
|
||||
$(rc32) -fo $@ -r -i "$(GENERICDIR)" -D__WIN32__ \
|
||||
|
||||
Vendored
+609
-733
File diff suppressed because it is too large
Load Diff
Vendored
+1248
-1402
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.69 for sqlite 3.32.0.
|
||||
# Generated by GNU Autoconf 2.69 for sqlite 3.27.0.
|
||||
#
|
||||
#
|
||||
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
|
||||
@@ -726,8 +726,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='sqlite'
|
||||
PACKAGE_TARNAME='sqlite'
|
||||
PACKAGE_VERSION='3.32.0'
|
||||
PACKAGE_STRING='sqlite 3.32.0'
|
||||
PACKAGE_VERSION='3.27.0'
|
||||
PACKAGE_STRING='sqlite 3.27.0'
|
||||
PACKAGE_BUGREPORT=''
|
||||
PACKAGE_URL=''
|
||||
|
||||
@@ -906,7 +906,6 @@ enable_amalgamation
|
||||
enable_load_extension
|
||||
enable_memsys5
|
||||
enable_memsys3
|
||||
enable_all
|
||||
enable_fts3
|
||||
enable_fts4
|
||||
enable_fts5
|
||||
@@ -1467,7 +1466,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures sqlite 3.32.0 to adapt to many kinds of systems.
|
||||
\`configure' configures sqlite 3.27.0 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1532,7 +1531,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlite 3.32.0:";;
|
||||
short | recursive ) echo "Configuration of sqlite 3.27.0:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1560,7 +1559,6 @@ Optional Features:
|
||||
Disable loading of external extensions
|
||||
--enable-memsys5 Enable MEMSYS5
|
||||
--enable-memsys3 Enable MEMSYS3
|
||||
--enable-all Enable FTS4, FTS5, Geopoly, JSON, RTree, Sessions
|
||||
--enable-fts3 Enable the FTS3 extension
|
||||
--enable-fts4 Enable the FTS4 extension
|
||||
--enable-fts5 Enable the FTS5 extension
|
||||
@@ -1659,7 +1657,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlite configure 3.32.0
|
||||
sqlite configure 3.27.0
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
@@ -2078,7 +2076,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by sqlite $as_me 3.32.0, which was
|
||||
It was created by sqlite $as_me 3.27.0, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -3936,13 +3934,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:3939: $ac_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:3937: $ac_compile\"" >&5)
|
||||
(eval "$ac_compile" 2>conftest.err)
|
||||
cat conftest.err >&5
|
||||
(eval echo "\"\$as_me:3942: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
|
||||
(eval echo "\"\$as_me:3940: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
|
||||
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
|
||||
cat conftest.err >&5
|
||||
(eval echo "\"\$as_me:3945: output\"" >&5)
|
||||
(eval echo "\"\$as_me:3943: output\"" >&5)
|
||||
cat conftest.out >&5
|
||||
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
|
||||
lt_cv_nm_interface="MS dumpbin"
|
||||
@@ -5148,7 +5146,7 @@ ia64-*-hpux*)
|
||||
;;
|
||||
*-*-irix6*)
|
||||
# Find out which ABI we are using.
|
||||
echo '#line 5151 "configure"' > conftest.$ac_ext
|
||||
echo '#line 5149 "configure"' > conftest.$ac_ext
|
||||
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
|
||||
(eval $ac_compile) 2>&5
|
||||
ac_status=$?
|
||||
@@ -6673,11 +6671,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:6676: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:6674: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:6680: \$? = $ac_status" >&5
|
||||
echo "$as_me:6678: \$? = $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.
|
||||
@@ -7012,11 +7010,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:7015: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7013: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:7019: \$? = $ac_status" >&5
|
||||
echo "$as_me:7017: \$? = $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.
|
||||
@@ -7117,11 +7115,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:7120: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7118: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:7124: \$? = $ac_status" >&5
|
||||
echo "$as_me:7122: \$? = $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
|
||||
@@ -7172,11 +7170,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:7175: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7173: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:7179: \$? = $ac_status" >&5
|
||||
echo "$as_me:7177: \$? = $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
|
||||
@@ -9552,7 +9550,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 9555 "configure"
|
||||
#line 9553 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@@ -9648,7 +9646,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 9651 "configure"
|
||||
#line 9649 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@@ -11452,15 +11450,6 @@ else
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
########
|
||||
# The --enable-extensions argument is short-hand to enable
|
||||
# multiple extensions.
|
||||
# Check whether --enable-all was given.
|
||||
if test "${enable_all+set}" = set; then :
|
||||
enableval=$enable_all;
|
||||
fi
|
||||
|
||||
|
||||
#########
|
||||
# See whether we should enable Full Text Search extensions
|
||||
# Check whether --enable-fts3 was given.
|
||||
@@ -11476,7 +11465,7 @@ if test "${enable_fts4+set}" = set; then :
|
||||
enableval=$enable_fts4;
|
||||
fi
|
||||
|
||||
if test "${enable_fts4}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
if test "${enable_fts4}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS4"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5
|
||||
$as_echo_n "checking for library containing log... " >&6; }
|
||||
@@ -11540,7 +11529,7 @@ if test "${enable_fts5+set}" = set; then :
|
||||
enableval=$enable_fts5;
|
||||
fi
|
||||
|
||||
if test "${enable_fts5}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
if test "${enable_fts5}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS5"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5
|
||||
$as_echo_n "checking for library containing log... " >&6; }
|
||||
@@ -11607,7 +11596,7 @@ if test "${enable_json1+set}" = set; then :
|
||||
enableval=$enable_json1;
|
||||
fi
|
||||
|
||||
if test "${enable_json1}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
if test "${enable_json1}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_JSON1"
|
||||
fi
|
||||
|
||||
@@ -11632,7 +11621,7 @@ else
|
||||
enable_geopoly=no
|
||||
fi
|
||||
|
||||
if test "${enable_geopoly}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
if test "${enable_geopoly}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_GEOPOLY"
|
||||
enable_rtree=yes
|
||||
fi
|
||||
@@ -11655,7 +11644,7 @@ if test "${enable_session+set}" = set; then :
|
||||
enableval=$enable_session;
|
||||
fi
|
||||
|
||||
if test "${enable_session}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
if test "${enable_session}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_SESSION"
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_PREUPDATE_HOOK"
|
||||
fi
|
||||
@@ -12243,7 +12232,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by sqlite $as_me 3.32.0, which was
|
||||
This file was extended by sqlite $as_me 3.27.0, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -12309,7 +12298,7 @@ _ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||
ac_cs_version="\\
|
||||
sqlite config.status 3.32.0
|
||||
sqlite config.status 3.27.0
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
+5
-11
@@ -613,12 +613,6 @@ else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
########
|
||||
# The --enable-extensions argument is short-hand to enable
|
||||
# multiple extensions.
|
||||
AC_ARG_ENABLE(all, AC_HELP_STRING([--enable-all],
|
||||
[Enable FTS4, FTS5, Geopoly, JSON, RTree, Sessions]))
|
||||
|
||||
#########
|
||||
# See whether we should enable Full Text Search extensions
|
||||
AC_ARG_ENABLE(fts3, AC_HELP_STRING([--enable-fts3],
|
||||
@@ -628,13 +622,13 @@ if test "${enable_fts3}" = "yes" ; then
|
||||
fi
|
||||
AC_ARG_ENABLE(fts4, AC_HELP_STRING([--enable-fts4],
|
||||
[Enable the FTS4 extension]))
|
||||
if test "${enable_fts4}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
if test "${enable_fts4}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS4"
|
||||
AC_SEARCH_LIBS([log],[m])
|
||||
fi
|
||||
AC_ARG_ENABLE(fts5, AC_HELP_STRING([--enable-fts5],
|
||||
[Enable the FTS5 extension]))
|
||||
if test "${enable_fts5}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
if test "${enable_fts5}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS5"
|
||||
AC_SEARCH_LIBS([log],[m])
|
||||
fi
|
||||
@@ -642,7 +636,7 @@ fi
|
||||
#########
|
||||
# See whether we should enable JSON1
|
||||
AC_ARG_ENABLE(json1, AC_HELP_STRING([--enable-json1],[Enable the JSON1 extension]))
|
||||
if test "${enable_json1}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
if test "${enable_json1}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_JSON1"
|
||||
fi
|
||||
|
||||
@@ -660,7 +654,7 @@ fi
|
||||
AC_ARG_ENABLE(geopoly, AC_HELP_STRING([--enable-geopoly],
|
||||
[Enable the GEOPOLY extension]),
|
||||
[enable_geopoly=yes],[enable_geopoly=no])
|
||||
if test "${enable_geopoly}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
if test "${enable_geopoly}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_GEOPOLY"
|
||||
enable_rtree=yes
|
||||
fi
|
||||
@@ -677,7 +671,7 @@ fi
|
||||
# See whether we should enable the SESSION extension
|
||||
AC_ARG_ENABLE(session, AC_HELP_STRING([--enable-session],
|
||||
[Enable the SESSION extension]))
|
||||
if test "${enable_session}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
if test "${enable_session}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_SESSION"
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_PREUPDATE_HOOK"
|
||||
fi
|
||||
|
||||
+6
-6
@@ -123,7 +123,7 @@ Suppress generation of the report file.
|
||||
<li><b>-r</b>
|
||||
Do not sort or renumber the parser states as part of optimization.
|
||||
<li><b>-s</b>
|
||||
Show parser statistics before exiting.
|
||||
Show parser statistics before existing.
|
||||
<li><b>-T<i>file</i></b>
|
||||
Use <i>file</i> as the template for the generated C-code parser implementation.
|
||||
<li><b>-x</b>
|
||||
@@ -488,7 +488,7 @@ is an error.</p>
|
||||
The precedence of a grammar rule is equal to the precedence of the
|
||||
left-most terminal symbol in the rule for which a precedence is
|
||||
defined. This is normally what you want, but in those cases where
|
||||
you want the precedence of a grammar rule to be something different,
|
||||
you want to precedence of a grammar rule to be something different,
|
||||
you can specify an alternative precedence symbol by putting the
|
||||
symbol in square braces after the period at the end of the rule and
|
||||
before any C-code. For example:</p>
|
||||
@@ -689,7 +689,7 @@ on Parse().
|
||||
<a name='extractx'></a>
|
||||
<h4>The <tt>%extra_context</tt> directive</h4>
|
||||
|
||||
The <tt>%extra_context</tt> directive instructs Lemon to add a 2nd parameter
|
||||
The <tt>%extra_context</tt> directive instructs Lemon to add a 2th parameter
|
||||
to the parameter list of the ParseAlloc() and ParseInif() functions. Lemon
|
||||
doesn't do anything itself with these extra argument, but it does
|
||||
store the value make it available to C-code action routines, destructors,
|
||||
@@ -699,9 +699,9 @@ and so forth. For example, if the grammar file contains:</p>
|
||||
%extra_context { MyStruct *pAbc }
|
||||
</pre></p>
|
||||
|
||||
<p>Then the ParseAlloc() and ParseInit() functions will have an 2nd parameter
|
||||
<p>Then the ParseAlloc() and ParseInit() functions will have an 2th parameter
|
||||
of type "MyStruct*" and all action routines will have access to
|
||||
a variable named "pAbc" that is the value of that 2nd parameter.</p>
|
||||
a variable named "pAbc" that is the value of that 2th parameter.</p>
|
||||
|
||||
<p>The <tt>%extra_argument</tt> directive works the same except that it
|
||||
is passed in on the Parse() routine instead of on ParseAlloc()/ParseInit().
|
||||
@@ -996,7 +996,7 @@ on the parser's stack associated with terminal and non-terminal
|
||||
symbols. The values of all terminal symbols must be of the same
|
||||
type. This turns out to be the same data type as the 3rd parameter
|
||||
to the Parse() function generated by Lemon. Typically, you will
|
||||
make the value of a terminal symbol be a pointer to some kind of
|
||||
make the value of a terminal symbol by a pointer to some kind of
|
||||
token structure. Like this:</p>
|
||||
|
||||
<p><pre>
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
# The new-security-options branch
|
||||
|
||||
## The problem that the [new-security-options](/timeline?r=new-security-options) branch tries to solve
|
||||
|
||||
An attacker might modify the schema of an SQLite database by adding
|
||||
structures that cause code to run when some other application opens and
|
||||
reads the database. For example, the attacker might replace a table
|
||||
definition with a view. Or the attacker might add triggers to tables
|
||||
or views, or add new CHECK constraints or generated columns or indexes
|
||||
with expressions in the index list or in the WHERE clause. If the
|
||||
added features invoke SQL functions or virtual tables with side effects,
|
||||
that might cause harm to the system if run by a high-privilege victim.
|
||||
Or, the added features might exfiltrate information if the database is
|
||||
read by a high-privilege victim.
|
||||
|
||||
The changes in this branch strive to make it easier for high-privilege
|
||||
applications to safely read SQLite database files that might have been
|
||||
maliciously corrupted by an attacker.
|
||||
|
||||
## Overview of changes in [new-security-options](/timeline?r=new-security-options)
|
||||
|
||||
The basic idea is to tag every SQL function and virtual table with one
|
||||
of three risk levels:
|
||||
|
||||
1. Innocuous
|
||||
2. Normal
|
||||
3. Direct-Only
|
||||
|
||||
Innocuous functions/vtabs are safe and can be used at any time.
|
||||
Direct-only elements, in contrast, might have cause side-effects and
|
||||
should only be used from top-level SQL, not from within triggers or views nor
|
||||
in elements of the schema such as CHECK constraint, DEFAULT values,
|
||||
generated columns, index expressions, or in the WHERE clause of a
|
||||
partial index that are potentially under the control of an attacker.
|
||||
Normal elements behave like Innocuous if TRUSTED\_SCHEMA=on
|
||||
and behave like direct-only if TRUSTED\_SCHEMA=off.
|
||||
|
||||
Application-defined functions and virtual tables go in as Normal unless
|
||||
the application takes deliberate steps to change the risk level.
|
||||
|
||||
For backwards compatibility, the default is TRUSTED\_SCHEMA=on. Documentation
|
||||
will be updated to recommend applications turn TRUSTED\_SCHEMA to off.
|
||||
|
||||
An innocuous function or virtual table is one that can only read content
|
||||
from the database file in which it resides, and can only alter the database
|
||||
in which it resides. Most SQL functions are innocuous. For example, there
|
||||
is no harm in an attacker running the abs() function.
|
||||
|
||||
Direct-only elements that have side-effects that go outside the database file
|
||||
in which it lives, or return information from outside of the database file.
|
||||
Examples of direct-only elements include:
|
||||
|
||||
1. The fts3\_tokenizer() function
|
||||
2. The writefile() function
|
||||
3. The readfile() function
|
||||
4. The zipvfs virtual table
|
||||
5. The csv virtual table
|
||||
|
||||
We do not want an attacker to be able to add these kinds of things to
|
||||
the database schema and possibly trick a high-privilege application
|
||||
from performing any of these actions. Therefore, functions and vtabs
|
||||
with side-effects are marked as Direct-Only.
|
||||
|
||||
Legacy applications might add other risky functions or vtabs. Those will
|
||||
go in as "Normal" by default. For optimal security, we want those risky
|
||||
app-defined functions and vtabs to be direct-only, but making that the
|
||||
default might break some legacy applications. Hence, all app-defined
|
||||
functions and vtabs go in as Normal, but the application can switch them
|
||||
over to "Direct-Only" behavior using a single pragma.
|
||||
|
||||
The restrictions on the use of functions and virtual tables do not apply
|
||||
to TEMP. A TEMP VIEW or a TEMP TRIGGER can use any valid SQL function
|
||||
or virtual table. The idea is that TEMP views and triggers must be
|
||||
directly created by the application and are thus under the control of the
|
||||
application. TEMP views and triggers cannot be created by an attacker who
|
||||
corrupts the schema of a persistent database file. Hence TEMP views and
|
||||
triggers are safe.
|
||||
|
||||
## Specific changes
|
||||
|
||||
1. New sqlite3\_db\_config() option SQLITE\_DBCONFIG\_TRUSTED\_SCHEMA for
|
||||
turning TRUSTED\_SCHEMA on and off. It defaults to ON.
|
||||
|
||||
2. Compile-time option -DSQLITE\_TRUSTED\_SCHEMA=0 causes the default
|
||||
TRUSTED\_SCHEMA setting to be off.
|
||||
|
||||
3. New pragma "PRAGMA trusted\_schema=(ON\|OFF);". This provides access
|
||||
to the TRUSTED_SCHEMA setting for application coded using scripting
|
||||
languages or other secondary languages where they are unable to make
|
||||
calls to sqlite3\_db\_config().
|
||||
|
||||
4. New options for the "enc" parameter to sqlite3\_create\_function() and
|
||||
its kin:
|
||||
<ol type="a">
|
||||
<li> _SQLITE\_INNOCUOUS_ → tags the new functions as Innocuous
|
||||
<li> _SQLITE\_DIRECTONLY_ → tags the new functions as Direct-Only
|
||||
</ol>
|
||||
|
||||
5. New options to sqlite3\_vtab\_config():
|
||||
<ol type="a">
|
||||
<li> _SQLITE\_VTAB\_INNOCUOUS_ → tags the vtab as Innocuous
|
||||
<li> _SQLITE\_VTAB\_DIRECTONLY_ → tags the vtab as Direct-Only
|
||||
</ol>
|
||||
|
||||
6. Change many of the functions and virtual tables in the SQLite source
|
||||
tree to use one of the tags above.
|
||||
|
||||
7. Enhanced PRAGMA function\_list and virtual-table "pragma\_function\_list"
|
||||
with additional columns. The columns now are:
|
||||
<ul>
|
||||
<li> _name_ → Name of the function
|
||||
<li> _builtin_ → 1 for built-in functions. 0 otherwise.
|
||||
<li> _type_ → 's'=Scalar, 'a'=Aggregate, 'w'=Window
|
||||
<li> _enc_ → 'utf8', 'utf16le', or 'utf16be'
|
||||
<li> _narg_ → number of argument
|
||||
<li> _flags_ → Bitmask of SQLITE\_INNOCUOUS, SQLITE\_DIRECTONLY,
|
||||
SQLITE\_DETERMINISTIC, SQLITE\_SUBTYPE, and
|
||||
SQLITE\_FUNC\_INTERNAL flags.
|
||||
</ul>
|
||||
<p>The last four columns are new.
|
||||
|
||||
8. The function\_list PRAGMA now also shows all entries for each function.
|
||||
So, for example, if a function can take either 2 or 3 arguments,
|
||||
there are separate rows for the 2-argument and 3-argument versions of
|
||||
the function.
|
||||
|
||||
## Additional Notes
|
||||
|
||||
The function_list enhancements allow the application to query the set
|
||||
of SQL functions that meet various criteria. For example, to see all
|
||||
SQL functions that are never allowed to be used in the schema or in
|
||||
trigger or views:
|
||||
|
||||
~~~
|
||||
SELECT DISTINCT name FROM pragma_function_list
|
||||
WHERE (flags & 0x80000)!=0
|
||||
ORDER BY name;
|
||||
~~~
|
||||
|
||||
Doing the same is not possible for virtual tables, as a virtual table
|
||||
might be Innocuous, Normal, or Direct-Only depending on the arguments
|
||||
passed into the xConnect method.
|
||||
+6
-17
@@ -37,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]
|
||||
}
|
||||
@@ -79,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} {
|
||||
@@ -141,7 +134,6 @@ do_setup_rec_test $tn.5 {
|
||||
SEARCH TABLE t1 USING COVERING INDEX t1_idx_000123a7 (a=?)
|
||||
}
|
||||
|
||||
if 0 {
|
||||
do_setup_rec_test $tn.6 {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
} {
|
||||
@@ -150,7 +142,6 @@ do_setup_rec_test $tn.6 {
|
||||
CREATE INDEX t1_idx_00000061 ON t1(a);
|
||||
SEARCH TABLE t1 USING COVERING INDEX t1_idx_00000061
|
||||
}
|
||||
}
|
||||
|
||||
do_setup_rec_test $tn.7 {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
@@ -252,10 +243,8 @@ do_setup_rec_test $tn.12.1 {
|
||||
CREATE INDEX t7_idx_00000062 ON t7(b);
|
||||
CREATE INDEX t7_idx_00000061 ON t7(a);
|
||||
MULTI-INDEX OR
|
||||
INDEX 1
|
||||
SEARCH TABLE t7 USING INDEX t7_idx_00000061 (a=?)
|
||||
INDEX 2
|
||||
SEARCH TABLE t7 USING INDEX t7_idx_00000062 (b=?)
|
||||
SEARCH TABLE t7 USING INDEX t7_idx_00000061 (a=?)
|
||||
SEARCH TABLE t7 USING INDEX t7_idx_00000062 (b=?)
|
||||
}
|
||||
|
||||
# rowid terms.
|
||||
@@ -343,7 +332,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);
|
||||
|
||||
@@ -353,7 +342,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
|
||||
@@ -362,14 +351,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
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
#if !defined(SQLITEEXPERT_H)
|
||||
#define SQLITEEXPERT_H 1
|
||||
|
||||
|
||||
#include "sqlite3.h"
|
||||
|
||||
typedef struct sqlite3expert sqlite3expert;
|
||||
@@ -165,4 +165,4 @@ const char *sqlite3_expert_report(sqlite3expert*, int iStmt, int eReport);
|
||||
*/
|
||||
void sqlite3_expert_destroy(sqlite3expert*);
|
||||
|
||||
#endif /* !defined(SQLITEEXPERT_H) */
|
||||
|
||||
|
||||
@@ -52,10 +52,8 @@
|
||||
|
||||
SECURITY: If the fts3 extension is used in an environment where potentially
|
||||
malicious users may execute arbitrary SQL (i.e. gears), they should be
|
||||
prevented from invoking the fts3_tokenizer() function. The
|
||||
fts3_tokenizer() function is disabled by default. It is only enabled
|
||||
by SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER. Do not enable it in
|
||||
security sensitive environments.
|
||||
prevented from invoking the fts3_tokenizer() function, possibly using the
|
||||
authorisation callback.
|
||||
|
||||
See "Sample code" below for an example of calling the fts3_tokenizer()
|
||||
function from C code.
|
||||
|
||||
+108
-213
@@ -320,14 +320,6 @@ int sqlite3Fts3Never(int b) { assert( !b ); return b; }
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This variable is set to false when running tests for which the on disk
|
||||
** structures should not be corrupt. Otherwise, true. If it is false, extra
|
||||
** assert() conditions in the fts3 code are activated - conditions that are
|
||||
** only true if it is guaranteed that the fts3 database is not corrupt.
|
||||
*/
|
||||
int sqlite3_fts3_may_be_corrupt = 1;
|
||||
|
||||
/*
|
||||
** Write a 64-bit variable-length integer to memory starting at p[0].
|
||||
** The length of data written will be between 1 and FTS3_VARINT_MAX bytes.
|
||||
@@ -346,13 +338,18 @@ int sqlite3Fts3PutVarint(char *p, sqlite_int64 v){
|
||||
}
|
||||
|
||||
#define GETVARINT_STEP(v, ptr, shift, mask1, mask2, var, ret) \
|
||||
v = (v & mask1) | ( (*(const unsigned char*)(ptr++)) << shift ); \
|
||||
v = (v & mask1) | ( (*ptr++) << shift ); \
|
||||
if( (v & mask2)==0 ){ var = v; return ret; }
|
||||
#define GETVARINT_INIT(v, ptr, shift, mask1, mask2, var, ret) \
|
||||
v = (*ptr++); \
|
||||
if( (v & mask2)==0 ){ var = v; return ret; }
|
||||
|
||||
int sqlite3Fts3GetVarintU(const char *pBuf, sqlite_uint64 *v){
|
||||
/*
|
||||
** Read a 64-bit variable-length integer from memory starting at p[0].
|
||||
** Return the number of bytes read, or 0 on error.
|
||||
** The value is stored in *v.
|
||||
*/
|
||||
int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
|
||||
const unsigned char *p = (const unsigned char*)pBuf;
|
||||
const unsigned char *pStart = p;
|
||||
u32 a;
|
||||
@@ -374,61 +371,25 @@ int sqlite3Fts3GetVarintU(const char *pBuf, sqlite_uint64 *v){
|
||||
return (int)(p - pStart);
|
||||
}
|
||||
|
||||
/*
|
||||
** Read a 64-bit variable-length integer from memory starting at p[0].
|
||||
** Return the number of bytes read, or 0 on error.
|
||||
** The value is stored in *v.
|
||||
*/
|
||||
int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
|
||||
return sqlite3Fts3GetVarintU(pBuf, (sqlite3_uint64*)v);
|
||||
}
|
||||
|
||||
/*
|
||||
** Read a 64-bit variable-length integer from memory starting at p[0] and
|
||||
** not extending past pEnd[-1].
|
||||
** Return the number of bytes read, or 0 on error.
|
||||
** The value is stored in *v.
|
||||
*/
|
||||
int sqlite3Fts3GetVarintBounded(
|
||||
const char *pBuf,
|
||||
const char *pEnd,
|
||||
sqlite_int64 *v
|
||||
){
|
||||
const unsigned char *p = (const unsigned char*)pBuf;
|
||||
const unsigned char *pStart = p;
|
||||
const unsigned char *pX = (const unsigned char*)pEnd;
|
||||
u64 b = 0;
|
||||
int shift;
|
||||
for(shift=0; shift<=63; shift+=7){
|
||||
u64 c = p<pX ? *p : 0;
|
||||
p++;
|
||||
b += (c&0x7F) << shift;
|
||||
if( (c & 0x80)==0 ) break;
|
||||
}
|
||||
*v = b;
|
||||
return (int)(p - pStart);
|
||||
}
|
||||
|
||||
/*
|
||||
** Similar to sqlite3Fts3GetVarint(), except that the output is truncated to
|
||||
** a non-negative 32-bit integer before it is returned.
|
||||
*/
|
||||
int sqlite3Fts3GetVarint32(const char *p, int *pi){
|
||||
const unsigned char *ptr = (const unsigned char*)p;
|
||||
u32 a;
|
||||
|
||||
#ifndef fts3GetVarint32
|
||||
GETVARINT_INIT(a, ptr, 0, 0x00, 0x80, *pi, 1);
|
||||
GETVARINT_INIT(a, p, 0, 0x00, 0x80, *pi, 1);
|
||||
#else
|
||||
a = (*ptr++);
|
||||
a = (*p++);
|
||||
assert( a & 0x80 );
|
||||
#endif
|
||||
|
||||
GETVARINT_STEP(a, ptr, 7, 0x7F, 0x4000, *pi, 2);
|
||||
GETVARINT_STEP(a, ptr, 14, 0x3FFF, 0x200000, *pi, 3);
|
||||
GETVARINT_STEP(a, ptr, 21, 0x1FFFFF, 0x10000000, *pi, 4);
|
||||
GETVARINT_STEP(a, p, 7, 0x7F, 0x4000, *pi, 2);
|
||||
GETVARINT_STEP(a, p, 14, 0x3FFF, 0x200000, *pi, 3);
|
||||
GETVARINT_STEP(a, p, 21, 0x1FFFFF, 0x10000000, *pi, 4);
|
||||
a = (a & 0x0FFFFFFF );
|
||||
*pi = (int)(a | ((u32)(*ptr & 0x07) << 28));
|
||||
*pi = (int)(a | ((u32)(*p & 0x07) << 28));
|
||||
assert( 0==(a & 0x80000000) );
|
||||
assert( *pi>=0 );
|
||||
return 5;
|
||||
@@ -599,18 +560,13 @@ static int fts3DestroyMethod(sqlite3_vtab *pVtab){
|
||||
sqlite3 *db = p->db; /* Database handle */
|
||||
|
||||
/* Drop the shadow tables */
|
||||
fts3DbExec(&rc, db,
|
||||
"DROP TABLE IF EXISTS %Q.'%q_segments';"
|
||||
"DROP TABLE IF EXISTS %Q.'%q_segdir';"
|
||||
"DROP TABLE IF EXISTS %Q.'%q_docsize';"
|
||||
"DROP TABLE IF EXISTS %Q.'%q_stat';"
|
||||
"%s DROP TABLE IF EXISTS %Q.'%q_content';",
|
||||
zDb, p->zName,
|
||||
zDb, p->zName,
|
||||
zDb, p->zName,
|
||||
zDb, p->zName,
|
||||
(p->zContentTbl ? "--" : ""), zDb,p->zName
|
||||
);
|
||||
if( p->zContentTbl==0 ){
|
||||
fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_content'", zDb, p->zName);
|
||||
}
|
||||
fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segments'", zDb,p->zName);
|
||||
fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segdir'", zDb, p->zName);
|
||||
fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_docsize'", zDb, p->zName);
|
||||
fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_stat'", zDb, p->zName);
|
||||
|
||||
/* If everything has worked, invoke fts3DisconnectMethod() to free the
|
||||
** memory associated with the Fts3Table structure and return SQLITE_OK.
|
||||
@@ -842,10 +798,10 @@ static void fts3Appendf(
|
||||
** memory.
|
||||
*/
|
||||
static char *fts3QuoteId(char const *zInput){
|
||||
sqlite3_int64 nRet;
|
||||
int nRet;
|
||||
char *zRet;
|
||||
nRet = 2 + (int)strlen(zInput)*2 + 1;
|
||||
zRet = sqlite3_malloc64(nRet);
|
||||
zRet = sqlite3_malloc(nRet);
|
||||
if( zRet ){
|
||||
int i;
|
||||
char *z = zRet;
|
||||
@@ -962,22 +918,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 +933,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;
|
||||
}
|
||||
|
||||
@@ -1040,7 +982,7 @@ static int fts3PrefixParameter(
|
||||
}
|
||||
}
|
||||
|
||||
aIndex = sqlite3_malloc64(sizeof(struct Fts3Index) * nIndex);
|
||||
aIndex = sqlite3_malloc(sizeof(struct Fts3Index) * nIndex);
|
||||
*apIndex = aIndex;
|
||||
if( !aIndex ){
|
||||
return SQLITE_NOMEM;
|
||||
@@ -1119,7 +1061,7 @@ static int fts3ContentColumns(
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
const char **azCol; /* Output array */
|
||||
sqlite3_int64 nStr = 0; /* Size of all column names (incl. 0x00) */
|
||||
int nStr = 0; /* Size of all column names (incl. 0x00) */
|
||||
int nCol; /* Number of table columns */
|
||||
int i; /* Used to iterate through columns */
|
||||
|
||||
@@ -1129,11 +1071,11 @@ static int fts3ContentColumns(
|
||||
nCol = sqlite3_column_count(pStmt);
|
||||
for(i=0; i<nCol; i++){
|
||||
const char *zCol = sqlite3_column_name(pStmt, i);
|
||||
nStr += strlen(zCol) + 1;
|
||||
nStr += (int)strlen(zCol) + 1;
|
||||
}
|
||||
|
||||
/* Allocate and populate the array to return. */
|
||||
azCol = (const char **)sqlite3_malloc64(sizeof(char *) * nCol + nStr);
|
||||
azCol = (const char **)sqlite3_malloc(sizeof(char *) * nCol + nStr);
|
||||
if( azCol==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -1181,7 +1123,7 @@ static int fts3InitVtab(
|
||||
Fts3Table *p = 0; /* Pointer to allocated vtab */
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
int i; /* Iterator variable */
|
||||
sqlite3_int64 nByte; /* Size of allocation used for *p */
|
||||
int nByte; /* Size of allocation used for *p */
|
||||
int iCol; /* Column index */
|
||||
int nString = 0; /* Bytes required to hold all column names */
|
||||
int nCol = 0; /* Number of columns in the FTS table */
|
||||
@@ -1215,10 +1157,10 @@ static int fts3InitVtab(
|
||||
nName = (int)strlen(argv[2]) + 1;
|
||||
|
||||
nByte = sizeof(const char *) * (argc-2);
|
||||
aCol = (const char **)sqlite3_malloc64(nByte);
|
||||
aCol = (const char **)sqlite3_malloc(nByte);
|
||||
if( aCol ){
|
||||
memset((void*)aCol, 0, nByte);
|
||||
azNotindexed = (char **)sqlite3_malloc64(nByte);
|
||||
azNotindexed = (char **)sqlite3_malloc(nByte);
|
||||
}
|
||||
if( azNotindexed ){
|
||||
memset(azNotindexed, 0, nByte);
|
||||
@@ -1413,7 +1355,7 @@ static int fts3InitVtab(
|
||||
nName + /* zName */
|
||||
nDb + /* zDb */
|
||||
nString; /* Space for azColumn strings */
|
||||
p = (Fts3Table*)sqlite3_malloc64(nByte);
|
||||
p = (Fts3Table*)sqlite3_malloc(nByte);
|
||||
if( p==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto fts3_init_out;
|
||||
@@ -1518,10 +1460,6 @@ static int fts3InitVtab(
|
||||
fts3DatabasePageSize(&rc, p);
|
||||
p->nNodeSize = p->nPgsz-35;
|
||||
|
||||
#if defined(SQLITE_DEBUG)||defined(SQLITE_TEST)
|
||||
p->nMergeCount = FTS3_MERGE_COUNT;
|
||||
#endif
|
||||
|
||||
/* Declare the table schema to SQLite. */
|
||||
fts3DeclareVtab(&rc, p);
|
||||
|
||||
@@ -1617,10 +1555,6 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
||||
int iDocidLe = -1; /* Index of docid<=x constraint, if present */
|
||||
int iIdx;
|
||||
|
||||
if( p->bLock ){
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/* By default use a full table scan. This is an expensive option,
|
||||
** so search through the constraints to see if a more efficient
|
||||
** strategy is possible.
|
||||
@@ -1819,11 +1753,7 @@ static int fts3CursorSeekStmt(Fts3Cursor *pCsr){
|
||||
}else{
|
||||
zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist);
|
||||
if( !zSql ) return SQLITE_NOMEM;
|
||||
p->bLock++;
|
||||
rc = sqlite3_prepare_v3(
|
||||
p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0
|
||||
);
|
||||
p->bLock--;
|
||||
rc = sqlite3_prepare_v3(p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0);
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
if( rc==SQLITE_OK ) pCsr->bSeekStmt = 1;
|
||||
@@ -1841,15 +1771,11 @@ static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
|
||||
if( pCsr->isRequireSeek ){
|
||||
rc = fts3CursorSeekStmt(pCsr);
|
||||
if( rc==SQLITE_OK ){
|
||||
Fts3Table *pTab = (Fts3Table*)pCsr->base.pVtab;
|
||||
pTab->bLock++;
|
||||
sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId);
|
||||
pCsr->isRequireSeek = 0;
|
||||
if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){
|
||||
pTab->bLock--;
|
||||
return SQLITE_OK;
|
||||
}else{
|
||||
pTab->bLock--;
|
||||
rc = sqlite3_reset(pCsr->pStmt);
|
||||
if( rc==SQLITE_OK && ((Fts3Table *)pCsr->base.pVtab)->zContentTbl==0 ){
|
||||
/* If no row was found and no error has occurred, then the %_content
|
||||
@@ -1898,7 +1824,6 @@ static int fts3ScanInteriorNode(
|
||||
i64 nAlloc = 0; /* Size of allocated buffer */
|
||||
int isFirstTerm = 1; /* True when processing first term on page */
|
||||
sqlite3_int64 iChild; /* Block id of child node to descend to */
|
||||
int nBuffer = 0; /* Total term size */
|
||||
|
||||
/* Skip over the 'height' varint that occurs at the start of every
|
||||
** interior node. Then load the blockid of the left-child of the b-tree
|
||||
@@ -1923,21 +1848,18 @@ static int fts3ScanInteriorNode(
|
||||
int cmp; /* memcmp() result */
|
||||
int nSuffix; /* Size of term suffix */
|
||||
int nPrefix = 0; /* Size of term prefix */
|
||||
int nBuffer; /* Total term size */
|
||||
|
||||
/* Load the next term on the node into zBuffer. Use realloc() to expand
|
||||
** the size of zBuffer if required. */
|
||||
if( !isFirstTerm ){
|
||||
zCsr += fts3GetVarint32(zCsr, &nPrefix);
|
||||
if( nPrefix>nBuffer ){
|
||||
rc = FTS_CORRUPT_VTAB;
|
||||
goto finish_scan;
|
||||
}
|
||||
}
|
||||
isFirstTerm = 0;
|
||||
zCsr += fts3GetVarint32(zCsr, &nSuffix);
|
||||
|
||||
assert( nPrefix>=0 && nSuffix>=0 );
|
||||
if( nPrefix>zCsr-zNode || nSuffix>zEnd-zCsr || nSuffix==0 ){
|
||||
if( nPrefix>zCsr-zNode || nSuffix>zEnd-zCsr ){
|
||||
rc = FTS_CORRUPT_VTAB;
|
||||
goto finish_scan;
|
||||
}
|
||||
@@ -2025,7 +1947,7 @@ static int fts3SelectLeaf(
|
||||
|
||||
fts3GetVarint32(zNode, &iHeight);
|
||||
rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2);
|
||||
assert_fts3_nc( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) );
|
||||
assert( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) );
|
||||
|
||||
if( rc==SQLITE_OK && iHeight>1 ){
|
||||
char *zBlob = 0; /* Blob read from %_segments table */
|
||||
@@ -2045,13 +1967,7 @@ static int fts3SelectLeaf(
|
||||
rc = sqlite3Fts3ReadBlock(p, piLeaf?*piLeaf:*piLeaf2, &zBlob, &nBlob, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
int iNewHeight = 0;
|
||||
fts3GetVarint32(zBlob, &iNewHeight);
|
||||
if( iNewHeight>=iHeight ){
|
||||
rc = FTS_CORRUPT_VTAB;
|
||||
}else{
|
||||
rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, piLeaf2);
|
||||
}
|
||||
rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, piLeaf2);
|
||||
}
|
||||
sqlite3_free(zBlob);
|
||||
}
|
||||
@@ -2156,11 +2072,10 @@ static void fts3ColumnlistCopy(char **pp, char **ppPoslist){
|
||||
}
|
||||
|
||||
/*
|
||||
** Value used to signify the end of an position-list. This must be
|
||||
** as large or larger than any value that might appear on the
|
||||
** position-list, even a position list that has been corrupted.
|
||||
** Value used to signify the end of an position-list. This is safe because
|
||||
** it is not possible to have a document with 2^31 terms.
|
||||
*/
|
||||
#define POSITION_LIST_END LARGEST_INT64
|
||||
#define POSITION_LIST_END 0x7fffffff
|
||||
|
||||
/*
|
||||
** This function is used to help parse position-lists. When this function is
|
||||
@@ -2219,7 +2134,7 @@ static int fts3PutColNumber(char **pp, int iCol){
|
||||
** updated appropriately. The caller is responsible for insuring
|
||||
** that there is enough space in *pp to hold the complete output.
|
||||
*/
|
||||
static int fts3PoslistMerge(
|
||||
static void fts3PoslistMerge(
|
||||
char **pp, /* Output buffer */
|
||||
char **pp1, /* Left input list */
|
||||
char **pp2 /* Right input list */
|
||||
@@ -2232,18 +2147,12 @@ static int fts3PoslistMerge(
|
||||
int iCol1; /* The current column index in pp1 */
|
||||
int iCol2; /* The current column index in pp2 */
|
||||
|
||||
if( *p1==POS_COLUMN ){
|
||||
fts3GetVarint32(&p1[1], &iCol1);
|
||||
if( iCol1==0 ) return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
else if( *p1==POS_END ) iCol1 = 0x7fffffff;
|
||||
if( *p1==POS_COLUMN ) fts3GetVarint32(&p1[1], &iCol1);
|
||||
else if( *p1==POS_END ) iCol1 = POSITION_LIST_END;
|
||||
else iCol1 = 0;
|
||||
|
||||
if( *p2==POS_COLUMN ){
|
||||
fts3GetVarint32(&p2[1], &iCol2);
|
||||
if( iCol2==0 ) return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
else if( *p2==POS_END ) iCol2 = 0x7fffffff;
|
||||
if( *p2==POS_COLUMN ) fts3GetVarint32(&p2[1], &iCol2);
|
||||
else if( *p2==POS_END ) iCol2 = POSITION_LIST_END;
|
||||
else iCol2 = 0;
|
||||
|
||||
if( iCol1==iCol2 ){
|
||||
@@ -2290,7 +2199,6 @@ static int fts3PoslistMerge(
|
||||
*pp = p;
|
||||
*pp1 = p1 + 1;
|
||||
*pp2 = p2 + 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2355,9 +2263,10 @@ static int fts3PoslistPhraseMerge(
|
||||
p += sqlite3Fts3PutVarint(p, iCol1);
|
||||
}
|
||||
|
||||
assert( *p1!=POS_END && *p1!=POS_COLUMN );
|
||||
assert( *p2!=POS_END && *p2!=POS_COLUMN );
|
||||
fts3GetDeltaVarint(&p1, &iPos1); iPos1 -= 2;
|
||||
fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2;
|
||||
if( iPos1<0 || iPos2<0 ) break;
|
||||
|
||||
while( 1 ){
|
||||
if( iPos2==iPos1+nToken
|
||||
@@ -2506,12 +2415,12 @@ static void fts3GetDeltaVarint3(
|
||||
if( *pp>=pEnd ){
|
||||
*pp = 0;
|
||||
}else{
|
||||
u64 iVal;
|
||||
*pp += sqlite3Fts3GetVarintU(*pp, &iVal);
|
||||
sqlite3_int64 iVal;
|
||||
*pp += sqlite3Fts3GetVarint(*pp, &iVal);
|
||||
if( bDescIdx ){
|
||||
*pVal = (i64)((u64)*pVal - iVal);
|
||||
*pVal -= iVal;
|
||||
}else{
|
||||
*pVal = (i64)((u64)*pVal + iVal);
|
||||
*pVal += iVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2538,16 +2447,14 @@ static void fts3PutDeltaVarint3(
|
||||
int *pbFirst, /* IN/OUT: True after first int written */
|
||||
sqlite3_int64 iVal /* Write this value to the list */
|
||||
){
|
||||
sqlite3_uint64 iWrite;
|
||||
sqlite3_int64 iWrite;
|
||||
if( bDescIdx==0 || *pbFirst==0 ){
|
||||
assert_fts3_nc( *pbFirst==0 || iVal>=*piPrev );
|
||||
iWrite = (u64)iVal - (u64)*piPrev;
|
||||
iWrite = iVal - *piPrev;
|
||||
}else{
|
||||
assert_fts3_nc( *piPrev>=iVal );
|
||||
iWrite = (u64)*piPrev - (u64)iVal;
|
||||
iWrite = *piPrev - iVal;
|
||||
}
|
||||
assert( *pbFirst || *piPrev==0 );
|
||||
assert_fts3_nc( *pbFirst==0 || iWrite>0 );
|
||||
assert( *pbFirst==0 || iWrite>0 );
|
||||
*pp += sqlite3Fts3PutVarint(*pp, iWrite);
|
||||
*piPrev = iVal;
|
||||
*pbFirst = 1;
|
||||
@@ -2563,8 +2470,7 @@ static void fts3PutDeltaVarint3(
|
||||
** Using this makes it easier to write code that can merge doclists that are
|
||||
** sorted in either ascending or descending order.
|
||||
*/
|
||||
/* #define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i64)((u64)i1-i2)) */
|
||||
#define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i1>i2?1:((i1==i2)?0:-1)))
|
||||
#define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i1-i2))
|
||||
|
||||
/*
|
||||
** This function does an "OR" merge of two doclists (output contains all
|
||||
@@ -2586,7 +2492,6 @@ static int fts3DoclistOrMerge(
|
||||
char *a2, int n2, /* Second doclist */
|
||||
char **paOut, int *pnOut /* OUT: Malloc'd doclist */
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_int64 i1 = 0;
|
||||
sqlite3_int64 i2 = 0;
|
||||
sqlite3_int64 iPrev = 0;
|
||||
@@ -2630,7 +2535,7 @@ static int fts3DoclistOrMerge(
|
||||
** A symetric argument may be made if the doclists are in descending
|
||||
** order.
|
||||
*/
|
||||
aOut = sqlite3_malloc64((i64)n1+n2+FTS3_VARINT_MAX-1+FTS3_BUFFER_PADDING);
|
||||
aOut = sqlite3_malloc(n1+n2+FTS3_VARINT_MAX-1);
|
||||
if( !aOut ) return SQLITE_NOMEM;
|
||||
|
||||
p = aOut;
|
||||
@@ -2641,8 +2546,7 @@ static int fts3DoclistOrMerge(
|
||||
|
||||
if( p2 && p1 && iDiff==0 ){
|
||||
fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i1);
|
||||
rc = fts3PoslistMerge(&p, &p1, &p2);
|
||||
if( rc ) break;
|
||||
fts3PoslistMerge(&p, &p1, &p2);
|
||||
fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1);
|
||||
fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2);
|
||||
}else if( !p2 || (p1 && iDiff<0) ){
|
||||
@@ -2654,20 +2558,12 @@ static int fts3DoclistOrMerge(
|
||||
fts3PoslistCopy(&p, &p2);
|
||||
fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2);
|
||||
}
|
||||
|
||||
assert( (p-aOut)<=((p1?(p1-a1):n1)+(p2?(p2-a2):n2)+FTS3_VARINT_MAX-1) );
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_free(aOut);
|
||||
p = aOut = 0;
|
||||
}else{
|
||||
assert( (p-aOut)<=n1+n2+FTS3_VARINT_MAX-1 );
|
||||
memset(&aOut[(p-aOut)], 0, FTS3_BUFFER_PADDING);
|
||||
}
|
||||
*paOut = aOut;
|
||||
*pnOut = (int)(p-aOut);
|
||||
return rc;
|
||||
assert( *pnOut<=n1+n2+FTS3_VARINT_MAX-1 );
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2702,7 +2598,7 @@ static int fts3DoclistPhraseMerge(
|
||||
|
||||
assert( nDist>0 );
|
||||
if( bDescDoclist ){
|
||||
aOut = sqlite3_malloc64((sqlite3_int64)*pnRight + FTS3_VARINT_MAX);
|
||||
aOut = sqlite3_malloc(*pnRight + FTS3_VARINT_MAX);
|
||||
if( aOut==0 ) return SQLITE_NOMEM;
|
||||
}else{
|
||||
aOut = aRight;
|
||||
@@ -2886,7 +2782,6 @@ static int fts3TermSelectMerge(
|
||||
pTS->anOutput[0] = nDoclist;
|
||||
if( pTS->aaOutput[0] ){
|
||||
memcpy(pTS->aaOutput[0], aDoclist, nDoclist);
|
||||
memset(&pTS->aaOutput[0][nDoclist], 0, FTS3_VARINT_MAX);
|
||||
}else{
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@@ -2938,8 +2833,8 @@ static int fts3SegReaderCursorAppend(
|
||||
){
|
||||
if( (pCsr->nSegment%16)==0 ){
|
||||
Fts3SegReader **apNew;
|
||||
sqlite3_int64 nByte = (pCsr->nSegment + 16)*sizeof(Fts3SegReader*);
|
||||
apNew = (Fts3SegReader **)sqlite3_realloc64(pCsr->apSegment, nByte);
|
||||
int nByte = (pCsr->nSegment + 16)*sizeof(Fts3SegReader*);
|
||||
apNew = (Fts3SegReader **)sqlite3_realloc(pCsr->apSegment, nByte);
|
||||
if( !apNew ){
|
||||
sqlite3Fts3SegReaderFree(pNew);
|
||||
return SQLITE_NOMEM;
|
||||
@@ -2978,7 +2873,7 @@ static int fts3SegReaderCursor(
|
||||
** Fts3SegReaderPending might segfault, as the data structures used by
|
||||
** fts4aux are not completely populated. So it's easiest to filter these
|
||||
** calls out here. */
|
||||
if( iLevel<0 && p->aIndex && p->iPrevLangid==iLangid ){
|
||||
if( iLevel<0 && p->aIndex ){
|
||||
Fts3SegReader *pSeg = 0;
|
||||
rc = sqlite3Fts3SegReaderPending(p, iIndex, zTerm, nTerm, isPrefix||isScan, &pSeg);
|
||||
if( rc==SQLITE_OK && pSeg ){
|
||||
@@ -3003,7 +2898,7 @@ static int fts3SegReaderCursor(
|
||||
|
||||
/* If zTerm is not NULL, and this segment is not stored entirely on its
|
||||
** root node, the range of leaves scanned can be reduced. Do this. */
|
||||
if( iStartBlock && zTerm && zRoot ){
|
||||
if( iStartBlock && zTerm ){
|
||||
sqlite3_int64 *pi = (isPrefix ? &iLeavesEndBlock : 0);
|
||||
rc = fts3SelectLeaf(p, zTerm, nTerm, zRoot, nRoot, &iStartBlock, pi);
|
||||
if( rc!=SQLITE_OK ) goto finished;
|
||||
@@ -3241,8 +3136,6 @@ static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
int rc;
|
||||
Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
|
||||
if( pCsr->eSearch==FTS3_DOCID_SEARCH || pCsr->eSearch==FTS3_FULLSCAN_SEARCH ){
|
||||
Fts3Table *pTab = (Fts3Table*)pCursor->pVtab;
|
||||
pTab->bLock++;
|
||||
if( SQLITE_ROW!=sqlite3_step(pCsr->pStmt) ){
|
||||
pCsr->isEof = 1;
|
||||
rc = sqlite3_reset(pCsr->pStmt);
|
||||
@@ -3250,7 +3143,6 @@ static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
pCsr->iPrevId = sqlite3_column_int64(pCsr->pStmt, 0);
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
pTab->bLock--;
|
||||
}else{
|
||||
rc = fts3EvalNext((Fts3Cursor *)pCursor);
|
||||
}
|
||||
@@ -3258,6 +3150,18 @@ static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** The following are copied from sqliteInt.h.
|
||||
**
|
||||
** Constants for the largest and smallest possible 64-bit signed integers.
|
||||
** These macros are designed to work correctly on both 32-bit and 64-bit
|
||||
** compilers.
|
||||
*/
|
||||
#ifndef SQLITE_AMALGAMATION
|
||||
# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
|
||||
# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** If the numeric type of argument pVal is "integer", then return it
|
||||
** converted to a 64-bit signed integer. Otherwise, return a copy of
|
||||
@@ -3311,10 +3215,6 @@ static int fts3FilterMethod(
|
||||
UNUSED_PARAMETER(idxStr);
|
||||
UNUSED_PARAMETER(nVal);
|
||||
|
||||
if( p->bLock ){
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
eSearch = (idxNum & 0x0000FFFF);
|
||||
assert( eSearch>=0 && eSearch<=(FTS3_FULLTEXT_SEARCH+p->nColumn) );
|
||||
assert( p->pSegments==0 );
|
||||
@@ -3386,11 +3286,7 @@ static int fts3FilterMethod(
|
||||
);
|
||||
}
|
||||
if( zSql ){
|
||||
p->bLock++;
|
||||
rc = sqlite3_prepare_v3(
|
||||
p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0
|
||||
);
|
||||
p->bLock--;
|
||||
rc = sqlite3_prepare_v3(p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0);
|
||||
sqlite3_free(zSql);
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
@@ -3944,6 +3840,7 @@ static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
Fts3Table *p = (Fts3Table*)pVtab;
|
||||
UNUSED_PARAMETER(iSavepoint);
|
||||
assert( p->inTransaction );
|
||||
assert( p->mxSavepoint >= iSavepoint );
|
||||
TESTONLY( p->mxSavepoint = iSavepoint );
|
||||
sqlite3Fts3PendingTermsClear(p);
|
||||
return SQLITE_OK;
|
||||
@@ -4407,7 +4304,7 @@ static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){
|
||||
int bIncrOk = (bOptOk
|
||||
&& pCsr->bDesc==pTab->bDescIdx
|
||||
&& p->nToken<=MAX_INCR_PHRASE_TOKENS && p->nToken>0
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
#ifdef SQLITE_TEST
|
||||
&& pTab->bNoIncrDoclist==0
|
||||
#endif
|
||||
);
|
||||
@@ -4549,16 +4446,15 @@ static void fts3EvalDlPhraseNext(
|
||||
u8 *pbEof
|
||||
){
|
||||
char *pIter; /* Used to iterate through aAll */
|
||||
char *pEnd; /* 1 byte past end of aAll */
|
||||
char *pEnd = &pDL->aAll[pDL->nAll]; /* 1 byte past end of aAll */
|
||||
|
||||
if( pDL->pNextDocid ){
|
||||
pIter = pDL->pNextDocid;
|
||||
assert( pDL->aAll!=0 || pIter==0 );
|
||||
}else{
|
||||
pIter = pDL->aAll;
|
||||
}
|
||||
|
||||
if( pIter==0 || pIter>=(pEnd = pDL->aAll + pDL->nAll) ){
|
||||
if( pIter>=pEnd ){
|
||||
/* We have already reached the end of this doclist. EOF. */
|
||||
*pbEof = 1;
|
||||
}else{
|
||||
@@ -4719,10 +4615,9 @@ static int fts3EvalIncrPhraseNext(
|
||||
if( bEof==0 ){
|
||||
int nList = 0;
|
||||
int nByte = a[p->nToken-1].nList;
|
||||
char *aDoclist = sqlite3_malloc(nByte+FTS3_BUFFER_PADDING);
|
||||
char *aDoclist = sqlite3_malloc(nByte+1);
|
||||
if( !aDoclist ) return SQLITE_NOMEM;
|
||||
memcpy(aDoclist, a[p->nToken-1].pList, nByte+1);
|
||||
memset(&aDoclist[nByte], 0, FTS3_BUFFER_PADDING);
|
||||
|
||||
for(i=0; i<(p->nToken-1); i++){
|
||||
if( a[i].bIgnore==0 ){
|
||||
@@ -4930,13 +4825,12 @@ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
|
||||
rc = sqlite3Fts3SelectDoctotal(p, &pStmt);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
a = sqlite3_column_blob(pStmt, 0);
|
||||
testcase( a==0 ); /* If %_stat.value set to X'' */
|
||||
if( a ){
|
||||
pEnd = &a[sqlite3_column_bytes(pStmt, 0)];
|
||||
a += sqlite3Fts3GetVarintBounded(a, pEnd, &nDoc);
|
||||
while( a<pEnd ){
|
||||
a += sqlite3Fts3GetVarintBounded(a, pEnd, &nByte);
|
||||
}
|
||||
assert( a );
|
||||
|
||||
pEnd = &a[sqlite3_column_bytes(pStmt, 0)];
|
||||
a += sqlite3Fts3GetVarint(a, &nDoc);
|
||||
while( a<pEnd ){
|
||||
a += sqlite3Fts3GetVarint(a, &nByte);
|
||||
}
|
||||
if( nDoc==0 || nByte==0 ){
|
||||
sqlite3_reset(pStmt);
|
||||
@@ -5114,7 +5008,7 @@ static int fts3EvalStart(Fts3Cursor *pCsr){
|
||||
if( rc==SQLITE_OK && nToken>1 && pTab->bFts4 ){
|
||||
Fts3TokenAndCost *aTC;
|
||||
Fts3Expr **apOr;
|
||||
aTC = (Fts3TokenAndCost *)sqlite3_malloc64(
|
||||
aTC = (Fts3TokenAndCost *)sqlite3_malloc(
|
||||
sizeof(Fts3TokenAndCost) * nToken
|
||||
+ sizeof(Fts3Expr *) * nOr * 2
|
||||
);
|
||||
@@ -5425,7 +5319,7 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
|
||||
&& (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR)
|
||||
){
|
||||
Fts3Expr *p;
|
||||
sqlite3_int64 nTmp = 0; /* Bytes of temp space */
|
||||
int nTmp = 0; /* Bytes of temp space */
|
||||
char *aTmp; /* Temp space for PoslistNearMerge() */
|
||||
|
||||
/* Allocate temporary working space. */
|
||||
@@ -5434,7 +5328,7 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
|
||||
nTmp += p->pRight->pPhrase->doclist.nList;
|
||||
}
|
||||
nTmp += p->pPhrase->doclist.nList;
|
||||
aTmp = sqlite3_malloc64(nTmp*2);
|
||||
aTmp = sqlite3_malloc(nTmp*2);
|
||||
if( !aTmp ){
|
||||
*pRc = SQLITE_NOMEM;
|
||||
res = 0;
|
||||
@@ -5704,14 +5598,15 @@ static void fts3EvalRestart(
|
||||
** found in Fts3Expr.pPhrase->doclist.pList for each of the phrase
|
||||
** expression nodes.
|
||||
*/
|
||||
static void fts3EvalUpdateCounts(Fts3Expr *pExpr, int nCol){
|
||||
static void fts3EvalUpdateCounts(Fts3Expr *pExpr){
|
||||
if( pExpr ){
|
||||
Fts3Phrase *pPhrase = pExpr->pPhrase;
|
||||
if( pPhrase && pPhrase->doclist.pList ){
|
||||
int iCol = 0;
|
||||
char *p = pPhrase->doclist.pList;
|
||||
|
||||
do{
|
||||
assert( *p );
|
||||
while( 1 ){
|
||||
u8 c = 0;
|
||||
int iCnt = 0;
|
||||
while( 0xFE & (*p | c) ){
|
||||
@@ -5727,11 +5622,11 @@ static void fts3EvalUpdateCounts(Fts3Expr *pExpr, int nCol){
|
||||
if( *p==0x00 ) break;
|
||||
p++;
|
||||
p += fts3GetVarint32(p, &iCol);
|
||||
}while( iCol<nCol );
|
||||
}
|
||||
}
|
||||
|
||||
fts3EvalUpdateCounts(pExpr->pLeft, nCol);
|
||||
fts3EvalUpdateCounts(pExpr->pRight, nCol);
|
||||
fts3EvalUpdateCounts(pExpr->pLeft);
|
||||
fts3EvalUpdateCounts(pExpr->pRight);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5775,7 +5670,7 @@ static int fts3EvalGatherStats(
|
||||
for(p=pRoot; p; p=p->pLeft){
|
||||
Fts3Expr *pE = (p->eType==FTSQUERY_PHRASE?p:p->pRight);
|
||||
assert( pE->aMI==0 );
|
||||
pE->aMI = (u32 *)sqlite3_malloc64(pTab->nColumn * 3 * sizeof(u32));
|
||||
pE->aMI = (u32 *)sqlite3_malloc(pTab->nColumn * 3 * sizeof(u32));
|
||||
if( !pE->aMI ) return SQLITE_NOMEM;
|
||||
memset(pE->aMI, 0, pTab->nColumn * 3 * sizeof(u32));
|
||||
}
|
||||
@@ -5801,7 +5696,7 @@ static int fts3EvalGatherStats(
|
||||
);
|
||||
|
||||
if( rc==SQLITE_OK && pCsr->isEof==0 ){
|
||||
fts3EvalUpdateCounts(pRoot, pTab->nColumn);
|
||||
fts3EvalUpdateCounts(pRoot);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-32
@@ -95,8 +95,6 @@ SQLITE_EXTENSION_INIT3
|
||||
*/
|
||||
#define FTS3_VARINT_MAX 10
|
||||
|
||||
#define FTS3_BUFFER_PADDING 8
|
||||
|
||||
/*
|
||||
** FTS4 virtual tables may maintain multiple indexes - one index of all terms
|
||||
** in the document set and zero or more prefix indexes. All indexes are stored
|
||||
@@ -129,18 +127,6 @@ SQLITE_EXTENSION_INIT3
|
||||
#define POS_COLUMN (1) /* Column-list terminator */
|
||||
#define POS_END (0) /* Position-list terminator */
|
||||
|
||||
/*
|
||||
** The assert_fts3_nc() macro is similar to the assert() macro, except that it
|
||||
** is used for assert() conditions that are true only if it can be
|
||||
** guranteed that the database is not corrupt.
|
||||
*/
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
extern int sqlite3_fts3_may_be_corrupt;
|
||||
# define assert_fts3_nc(x) assert(sqlite3_fts3_may_be_corrupt || (x))
|
||||
#else
|
||||
# define assert_fts3_nc(x) assert(x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This section provides definitions to allow the
|
||||
** FTS3 extension to be compiled outside of the
|
||||
@@ -196,9 +182,6 @@ typedef sqlite3_int64 i64; /* 8-byte signed integer */
|
||||
# define TESTONLY(X)
|
||||
#endif
|
||||
|
||||
#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
|
||||
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
|
||||
|
||||
#endif /* SQLITE_AMALGAMATION */
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
@@ -242,7 +225,6 @@ struct Fts3Table {
|
||||
char *zLanguageid; /* languageid=xxx option, or NULL */
|
||||
int nAutoincrmerge; /* Value configured by 'automerge' */
|
||||
u32 nLeafAdd; /* Number of leaf blocks added this trans */
|
||||
int bLock; /* Used to prevent recursive content= tbls */
|
||||
|
||||
/* Precompiled statements used by the implementation. Each of these
|
||||
** statements is run and reset within a single virtual table API call.
|
||||
@@ -301,23 +283,13 @@ struct Fts3Table {
|
||||
int mxSavepoint; /* Largest valid xSavepoint integer */
|
||||
#endif
|
||||
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
#ifdef SQLITE_TEST
|
||||
/* True to disable the incremental doclist optimization. This is controled
|
||||
** by special insert command 'test-no-incr-doclist'. */
|
||||
int bNoIncrDoclist;
|
||||
|
||||
/* Number of segments in a level */
|
||||
int nMergeCount;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Macro to find the number of segments to merge */
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
# define MergeCount(P) ((P)->nMergeCount)
|
||||
#else
|
||||
# define MergeCount(P) FTS3_MERGE_COUNT
|
||||
#endif
|
||||
|
||||
/*
|
||||
** When the core wants to read from the virtual table, it creates a
|
||||
** virtual table cursor (an instance of the following structure) using
|
||||
@@ -581,8 +553,6 @@ int sqlite3Fts3Incrmerge(Fts3Table*,int,int);
|
||||
void sqlite3Fts3ErrMsg(char**,const char*,...);
|
||||
int sqlite3Fts3PutVarint(char *, sqlite3_int64);
|
||||
int sqlite3Fts3GetVarint(const char *, sqlite_int64 *);
|
||||
int sqlite3Fts3GetVarintU(const char *, sqlite_uint64 *);
|
||||
int sqlite3Fts3GetVarintBounded(const char*,const char*,sqlite3_int64*);
|
||||
int sqlite3Fts3GetVarint32(const char *, int *);
|
||||
int sqlite3Fts3VarintLen(sqlite3_uint64);
|
||||
void sqlite3Fts3Dequote(char *);
|
||||
@@ -591,7 +561,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 *);
|
||||
|
||||
+5
-5
@@ -66,7 +66,7 @@ static int fts3auxConnectMethod(
|
||||
char const *zFts3; /* Name of fts3 table */
|
||||
int nDb; /* Result of strlen(zDb) */
|
||||
int nFts3; /* Result of strlen(zFts3) */
|
||||
sqlite3_int64 nByte; /* Bytes of space to allocate here */
|
||||
int nByte; /* Bytes of space to allocate here */
|
||||
int rc; /* value returned by declare_vtab() */
|
||||
Fts3auxTable *p; /* Virtual table object to return */
|
||||
|
||||
@@ -98,7 +98,7 @@ static int fts3auxConnectMethod(
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
nByte = sizeof(Fts3auxTable) + sizeof(Fts3Table) + nDb + nFts3 + 2;
|
||||
p = (Fts3auxTable *)sqlite3_malloc64(nByte);
|
||||
p = (Fts3auxTable *)sqlite3_malloc(nByte);
|
||||
if( !p ) return SQLITE_NOMEM;
|
||||
memset(p, 0, nByte);
|
||||
|
||||
@@ -248,7 +248,7 @@ static int fts3auxCloseMethod(sqlite3_vtab_cursor *pCursor){
|
||||
static int fts3auxGrowStatArray(Fts3auxCursor *pCsr, int nSize){
|
||||
if( nSize>pCsr->nStat ){
|
||||
struct Fts3auxColstats *aNew;
|
||||
aNew = (struct Fts3auxColstats *)sqlite3_realloc64(pCsr->aStat,
|
||||
aNew = (struct Fts3auxColstats *)sqlite3_realloc(pCsr->aStat,
|
||||
sizeof(struct Fts3auxColstats) * nSize
|
||||
);
|
||||
if( aNew==0 ) return SQLITE_NOMEM;
|
||||
@@ -416,15 +416,15 @@ static int fts3auxFilterMethod(
|
||||
assert( (iEq==0 && iGe==-1) || (iEq==-1 && iGe==0) );
|
||||
if( zStr ){
|
||||
pCsr->filter.zTerm = sqlite3_mprintf("%s", zStr);
|
||||
pCsr->filter.nTerm = sqlite3_value_bytes(apVal[0]);
|
||||
if( pCsr->filter.zTerm==0 ) return SQLITE_NOMEM;
|
||||
pCsr->filter.nTerm = (int)strlen(pCsr->filter.zTerm);
|
||||
}
|
||||
}
|
||||
|
||||
if( iLe>=0 ){
|
||||
pCsr->zStop = sqlite3_mprintf("%s", sqlite3_value_text(apVal[iLe]));
|
||||
pCsr->nStop = sqlite3_value_bytes(apVal[iLe]);
|
||||
if( pCsr->zStop==0 ) return SQLITE_NOMEM;
|
||||
pCsr->nStop = (int)strlen(pCsr->zStop);
|
||||
}
|
||||
|
||||
if( iLangid>=0 ){
|
||||
|
||||
+12
-8
@@ -122,8 +122,8 @@ static int fts3isspace(char c){
|
||||
** zero the memory before returning a pointer to it. If unsuccessful,
|
||||
** return NULL.
|
||||
*/
|
||||
static void *fts3MallocZero(sqlite3_int64 nByte){
|
||||
void *pRet = sqlite3_malloc64(nByte);
|
||||
static void *fts3MallocZero(int nByte){
|
||||
void *pRet = sqlite3_malloc(nByte);
|
||||
if( pRet ) memset(pRet, 0, nByte);
|
||||
return pRet;
|
||||
}
|
||||
@@ -198,7 +198,7 @@ static int getNextToken(
|
||||
if( rc==SQLITE_OK ){
|
||||
const char *zToken;
|
||||
int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0;
|
||||
sqlite3_int64 nByte; /* total space to allocate */
|
||||
int nByte; /* total space to allocate */
|
||||
|
||||
rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition);
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -252,8 +252,8 @@ static int getNextToken(
|
||||
** Enlarge a memory allocation. If an out-of-memory allocation occurs,
|
||||
** then free the old allocation.
|
||||
*/
|
||||
static void *fts3ReallocOrFree(void *pOrig, sqlite3_int64 nNew){
|
||||
void *pRet = sqlite3_realloc64(pOrig, nNew);
|
||||
static void *fts3ReallocOrFree(void *pOrig, int nNew){
|
||||
void *pRet = sqlite3_realloc(pOrig, nNew);
|
||||
if( !pRet ){
|
||||
sqlite3_free(pOrig);
|
||||
}
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,6 +497,7 @@ static int getNextNode(
|
||||
int nConsumed = 0;
|
||||
pParse->nNest++;
|
||||
rc = fts3ExprParse(pParse, zInput+1, nInput-1, ppExpr, &nConsumed);
|
||||
if( rc==SQLITE_OK && !*ppExpr ){ rc = SQLITE_DONE; }
|
||||
*pnConsumed = (int)(zInput - z) + 1 + nConsumed;
|
||||
return rc;
|
||||
}else if( *zInput==')' ){
|
||||
@@ -792,7 +796,7 @@ static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){
|
||||
if( rc==SQLITE_OK ){
|
||||
if( (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){
|
||||
Fts3Expr **apLeaf;
|
||||
apLeaf = (Fts3Expr **)sqlite3_malloc64(sizeof(Fts3Expr *) * nMaxDepth);
|
||||
apLeaf = (Fts3Expr **)sqlite3_malloc(sizeof(Fts3Expr *) * nMaxDepth);
|
||||
if( 0==apLeaf ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -1212,7 +1216,7 @@ static void fts3ExprTestCommon(
|
||||
zExpr = (const char *)sqlite3_value_text(argv[1]);
|
||||
nExpr = sqlite3_value_bytes(argv[1]);
|
||||
nCol = argc-2;
|
||||
azCol = (char **)sqlite3_malloc64(nCol*sizeof(char *));
|
||||
azCol = (char **)sqlite3_malloc(nCol*sizeof(char *));
|
||||
if( !azCol ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
goto exprtest_out;
|
||||
|
||||
@@ -35,8 +35,8 @@
|
||||
/*
|
||||
** Malloc and Free functions
|
||||
*/
|
||||
static void *fts3HashMalloc(sqlite3_int64 n){
|
||||
void *p = sqlite3_malloc64(n);
|
||||
static void *fts3HashMalloc(int n){
|
||||
void *p = sqlite3_malloc(n);
|
||||
if( p ){
|
||||
memset(p, 0, n);
|
||||
}
|
||||
|
||||
+2
-2
@@ -60,7 +60,7 @@ static int icuCreate(
|
||||
if( argc>0 ){
|
||||
n = strlen(argv[0])+1;
|
||||
}
|
||||
p = (IcuTokenizer *)sqlite3_malloc64(sizeof(IcuTokenizer)+n);
|
||||
p = (IcuTokenizer *)sqlite3_malloc(sizeof(IcuTokenizer)+n);
|
||||
if( !p ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@@ -117,7 +117,7 @@ static int icuOpen(
|
||||
nInput = strlen(zInput);
|
||||
}
|
||||
nChar = nInput+1;
|
||||
pCsr = (IcuCursor *)sqlite3_malloc64(
|
||||
pCsr = (IcuCursor *)sqlite3_malloc(
|
||||
sizeof(IcuCursor) + /* IcuCursor */
|
||||
((nChar+3)&~3) * sizeof(UChar) + /* IcuCursor.aChar[] */
|
||||
(nChar+1) * sizeof(int) /* IcuCursor.aOffset[] */
|
||||
|
||||
+46
-88
@@ -128,19 +128,17 @@ struct StrBuffer {
|
||||
/*
|
||||
** Allocate a two-slot MatchinfoBuffer object.
|
||||
*/
|
||||
static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){
|
||||
static MatchinfoBuffer *fts3MIBufferNew(int nElem, const char *zMatchinfo){
|
||||
MatchinfoBuffer *pRet;
|
||||
sqlite3_int64 nByte = sizeof(u32) * (2*(sqlite3_int64)nElem + 1)
|
||||
+ sizeof(MatchinfoBuffer);
|
||||
sqlite3_int64 nStr = strlen(zMatchinfo);
|
||||
int nByte = sizeof(u32) * (2*nElem + 1) + sizeof(MatchinfoBuffer);
|
||||
int nStr = (int)strlen(zMatchinfo);
|
||||
|
||||
pRet = sqlite3_malloc64(nByte + nStr+1);
|
||||
pRet = sqlite3_malloc(nByte + nStr+1);
|
||||
if( pRet ){
|
||||
memset(pRet, 0, nByte);
|
||||
pRet->aMatchinfo[0] = (u8*)(&pRet->aMatchinfo[1]) - (u8*)pRet;
|
||||
pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0]
|
||||
+ sizeof(u32)*((int)nElem+1);
|
||||
pRet->nElem = (int)nElem;
|
||||
pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0] + sizeof(u32)*(nElem+1);
|
||||
pRet->nElem = nElem;
|
||||
pRet->zMatchinfo = ((char*)pRet) + nByte;
|
||||
memcpy(pRet->zMatchinfo, zMatchinfo, nStr+1);
|
||||
pRet->aRef[0] = 1;
|
||||
@@ -180,7 +178,7 @@ static void (*fts3MIBufferAlloc(MatchinfoBuffer *p, u32 **paOut))(void*){
|
||||
aOut = &p->aMatchinfo[p->nElem+2];
|
||||
xRet = fts3MIBufferFree;
|
||||
}else{
|
||||
aOut = (u32*)sqlite3_malloc64(p->nElem * sizeof(u32));
|
||||
aOut = (u32*)sqlite3_malloc(p->nElem * sizeof(u32));
|
||||
if( aOut ){
|
||||
xRet = sqlite3_free;
|
||||
if( p->bGlobal ) memcpy(aOut, &p->aMatchinfo[1], p->nElem*sizeof(u32));
|
||||
@@ -431,12 +429,11 @@ static void fts3SnippetDetails(
|
||||
char *pCsr = pPhrase->pTail;
|
||||
int iCsr = pPhrase->iTail;
|
||||
|
||||
while( iCsr<(iStart+pIter->nSnippet) && iCsr>=iStart ){
|
||||
while( iCsr<(iStart+pIter->nSnippet) ){
|
||||
int j;
|
||||
u64 mPhrase = (u64)1 << (i%64);
|
||||
u64 mPhrase = (u64)1 << i;
|
||||
u64 mPos = (u64)1 << (iCsr - iStart);
|
||||
assert( iCsr>=iStart && (iCsr - iStart)<=64 );
|
||||
assert( i>=0 );
|
||||
assert( iCsr>=iStart );
|
||||
if( (mCover|mCovered)&mPhrase ){
|
||||
iScore++;
|
||||
}else{
|
||||
@@ -478,14 +475,11 @@ static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
||||
int iFirst = 0;
|
||||
pPhrase->pList = pCsr;
|
||||
fts3GetDeltaPosition(&pCsr, &iFirst);
|
||||
if( iFirst<0 ){
|
||||
rc = FTS_CORRUPT_VTAB;
|
||||
}else{
|
||||
pPhrase->pHead = pCsr;
|
||||
pPhrase->pTail = pCsr;
|
||||
pPhrase->iHead = iFirst;
|
||||
pPhrase->iTail = iFirst;
|
||||
}
|
||||
assert( iFirst>=0 );
|
||||
pPhrase->pHead = pCsr;
|
||||
pPhrase->pTail = pCsr;
|
||||
pPhrase->iHead = iFirst;
|
||||
pPhrase->iTail = iFirst;
|
||||
}else{
|
||||
assert( rc!=SQLITE_OK || (
|
||||
pPhrase->pList==0 && pPhrase->pHead==0 && pPhrase->pTail==0
|
||||
@@ -522,7 +516,7 @@ static int fts3BestSnippet(
|
||||
int rc; /* Return Code */
|
||||
int nList; /* Number of phrases in expression */
|
||||
SnippetIter sIter; /* Iterates through snippet candidates */
|
||||
sqlite3_int64 nByte; /* Number of bytes of space to allocate */
|
||||
int nByte; /* Number of bytes of space to allocate */
|
||||
int iBestScore = -1; /* Best snippet score found so far */
|
||||
int i; /* Loop counter */
|
||||
|
||||
@@ -540,7 +534,7 @@ static int fts3BestSnippet(
|
||||
** the required space using malloc().
|
||||
*/
|
||||
nByte = sizeof(SnippetPhrase) * nList;
|
||||
sIter.aPhrase = (SnippetPhrase *)sqlite3_malloc64(nByte);
|
||||
sIter.aPhrase = (SnippetPhrase *)sqlite3_malloc(nByte);
|
||||
if( !sIter.aPhrase ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@@ -560,7 +554,7 @@ static int fts3BestSnippet(
|
||||
/* Set the *pmSeen output variable. */
|
||||
for(i=0; i<nList; i++){
|
||||
if( sIter.aPhrase[i].pHead ){
|
||||
*pmSeen |= (u64)1 << (i%64);
|
||||
*pmSeen |= (u64)1 << i;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -610,8 +604,8 @@ static int fts3StringAppend(
|
||||
** appended data.
|
||||
*/
|
||||
if( pStr->n+nAppend+1>=pStr->nAlloc ){
|
||||
sqlite3_int64 nAlloc = pStr->nAlloc+(sqlite3_int64)nAppend+100;
|
||||
char *zNew = sqlite3_realloc64(pStr->z, nAlloc);
|
||||
int nAlloc = pStr->nAlloc+nAppend+100;
|
||||
char *zNew = sqlite3_realloc(pStr->z, nAlloc);
|
||||
if( !zNew ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@@ -666,7 +660,6 @@ static int fts3SnippetShift(
|
||||
|
||||
for(nLeft=0; !(hlmask & ((u64)1 << nLeft)); nLeft++);
|
||||
for(nRight=0; !(hlmask & ((u64)1 << (nSnippet-1-nRight))); nRight++);
|
||||
assert( (nSnippet-1-nRight)<=63 && (nSnippet-1-nRight)>=0 );
|
||||
nDesired = (nLeft-nRight)/2;
|
||||
|
||||
/* Ideally, the start of the snippet should be pushed forward in the
|
||||
@@ -859,7 +852,7 @@ static int fts3ColumnlistCount(char **ppCollist){
|
||||
/*
|
||||
** This function gathers 'y' or 'b' data for a single phrase.
|
||||
*/
|
||||
static int fts3ExprLHits(
|
||||
static void fts3ExprLHits(
|
||||
Fts3Expr *pExpr, /* Phrase expression node */
|
||||
MatchInfo *p /* Matchinfo context */
|
||||
){
|
||||
@@ -889,29 +882,25 @@ static int fts3ExprLHits(
|
||||
if( *pIter!=0x01 ) break;
|
||||
pIter++;
|
||||
pIter += fts3GetVarint32(pIter, &iCol);
|
||||
if( iCol>=p->nCol ) return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Gather the results for matchinfo directives 'y' and 'b'.
|
||||
*/
|
||||
static int fts3ExprLHitGather(
|
||||
static void fts3ExprLHitGather(
|
||||
Fts3Expr *pExpr,
|
||||
MatchInfo *p
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
assert( (pExpr->pLeft==0)==(pExpr->pRight==0) );
|
||||
if( pExpr->bEof==0 && pExpr->iDocid==p->pCursor->iPrevId ){
|
||||
if( pExpr->pLeft ){
|
||||
rc = fts3ExprLHitGather(pExpr->pLeft, p);
|
||||
if( rc==SQLITE_OK ) rc = fts3ExprLHitGather(pExpr->pRight, p);
|
||||
fts3ExprLHitGather(pExpr->pLeft, p);
|
||||
fts3ExprLHitGather(pExpr->pRight, p);
|
||||
}else{
|
||||
rc = fts3ExprLHits(pExpr, p);
|
||||
fts3ExprLHits(pExpr, p);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1001,8 +990,8 @@ static int fts3MatchinfoCheck(
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
static size_t fts3MatchinfoSize(MatchInfo *pInfo, char cArg){
|
||||
size_t nVal; /* Number of integers output by cArg */
|
||||
static int fts3MatchinfoSize(MatchInfo *pInfo, char cArg){
|
||||
int nVal; /* Number of integers output by cArg */
|
||||
|
||||
switch( cArg ){
|
||||
case FTS3_MATCHINFO_NDOC:
|
||||
@@ -1038,15 +1027,11 @@ static int fts3MatchinfoSelectDoctotal(
|
||||
Fts3Table *pTab,
|
||||
sqlite3_stmt **ppStmt,
|
||||
sqlite3_int64 *pnDoc,
|
||||
const char **paLen,
|
||||
const char **ppEnd
|
||||
const char **paLen
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
const char *a;
|
||||
const char *pEnd;
|
||||
sqlite3_int64 nDoc;
|
||||
int n;
|
||||
|
||||
|
||||
if( !*ppStmt ){
|
||||
int rc = sqlite3Fts3SelectDoctotal(pTab, ppStmt);
|
||||
@@ -1055,20 +1040,12 @@ static int fts3MatchinfoSelectDoctotal(
|
||||
pStmt = *ppStmt;
|
||||
assert( sqlite3_data_count(pStmt)==1 );
|
||||
|
||||
n = sqlite3_column_bytes(pStmt, 0);
|
||||
a = sqlite3_column_blob(pStmt, 0);
|
||||
if( a==0 ){
|
||||
return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
pEnd = a + n;
|
||||
a += sqlite3Fts3GetVarintBounded(a, pEnd, &nDoc);
|
||||
if( nDoc<=0 || a>pEnd ){
|
||||
return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
*pnDoc = nDoc;
|
||||
a += sqlite3Fts3GetVarint(a, &nDoc);
|
||||
if( nDoc==0 ) return FTS_CORRUPT_VTAB;
|
||||
*pnDoc = (u32)nDoc;
|
||||
|
||||
if( paLen ) *paLen = a;
|
||||
if( ppEnd ) *ppEnd = pEnd;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -1140,12 +1117,11 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
|
||||
int i;
|
||||
int iCol;
|
||||
int nToken = 0;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
/* Allocate and populate the array of LcsIterator objects. The array
|
||||
** contains one element for each matchable phrase in the query.
|
||||
**/
|
||||
aIter = sqlite3_malloc64(sizeof(LcsIterator) * pCsr->nPhrase);
|
||||
aIter = sqlite3_malloc(sizeof(LcsIterator) * pCsr->nPhrase);
|
||||
if( !aIter ) return SQLITE_NOMEM;
|
||||
memset(aIter, 0, sizeof(LcsIterator) * pCsr->nPhrase);
|
||||
(void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter);
|
||||
@@ -1161,16 +1137,13 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
|
||||
int nLive = 0; /* Number of iterators in aIter not at EOF */
|
||||
|
||||
for(i=0; i<pInfo->nPhrase; i++){
|
||||
int rc;
|
||||
LcsIterator *pIt = &aIter[i];
|
||||
rc = sqlite3Fts3EvalPhrasePoslist(pCsr, pIt->pExpr, iCol, &pIt->pRead);
|
||||
if( rc!=SQLITE_OK ) goto matchinfo_lcs_out;
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
if( pIt->pRead ){
|
||||
pIt->iPos = pIt->iPosOffset;
|
||||
fts3LcsIteratorAdvance(pIt);
|
||||
if( pIt->pRead==0 ){
|
||||
rc = FTS_CORRUPT_VTAB;
|
||||
goto matchinfo_lcs_out;
|
||||
}
|
||||
fts3LcsIteratorAdvance(&aIter[i]);
|
||||
nLive++;
|
||||
}
|
||||
}
|
||||
@@ -1202,9 +1175,8 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
|
||||
pInfo->aMatchinfo[iCol] = nLcs;
|
||||
}
|
||||
|
||||
matchinfo_lcs_out:
|
||||
sqlite3_free(aIter);
|
||||
return rc;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1249,7 +1221,7 @@ static int fts3MatchinfoValues(
|
||||
case FTS3_MATCHINFO_NDOC:
|
||||
if( bGlobal ){
|
||||
sqlite3_int64 nDoc = 0;
|
||||
rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, 0, 0);
|
||||
rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, 0);
|
||||
pInfo->aMatchinfo[0] = (u32)nDoc;
|
||||
}
|
||||
break;
|
||||
@@ -1258,19 +1230,14 @@ static int fts3MatchinfoValues(
|
||||
if( bGlobal ){
|
||||
sqlite3_int64 nDoc; /* Number of rows in table */
|
||||
const char *a; /* Aggregate column length array */
|
||||
const char *pEnd; /* First byte past end of length array */
|
||||
|
||||
rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, &a, &pEnd);
|
||||
rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, &a);
|
||||
if( rc==SQLITE_OK ){
|
||||
int iCol;
|
||||
for(iCol=0; iCol<pInfo->nCol; iCol++){
|
||||
u32 iVal;
|
||||
sqlite3_int64 nToken;
|
||||
a += sqlite3Fts3GetVarint(a, &nToken);
|
||||
if( a>pEnd ){
|
||||
rc = SQLITE_CORRUPT_VTAB;
|
||||
break;
|
||||
}
|
||||
iVal = (u32)(((u32)(nToken&0xffffffff)+nDoc/2)/nDoc);
|
||||
pInfo->aMatchinfo[iCol] = iVal;
|
||||
}
|
||||
@@ -1284,14 +1251,9 @@ static int fts3MatchinfoValues(
|
||||
if( rc==SQLITE_OK ){
|
||||
int iCol;
|
||||
const char *a = sqlite3_column_blob(pSelectDocsize, 0);
|
||||
const char *pEnd = a + sqlite3_column_bytes(pSelectDocsize, 0);
|
||||
for(iCol=0; iCol<pInfo->nCol; iCol++){
|
||||
sqlite3_int64 nToken;
|
||||
a += sqlite3Fts3GetVarintBounded(a, pEnd, &nToken);
|
||||
if( a>pEnd ){
|
||||
rc = SQLITE_CORRUPT_VTAB;
|
||||
break;
|
||||
}
|
||||
a += sqlite3Fts3GetVarint(a, &nToken);
|
||||
pInfo->aMatchinfo[iCol] = (u32)nToken;
|
||||
}
|
||||
}
|
||||
@@ -1308,9 +1270,9 @@ static int fts3MatchinfoValues(
|
||||
|
||||
case FTS3_MATCHINFO_LHITS_BM:
|
||||
case FTS3_MATCHINFO_LHITS: {
|
||||
size_t nZero = fts3MatchinfoSize(pInfo, zArg[i]) * sizeof(u32);
|
||||
int nZero = fts3MatchinfoSize(pInfo, zArg[i]) * sizeof(u32);
|
||||
memset(pInfo->aMatchinfo, 0, nZero);
|
||||
rc = fts3ExprLHitGather(pCsr->pExpr, pInfo);
|
||||
fts3ExprLHitGather(pCsr->pExpr, pInfo);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1322,7 +1284,7 @@ static int fts3MatchinfoValues(
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
if( bGlobal ){
|
||||
if( pCsr->pDeferred ){
|
||||
rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &pInfo->nDoc,0,0);
|
||||
rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &pInfo->nDoc, 0);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
}
|
||||
rc = fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo);
|
||||
@@ -1377,7 +1339,7 @@ static void fts3GetMatchinfo(
|
||||
** initialize those elements that are constant for every row.
|
||||
*/
|
||||
if( pCsr->pMIBuffer==0 ){
|
||||
size_t nMatchinfo = 0; /* Number of u32 elements in match-info */
|
||||
int nMatchinfo = 0; /* Number of u32 elements in match-info */
|
||||
int i; /* Used to iterate through zArg */
|
||||
|
||||
/* Determine the number of phrases in the query */
|
||||
@@ -1462,10 +1424,6 @@ void sqlite3Fts3Snippet(
|
||||
return;
|
||||
}
|
||||
|
||||
/* Limit the snippet length to 64 tokens. */
|
||||
if( nToken<-64 ) nToken = -64;
|
||||
if( nToken>+64 ) nToken = +64;
|
||||
|
||||
for(nSnippet=1; 1; nSnippet++){
|
||||
|
||||
int iSnip; /* Loop counter 0..nSnippet-1 */
|
||||
@@ -1567,7 +1525,7 @@ static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
||||
nTerm = pExpr->pPhrase->nToken;
|
||||
if( pList ){
|
||||
fts3GetDeltaPosition(&pList, &iPos);
|
||||
assert_fts3_nc( iPos>=0 );
|
||||
assert( iPos>=0 );
|
||||
}
|
||||
|
||||
for(iTerm=0; iTerm<nTerm; iTerm++){
|
||||
@@ -1608,7 +1566,7 @@ void sqlite3Fts3Offsets(
|
||||
if( rc!=SQLITE_OK ) goto offsets_out;
|
||||
|
||||
/* Allocate the array of TermOffset iterators. */
|
||||
sCtx.aTerm = (TermOffset *)sqlite3_malloc64(sizeof(TermOffset)*nToken);
|
||||
sCtx.aTerm = (TermOffset *)sqlite3_malloc(sizeof(TermOffset)*nToken);
|
||||
if( 0==sCtx.aTerm ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto offsets_out;
|
||||
@@ -1677,7 +1635,7 @@ void sqlite3Fts3Offsets(
|
||||
/* All offsets for this column have been gathered. */
|
||||
rc = SQLITE_DONE;
|
||||
}else{
|
||||
assert_fts3_nc( iCurrent<=iMinPos );
|
||||
assert( iCurrent<=iMinPos );
|
||||
if( 0==(0xFE&*pTerm->pList) ){
|
||||
pTerm->pList = 0;
|
||||
}else{
|
||||
|
||||
@@ -68,9 +68,9 @@ static int fts3termConnectMethod(
|
||||
char const *zFts3; /* Name of fts3 table */
|
||||
int nDb; /* Result of strlen(zDb) */
|
||||
int nFts3; /* Result of strlen(zFts3) */
|
||||
sqlite3_int64 nByte; /* Bytes of space to allocate here */
|
||||
int nByte; /* Bytes of space to allocate here */
|
||||
int rc; /* value returned by declare_vtab() */
|
||||
Fts3termTable *p; /* Virtual table object to return */
|
||||
Fts3termTable *p; /* Virtual table object to return */
|
||||
int iIndex = 0;
|
||||
|
||||
UNUSED_PARAMETER(pCtx);
|
||||
@@ -96,9 +96,9 @@ static int fts3termConnectMethod(
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
nByte = sizeof(Fts3termTable) + sizeof(Fts3Table) + nDb + nFts3 + 2;
|
||||
p = (Fts3termTable *)sqlite3_malloc64(nByte);
|
||||
p = (Fts3termTable *)sqlite3_malloc(nByte);
|
||||
if( !p ) return SQLITE_NOMEM;
|
||||
memset(p, 0, (size_t)nByte);
|
||||
memset(p, 0, nByte);
|
||||
|
||||
p->pFts3Tab = (Fts3Table *)&p[1];
|
||||
p->pFts3Tab->zDb = (char *)&p->pFts3Tab[1];
|
||||
|
||||
+5
-34
@@ -448,14 +448,14 @@ static int testTokenizerNext(
|
||||
}else{
|
||||
/* Advance to the end of the token */
|
||||
const char *pToken = p;
|
||||
sqlite3_int64 nToken;
|
||||
int nToken;
|
||||
while( p<pEnd && testIsTokenChar(*p) ) p++;
|
||||
nToken = (sqlite3_int64)(p-pToken);
|
||||
nToken = (int)(p-pToken);
|
||||
|
||||
/* Copy the token into the buffer */
|
||||
if( nToken>pCsr->nBuffer ){
|
||||
sqlite3_free(pCsr->aBuffer);
|
||||
pCsr->aBuffer = sqlite3_malloc64(nToken);
|
||||
pCsr->aBuffer = sqlite3_malloc(nToken);
|
||||
}
|
||||
if( pCsr->aBuffer==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
@@ -471,7 +471,7 @@ static int testTokenizerNext(
|
||||
pCsr->iInput = (int)(p - pCsr->aInput);
|
||||
|
||||
*ppToken = pCsr->aBuffer;
|
||||
*pnBytes = (int)nToken;
|
||||
*pnBytes = nToken;
|
||||
*piStartOffset = (int)(pToken - pCsr->aInput);
|
||||
*piEndOffset = (int)(p - pCsr->aInput);
|
||||
*piPosition = pCsr->iToken;
|
||||
@@ -574,33 +574,6 @@ static int SQLITE_TCLAPI fts3_test_varint_cmd(
|
||||
** End of tokenizer code.
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
** sqlite3_fts3_may_be_corrupt BOOLEAN
|
||||
**
|
||||
** Set or clear the global "may-be-corrupt" flag. Return the old value.
|
||||
*/
|
||||
static int SQLITE_TCLAPI fts3_may_be_corrupt(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
int bOld = sqlite3_fts3_may_be_corrupt;
|
||||
|
||||
if( objc!=2 && objc!=1 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "?BOOLEAN?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( objc==2 ){
|
||||
int bNew;
|
||||
if( Tcl_GetBooleanFromObj(interp, objv[1], &bNew) ) return TCL_ERROR;
|
||||
sqlite3_fts3_may_be_corrupt = bNew;
|
||||
}
|
||||
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(bOld));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
int Sqlitetestfts3_Init(Tcl_Interp *interp){
|
||||
Tcl_CreateObjCommand(interp, "fts3_near_match", fts3_near_match_cmd, 0, 0);
|
||||
Tcl_CreateObjCommand(interp,
|
||||
@@ -609,12 +582,10 @@ int Sqlitetestfts3_Init(Tcl_Interp *interp){
|
||||
Tcl_CreateObjCommand(
|
||||
interp, "fts3_test_tokenizer", fts3_test_tokenizer_cmd, 0, 0
|
||||
);
|
||||
|
||||
Tcl_CreateObjCommand(
|
||||
interp, "fts3_test_varint", fts3_test_varint_cmd, 0, 0
|
||||
);
|
||||
Tcl_CreateObjCommand(
|
||||
interp, "sqlite3_fts3_may_be_corrupt", fts3_may_be_corrupt, 0, 0
|
||||
);
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_FTS3 || SQLITE_ENABLE_FTS4 */
|
||||
|
||||
@@ -122,7 +122,7 @@ static int fts3tokDequoteArray(
|
||||
nByte += (int)(strlen(argv[i]) + 1);
|
||||
}
|
||||
|
||||
*pazDequote = azDequote = sqlite3_malloc64(sizeof(char *)*argc + nByte);
|
||||
*pazDequote = azDequote = sqlite3_malloc(sizeof(char *)*argc + nByte);
|
||||
if( azDequote==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -346,11 +346,11 @@ static int fts3tokFilterMethod(
|
||||
if( idxNum==1 ){
|
||||
const char *zByte = (const char *)sqlite3_value_text(apVal[0]);
|
||||
int nByte = sqlite3_value_bytes(apVal[0]);
|
||||
pCsr->zInput = sqlite3_malloc64(nByte+1);
|
||||
pCsr->zInput = sqlite3_malloc(nByte+1);
|
||||
if( pCsr->zInput==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
if( nByte>0 ) memcpy(pCsr->zInput, zByte, nByte);
|
||||
memcpy(pCsr->zInput, zByte, nByte);
|
||||
pCsr->zInput[nByte] = 0;
|
||||
rc = pTab->pMod->xOpen(pTab->pTok, pCsr->zInput, nByte, &pCsr->pCsr);
|
||||
if( rc==SQLITE_OK ){
|
||||
|
||||
@@ -79,7 +79,7 @@ static void fts3TokenizerFunc(
|
||||
nName = sqlite3_value_bytes(argv[0])+1;
|
||||
|
||||
if( argc==2 ){
|
||||
if( fts3TokenizerEnabled(context) || sqlite3_value_frombind(argv[1]) ){
|
||||
if( fts3TokenizerEnabled(context) ){
|
||||
void *pOld;
|
||||
int n = sqlite3_value_bytes(argv[1]);
|
||||
if( zName==0 || n!=sizeof(pPtr) ){
|
||||
@@ -106,9 +106,7 @@ static void fts3TokenizerFunc(
|
||||
return;
|
||||
}
|
||||
}
|
||||
if( fts3TokenizerEnabled(context) || sqlite3_value_frombind(argv[0]) ){
|
||||
sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT);
|
||||
}
|
||||
sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
int sqlite3Fts3IsIdChar(char c){
|
||||
@@ -196,8 +194,8 @@ int sqlite3Fts3InitTokenizer(
|
||||
int iArg = 0;
|
||||
z = &z[n+1];
|
||||
while( z<zEnd && (NULL!=(z = (char *)sqlite3Fts3NextToken(z, &n))) ){
|
||||
sqlite3_int64 nNew = sizeof(char *)*(iArg+1);
|
||||
char const **aNew = (const char **)sqlite3_realloc64((void *)aArg, nNew);
|
||||
int nNew = sizeof(char *)*(iArg+1);
|
||||
char const **aNew = (const char **)sqlite3_realloc((void *)aArg, nNew);
|
||||
if( !aNew ){
|
||||
sqlite3_free(zCopy);
|
||||
sqlite3_free((void *)aArg);
|
||||
@@ -390,9 +388,7 @@ int queryTokenizer(
|
||||
|
||||
sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC);
|
||||
if( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB
|
||||
&& sqlite3_column_bytes(pStmt, 0)==sizeof(*pp)
|
||||
){
|
||||
if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB ){
|
||||
memcpy((void *)pp, sqlite3_column_blob(pStmt, 0), sizeof(*pp));
|
||||
}
|
||||
}
|
||||
@@ -481,7 +477,7 @@ int sqlite3Fts3InitHashTable(
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
void *p = (void *)pHash;
|
||||
const int any = SQLITE_UTF8|SQLITE_DIRECTONLY;
|
||||
const int any = SQLITE_ANY;
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
char *zTest = 0;
|
||||
|
||||
@@ -155,7 +155,7 @@ static int unicodeAddExceptions(
|
||||
int *aNew; /* New aiException[] array */
|
||||
int nNew; /* Number of valid entries in array aNew[] */
|
||||
|
||||
aNew = sqlite3_realloc64(p->aiException,(p->nException+nEntry)*sizeof(int));
|
||||
aNew = sqlite3_realloc(p->aiException, (p->nException+nEntry)*sizeof(int));
|
||||
if( aNew==0 ) return SQLITE_NOMEM;
|
||||
nNew = p->nException;
|
||||
|
||||
@@ -344,7 +344,7 @@ static int unicodeNext(
|
||||
|
||||
/* Grow the output buffer if required. */
|
||||
if( (zOut-pCsr->zToken)>=(pCsr->nAlloc-4) ){
|
||||
char *zNew = sqlite3_realloc64(pCsr->zToken, pCsr->nAlloc+64);
|
||||
char *zNew = sqlite3_realloc(pCsr->zToken, pCsr->nAlloc+64);
|
||||
if( !zNew ) return SQLITE_NOMEM;
|
||||
zOut = &zNew[zOut - pCsr->zToken];
|
||||
pCsr->zToken = zNew;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** 2012-05-25
|
||||
** 2012 May 25
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
@@ -178,8 +178,8 @@ static int remove_diacritic(int c, int bComplex){
|
||||
62830, 62890, 62924, 62974, 63032, 63050, 63082, 63118,
|
||||
63182, 63242, 63274, 63310, 63368, 63390,
|
||||
};
|
||||
#define HIBIT ((unsigned char)0x80)
|
||||
unsigned char aChar[] = {
|
||||
#define HIBIT ((char)0x80)
|
||||
char aChar[] = {
|
||||
'\0', 'a', 'c', 'e', 'i', 'n',
|
||||
'o', 'u', 'y', 'y', 'a', 'c',
|
||||
'd', 'e', 'e', 'g', 'h', 'i',
|
||||
@@ -200,7 +200,7 @@ static int remove_diacritic(int c, int bComplex){
|
||||
'w', 'x', 'y', 'z', 'h', 't',
|
||||
'w', 'y', 'a', 'a'|HIBIT, 'a'|HIBIT, 'a'|HIBIT,
|
||||
'e', 'e'|HIBIT, 'e'|HIBIT, 'i', 'o', 'o'|HIBIT,
|
||||
'o'|HIBIT, 'o'|HIBIT, 'u', 'u'|HIBIT, 'u'|HIBIT, 'y',
|
||||
'o'|HIBIT, 'o'|HIBIT, 'u', 'u'|HIBIT, 'u'|HIBIT, 'y',
|
||||
};
|
||||
|
||||
unsigned int key = (((unsigned int)c)<<3) | 0x00000007;
|
||||
@@ -231,8 +231,8 @@ int sqlite3FtsUnicodeIsdiacritic(int c){
|
||||
unsigned int mask1 = 0x000361F8;
|
||||
if( c<768 || c>817 ) return 0;
|
||||
return (c < 768+32) ?
|
||||
(mask0 & ((unsigned int)1 << (c-768))) :
|
||||
(mask1 & ((unsigned int)1 << (c-768-32)));
|
||||
(mask0 & (1 << (c-768))) :
|
||||
(mask1 & (1 << (c-768-32)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
+108
-196
@@ -23,7 +23,7 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#define FTS_MAX_APPENDABLE_HEIGHT 16
|
||||
|
||||
@@ -67,7 +67,7 @@ int test_fts3_node_chunk_threshold = (4*1024)*4;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The values that may be meaningfully bound to the :1 parameter in
|
||||
** The two values that may be meaningfully bound to the :1 parameter in
|
||||
** statements SQL_REPLACE_STAT and SQL_SELECT_STAT.
|
||||
*/
|
||||
#define FTS_STAT_DOCTOTAL 0
|
||||
@@ -335,7 +335,7 @@ static int fts3SqlStmt(
|
||||
** returns zero rows. */
|
||||
/* 28 */ "SELECT level, count(*) AS cnt FROM %Q.'%q_segdir' "
|
||||
" GROUP BY level HAVING cnt>=?"
|
||||
" ORDER BY (level %% 1024) ASC, 2 DESC LIMIT 1",
|
||||
" ORDER BY (level %% 1024) ASC LIMIT 1",
|
||||
|
||||
/* Estimate the upper limit on the number of leaf nodes in a new segment
|
||||
** created by merging the oldest :2 segments from absolute level :1. See
|
||||
@@ -396,12 +396,10 @@ static int fts3SqlStmt(
|
||||
|
||||
pStmt = p->aStmt[eStmt];
|
||||
if( !pStmt ){
|
||||
int f = SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB;
|
||||
char *zSql;
|
||||
if( eStmt==SQL_CONTENT_INSERT ){
|
||||
zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist);
|
||||
}else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){
|
||||
f &= ~SQLITE_PREPARE_NO_VTAB;
|
||||
zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist);
|
||||
}else{
|
||||
zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName);
|
||||
@@ -409,7 +407,8 @@ static int fts3SqlStmt(
|
||||
if( !zSql ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
rc = sqlite3_prepare_v3(p->db, zSql, -1, f, &pStmt, NULL);
|
||||
rc = sqlite3_prepare_v3(p->db, zSql, -1, SQLITE_PREPARE_PERSISTENT,
|
||||
&pStmt, NULL);
|
||||
sqlite3_free(zSql);
|
||||
assert( rc==SQLITE_OK || pStmt==0 );
|
||||
p->aStmt[eStmt] = pStmt;
|
||||
@@ -567,7 +566,7 @@ static sqlite3_int64 getAbsoluteLevel(
|
||||
int iLevel /* Level of segments */
|
||||
){
|
||||
sqlite3_int64 iBase; /* First absolute level for iLangid/iIndex */
|
||||
assert_fts3_nc( iLangid>=0 );
|
||||
assert( iLangid>=0 );
|
||||
assert( p->nIndex>0 );
|
||||
assert( iIndex>=0 && iIndex<p->nIndex );
|
||||
|
||||
@@ -696,7 +695,7 @@ static int fts3PendingListAppend(
|
||||
assert( !p || p->iLastDocid<=iDocid );
|
||||
|
||||
if( !p || p->iLastDocid!=iDocid ){
|
||||
u64 iDelta = (u64)iDocid - (u64)(p ? p->iLastDocid : 0);
|
||||
sqlite3_int64 iDelta = iDocid - (p ? p->iLastDocid : 0);
|
||||
if( p ){
|
||||
assert( p->nData<p->nSpace );
|
||||
assert( p->aData[p->nData]==0 );
|
||||
@@ -1153,7 +1152,7 @@ static int fts3AllocateSegdirIdx(
|
||||
** segment and allocate (newly freed) index 0 at level iLevel. Otherwise,
|
||||
** if iNext is less than FTS3_MERGE_COUNT, allocate index iNext.
|
||||
*/
|
||||
if( iNext>=MergeCount(p) ){
|
||||
if( iNext>=FTS3_MERGE_COUNT ){
|
||||
fts3LogMerge(16, getAbsoluteLevel(p, iLangid, iIndex, iLevel));
|
||||
rc = fts3SegmentMerge(p, iLangid, iIndex, iLevel);
|
||||
*piIdx = 0;
|
||||
@@ -1237,8 +1236,6 @@ int sqlite3Fts3ReadBlock(
|
||||
}
|
||||
*paBlob = aByte;
|
||||
}
|
||||
}else if( rc==SQLITE_ERROR ){
|
||||
rc = FTS_CORRUPT_VTAB;
|
||||
}
|
||||
|
||||
return rc;
|
||||
@@ -1350,9 +1347,7 @@ static int fts3SegReaderNext(
|
||||
|
||||
/* If iCurrentBlock>=iLeafEndBlock, this is an EOF condition. All leaf
|
||||
** blocks have already been traversed. */
|
||||
#ifdef CORRUPT_DB
|
||||
assert( pReader->iCurrentBlock<=pReader->iLeafEndBlock || CORRUPT_DB );
|
||||
#endif
|
||||
assert( pReader->iCurrentBlock<=pReader->iLeafEndBlock );
|
||||
if( pReader->iCurrentBlock>=pReader->iLeafEndBlock ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -1381,7 +1376,7 @@ static int fts3SegReaderNext(
|
||||
pNext += fts3GetVarint32(pNext, &nSuffix);
|
||||
if( nSuffix<=0
|
||||
|| (&pReader->aNode[pReader->nNode] - pNext)<nSuffix
|
||||
|| nPrefix>pReader->nTerm
|
||||
|| nPrefix>pReader->nTermAlloc
|
||||
){
|
||||
return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
@@ -1413,9 +1408,8 @@ static int fts3SegReaderNext(
|
||||
** b-tree node. And that the final byte of the doclist is 0x00. If either
|
||||
** of these statements is untrue, then the data structure is corrupt.
|
||||
*/
|
||||
if( pReader->nDoclist > pReader->nNode-(pReader->aDoclist-pReader->aNode)
|
||||
if( (&pReader->aNode[pReader->nNode] - pReader->aDoclist)<pReader->nDoclist
|
||||
|| (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1])
|
||||
|| pReader->nDoclist==0
|
||||
){
|
||||
return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
@@ -1532,18 +1526,18 @@ static int fts3SegReaderNextDocid(
|
||||
}else{
|
||||
rc = fts3SegReaderRequire(pReader, p, FTS3_VARINT_MAX);
|
||||
if( rc==SQLITE_OK ){
|
||||
u64 iDelta;
|
||||
pReader->pOffsetList = p + sqlite3Fts3GetVarintU(p, &iDelta);
|
||||
sqlite3_int64 iDelta;
|
||||
pReader->pOffsetList = p + sqlite3Fts3GetVarint(p, &iDelta);
|
||||
if( pTab->bDescIdx ){
|
||||
pReader->iDocid = (i64)((u64)pReader->iDocid - iDelta);
|
||||
pReader->iDocid -= iDelta;
|
||||
}else{
|
||||
pReader->iDocid = (i64)((u64)pReader->iDocid + iDelta);
|
||||
pReader->iDocid += iDelta;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -1614,13 +1608,8 @@ int sqlite3Fts3SegReaderNew(
|
||||
Fts3SegReader *pReader; /* Newly allocated SegReader object */
|
||||
int nExtra = 0; /* Bytes to allocate segment root node */
|
||||
|
||||
assert( zRoot!=0 || nRoot==0 );
|
||||
#ifdef CORRUPT_DB
|
||||
assert( zRoot!=0 || CORRUPT_DB );
|
||||
#endif
|
||||
|
||||
assert( iStartLeaf<=iEndLeaf );
|
||||
if( iStartLeaf==0 ){
|
||||
if( iEndLeaf!=0 ) return FTS_CORRUPT_VTAB;
|
||||
nExtra = nRoot + FTS3_NODE_PADDING;
|
||||
}
|
||||
|
||||
@@ -1640,7 +1629,7 @@ int sqlite3Fts3SegReaderNew(
|
||||
pReader->aNode = (char *)&pReader[1];
|
||||
pReader->rootOnly = 1;
|
||||
pReader->nNode = nRoot;
|
||||
if( nRoot ) memcpy(pReader->aNode, zRoot, nRoot);
|
||||
memcpy(pReader->aNode, zRoot, nRoot);
|
||||
memset(&pReader->aNode[nRoot], 0, FTS3_NODE_PADDING);
|
||||
}else{
|
||||
pReader->iCurrentBlock = iStartLeaf-1;
|
||||
@@ -1755,9 +1744,8 @@ int sqlite3Fts3SegReaderPending(
|
||||
}
|
||||
|
||||
if( nElem>0 ){
|
||||
sqlite3_int64 nByte;
|
||||
nByte = sizeof(Fts3SegReader) + (nElem+1)*sizeof(Fts3HashElem *);
|
||||
pReader = (Fts3SegReader *)sqlite3_malloc64(nByte);
|
||||
int nByte = sizeof(Fts3SegReader) + (nElem+1)*sizeof(Fts3HashElem *);
|
||||
pReader = (Fts3SegReader *)sqlite3_malloc(nByte);
|
||||
if( !pReader ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -2033,11 +2021,6 @@ static int fts3NodeAddTerm(
|
||||
nPrefix = fts3PrefixCompress(pTree->zTerm, pTree->nTerm, zTerm, nTerm);
|
||||
nSuffix = nTerm-nPrefix;
|
||||
|
||||
/* If nSuffix is zero or less, then zTerm/nTerm must be a prefix of
|
||||
** pWriter->zTerm/pWriter->nTerm. i.e. must be equal to or less than when
|
||||
** compared with BINARY collation. This indicates corruption. */
|
||||
if( nSuffix<=0 ) return FTS_CORRUPT_VTAB;
|
||||
|
||||
nReq += sqlite3Fts3VarintLen(nPrefix)+sqlite3Fts3VarintLen(nSuffix)+nSuffix;
|
||||
if( nReq<=p->nNodeSize || !pTree->zTerm ){
|
||||
|
||||
@@ -2266,11 +2249,6 @@ static int fts3SegWriterAdd(
|
||||
nPrefix = fts3PrefixCompress(pWriter->zTerm, pWriter->nTerm, zTerm, nTerm);
|
||||
nSuffix = nTerm-nPrefix;
|
||||
|
||||
/* If nSuffix is zero or less, then zTerm/nTerm must be a prefix of
|
||||
** pWriter->zTerm/pWriter->nTerm. i.e. must be equal to or less than when
|
||||
** compared with BINARY collation. This indicates corruption. */
|
||||
if( nSuffix<=0 ) return FTS_CORRUPT_VTAB;
|
||||
|
||||
/* Figure out how many bytes are required by this new entry */
|
||||
nReq = sqlite3Fts3VarintLen(nPrefix) + /* varint containing prefix size */
|
||||
sqlite3Fts3VarintLen(nSuffix) + /* varint containing suffix size */
|
||||
@@ -2282,7 +2260,6 @@ static int fts3SegWriterAdd(
|
||||
int rc;
|
||||
|
||||
/* The current leaf node is full. Write it out to the database. */
|
||||
if( pWriter->iFree==LARGEST_INT64 ) return FTS_CORRUPT_VTAB;
|
||||
rc = fts3WriteSegment(p, pWriter->iFree++, pWriter->aData, nData);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
p->nLeafAdd++;
|
||||
@@ -2332,11 +2309,9 @@ static int fts3SegWriterAdd(
|
||||
/* Append the prefix-compressed term and doclist to the buffer. */
|
||||
nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nPrefix);
|
||||
nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nSuffix);
|
||||
assert( nSuffix>0 );
|
||||
memcpy(&pWriter->aData[nData], &zTerm[nPrefix], nSuffix);
|
||||
nData += nSuffix;
|
||||
nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nDoclist);
|
||||
assert( nDoclist>0 );
|
||||
memcpy(&pWriter->aData[nData], aDoclist, nDoclist);
|
||||
pWriter->nData = nData + nDoclist;
|
||||
|
||||
@@ -2356,7 +2331,6 @@ static int fts3SegWriterAdd(
|
||||
pWriter->zTerm = zNew;
|
||||
}
|
||||
assert( pWriter->zTerm==pWriter->zMalloc );
|
||||
assert( nTerm>0 );
|
||||
memcpy(pWriter->zTerm, zTerm, nTerm);
|
||||
}else{
|
||||
pWriter->zTerm = (char *)zTerm;
|
||||
@@ -2503,7 +2477,7 @@ static int fts3SegmentIsMaxLevel(Fts3Table *p, i64 iAbsLevel, int *pbMax){
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
sqlite3_bind_int64(pStmt, 1, iAbsLevel+1);
|
||||
sqlite3_bind_int64(pStmt, 2,
|
||||
(((u64)iAbsLevel/FTS3_SEGDIR_MAXLEVEL)+1) * FTS3_SEGDIR_MAXLEVEL
|
||||
((iAbsLevel/FTS3_SEGDIR_MAXLEVEL)+1) * FTS3_SEGDIR_MAXLEVEL
|
||||
);
|
||||
|
||||
*pbMax = 0;
|
||||
@@ -2631,14 +2605,14 @@ static void fts3ColumnFilter(
|
||||
|
||||
nList -= (int)(p - pList);
|
||||
pList = p;
|
||||
if( nList<=0 ){
|
||||
if( nList==0 ){
|
||||
break;
|
||||
}
|
||||
p = &pList[1];
|
||||
p += fts3GetVarint32(p, &iCurrent);
|
||||
}
|
||||
|
||||
if( bZero && (pEnd - &pList[nList])>0){
|
||||
if( bZero && &pList[nList]!=pEnd ){
|
||||
memset(&pList[nList], 0, pEnd - &pList[nList]);
|
||||
}
|
||||
*ppList = pList;
|
||||
@@ -2665,7 +2639,6 @@ static int fts3MsrBufferData(
|
||||
pMsr->aBuffer = pNew;
|
||||
}
|
||||
|
||||
assert( nList>0 );
|
||||
memcpy(pMsr->aBuffer, pList, nList);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -2979,12 +2952,12 @@ int sqlite3Fts3SegReaderStep(
|
||||
** doclist. */
|
||||
sqlite3_int64 iDelta;
|
||||
if( p->bDescIdx && nDoclist>0 ){
|
||||
if( iPrev<=iDocid ) return FTS_CORRUPT_VTAB;
|
||||
iDelta = (i64)((u64)iPrev - (u64)iDocid);
|
||||
iDelta = iPrev - iDocid;
|
||||
}else{
|
||||
if( nDoclist>0 && iPrev>=iDocid ) return FTS_CORRUPT_VTAB;
|
||||
iDelta = (i64)((u64)iDocid - (u64)iPrev);
|
||||
iDelta = iDocid - iPrev;
|
||||
}
|
||||
assert( iDelta>0 || (nDoclist==0 && iDelta==iDocid) );
|
||||
assert( nDoclist>0 || iDelta==iDocid );
|
||||
|
||||
nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0);
|
||||
if( nDoclist+nByte>pCsr->nBuffer ){
|
||||
@@ -3069,11 +3042,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]=='-' ){
|
||||
@@ -3083,7 +3056,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3249,10 +3222,8 @@ static int fts3SegmentMerge(
|
||||
if( rc!=SQLITE_OK ) goto finished;
|
||||
|
||||
assert( csr.nSegment>0 );
|
||||
assert_fts3_nc( iNewLevel>=getAbsoluteLevel(p, iLangid, iIndex, 0) );
|
||||
assert_fts3_nc(
|
||||
iNewLevel<getAbsoluteLevel(p, iLangid, iIndex,FTS3_SEGDIR_MAXLEVEL)
|
||||
);
|
||||
assert( iNewLevel>=getAbsoluteLevel(p, iLangid, iIndex, 0) );
|
||||
assert( iNewLevel<getAbsoluteLevel(p, iLangid, iIndex,FTS3_SEGDIR_MAXLEVEL) );
|
||||
|
||||
memset(&filter, 0, sizeof(Fts3SegFilter));
|
||||
filter.flags = FTS3_SEGMENT_REQUIRE_POS;
|
||||
@@ -3266,7 +3237,7 @@ static int fts3SegmentMerge(
|
||||
csr.zTerm, csr.nTerm, csr.aDoclist, csr.nDoclist);
|
||||
}
|
||||
if( rc!=SQLITE_OK ) goto finished;
|
||||
assert_fts3_nc( pWriter || bIgnoreEmpty );
|
||||
assert( pWriter || bIgnoreEmpty );
|
||||
|
||||
if( iLevel!=FTS3_SEGCURSOR_PENDING ){
|
||||
rc = fts3DeleteSegdir(
|
||||
@@ -3351,16 +3322,14 @@ static void fts3DecodeIntArray(
|
||||
const char *zBuf, /* The BLOB containing the varints */
|
||||
int nBuf /* size of the BLOB */
|
||||
){
|
||||
int i = 0;
|
||||
if( nBuf && (zBuf[nBuf-1]&0x80)==0 ){
|
||||
int j;
|
||||
for(i=j=0; i<N && j<nBuf; i++){
|
||||
sqlite3_int64 x;
|
||||
j += sqlite3Fts3GetVarint(&zBuf[j], &x);
|
||||
a[i] = (u32)(x & 0xffffffff);
|
||||
}
|
||||
int i, j;
|
||||
UNUSED_PARAMETER(nBuf);
|
||||
for(i=j=0; i<N; i++){
|
||||
sqlite3_int64 x;
|
||||
j += sqlite3Fts3GetVarint(&zBuf[j], &x);
|
||||
assert(j<=nBuf);
|
||||
a[i] = (u32)(x & 0xffffffff);
|
||||
}
|
||||
while( i<N ) a[i++] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3379,7 +3348,7 @@ static void fts3InsertDocsize(
|
||||
int rc; /* Result code from subfunctions */
|
||||
|
||||
if( *pRC ) return;
|
||||
pBlob = sqlite3_malloc64( 10*(sqlite3_int64)p->nColumn );
|
||||
pBlob = sqlite3_malloc( 10*p->nColumn );
|
||||
if( pBlob==0 ){
|
||||
*pRC = SQLITE_NOMEM;
|
||||
return;
|
||||
@@ -3429,7 +3398,7 @@ static void fts3UpdateDocTotals(
|
||||
const int nStat = p->nColumn+2;
|
||||
|
||||
if( *pRC ) return;
|
||||
a = sqlite3_malloc64( (sizeof(u32)+10)*(sqlite3_int64)nStat );
|
||||
a = sqlite3_malloc( (sizeof(u32)+10)*nStat );
|
||||
if( a==0 ){
|
||||
*pRC = SQLITE_NOMEM;
|
||||
return;
|
||||
@@ -3493,10 +3462,7 @@ static int fts3DoOptimize(Fts3Table *p, int bReturnDone){
|
||||
int rc;
|
||||
sqlite3_stmt *pAllLangid = 0;
|
||||
|
||||
rc = sqlite3Fts3PendingTermsFlush(p);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0);
|
||||
}
|
||||
rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
int rc2;
|
||||
sqlite3_bind_int(pAllLangid, 1, p->iPrevLangid);
|
||||
@@ -3517,6 +3483,7 @@ static int fts3DoOptimize(Fts3Table *p, int bReturnDone){
|
||||
}
|
||||
|
||||
sqlite3Fts3SegmentsClose(p);
|
||||
sqlite3Fts3PendingTermsClear(p);
|
||||
|
||||
return (rc==SQLITE_OK && bReturnDone && bSeenDone) ? SQLITE_DONE : rc;
|
||||
}
|
||||
@@ -3552,8 +3519,8 @@ static int fts3DoRebuild(Fts3Table *p){
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_int64 nByte = sizeof(u32) * ((sqlite3_int64)p->nColumn+1)*3;
|
||||
aSz = (u32 *)sqlite3_malloc64(nByte);
|
||||
int nByte = sizeof(u32) * (p->nColumn+1)*3;
|
||||
aSz = (u32 *)sqlite3_malloc(nByte);
|
||||
if( aSz==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -3619,12 +3586,12 @@ static int fts3IncrmergeCsr(
|
||||
){
|
||||
int rc; /* Return Code */
|
||||
sqlite3_stmt *pStmt = 0; /* Statement used to read %_segdir entry */
|
||||
sqlite3_int64 nByte; /* Bytes allocated at pCsr->apSegment[] */
|
||||
int nByte; /* Bytes allocated at pCsr->apSegment[] */
|
||||
|
||||
/* Allocate space for the Fts3MultiSegReader.aCsr[] array */
|
||||
memset(pCsr, 0, sizeof(*pCsr));
|
||||
nByte = sizeof(Fts3SegReader *) * nSeg;
|
||||
pCsr->apSegment = (Fts3SegReader **)sqlite3_malloc64(nByte);
|
||||
pCsr->apSegment = (Fts3SegReader **)sqlite3_malloc(nByte);
|
||||
|
||||
if( pCsr->apSegment==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
@@ -3767,8 +3734,8 @@ static int nodeReaderNext(NodeReader *p){
|
||||
}
|
||||
p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nSuffix);
|
||||
|
||||
if( nPrefix>p->term.n || nSuffix>p->nNode-p->iOff || nSuffix==0 ){
|
||||
return FTS_CORRUPT_VTAB;
|
||||
if( nPrefix>p->iOff || nSuffix>p->nNode-p->iOff ){
|
||||
return SQLITE_CORRUPT_VTAB;
|
||||
}
|
||||
blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc);
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -3778,7 +3745,7 @@ static int nodeReaderNext(NodeReader *p){
|
||||
if( p->iChild==0 ){
|
||||
p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &p->nDoclist);
|
||||
if( (p->nNode-p->iOff)<p->nDoclist ){
|
||||
return FTS_CORRUPT_VTAB;
|
||||
return SQLITE_CORRUPT_VTAB;
|
||||
}
|
||||
p->aDoclist = &p->aNode[p->iOff];
|
||||
p->iOff += p->nDoclist;
|
||||
@@ -3786,7 +3753,7 @@ static int nodeReaderNext(NodeReader *p){
|
||||
}
|
||||
}
|
||||
|
||||
assert_fts3_nc( p->iOff<=p->nNode );
|
||||
assert( p->iOff<=p->nNode );
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -3810,14 +3777,14 @@ static int nodeReaderInit(NodeReader *p, const char *aNode, int nNode){
|
||||
p->nNode = nNode;
|
||||
|
||||
/* Figure out if this is a leaf or an internal node. */
|
||||
if( aNode && aNode[0] ){
|
||||
if( p->aNode[0] ){
|
||||
/* An internal node. */
|
||||
p->iOff = 1 + sqlite3Fts3GetVarint(&p->aNode[1], &p->iChild);
|
||||
}else{
|
||||
p->iOff = 1;
|
||||
}
|
||||
|
||||
return aNode ? nodeReaderNext(p) : SQLITE_OK;
|
||||
return nodeReaderNext(p);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3854,7 +3821,6 @@ static int fts3IncrmergePush(
|
||||
** be added to. */
|
||||
nPrefix = fts3PrefixCompress(pNode->key.a, pNode->key.n, zTerm, nTerm);
|
||||
nSuffix = nTerm - nPrefix;
|
||||
if(nSuffix<=0 ) return FTS_CORRUPT_VTAB;
|
||||
nSpace = sqlite3Fts3VarintLen(nPrefix);
|
||||
nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix;
|
||||
|
||||
@@ -3948,14 +3914,13 @@ static int fts3AppendToNode(
|
||||
/* Node must have already been started. There must be a doclist for a
|
||||
** leaf node, and there must not be a doclist for an internal node. */
|
||||
assert( pNode->n>0 );
|
||||
assert_fts3_nc( (pNode->a[0]=='\0')==(aDoclist!=0) );
|
||||
assert( (pNode->a[0]=='\0')==(aDoclist!=0) );
|
||||
|
||||
blobGrowBuffer(pPrev, nTerm, &rc);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
nPrefix = fts3PrefixCompress(pPrev->a, pPrev->n, zTerm, nTerm);
|
||||
nSuffix = nTerm - nPrefix;
|
||||
if( nSuffix<=0 ) return FTS_CORRUPT_VTAB;
|
||||
memcpy(pPrev->a, zTerm, nTerm);
|
||||
pPrev->n = nTerm;
|
||||
|
||||
@@ -4165,7 +4130,7 @@ static int fts3TermCmp(
|
||||
int nCmp = MIN(nLhs, nRhs);
|
||||
int res;
|
||||
|
||||
res = (nCmp ? memcmp(zLhs, zRhs, nCmp) : 0);
|
||||
res = memcmp(zLhs, zRhs, nCmp);
|
||||
if( res==0 ) res = nLhs - nRhs;
|
||||
|
||||
return res;
|
||||
@@ -4249,10 +4214,6 @@ static int fts3IncrmergeLoad(
|
||||
pWriter->bNoLeafData = (pWriter->nLeafData==0);
|
||||
nRoot = sqlite3_column_bytes(pSelect, 4);
|
||||
aRoot = sqlite3_column_blob(pSelect, 4);
|
||||
if( aRoot==0 ){
|
||||
sqlite3_reset(pSelect);
|
||||
return nRoot ? SQLITE_NOMEM : FTS_CORRUPT_VTAB;
|
||||
}
|
||||
}else{
|
||||
return sqlite3_reset(pSelect);
|
||||
}
|
||||
@@ -4288,10 +4249,6 @@ static int fts3IncrmergeLoad(
|
||||
int i;
|
||||
int nHeight = (int)aRoot[0];
|
||||
NodeWriter *pNode;
|
||||
if( nHeight<1 || nHeight>FTS_MAX_APPENDABLE_HEIGHT ){
|
||||
sqlite3_reset(pSelect);
|
||||
return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
|
||||
pWriter->nLeafEst = (int)((iEnd - iStart) + 1)/FTS_MAX_APPENDABLE_HEIGHT;
|
||||
pWriter->iStart = iStart;
|
||||
@@ -4305,42 +4262,34 @@ static int fts3IncrmergeLoad(
|
||||
|
||||
pNode = &pWriter->aNodeWriter[nHeight];
|
||||
pNode->iBlock = pWriter->iStart + pWriter->nLeafEst*nHeight;
|
||||
blobGrowBuffer(&pNode->block,
|
||||
MAX(nRoot, p->nNodeSize)+FTS3_NODE_PADDING, &rc
|
||||
);
|
||||
blobGrowBuffer(&pNode->block, MAX(nRoot, p->nNodeSize), &rc);
|
||||
if( rc==SQLITE_OK ){
|
||||
memcpy(pNode->block.a, aRoot, nRoot);
|
||||
pNode->block.n = nRoot;
|
||||
memset(&pNode->block.a[nRoot], 0, FTS3_NODE_PADDING);
|
||||
}
|
||||
|
||||
for(i=nHeight; i>=0 && rc==SQLITE_OK; i--){
|
||||
NodeReader reader;
|
||||
pNode = &pWriter->aNodeWriter[i];
|
||||
|
||||
if( pNode->block.a){
|
||||
rc = nodeReaderInit(&reader, pNode->block.a, pNode->block.n);
|
||||
while( reader.aNode && rc==SQLITE_OK ) rc = nodeReaderNext(&reader);
|
||||
blobGrowBuffer(&pNode->key, reader.term.n, &rc);
|
||||
if( rc==SQLITE_OK ){
|
||||
memcpy(pNode->key.a, reader.term.a, reader.term.n);
|
||||
pNode->key.n = reader.term.n;
|
||||
if( i>0 ){
|
||||
char *aBlock = 0;
|
||||
int nBlock = 0;
|
||||
pNode = &pWriter->aNodeWriter[i-1];
|
||||
pNode->iBlock = reader.iChild;
|
||||
rc = sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock, 0);
|
||||
blobGrowBuffer(&pNode->block,
|
||||
MAX(nBlock, p->nNodeSize)+FTS3_NODE_PADDING, &rc
|
||||
);
|
||||
if( rc==SQLITE_OK ){
|
||||
memcpy(pNode->block.a, aBlock, nBlock);
|
||||
pNode->block.n = nBlock;
|
||||
memset(&pNode->block.a[nBlock], 0, FTS3_NODE_PADDING);
|
||||
}
|
||||
sqlite3_free(aBlock);
|
||||
rc = nodeReaderInit(&reader, pNode->block.a, pNode->block.n);
|
||||
while( reader.aNode && rc==SQLITE_OK ) rc = nodeReaderNext(&reader);
|
||||
blobGrowBuffer(&pNode->key, reader.term.n, &rc);
|
||||
if( rc==SQLITE_OK ){
|
||||
memcpy(pNode->key.a, reader.term.a, reader.term.n);
|
||||
pNode->key.n = reader.term.n;
|
||||
if( i>0 ){
|
||||
char *aBlock = 0;
|
||||
int nBlock = 0;
|
||||
pNode = &pWriter->aNodeWriter[i-1];
|
||||
pNode->iBlock = reader.iChild;
|
||||
rc = sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock, 0);
|
||||
blobGrowBuffer(&pNode->block, MAX(nBlock, p->nNodeSize), &rc);
|
||||
if( rc==SQLITE_OK ){
|
||||
memcpy(pNode->block.a, aBlock, nBlock);
|
||||
pNode->block.n = nBlock;
|
||||
}
|
||||
sqlite3_free(aBlock);
|
||||
}
|
||||
}
|
||||
nodeReaderRelease(&reader);
|
||||
@@ -4583,10 +4532,7 @@ static int fts3TruncateNode(
|
||||
NodeReader reader; /* Reader object */
|
||||
Blob prev = {0, 0, 0}; /* Previous term written to new node */
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
int bLeaf; /* True for a leaf node */
|
||||
|
||||
if( nNode<1 ) return FTS_CORRUPT_VTAB;
|
||||
bLeaf = aNode[0]=='\0';
|
||||
int bLeaf = aNode[0]=='\0'; /* True for a leaf node */
|
||||
|
||||
/* Allocate required output space */
|
||||
blobGrowBuffer(pNew, nNode, &rc);
|
||||
@@ -4852,17 +4798,13 @@ static int fts3IncrmergeHintPop(Blob *pHint, i64 *piAbsLevel, int *pnInput){
|
||||
const int nHint = pHint->n;
|
||||
int i;
|
||||
|
||||
i = pHint->n-1;
|
||||
if( (pHint->a[i] & 0x80) ) return FTS_CORRUPT_VTAB;
|
||||
i = pHint->n-2;
|
||||
while( i>0 && (pHint->a[i-1] & 0x80) ) i--;
|
||||
if( i==0 ) return FTS_CORRUPT_VTAB;
|
||||
i--;
|
||||
while( i>0 && (pHint->a[i-1] & 0x80) ) i--;
|
||||
|
||||
pHint->n = i;
|
||||
i += sqlite3Fts3GetVarint(&pHint->a[i], piAbsLevel);
|
||||
i += fts3GetVarint32(&pHint->a[i], pnInput);
|
||||
assert( i<=nHint );
|
||||
if( i!=nHint ) return FTS_CORRUPT_VTAB;
|
||||
|
||||
return SQLITE_OK;
|
||||
@@ -4932,14 +4874,8 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
|
||||
|
||||
rc = fts3IncrmergeHintPop(&hint, &iHintAbsLevel, &nHintSeg);
|
||||
if( nSeg<0 || (iAbsLevel % nMod) >= (iHintAbsLevel % nMod) ){
|
||||
/* Based on the scan in the block above, it is known that there
|
||||
** are no levels with a relative level smaller than that of
|
||||
** iAbsLevel with more than nSeg segments, or if nSeg is -1,
|
||||
** no levels with more than nMin segments. Use this to limit the
|
||||
** value of nHintSeg to avoid a large memory allocation in case the
|
||||
** merge-hint is corrupt*/
|
||||
iAbsLevel = iHintAbsLevel;
|
||||
nSeg = MIN(MAX(nMin,nSeg), nHintSeg);
|
||||
nSeg = nHintSeg;
|
||||
bUseHint = 1;
|
||||
bDirtyHint = 1;
|
||||
}else{
|
||||
@@ -4952,13 +4888,7 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
|
||||
/* If nSeg is less that zero, then there is no level with at least
|
||||
** nMin segments and no hint in the %_stat table. No work to do.
|
||||
** Exit early in this case. */
|
||||
if( nSeg<=0 ) break;
|
||||
|
||||
assert( nMod<=0x7FFFFFFF );
|
||||
if( iAbsLevel<0 || iAbsLevel>(nMod<<32) ){
|
||||
rc = FTS_CORRUPT_VTAB;
|
||||
break;
|
||||
}
|
||||
if( nSeg<0 ) break;
|
||||
|
||||
/* Open a cursor to iterate through the contents of the oldest nSeg
|
||||
** indexes of absolute level iAbsLevel. If this cursor is opened using
|
||||
@@ -4986,15 +4916,8 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
|
||||
}
|
||||
if( SQLITE_OK==rc && pCsr->nSegment==nSeg
|
||||
&& SQLITE_OK==(rc = sqlite3Fts3SegReaderStart(p, pCsr, pFilter))
|
||||
&& SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, pCsr))
|
||||
){
|
||||
int bEmpty = 0;
|
||||
rc = sqlite3Fts3SegReaderStep(p, pCsr);
|
||||
if( rc==SQLITE_OK ){
|
||||
bEmpty = 1;
|
||||
}else if( rc!=SQLITE_ROW ){
|
||||
sqlite3Fts3SegReaderFinish(pCsr);
|
||||
break;
|
||||
}
|
||||
if( bUseHint && iIdx>0 ){
|
||||
const char *zKey = pCsr->zTerm;
|
||||
int nKey = pCsr->nTerm;
|
||||
@@ -5005,13 +4928,11 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
|
||||
|
||||
if( rc==SQLITE_OK && pWriter->nLeafEst ){
|
||||
fts3LogMerge(nSeg, iAbsLevel);
|
||||
if( bEmpty==0 ){
|
||||
do {
|
||||
rc = fts3IncrmergeAppend(p, pWriter, pCsr);
|
||||
if( rc==SQLITE_OK ) rc = sqlite3Fts3SegReaderStep(p, pCsr);
|
||||
if( pWriter->nWork>=nRem && rc==SQLITE_ROW ) rc = SQLITE_OK;
|
||||
}while( rc==SQLITE_ROW );
|
||||
}
|
||||
do {
|
||||
rc = fts3IncrmergeAppend(p, pWriter, pCsr);
|
||||
if( rc==SQLITE_OK ) rc = sqlite3Fts3SegReaderStep(p, pCsr);
|
||||
if( pWriter->nWork>=nRem && rc==SQLITE_ROW ) rc = SQLITE_OK;
|
||||
}while( rc==SQLITE_ROW );
|
||||
|
||||
/* Update or delete the input segments */
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -5076,7 +4997,7 @@ static int fts3DoIncrmerge(
|
||||
const char *zParam /* Nul-terminated string containing "A,B" */
|
||||
){
|
||||
int rc;
|
||||
int nMin = (MergeCount(p) / 2);
|
||||
int nMin = (FTS3_MERGE_COUNT / 2);
|
||||
int nMerge = 0;
|
||||
const char *z = zParam;
|
||||
|
||||
@@ -5121,7 +5042,7 @@ static int fts3DoAutoincrmerge(
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
p->nAutoincrmerge = fts3Getint(&zParam);
|
||||
if( p->nAutoincrmerge==1 || p->nAutoincrmerge>MergeCount(p) ){
|
||||
if( p->nAutoincrmerge==1 || p->nAutoincrmerge>FTS3_MERGE_COUNT ){
|
||||
p->nAutoincrmerge = 8;
|
||||
}
|
||||
if( !p->bHasStat ){
|
||||
@@ -5204,12 +5125,12 @@ static u64 fts3ChecksumIndex(
|
||||
|
||||
i64 iDocid = 0;
|
||||
i64 iCol = 0;
|
||||
u64 iPos = 0;
|
||||
i64 iPos = 0;
|
||||
|
||||
pCsr += sqlite3Fts3GetVarint(pCsr, &iDocid);
|
||||
while( pCsr<pEnd ){
|
||||
u64 iVal = 0;
|
||||
pCsr += sqlite3Fts3GetVarintU(pCsr, &iVal);
|
||||
i64 iVal = 0;
|
||||
pCsr += sqlite3Fts3GetVarint(pCsr, &iVal);
|
||||
if( pCsr<pEnd ){
|
||||
if( iVal==0 || iVal==1 ){
|
||||
iCol = 0;
|
||||
@@ -5217,12 +5138,8 @@ static u64 fts3ChecksumIndex(
|
||||
if( iVal ){
|
||||
pCsr += sqlite3Fts3GetVarint(pCsr, &iCol);
|
||||
}else{
|
||||
pCsr += sqlite3Fts3GetVarintU(pCsr, &iVal);
|
||||
if( p->bDescIdx ){
|
||||
iDocid = (i64)((u64)iDocid - iVal);
|
||||
}else{
|
||||
iDocid = (i64)((u64)iDocid + iVal);
|
||||
}
|
||||
pCsr += sqlite3Fts3GetVarint(pCsr, &iVal);
|
||||
iDocid += iVal;
|
||||
}
|
||||
}else{
|
||||
iPos += (iVal - 2);
|
||||
@@ -5295,9 +5212,10 @@ static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
|
||||
for(iCol=0; rc==SQLITE_OK && iCol<p->nColumn; iCol++){
|
||||
if( p->abNotindexed[iCol]==0 ){
|
||||
const char *zText = (const char *)sqlite3_column_text(pStmt, iCol+1);
|
||||
int nText = sqlite3_column_bytes(pStmt, iCol+1);
|
||||
sqlite3_tokenizer_cursor *pT = 0;
|
||||
|
||||
rc = sqlite3Fts3OpenTokenizer(p->pTokenizer, iLang, zText, -1, &pT);
|
||||
rc = sqlite3Fts3OpenTokenizer(p->pTokenizer, iLang, zText, nText,&pT);
|
||||
while( rc==SQLITE_OK ){
|
||||
char const *zToken; /* Buffer containing token */
|
||||
int nToken = 0; /* Number of bytes in token */
|
||||
@@ -5382,7 +5300,7 @@ static int fts3DoIntegrityCheck(
|
||||
** meaningful value to insert is the text 'optimize'.
|
||||
*/
|
||||
static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
|
||||
int rc = SQLITE_ERROR; /* Return Code */
|
||||
int rc; /* Return Code */
|
||||
const char *zVal = (const char *)sqlite3_value_text(pVal);
|
||||
int nVal = sqlite3_value_bytes(pVal);
|
||||
|
||||
@@ -5398,27 +5316,21 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
|
||||
rc = fts3DoIncrmerge(p, &zVal[6]);
|
||||
}else if( nVal>10 && 0==sqlite3_strnicmp(zVal, "automerge=", 10) ){
|
||||
rc = fts3DoAutoincrmerge(p, &zVal[10]);
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
}else{
|
||||
int v;
|
||||
if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
|
||||
v = atoi(&zVal[9]);
|
||||
if( v>=24 && v<=p->nPgsz-35 ) p->nNodeSize = v;
|
||||
rc = SQLITE_OK;
|
||||
}else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){
|
||||
v = atoi(&zVal[11]);
|
||||
if( v>=64 && v<=FTS3_MAX_PENDING_DATA ) p->nMaxPendingData = v;
|
||||
rc = SQLITE_OK;
|
||||
}else if( nVal>21 && 0==sqlite3_strnicmp(zVal,"test-no-incr-doclist=",21) ){
|
||||
p->bNoIncrDoclist = atoi(&zVal[21]);
|
||||
rc = SQLITE_OK;
|
||||
}else if( nVal>11 && 0==sqlite3_strnicmp(zVal,"mergecount=",11) ){
|
||||
v = atoi(&zVal[11]);
|
||||
if( v>=4 && v<=FTS3_MERGE_COUNT && (v&1)==0 ) p->nMergeCount = v;
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
#ifdef SQLITE_TEST
|
||||
}else if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
|
||||
p->nNodeSize = atoi(&zVal[9]);
|
||||
rc = SQLITE_OK;
|
||||
}else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){
|
||||
p->nMaxPendingData = atoi(&zVal[11]);
|
||||
rc = SQLITE_OK;
|
||||
}else if( nVal>21 && 0==sqlite3_strnicmp(zVal, "test-no-incr-doclist=", 21) ){
|
||||
p->bNoIncrDoclist = atoi(&zVal[21]);
|
||||
rc = SQLITE_OK;
|
||||
#endif
|
||||
}else{
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -5659,7 +5571,7 @@ int sqlite3Fts3UpdateMethod(
|
||||
}
|
||||
|
||||
/* Allocate space to hold the change in document sizes */
|
||||
aSzDel = sqlite3_malloc64(sizeof(aSzDel[0])*((sqlite3_int64)p->nColumn+1)*2);
|
||||
aSzDel = sqlite3_malloc( sizeof(aSzDel[0])*(p->nColumn+1)*2 );
|
||||
if( aSzDel==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto update_out;
|
||||
|
||||
@@ -63,15 +63,14 @@ proc print_rd {map} {
|
||||
}
|
||||
puts ""
|
||||
puts " \};"
|
||||
puts "#define HIBIT ((unsigned char)0x80)"
|
||||
puts " unsigned char aChar\[\] = \{"
|
||||
puts " char aChar\[\] = \{"
|
||||
puts -nonewline " '\\0', "
|
||||
set i 1
|
||||
foreach c $aChar f $aFlag {
|
||||
if { $f } {
|
||||
set str "'$c'|HIBIT, "
|
||||
set str "'$c'|0x80, "
|
||||
} else {
|
||||
set str "'$c', "
|
||||
set str "'$c'|0x00, "
|
||||
}
|
||||
if {$c == ""} { set str "'\\0', " }
|
||||
|
||||
@@ -135,8 +134,8 @@ proc print_isdiacritic {zFunc map} {
|
||||
|
||||
puts " if( c<$iFirst || c>$iLast ) return 0;"
|
||||
puts " return (c < $iFirst+32) ?"
|
||||
puts " (mask0 & ((unsigned int)1 << (c-$iFirst))) :"
|
||||
puts " (mask1 & ((unsigned int)1 << (c-$iFirst-32)));"
|
||||
puts " (mask0 & (1 << (c-$iFirst))) :"
|
||||
puts " (mask1 & (1 << (c-$iFirst-32)));"
|
||||
puts "\}"
|
||||
}
|
||||
|
||||
@@ -700,7 +699,7 @@ proc print_categories {lMap} {
|
||||
static u16 aFts5UnicodeMap[] = {$aMapArray};
|
||||
static u16 aFts5UnicodeData[] = {$aDataArray};
|
||||
|
||||
int sqlite3Fts5UnicodeCategory(u32 iCode) {
|
||||
int sqlite3Fts5UnicodeCategory(int iCode) {
|
||||
int iRes = -1;
|
||||
int iHi;
|
||||
int iLo;
|
||||
@@ -738,7 +737,7 @@ proc print_categories {lMap} {
|
||||
int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ];
|
||||
int n = (aFts5UnicodeData[iTbl] >> 5) + i;
|
||||
for(; i<128 && i<n; i++){
|
||||
aAscii[i] = (u8)bToken;
|
||||
aAscii[i] = bToken;
|
||||
}
|
||||
iTbl++;
|
||||
}
|
||||
@@ -783,7 +782,7 @@ proc print_test_categories {lMap} {
|
||||
aArray[0] = 1;
|
||||
}
|
||||
|
||||
c = sqlite3Fts5UnicodeCategory((u32)i);
|
||||
c = sqlite3Fts5UnicodeCategory(i);
|
||||
if( aArray[c]==0 ){
|
||||
*piCode = i;
|
||||
return 1;
|
||||
@@ -838,7 +837,7 @@ proc print_fold_test {zFunc mappings} {
|
||||
proc print_fileheader {} {
|
||||
puts [string trim {
|
||||
/*
|
||||
** 2012-05-25
|
||||
** 2012 May 25
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
|
||||
+17
-13
@@ -120,8 +120,12 @@ struct Fts5PhraseIter {
|
||||
**
|
||||
** Usually, output parameter *piPhrase is set to the phrase number, *piCol
|
||||
** to the column in which it occurs and *piOff the token offset of the
|
||||
** first token of the phrase. Returns SQLITE_OK if successful, or an error
|
||||
** code (i.e. SQLITE_NOMEM) if an error occurs.
|
||||
** first token of the phrase. The exception is if the table was created
|
||||
** with the offsets=0 option specified. In this case *piOff is always
|
||||
** set to -1.
|
||||
**
|
||||
** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM)
|
||||
** if an error occurs.
|
||||
**
|
||||
** This API can be quite slow if used with an FTS5 table created with the
|
||||
** "detail=none" or "detail=column" option.
|
||||
@@ -159,10 +163,10 @@ struct Fts5PhraseIter {
|
||||
**
|
||||
** xSetAuxdata(pFts5, pAux, xDelete)
|
||||
**
|
||||
** Save the pointer passed as the second argument as the extension function's
|
||||
** Save the pointer passed as the second argument as the extension functions
|
||||
** "auxiliary data". The pointer may then be retrieved by the current or any
|
||||
** future invocation of the same fts5 extension function made as part of
|
||||
** the same MATCH query using the xGetAuxdata() API.
|
||||
** of the same MATCH query using the xGetAuxdata() API.
|
||||
**
|
||||
** Each extension function is allocated a single auxiliary data slot for
|
||||
** each FTS query (MATCH expression). If the extension function is invoked
|
||||
@@ -177,7 +181,7 @@ struct Fts5PhraseIter {
|
||||
** The xDelete callback, if one is specified, is also invoked on the
|
||||
** auxiliary data pointer after the FTS5 query has finished.
|
||||
**
|
||||
** If an error (e.g. an OOM condition) occurs within this function,
|
||||
** If an error (e.g. an OOM condition) occurs within this function, an
|
||||
** the auxiliary data is set to NULL and an error code returned. If the
|
||||
** xDelete parameter was not NULL, it is invoked on the auxiliary data
|
||||
** pointer before returning.
|
||||
@@ -401,8 +405,8 @@ struct Fts5ExtensionApi {
|
||||
**
|
||||
** There are several ways to approach this in FTS5:
|
||||
**
|
||||
** <ol><li> By mapping all synonyms to a single token. In this case, using
|
||||
** the above example, this means that the tokenizer returns the
|
||||
** <ol><li> By mapping all synonyms to a single token. In this case, the
|
||||
** In the above example, this means that the tokenizer returns the
|
||||
** same token for inputs "first" and "1st". Say that token is in
|
||||
** fact "first", so that when the user inserts the document "I won
|
||||
** 1st place" entries are added to the index for tokens "i", "won",
|
||||
@@ -410,11 +414,11 @@ struct Fts5ExtensionApi {
|
||||
** the tokenizer substitutes "first" for "1st" and the query works
|
||||
** as expected.
|
||||
**
|
||||
** <li> By querying the index for all synonyms of each query term
|
||||
** separately. In this case, when tokenizing query text, the
|
||||
** tokenizer may provide multiple synonyms for a single term
|
||||
** within the document. FTS5 then queries the index for each
|
||||
** synonym individually. For example, faced with the query:
|
||||
** <li> By adding multiple synonyms for a single term to the FTS index.
|
||||
** In this case, when tokenizing query text, the tokenizer may
|
||||
** provide multiple synonyms for a single term within the document.
|
||||
** FTS5 then queries the index for each synonym individually. For
|
||||
** example, faced with the query:
|
||||
**
|
||||
** <codeblock>
|
||||
** ... MATCH 'first place'</codeblock>
|
||||
@@ -438,7 +442,7 @@ struct Fts5ExtensionApi {
|
||||
** "place".
|
||||
**
|
||||
** This way, even if the tokenizer does not provide synonyms
|
||||
** when tokenizing query text (it should not - to do so would be
|
||||
** when tokenizing query text (it should not - to do would be
|
||||
** inefficient), it doesn't matter if the user queries for
|
||||
** 'first + place' or '1st + place', as there are entries in the
|
||||
** FTS index corresponding to both forms of the first token.
|
||||
|
||||
+6
-37
@@ -61,11 +61,6 @@ typedef sqlite3_uint64 u64;
|
||||
*/
|
||||
#define FTS5_MAX_PREFIX_INDEXES 31
|
||||
|
||||
/*
|
||||
** Maximum segments permitted in a single index
|
||||
*/
|
||||
#define FTS5_MAX_SEGMENT 2000
|
||||
|
||||
#define FTS5_DEFAULT_NEARDIST 10
|
||||
#define FTS5_DEFAULT_RANK "bm25"
|
||||
|
||||
@@ -92,12 +87,6 @@ extern int sqlite3_fts5_may_be_corrupt;
|
||||
# define assert_nc(x) assert(x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** A version of memcmp() that does not cause asan errors if one of the pointer
|
||||
** parameters is NULL and the number of bytes to compare is zero.
|
||||
*/
|
||||
#define fts5Memcmp(s1, s2, n) ((n)==0 ? 0 : memcmp((s1), (s2), (n)))
|
||||
|
||||
/* Mark a function parameter as unused, to suppress nuisance compiler
|
||||
** warnings. */
|
||||
#ifndef UNUSED_PARAM
|
||||
@@ -183,7 +172,6 @@ struct Fts5Config {
|
||||
char *zContentExprlist;
|
||||
Fts5Tokenizer *pTok;
|
||||
fts5_tokenizer *pTokApi;
|
||||
int bLock; /* True when table is preparing statement */
|
||||
|
||||
/* Values loaded from the %_config table */
|
||||
int iCookie; /* Incremented when %_config is modified */
|
||||
@@ -286,7 +274,7 @@ void sqlite3Fts5Put32(u8*, int);
|
||||
int sqlite3Fts5Get32(const u8*);
|
||||
|
||||
#define FTS5_POS2COLUMN(iPos) (int)(iPos >> 32)
|
||||
#define FTS5_POS2OFFSET(iPos) (int)(iPos & 0x7FFFFFFF)
|
||||
#define FTS5_POS2OFFSET(iPos) (int)(iPos & 0xFFFFFFFF)
|
||||
|
||||
typedef struct Fts5PoslistReader Fts5PoslistReader;
|
||||
struct Fts5PoslistReader {
|
||||
@@ -321,7 +309,7 @@ int sqlite3Fts5PoslistNext64(
|
||||
);
|
||||
|
||||
/* Malloc utility */
|
||||
void *sqlite3Fts5MallocZero(int *pRc, sqlite3_int64 nByte);
|
||||
void *sqlite3Fts5MallocZero(int *pRc, int nByte);
|
||||
char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn);
|
||||
|
||||
/* Character set tests (like isspace(), isalpha() etc.) */
|
||||
@@ -422,11 +410,6 @@ int sqlite3Fts5IterNextFrom(Fts5IndexIter*, i64 iMatch);
|
||||
*/
|
||||
void sqlite3Fts5IterClose(Fts5IndexIter*);
|
||||
|
||||
/*
|
||||
** Close the reader blob handle, if it is open.
|
||||
*/
|
||||
void sqlite3Fts5IndexCloseReader(Fts5Index*);
|
||||
|
||||
/*
|
||||
** This interface is used by the fts5vocab module.
|
||||
*/
|
||||
@@ -537,19 +520,9 @@ int sqlite3Fts5PutVarint(unsigned char *p, u64 v);
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
** Interface to code in fts5_main.c.
|
||||
** Interface to code in fts5.c.
|
||||
*/
|
||||
|
||||
/*
|
||||
** Virtual-table object.
|
||||
*/
|
||||
typedef struct Fts5Table Fts5Table;
|
||||
struct Fts5Table {
|
||||
sqlite3_vtab base; /* Base class used by SQLite core */
|
||||
Fts5Config *pConfig; /* Virtual table configuration */
|
||||
Fts5Index *pIndex; /* Full-text index */
|
||||
};
|
||||
|
||||
int sqlite3Fts5GetTokenizer(
|
||||
Fts5Global*,
|
||||
const char **azArg,
|
||||
@@ -559,9 +532,7 @@ int sqlite3Fts5GetTokenizer(
|
||||
char **pzErr
|
||||
);
|
||||
|
||||
Fts5Table *sqlite3Fts5TableFromCsrid(Fts5Global*, i64);
|
||||
|
||||
int sqlite3Fts5FlushToDisk(Fts5Table*);
|
||||
Fts5Index *sqlite3Fts5IndexFromCsrid(Fts5Global*, i64, Fts5Config **);
|
||||
|
||||
/*
|
||||
** End of interface to code in fts5.c.
|
||||
@@ -594,9 +565,8 @@ void sqlite3Fts5HashClear(Fts5Hash*);
|
||||
|
||||
int sqlite3Fts5HashQuery(
|
||||
Fts5Hash*, /* Hash table to query */
|
||||
int nPre,
|
||||
const char *pTerm, int nTerm, /* Query term */
|
||||
void **ppObj, /* OUT: Pointer to doclist for pTerm */
|
||||
const u8 **ppDoclist, /* OUT: Pointer to doclist for pTerm */
|
||||
int *pnDoclist /* OUT: Size of doclist in bytes */
|
||||
);
|
||||
|
||||
@@ -705,7 +675,6 @@ int sqlite3Fts5ExprEof(Fts5Expr*);
|
||||
i64 sqlite3Fts5ExprRowid(Fts5Expr*);
|
||||
|
||||
void sqlite3Fts5ExprFree(Fts5Expr*);
|
||||
int sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2);
|
||||
|
||||
/* Called during startup to register a UDF with SQLite */
|
||||
int sqlite3Fts5ExprInit(Fts5Global*, sqlite3*);
|
||||
@@ -819,7 +788,7 @@ int sqlite3Fts5UnicodeIsdiacritic(int c);
|
||||
int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
|
||||
|
||||
int sqlite3Fts5UnicodeCatParse(const char*, u8*);
|
||||
int sqlite3Fts5UnicodeCategory(u32 iCode);
|
||||
int sqlite3Fts5UnicodeCategory(int iCode);
|
||||
void sqlite3Fts5UnicodeAscii(u8*, u8*);
|
||||
/*
|
||||
** End of interface to code in fts5_unicode2.c.
|
||||
|
||||
+11
-13
@@ -136,7 +136,7 @@ static void fts5HighlightAppend(
|
||||
HighlightContext *p,
|
||||
const char *z, int n
|
||||
){
|
||||
if( *pRc==SQLITE_OK && z ){
|
||||
if( *pRc==SQLITE_OK ){
|
||||
if( n<0 ) n = (int)strlen(z);
|
||||
p->zOut = sqlite3_mprintf("%z%.*s", p->zOut, n, z);
|
||||
if( p->zOut==0 ) *pRc = SQLITE_NOMEM;
|
||||
@@ -268,7 +268,7 @@ static int fts5SentenceFinderAdd(Fts5SFinder *p, int iAdd){
|
||||
int nNew = p->nFirstAlloc ? p->nFirstAlloc*2 : 64;
|
||||
int *aNew;
|
||||
|
||||
aNew = (int*)sqlite3_realloc64(p->aFirst, nNew*sizeof(int));
|
||||
aNew = (int*)sqlite3_realloc(p->aFirst, nNew*sizeof(int));
|
||||
if( aNew==0 ) return SQLITE_NOMEM;
|
||||
p->aFirst = aNew;
|
||||
p->nFirstAlloc = nNew;
|
||||
@@ -335,12 +335,11 @@ static int fts5SnippetScore(
|
||||
int nInst;
|
||||
int nScore = 0;
|
||||
int iLast = 0;
|
||||
sqlite3_int64 iEnd = (sqlite3_int64)iPos + nToken;
|
||||
|
||||
rc = pApi->xInstCount(pFts, &nInst);
|
||||
for(i=0; i<nInst && rc==SQLITE_OK; i++){
|
||||
rc = pApi->xInst(pFts, i, &ip, &ic, &iOff);
|
||||
if( rc==SQLITE_OK && ic==iCol && iOff>=iPos && iOff<iEnd ){
|
||||
if( rc==SQLITE_OK && ic==iCol && iOff>=iPos && iOff<(iPos+nToken) ){
|
||||
nScore += (aSeen[ip] ? 1 : 1000);
|
||||
aSeen[ip] = 1;
|
||||
if( iFirst<0 ) iFirst = iOff;
|
||||
@@ -350,10 +349,10 @@ static int fts5SnippetScore(
|
||||
|
||||
*pnScore = nScore;
|
||||
if( piPos ){
|
||||
sqlite3_int64 iAdj = iFirst - (nToken - (iLast-iFirst)) / 2;
|
||||
int iAdj = iFirst - (nToken - (iLast-iFirst)) / 2;
|
||||
if( (iAdj+nToken)>nDocsize ) iAdj = nDocsize - nToken;
|
||||
if( iAdj<0 ) iAdj = 0;
|
||||
*piPos = (int)iAdj;
|
||||
*piPos = iAdj;
|
||||
}
|
||||
|
||||
return rc;
|
||||
@@ -443,9 +442,7 @@ static void fts5SnippetFunction(
|
||||
int jj;
|
||||
|
||||
rc = pApi->xInst(pFts, ii, &ip, &ic, &io);
|
||||
if( ic!=i ) continue;
|
||||
if( io>nDocsize ) rc = FTS5_CORRUPT;
|
||||
if( rc!=SQLITE_OK ) continue;
|
||||
if( ic!=i || rc!=SQLITE_OK ) continue;
|
||||
memset(aSeen, 0, nPhrase);
|
||||
rc = fts5SnippetScore(pApi, pFts, nDocsize, aSeen, i,
|
||||
io, nToken, &nScore, &iAdj
|
||||
@@ -571,17 +568,17 @@ static int fts5Bm25GetData(
|
||||
int nPhrase; /* Number of phrases in query */
|
||||
sqlite3_int64 nRow = 0; /* Number of rows in table */
|
||||
sqlite3_int64 nToken = 0; /* Number of tokens in table */
|
||||
sqlite3_int64 nByte; /* Bytes of space to allocate */
|
||||
int nByte; /* Bytes of space to allocate */
|
||||
int i;
|
||||
|
||||
/* Allocate the Fts5Bm25Data object */
|
||||
nPhrase = pApi->xPhraseCount(pFts);
|
||||
nByte = sizeof(Fts5Bm25Data) + nPhrase*2*sizeof(double);
|
||||
p = (Fts5Bm25Data*)sqlite3_malloc64(nByte);
|
||||
p = (Fts5Bm25Data*)sqlite3_malloc(nByte);
|
||||
if( p==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
memset(p, 0, (size_t)nByte);
|
||||
memset(p, 0, nByte);
|
||||
p->nPhrase = nPhrase;
|
||||
p->aIDF = (double*)&p[1];
|
||||
p->aFreq = &p->aIDF[nPhrase];
|
||||
@@ -589,7 +586,6 @@ static int fts5Bm25GetData(
|
||||
|
||||
/* Calculate the average document length for this FTS5 table */
|
||||
if( rc==SQLITE_OK ) rc = pApi->xRowCount(pFts, &nRow);
|
||||
assert( rc!=SQLITE_OK || nRow>0 );
|
||||
if( rc==SQLITE_OK ) rc = pApi->xColumnTotalSize(pFts, -1, &nToken);
|
||||
if( rc==SQLITE_OK ) p->avgdl = (double)nToken / (double)nRow;
|
||||
|
||||
@@ -714,3 +710,5 @@ int sqlite3Fts5AuxInit(fts5_api *pApi){
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+9
-18
@@ -17,17 +17,17 @@
|
||||
|
||||
int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, u32 nByte){
|
||||
if( (u32)pBuf->nSpace<nByte ){
|
||||
u64 nNew = pBuf->nSpace ? pBuf->nSpace : 64;
|
||||
u32 nNew = pBuf->nSpace ? pBuf->nSpace : 64;
|
||||
u8 *pNew;
|
||||
while( nNew<nByte ){
|
||||
nNew = nNew * 2;
|
||||
}
|
||||
pNew = sqlite3_realloc64(pBuf->p, nNew);
|
||||
pNew = sqlite3_realloc(pBuf->p, nNew);
|
||||
if( pNew==0 ){
|
||||
*pRc = SQLITE_NOMEM;
|
||||
return 1;
|
||||
}else{
|
||||
pBuf->nSpace = (int)nNew;
|
||||
pBuf->nSpace = nNew;
|
||||
pBuf->p = pNew;
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ void sqlite3Fts5Put32(u8 *aBuf, int iVal){
|
||||
}
|
||||
|
||||
int sqlite3Fts5Get32(const u8 *aBuf){
|
||||
return (int)((((u32)aBuf[0])<<24) + (aBuf[1]<<16) + (aBuf[2]<<8) + aBuf[3]);
|
||||
return (aBuf[0] << 24) + (aBuf[1] << 16) + (aBuf[2] << 8) + aBuf[3];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -178,21 +178,12 @@ int sqlite3Fts5PoslistNext64(
|
||||
i64 iOff = *piOff;
|
||||
int iVal;
|
||||
fts5FastGetVarint32(a, i, iVal);
|
||||
if( iVal<=1 ){
|
||||
if( iVal==0 ){
|
||||
*pi = i;
|
||||
return 0;
|
||||
}
|
||||
if( iVal==1 ){
|
||||
fts5FastGetVarint32(a, i, iVal);
|
||||
iOff = ((i64)iVal) << 32;
|
||||
fts5FastGetVarint32(a, i, iVal);
|
||||
if( iVal<2 ){
|
||||
/* This is a corrupt record. So stop parsing it here. */
|
||||
*piOff = -1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
*piOff = iOff + ((iVal-2) & 0x7FFFFFFF);
|
||||
*piOff = iOff + (iVal-2);
|
||||
*pi = i;
|
||||
return 0;
|
||||
}
|
||||
@@ -253,14 +244,14 @@ int sqlite3Fts5PoslistWriterAppend(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
void *sqlite3Fts5MallocZero(int *pRc, sqlite3_int64 nByte){
|
||||
void *sqlite3Fts5MallocZero(int *pRc, int nByte){
|
||||
void *pRet = 0;
|
||||
if( *pRc==SQLITE_OK ){
|
||||
pRet = sqlite3_malloc64(nByte);
|
||||
pRet = sqlite3_malloc(nByte);
|
||||
if( pRet==0 ){
|
||||
if( nByte>0 ) *pRc = SQLITE_NOMEM;
|
||||
}else{
|
||||
memset(pRet, 0, (size_t)nByte);
|
||||
memset(pRet, 0, nByte);
|
||||
}
|
||||
}
|
||||
return pRet;
|
||||
|
||||
+10
-11
@@ -23,7 +23,7 @@
|
||||
#define FTS5_DEFAULT_HASHSIZE (1024*1024)
|
||||
|
||||
/* Maximum allowed page size */
|
||||
#define FTS5_MAX_PAGE_SIZE (64*1024)
|
||||
#define FTS5_MAX_PAGE_SIZE (128*1024)
|
||||
|
||||
static int fts5_iswhitespace(char x){
|
||||
return (x==' ');
|
||||
@@ -150,7 +150,7 @@ static int fts5Dequote(char *z){
|
||||
assert( q=='[' || q=='\'' || q=='"' || q=='`' );
|
||||
if( q=='[' ) q = ']';
|
||||
|
||||
while( z[iIn] ){
|
||||
while( ALWAYS(z[iIn]) ){
|
||||
if( z[iIn]==q ){
|
||||
if( z[iIn+1]!=q ){
|
||||
/* Character iIn was the close quote. */
|
||||
@@ -295,7 +295,7 @@ static int fts5ConfigParseSpecial(
|
||||
|
||||
if( sqlite3_strnicmp("tokenize", zCmd, nCmd)==0 ){
|
||||
const char *p = (const char*)zArg;
|
||||
sqlite3_int64 nArg = strlen(zArg) + 1;
|
||||
int nArg = (int)strlen(zArg) + 1;
|
||||
char **azArg = sqlite3Fts5MallocZero(&rc, sizeof(char*) * nArg);
|
||||
char *pDel = sqlite3Fts5MallocZero(&rc, nArg * 2);
|
||||
char *pSpace = pDel;
|
||||
@@ -325,7 +325,7 @@ static int fts5ConfigParseSpecial(
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
rc = sqlite3Fts5GetTokenizer(pGlobal,
|
||||
(const char**)azArg, (int)nArg, &pConfig->pTok, &pConfig->pTokApi,
|
||||
(const char**)azArg, nArg, &pConfig->pTok, &pConfig->pTokApi,
|
||||
pzErr
|
||||
);
|
||||
}
|
||||
@@ -425,8 +425,8 @@ static const char *fts5ConfigGobbleWord(
|
||||
){
|
||||
const char *zRet = 0;
|
||||
|
||||
sqlite3_int64 nIn = strlen(zIn);
|
||||
char *zOut = sqlite3_malloc64(nIn+1);
|
||||
int nIn = (int)strlen(zIn);
|
||||
char *zOut = sqlite3_malloc(nIn+1);
|
||||
|
||||
assert( *pRc==SQLITE_OK );
|
||||
*pbQuoted = 0;
|
||||
@@ -435,7 +435,7 @@ static const char *fts5ConfigGobbleWord(
|
||||
if( zOut==0 ){
|
||||
*pRc = SQLITE_NOMEM;
|
||||
}else{
|
||||
memcpy(zOut, zIn, (size_t)(nIn+1));
|
||||
memcpy(zOut, zIn, nIn+1);
|
||||
if( fts5_isopenquote(zOut[0]) ){
|
||||
int ii = fts5Dequote(zOut);
|
||||
zRet = &zIn[ii];
|
||||
@@ -529,7 +529,7 @@ int sqlite3Fts5ConfigParse(
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
Fts5Config *pRet; /* New object to return */
|
||||
int i;
|
||||
sqlite3_int64 nByte;
|
||||
int nByte;
|
||||
|
||||
*ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config));
|
||||
if( pRet==0 ) return SQLITE_NOMEM;
|
||||
@@ -683,7 +683,7 @@ int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig){
|
||||
rc = sqlite3_declare_vtab(pConfig->db, zSql);
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -828,7 +828,7 @@ int sqlite3Fts5ConfigSetValue(
|
||||
if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
|
||||
pgsz = sqlite3_value_int(pVal);
|
||||
}
|
||||
if( pgsz<32 || pgsz>FTS5_MAX_PAGE_SIZE ){
|
||||
if( pgsz<=0 || pgsz>FTS5_MAX_PAGE_SIZE ){
|
||||
*pbBadkey = 1;
|
||||
}else{
|
||||
pConfig->pgsz = pgsz;
|
||||
@@ -881,7 +881,6 @@ int sqlite3Fts5ConfigSetValue(
|
||||
*pbBadkey = 1;
|
||||
}else{
|
||||
if( nCrisisMerge<=1 ) nCrisisMerge = FTS5_DEFAULT_CRISISMERGE;
|
||||
if( nCrisisMerge>=FTS5_MAX_SEGMENT ) nCrisisMerge = FTS5_MAX_SEGMENT-1;
|
||||
pConfig->nCrisisMerge = nCrisisMerge;
|
||||
}
|
||||
}
|
||||
|
||||
+31
-72
@@ -211,7 +211,7 @@ static int fts5ExprGetToken(
|
||||
return tok;
|
||||
}
|
||||
|
||||
static void *fts5ParseAlloc(u64 t){ return sqlite3_malloc64((sqlite3_int64)t);}
|
||||
static void *fts5ParseAlloc(u64 t){ return sqlite3_malloc((int)t); }
|
||||
static void fts5ParseFree(void *p){ sqlite3_free(p); }
|
||||
|
||||
int sqlite3Fts5ExprNew(
|
||||
@@ -309,42 +309,6 @@ void sqlite3Fts5ExprFree(Fts5Expr *p){
|
||||
}
|
||||
}
|
||||
|
||||
int sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2){
|
||||
Fts5Parse sParse;
|
||||
memset(&sParse, 0, sizeof(sParse));
|
||||
|
||||
if( *pp1 ){
|
||||
Fts5Expr *p1 = *pp1;
|
||||
int nPhrase = p1->nPhrase + p2->nPhrase;
|
||||
|
||||
p1->pRoot = sqlite3Fts5ParseNode(&sParse, FTS5_AND, p1->pRoot, p2->pRoot,0);
|
||||
p2->pRoot = 0;
|
||||
|
||||
if( sParse.rc==SQLITE_OK ){
|
||||
Fts5ExprPhrase **ap = (Fts5ExprPhrase**)sqlite3_realloc(
|
||||
p1->apExprPhrase, nPhrase * sizeof(Fts5ExprPhrase*)
|
||||
);
|
||||
if( ap==0 ){
|
||||
sParse.rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
int i;
|
||||
memmove(&ap[p2->nPhrase], ap, p1->nPhrase*sizeof(Fts5ExprPhrase*));
|
||||
for(i=0; i<p2->nPhrase; i++){
|
||||
ap[i] = p2->apExprPhrase[i];
|
||||
}
|
||||
p1->nPhrase = nPhrase;
|
||||
p1->apExprPhrase = ap;
|
||||
}
|
||||
}
|
||||
sqlite3_free(p2->apExprPhrase);
|
||||
sqlite3_free(p2);
|
||||
}else{
|
||||
*pp1 = p2;
|
||||
}
|
||||
|
||||
return sParse.rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Argument pTerm must be a synonym iterator. Return the current rowid
|
||||
** that it points to.
|
||||
@@ -392,8 +356,8 @@ static int fts5ExprSynonymList(
|
||||
if( sqlite3Fts5IterEof(pIter)==0 && pIter->iRowid==iRowid ){
|
||||
if( pIter->nData==0 ) continue;
|
||||
if( nIter==nAlloc ){
|
||||
sqlite3_int64 nByte = sizeof(Fts5PoslistReader) * nAlloc * 2;
|
||||
Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc64(nByte);
|
||||
int nByte = sizeof(Fts5PoslistReader) * nAlloc * 2;
|
||||
Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc(nByte);
|
||||
if( aNew==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto synonym_poslist_out;
|
||||
@@ -473,8 +437,8 @@ static int fts5ExprPhraseIsMatch(
|
||||
/* If the aStatic[] array is not large enough, allocate a large array
|
||||
** using sqlite3_malloc(). This approach could be improved upon. */
|
||||
if( pPhrase->nTerm>ArraySize(aStatic) ){
|
||||
sqlite3_int64 nByte = sizeof(Fts5PoslistReader) * pPhrase->nTerm;
|
||||
aIter = (Fts5PoslistReader*)sqlite3_malloc64(nByte);
|
||||
int nByte = sizeof(Fts5PoslistReader) * pPhrase->nTerm;
|
||||
aIter = (Fts5PoslistReader*)sqlite3_malloc(nByte);
|
||||
if( !aIter ) return SQLITE_NOMEM;
|
||||
}
|
||||
memset(aIter, 0, sizeof(Fts5PoslistReader) * pPhrase->nTerm);
|
||||
@@ -608,7 +572,7 @@ static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){
|
||||
/* If the aStatic[] array is not large enough, allocate a large array
|
||||
** using sqlite3_malloc(). This approach could be improved upon. */
|
||||
if( pNear->nPhrase>ArraySize(aStatic) ){
|
||||
sqlite3_int64 nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase;
|
||||
int nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase;
|
||||
a = (Fts5NearTrimmer*)sqlite3Fts5MallocZero(&rc, nByte);
|
||||
}else{
|
||||
memset(aStatic, 0, sizeof(aStatic));
|
||||
@@ -1517,20 +1481,18 @@ Fts5ExprNearset *sqlite3Fts5ParseNearset(
|
||||
return pNear;
|
||||
}
|
||||
if( pNear==0 ){
|
||||
sqlite3_int64 nByte;
|
||||
nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*);
|
||||
pRet = sqlite3_malloc64(nByte);
|
||||
int nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*);
|
||||
pRet = sqlite3_malloc(nByte);
|
||||
if( pRet==0 ){
|
||||
pParse->rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
memset(pRet, 0, (size_t)nByte);
|
||||
memset(pRet, 0, nByte);
|
||||
}
|
||||
}else if( (pNear->nPhrase % SZALLOC)==0 ){
|
||||
int nNew = pNear->nPhrase + SZALLOC;
|
||||
sqlite3_int64 nByte;
|
||||
int nByte = sizeof(Fts5ExprNearset) + nNew * sizeof(Fts5ExprPhrase*);
|
||||
|
||||
nByte = sizeof(Fts5ExprNearset) + nNew * sizeof(Fts5ExprPhrase*);
|
||||
pRet = (Fts5ExprNearset*)sqlite3_realloc64(pNear, nByte);
|
||||
pRet = (Fts5ExprNearset*)sqlite3_realloc(pNear, nByte);
|
||||
if( pRet==0 ){
|
||||
pParse->rc = SQLITE_NOMEM;
|
||||
}
|
||||
@@ -1594,12 +1556,12 @@ static int fts5ParseTokenize(
|
||||
|
||||
if( pPhrase && pPhrase->nTerm>0 && (tflags & FTS5_TOKEN_COLOCATED) ){
|
||||
Fts5ExprTerm *pSyn;
|
||||
sqlite3_int64 nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1;
|
||||
pSyn = (Fts5ExprTerm*)sqlite3_malloc64(nByte);
|
||||
int nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1;
|
||||
pSyn = (Fts5ExprTerm*)sqlite3_malloc(nByte);
|
||||
if( pSyn==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
memset(pSyn, 0, (size_t)nByte);
|
||||
memset(pSyn, 0, nByte);
|
||||
pSyn->zTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer);
|
||||
memcpy(pSyn->zTerm, pToken, nToken);
|
||||
pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym;
|
||||
@@ -1611,7 +1573,7 @@ static int fts5ParseTokenize(
|
||||
Fts5ExprPhrase *pNew;
|
||||
int nNew = SZALLOC + (pPhrase ? pPhrase->nTerm : 0);
|
||||
|
||||
pNew = (Fts5ExprPhrase*)sqlite3_realloc64(pPhrase,
|
||||
pNew = (Fts5ExprPhrase*)sqlite3_realloc(pPhrase,
|
||||
sizeof(Fts5ExprPhrase) + sizeof(Fts5ExprTerm) * nNew
|
||||
);
|
||||
if( pNew==0 ){
|
||||
@@ -1697,9 +1659,9 @@ Fts5ExprPhrase *sqlite3Fts5ParseTerm(
|
||||
|
||||
if( pAppend==0 ){
|
||||
if( (pParse->nPhrase % 8)==0 ){
|
||||
sqlite3_int64 nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8);
|
||||
int nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8);
|
||||
Fts5ExprPhrase **apNew;
|
||||
apNew = (Fts5ExprPhrase**)sqlite3_realloc64(pParse->apPhrase, nByte);
|
||||
apNew = (Fts5ExprPhrase**)sqlite3_realloc(pParse->apPhrase, nByte);
|
||||
if( apNew==0 ){
|
||||
pParse->rc = SQLITE_NOMEM;
|
||||
fts5ExprPhraseFree(sCtx.pPhrase);
|
||||
@@ -1754,12 +1716,10 @@ int sqlite3Fts5ExprClonePhrase(
|
||||
if( rc==SQLITE_OK ){
|
||||
Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset;
|
||||
if( pColsetOrig ){
|
||||
sqlite3_int64 nByte;
|
||||
Fts5Colset *pColset;
|
||||
nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int);
|
||||
pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte);
|
||||
int nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int);
|
||||
Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte);
|
||||
if( pColset ){
|
||||
memcpy(pColset, pColsetOrig, (size_t)nByte);
|
||||
memcpy(pColset, pColsetOrig, nByte);
|
||||
}
|
||||
pNew->pRoot->pNear->pColset = pColset;
|
||||
}
|
||||
@@ -1877,7 +1837,7 @@ static Fts5Colset *fts5ParseColset(
|
||||
assert( pParse->rc==SQLITE_OK );
|
||||
assert( iCol>=0 && iCol<pParse->pConfig->nCol );
|
||||
|
||||
pNew = sqlite3_realloc64(p, sizeof(Fts5Colset) + sizeof(int)*nCol);
|
||||
pNew = sqlite3_realloc(p, sizeof(Fts5Colset) + sizeof(int)*nCol);
|
||||
if( pNew==0 ){
|
||||
pParse->rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -1973,10 +1933,10 @@ Fts5Colset *sqlite3Fts5ParseColset(
|
||||
static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){
|
||||
Fts5Colset *pRet;
|
||||
if( pOrig ){
|
||||
sqlite3_int64 nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int);
|
||||
int nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int);
|
||||
pRet = (Fts5Colset*)sqlite3Fts5MallocZero(pRc, nByte);
|
||||
if( pRet ){
|
||||
memcpy(pRet, pOrig, (size_t)nByte);
|
||||
memcpy(pRet, pOrig, nByte);
|
||||
}
|
||||
}else{
|
||||
pRet = 0;
|
||||
@@ -2127,7 +2087,7 @@ Fts5ExprNode *sqlite3Fts5ParseNode(
|
||||
|
||||
if( pParse->rc==SQLITE_OK ){
|
||||
int nChild = 0; /* Number of children of returned node */
|
||||
sqlite3_int64 nByte; /* Bytes of space to allocate for this node */
|
||||
int nByte; /* Bytes of space to allocate for this node */
|
||||
|
||||
assert( (eType!=FTS5_STRING && !pNear)
|
||||
|| (eType==FTS5_STRING && !pLeft && !pRight)
|
||||
@@ -2259,7 +2219,7 @@ Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
|
||||
}
|
||||
|
||||
static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
|
||||
sqlite3_int64 nByte = 0;
|
||||
int nByte = 0;
|
||||
Fts5ExprTerm *p;
|
||||
char *zQuoted;
|
||||
|
||||
@@ -2267,7 +2227,7 @@ static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
|
||||
for(p=pTerm; p; p=p->pSynonym){
|
||||
nByte += (int)strlen(pTerm->zTerm) * 2 + 3 + 2;
|
||||
}
|
||||
zQuoted = sqlite3_malloc64(nByte);
|
||||
zQuoted = sqlite3_malloc(nByte);
|
||||
|
||||
if( zQuoted ){
|
||||
int i = 0;
|
||||
@@ -2507,7 +2467,7 @@ static void fts5ExprFunction(
|
||||
}
|
||||
|
||||
nConfig = 3 + (nArg-iArg);
|
||||
azConfig = (const char**)sqlite3_malloc64(sizeof(char*) * nConfig);
|
||||
azConfig = (const char**)sqlite3_malloc(sizeof(char*) * nConfig);
|
||||
if( azConfig==0 ){
|
||||
sqlite3_result_error_nomem(pCtx);
|
||||
return;
|
||||
@@ -2516,12 +2476,10 @@ static void fts5ExprFunction(
|
||||
azConfig[1] = "main";
|
||||
azConfig[2] = "tbl";
|
||||
for(i=3; iArg<nArg; iArg++){
|
||||
const char *z = (const char*)sqlite3_value_text(apVal[iArg]);
|
||||
azConfig[i++] = (z ? z : "");
|
||||
azConfig[i++] = (const char*)sqlite3_value_text(apVal[iArg]);
|
||||
}
|
||||
|
||||
zExpr = (const char*)sqlite3_value_text(apVal[0]);
|
||||
if( zExpr==0 ) zExpr = "";
|
||||
|
||||
rc = sqlite3Fts5ConfigParse(pGlobal, db, nConfig, azConfig, &pConfig, &zErr);
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -2595,7 +2553,7 @@ static void fts5ExprIsAlnum(
|
||||
sqlite3Fts5UnicodeCatParse("N*", aArr);
|
||||
sqlite3Fts5UnicodeCatParse("Co", aArr);
|
||||
iCode = sqlite3_value_int(apVal[0]);
|
||||
sqlite3_result_int(pCtx, aArr[sqlite3Fts5UnicodeCategory((u32)iCode)]);
|
||||
sqlite3_result_int(pCtx, aArr[sqlite3Fts5UnicodeCategory(iCode)]);
|
||||
}
|
||||
|
||||
static void fts5ExprFold(
|
||||
@@ -2690,7 +2648,7 @@ struct Fts5PoslistPopulator {
|
||||
|
||||
Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int bLive){
|
||||
Fts5PoslistPopulator *pRet;
|
||||
pRet = sqlite3_malloc64(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase);
|
||||
pRet = sqlite3_malloc(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase);
|
||||
if( pRet ){
|
||||
int i;
|
||||
memset(pRet, 0, sizeof(Fts5PoslistPopulator)*pExpr->nPhrase);
|
||||
@@ -2889,3 +2847,4 @@ int sqlite3Fts5ExprPhraseCollist(
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
+31
-54
@@ -90,20 +90,20 @@ int sqlite3Fts5HashNew(Fts5Config *pConfig, Fts5Hash **ppNew, int *pnByte){
|
||||
if( pNew==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
sqlite3_int64 nByte;
|
||||
int nByte;
|
||||
memset(pNew, 0, sizeof(Fts5Hash));
|
||||
pNew->pnByte = pnByte;
|
||||
pNew->eDetail = pConfig->eDetail;
|
||||
|
||||
pNew->nSlot = 1024;
|
||||
nByte = sizeof(Fts5HashEntry*) * pNew->nSlot;
|
||||
pNew->aSlot = (Fts5HashEntry**)sqlite3_malloc64(nByte);
|
||||
pNew->aSlot = (Fts5HashEntry**)sqlite3_malloc(nByte);
|
||||
if( pNew->aSlot==0 ){
|
||||
sqlite3_free(pNew);
|
||||
*ppNew = 0;
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
memset(pNew->aSlot, 0, (size_t)nByte);
|
||||
memset(pNew->aSlot, 0, nByte);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
@@ -165,7 +165,7 @@ static int fts5HashResize(Fts5Hash *pHash){
|
||||
Fts5HashEntry **apNew;
|
||||
Fts5HashEntry **apOld = pHash->aSlot;
|
||||
|
||||
apNew = (Fts5HashEntry**)sqlite3_malloc64(nNew*sizeof(Fts5HashEntry*));
|
||||
apNew = (Fts5HashEntry**)sqlite3_malloc(nNew*sizeof(Fts5HashEntry*));
|
||||
if( !apNew ) return SQLITE_NOMEM;
|
||||
memset(apNew, 0, nNew*sizeof(Fts5HashEntry*));
|
||||
|
||||
@@ -187,25 +187,19 @@ static int fts5HashResize(Fts5Hash *pHash){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int fts5HashAddPoslistSize(
|
||||
Fts5Hash *pHash,
|
||||
Fts5HashEntry *p,
|
||||
Fts5HashEntry *p2
|
||||
){
|
||||
int nRet = 0;
|
||||
static void fts5HashAddPoslistSize(Fts5Hash *pHash, Fts5HashEntry *p){
|
||||
if( p->iSzPoslist ){
|
||||
u8 *pPtr = p2 ? (u8*)p2 : (u8*)p;
|
||||
int nData = p->nData;
|
||||
u8 *pPtr = (u8*)p;
|
||||
if( pHash->eDetail==FTS5_DETAIL_NONE ){
|
||||
assert( nData==p->iSzPoslist );
|
||||
assert( p->nData==p->iSzPoslist );
|
||||
if( p->bDel ){
|
||||
pPtr[nData++] = 0x00;
|
||||
pPtr[p->nData++] = 0x00;
|
||||
if( p->bContent ){
|
||||
pPtr[nData++] = 0x00;
|
||||
pPtr[p->nData++] = 0x00;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
int nSz = (nData - p->iSzPoslist - 1); /* Size in bytes */
|
||||
int nSz = (p->nData - p->iSzPoslist - 1); /* Size in bytes */
|
||||
int nPos = nSz*2 + p->bDel; /* Value of nPos field */
|
||||
|
||||
assert( p->bDel==0 || p->bDel==1 );
|
||||
@@ -215,19 +209,14 @@ static int fts5HashAddPoslistSize(
|
||||
int nByte = sqlite3Fts5GetVarintLen((u32)nPos);
|
||||
memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz);
|
||||
sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos);
|
||||
nData += (nByte-1);
|
||||
p->nData += (nByte-1);
|
||||
}
|
||||
}
|
||||
|
||||
nRet = nData - p->nData;
|
||||
if( p2==0 ){
|
||||
p->iSzPoslist = 0;
|
||||
p->bDel = 0;
|
||||
p->bContent = 0;
|
||||
p->nData = nData;
|
||||
}
|
||||
p->iSzPoslist = 0;
|
||||
p->bDel = 0;
|
||||
p->bContent = 0;
|
||||
}
|
||||
return nRet;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -270,7 +259,7 @@ int sqlite3Fts5HashWrite(
|
||||
if( p==0 ){
|
||||
/* Figure out how much space to allocate */
|
||||
char *zKey;
|
||||
sqlite3_int64 nByte = sizeof(Fts5HashEntry) + (nToken+1) + 1 + 64;
|
||||
int nByte = sizeof(Fts5HashEntry) + (nToken+1) + 1 + 64;
|
||||
if( nByte<128 ) nByte = 128;
|
||||
|
||||
/* Grow the Fts5Hash.aSlot[] array if necessary. */
|
||||
@@ -281,10 +270,10 @@ int sqlite3Fts5HashWrite(
|
||||
}
|
||||
|
||||
/* Allocate new Fts5HashEntry and add it to the hash table. */
|
||||
p = (Fts5HashEntry*)sqlite3_malloc64(nByte);
|
||||
p = (Fts5HashEntry*)sqlite3_malloc(nByte);
|
||||
if( !p ) return SQLITE_NOMEM;
|
||||
memset(p, 0, sizeof(Fts5HashEntry));
|
||||
p->nAlloc = (int)nByte;
|
||||
p->nAlloc = nByte;
|
||||
zKey = fts5EntryKey(p);
|
||||
zKey[0] = bByte;
|
||||
memcpy(&zKey[1], pToken, nToken);
|
||||
@@ -320,12 +309,12 @@ int sqlite3Fts5HashWrite(
|
||||
** + 5 bytes for the new position offset (32-bit max).
|
||||
*/
|
||||
if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){
|
||||
sqlite3_int64 nNew = p->nAlloc * 2;
|
||||
int nNew = p->nAlloc * 2;
|
||||
Fts5HashEntry *pNew;
|
||||
Fts5HashEntry **pp;
|
||||
pNew = (Fts5HashEntry*)sqlite3_realloc64(p, nNew);
|
||||
pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew);
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
pNew->nAlloc = (int)nNew;
|
||||
pNew->nAlloc = nNew;
|
||||
for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext);
|
||||
*pp = pNew;
|
||||
p = pNew;
|
||||
@@ -339,7 +328,7 @@ 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 ){
|
||||
fts5HashAddPoslistSize(pHash, p, 0);
|
||||
fts5HashAddPoslistSize(pHash, p);
|
||||
p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid);
|
||||
p->iRowid = iRowid;
|
||||
bNew = 1;
|
||||
@@ -449,16 +438,14 @@ static int fts5HashEntrySort(
|
||||
int i;
|
||||
|
||||
*ppSorted = 0;
|
||||
ap = sqlite3_malloc64(sizeof(Fts5HashEntry*) * nMergeSlot);
|
||||
ap = sqlite3_malloc(sizeof(Fts5HashEntry*) * nMergeSlot);
|
||||
if( !ap ) return SQLITE_NOMEM;
|
||||
memset(ap, 0, sizeof(Fts5HashEntry*) * nMergeSlot);
|
||||
|
||||
for(iSlot=0; iSlot<pHash->nSlot; iSlot++){
|
||||
Fts5HashEntry *pIter;
|
||||
for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){
|
||||
if( pTerm==0
|
||||
|| (pIter->nKey+1>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm))
|
||||
){
|
||||
if( pTerm==0 || 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm) ){
|
||||
Fts5HashEntry *pEntry = pIter;
|
||||
pEntry->pScanNext = 0;
|
||||
for(i=0; ap[i]; i++){
|
||||
@@ -486,9 +473,8 @@ static int fts5HashEntrySort(
|
||||
*/
|
||||
int sqlite3Fts5HashQuery(
|
||||
Fts5Hash *pHash, /* Hash table to query */
|
||||
int nPre,
|
||||
const char *pTerm, int nTerm, /* Query term */
|
||||
void **ppOut, /* OUT: Pointer to new object */
|
||||
const u8 **ppDoclist, /* OUT: Pointer to doclist for pTerm */
|
||||
int *pnDoclist /* OUT: Size of doclist in bytes */
|
||||
){
|
||||
unsigned int iHash = fts5HashKey(pHash->nSlot, (const u8*)pTerm, nTerm);
|
||||
@@ -497,25 +483,15 @@ int sqlite3Fts5HashQuery(
|
||||
|
||||
for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
|
||||
zKey = fts5EntryKey(p);
|
||||
assert( p->nKey+1==(int)strlen(zKey) );
|
||||
if( nTerm==p->nKey+1 && memcmp(zKey, pTerm, nTerm)==0 ) break;
|
||||
if( memcmp(zKey, pTerm, nTerm)==0 && zKey[nTerm]==0 ) break;
|
||||
}
|
||||
|
||||
if( p ){
|
||||
int nHashPre = sizeof(Fts5HashEntry) + nTerm + 1;
|
||||
int nList = p->nData - nHashPre;
|
||||
u8 *pRet = (u8*)(*ppOut = sqlite3_malloc64(nPre + nList + 10));
|
||||
if( pRet ){
|
||||
Fts5HashEntry *pFaux = (Fts5HashEntry*)&pRet[nPre-nHashPre];
|
||||
memcpy(&pRet[nPre], &((u8*)p)[nHashPre], nList);
|
||||
nList += fts5HashAddPoslistSize(pHash, p, pFaux);
|
||||
*pnDoclist = nList;
|
||||
}else{
|
||||
*pnDoclist = 0;
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
fts5HashAddPoslistSize(pHash, p);
|
||||
*ppDoclist = (const u8*)&zKey[nTerm+1];
|
||||
*pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1);
|
||||
}else{
|
||||
*ppOut = 0;
|
||||
*ppDoclist = 0;
|
||||
*pnDoclist = 0;
|
||||
}
|
||||
|
||||
@@ -548,7 +524,7 @@ void sqlite3Fts5HashScanEntry(
|
||||
if( (p = pHash->pScan) ){
|
||||
char *zKey = fts5EntryKey(p);
|
||||
int nTerm = (int)strlen(zKey);
|
||||
fts5HashAddPoslistSize(pHash, p, 0);
|
||||
fts5HashAddPoslistSize(pHash, p);
|
||||
*pzTerm = zKey;
|
||||
*ppDoclist = (const u8*)&zKey[nTerm+1];
|
||||
*pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1);
|
||||
@@ -558,3 +534,4 @@ void sqlite3Fts5HashScanEntry(
|
||||
*pnDoclist = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+136
-257
@@ -239,6 +239,11 @@
|
||||
#define FTS5_SEGMENT_ROWID(segid, pgno) fts5_dri(segid, 0, 0, pgno)
|
||||
#define FTS5_DLIDX_ROWID(segid, height, pgno) fts5_dri(segid, 1, height, pgno)
|
||||
|
||||
/*
|
||||
** Maximum segments permitted in a single index
|
||||
*/
|
||||
#define FTS5_MAX_SEGMENT 2000
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
int sqlite3Fts5Corrupt() { return SQLITE_CORRUPT_VTAB; }
|
||||
#endif
|
||||
@@ -507,6 +512,7 @@ struct Fts5Iter {
|
||||
Fts5IndexIter base; /* Base class containing output vars */
|
||||
|
||||
Fts5Index *pIndex; /* Index that owns this iterator */
|
||||
Fts5Structure *pStruct; /* Database structure for this iterator */
|
||||
Fts5Buffer poslist; /* Buffer containing current poslist */
|
||||
Fts5Colset *pColset; /* Restrict matches to these columns */
|
||||
|
||||
@@ -567,7 +573,7 @@ static u16 fts5GetU16(const u8 *aIn){
|
||||
** If an OOM error is encountered, return NULL and set the error code in
|
||||
** the Fts5Index handle passed as the first argument.
|
||||
*/
|
||||
static void *fts5IdxMalloc(Fts5Index *p, sqlite3_int64 nByte){
|
||||
static void *fts5IdxMalloc(Fts5Index *p, int nByte){
|
||||
return sqlite3Fts5MallocZero(&p->rc, nByte);
|
||||
}
|
||||
|
||||
@@ -601,7 +607,7 @@ static int fts5BufferCompareBlob(
|
||||
*/
|
||||
static int fts5BufferCompare(Fts5Buffer *pLeft, Fts5Buffer *pRight){
|
||||
int nCmp = MIN(pLeft->n, pRight->n);
|
||||
int res = fts5Memcmp(pLeft->p, pRight->p, nCmp);
|
||||
int res = memcmp(pLeft->p, pRight->p, nCmp);
|
||||
return (res==0 ? (pLeft->n - pRight->n) : res);
|
||||
}
|
||||
|
||||
@@ -614,7 +620,7 @@ static int fts5LeafFirstTermOff(Fts5Data *pLeaf){
|
||||
/*
|
||||
** Close the read-only blob handle, if it is open.
|
||||
*/
|
||||
void sqlite3Fts5IndexCloseReader(Fts5Index *p){
|
||||
static void fts5CloseReader(Fts5Index *p){
|
||||
if( p->pReader ){
|
||||
sqlite3_blob *pReader = p->pReader;
|
||||
p->pReader = 0;
|
||||
@@ -643,7 +649,7 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
|
||||
assert( p->pReader==0 );
|
||||
p->pReader = pBlob;
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3Fts5IndexCloseReader(p);
|
||||
fts5CloseReader(p);
|
||||
}
|
||||
if( rc==SQLITE_ABORT ) rc = SQLITE_OK;
|
||||
}
|
||||
@@ -667,8 +673,8 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
|
||||
if( rc==SQLITE_OK ){
|
||||
u8 *aOut = 0; /* Read blob data into this buffer */
|
||||
int nByte = sqlite3_blob_bytes(p->pReader);
|
||||
sqlite3_int64 nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING;
|
||||
pRet = (Fts5Data*)sqlite3_malloc64(nAlloc);
|
||||
int nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING;
|
||||
pRet = (Fts5Data*)sqlite3_malloc(nAlloc);
|
||||
if( pRet ){
|
||||
pRet->nn = nByte;
|
||||
aOut = pRet->p = (u8*)&pRet[1];
|
||||
@@ -684,8 +690,6 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
|
||||
pRet = 0;
|
||||
}else{
|
||||
/* TODO1: Fix this */
|
||||
pRet->p[nByte] = 0x00;
|
||||
pRet->p[nByte+1] = 0x00;
|
||||
pRet->szLeaf = fts5GetU16(&pRet->p[2]);
|
||||
}
|
||||
}
|
||||
@@ -708,7 +712,7 @@ static void fts5DataRelease(Fts5Data *pData){
|
||||
static Fts5Data *fts5LeafRead(Fts5Index *p, i64 iRowid){
|
||||
Fts5Data *pRet = fts5DataRead(p, iRowid);
|
||||
if( pRet ){
|
||||
if( pRet->nn<4 || pRet->szLeaf>pRet->nn ){
|
||||
if( pRet->szLeaf>pRet->nn ){
|
||||
p->rc = FTS5_CORRUPT;
|
||||
fts5DataRelease(pRet);
|
||||
pRet = 0;
|
||||
@@ -725,8 +729,7 @@ static int fts5IndexPrepareStmt(
|
||||
if( p->rc==SQLITE_OK ){
|
||||
if( zSql ){
|
||||
p->rc = sqlite3_prepare_v3(p->pConfig->db, zSql, -1,
|
||||
SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB,
|
||||
ppStmt, 0);
|
||||
SQLITE_PREPARE_PERSISTENT, ppStmt, 0);
|
||||
}else{
|
||||
p->rc = SQLITE_NOMEM;
|
||||
}
|
||||
@@ -767,12 +770,23 @@ static void fts5DataDelete(Fts5Index *p, i64 iFirst, i64 iLast){
|
||||
if( p->rc!=SQLITE_OK ) return;
|
||||
|
||||
if( p->pDeleter==0 ){
|
||||
int rc;
|
||||
Fts5Config *pConfig = p->pConfig;
|
||||
char *zSql = sqlite3_mprintf(
|
||||
"DELETE FROM '%q'.'%q_data' WHERE id>=? AND id<=?",
|
||||
pConfig->zDb, pConfig->zName
|
||||
);
|
||||
if( fts5IndexPrepareStmt(p, &p->pDeleter, zSql) ) return;
|
||||
if( zSql==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
rc = sqlite3_prepare_v3(pConfig->db, zSql, -1,
|
||||
SQLITE_PREPARE_PERSISTENT, &p->pDeleter, 0);
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
p->rc = rc;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_bind_int64(p->pDeleter, 1, iFirst);
|
||||
@@ -844,7 +858,7 @@ static int fts5StructureDecode(
|
||||
int iLvl;
|
||||
int nLevel = 0;
|
||||
int nSegment = 0;
|
||||
sqlite3_int64 nByte; /* Bytes of space to allocate at pRet */
|
||||
int nByte; /* Bytes of space to allocate at pRet */
|
||||
Fts5Structure *pRet = 0; /* Structure object to return */
|
||||
|
||||
/* Grab the cookie value */
|
||||
@@ -855,11 +869,6 @@ static int fts5StructureDecode(
|
||||
** structure record. */
|
||||
i += fts5GetVarint32(&pData[i], nLevel);
|
||||
i += fts5GetVarint32(&pData[i], nSegment);
|
||||
if( nLevel>FTS5_MAX_SEGMENT || nLevel<0
|
||||
|| nSegment>FTS5_MAX_SEGMENT || nSegment<0
|
||||
){
|
||||
return FTS5_CORRUPT;
|
||||
}
|
||||
nByte = (
|
||||
sizeof(Fts5Structure) + /* Main structure */
|
||||
sizeof(Fts5StructureLevel) * (nLevel-1) /* aLevel[] array */
|
||||
@@ -882,35 +891,25 @@ static int fts5StructureDecode(
|
||||
}else{
|
||||
i += fts5GetVarint32(&pData[i], pLvl->nMerge);
|
||||
i += fts5GetVarint32(&pData[i], nTotal);
|
||||
if( nTotal<pLvl->nMerge ) rc = FTS5_CORRUPT;
|
||||
assert( nTotal>=pLvl->nMerge );
|
||||
pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc,
|
||||
nTotal * sizeof(Fts5StructureSegment)
|
||||
);
|
||||
nSegment -= nTotal;
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
pLvl->nSeg = nTotal;
|
||||
for(iSeg=0; iSeg<nTotal; iSeg++){
|
||||
Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg];
|
||||
if( i>=nData ){
|
||||
rc = FTS5_CORRUPT;
|
||||
break;
|
||||
}
|
||||
i += fts5GetVarint32(&pData[i], pSeg->iSegid);
|
||||
i += fts5GetVarint32(&pData[i], pSeg->pgnoFirst);
|
||||
i += fts5GetVarint32(&pData[i], pSeg->pgnoLast);
|
||||
if( pSeg->pgnoLast<pSeg->pgnoFirst ){
|
||||
rc = FTS5_CORRUPT;
|
||||
break;
|
||||
}
|
||||
i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].iSegid);
|
||||
i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoFirst);
|
||||
i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoLast);
|
||||
}
|
||||
if( iLvl>0 && pLvl[-1].nMerge && nTotal==0 ) rc = FTS5_CORRUPT;
|
||||
if( iLvl==nLevel-1 && pLvl->nMerge ) rc = FTS5_CORRUPT;
|
||||
}
|
||||
}
|
||||
if( nSegment!=0 && rc==SQLITE_OK ) rc = FTS5_CORRUPT;
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
fts5StructureRelease(pRet);
|
||||
pRet = 0;
|
||||
@@ -928,12 +927,12 @@ static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){
|
||||
if( *pRc==SQLITE_OK ){
|
||||
Fts5Structure *pStruct = *ppStruct;
|
||||
int nLevel = pStruct->nLevel;
|
||||
sqlite3_int64 nByte = (
|
||||
int nByte = (
|
||||
sizeof(Fts5Structure) + /* Main structure */
|
||||
sizeof(Fts5StructureLevel) * (nLevel+1) /* aLevel[] array */
|
||||
);
|
||||
|
||||
pStruct = sqlite3_realloc64(pStruct, nByte);
|
||||
pStruct = sqlite3_realloc(pStruct, nByte);
|
||||
if( pStruct ){
|
||||
memset(&pStruct->aLevel[nLevel], 0, sizeof(Fts5StructureLevel));
|
||||
pStruct->nLevel++;
|
||||
@@ -958,10 +957,10 @@ static void fts5StructureExtendLevel(
|
||||
if( *pRc==SQLITE_OK ){
|
||||
Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl];
|
||||
Fts5StructureSegment *aNew;
|
||||
sqlite3_int64 nByte;
|
||||
int nByte;
|
||||
|
||||
nByte = (pLvl->nSeg + nExtra) * sizeof(Fts5StructureSegment);
|
||||
aNew = sqlite3_realloc64(pLvl->aSeg, nByte);
|
||||
aNew = sqlite3_realloc(pLvl->aSeg, nByte);
|
||||
if( aNew ){
|
||||
if( bInsert==0 ){
|
||||
memset(&aNew[pLvl->nSeg], 0, sizeof(Fts5StructureSegment) * nExtra);
|
||||
@@ -988,7 +987,7 @@ static Fts5Structure *fts5StructureReadUncached(Fts5Index *p){
|
||||
/* TODO: Do we need this if the leaf-index is appended? Probably... */
|
||||
memset(&pData->p[pData->nn], 0, FTS5_DATA_PADDING);
|
||||
p->rc = fts5StructureDecode(pData->p, pData->nn, &iCookie, &pRet);
|
||||
if( p->rc==SQLITE_OK && (pConfig->pgsz==0 || pConfig->iCookie!=iCookie) ){
|
||||
if( p->rc==SQLITE_OK && pConfig->iCookie!=iCookie ){
|
||||
p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie);
|
||||
}
|
||||
fts5DataRelease(pData);
|
||||
@@ -1475,10 +1474,10 @@ static Fts5DlidxIter *fts5DlidxIterInit(
|
||||
int bDone = 0;
|
||||
|
||||
for(i=0; p->rc==SQLITE_OK && bDone==0; i++){
|
||||
sqlite3_int64 nByte = sizeof(Fts5DlidxIter) + i * sizeof(Fts5DlidxLvl);
|
||||
int nByte = sizeof(Fts5DlidxIter) + i * sizeof(Fts5DlidxLvl);
|
||||
Fts5DlidxIter *pNew;
|
||||
|
||||
pNew = (Fts5DlidxIter*)sqlite3_realloc64(pIter, nByte);
|
||||
pNew = (Fts5DlidxIter*)sqlite3_realloc(pIter, nByte);
|
||||
if( pNew==0 ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -1648,13 +1647,12 @@ static void fts5SegIterLoadTerm(Fts5Index *p, Fts5SegIter *pIter, int nKeep){
|
||||
int nNew; /* Bytes of new data */
|
||||
|
||||
iOff += fts5GetVarint32(&a[iOff], nNew);
|
||||
if( iOff+nNew>pIter->pLeaf->szLeaf || nKeep>pIter->term.n || nNew==0 ){
|
||||
if( iOff+nNew>pIter->pLeaf->nn ){
|
||||
p->rc = FTS5_CORRUPT;
|
||||
return;
|
||||
}
|
||||
pIter->term.n = nKeep;
|
||||
fts5BufferAppendBlob(&p->rc, &pIter->term, nNew, &a[iOff]);
|
||||
assert( pIter->term.n<=pIter->term.nSpace );
|
||||
iOff += nNew;
|
||||
pIter->iTermLeafOffset = iOff;
|
||||
pIter->iTermLeafPgno = pIter->iLeafPgno;
|
||||
@@ -1719,7 +1717,7 @@ static void fts5SegIterInit(
|
||||
if( p->rc==SQLITE_OK ){
|
||||
pIter->iLeafOffset = 4;
|
||||
assert_nc( pIter->pLeaf->nn>4 );
|
||||
assert_nc( fts5LeafFirstTermOff(pIter->pLeaf)==4 );
|
||||
assert( fts5LeafFirstTermOff(pIter->pLeaf)==4 );
|
||||
pIter->iPgidxOff = pIter->pLeaf->szLeaf+1;
|
||||
fts5SegIterLoadTerm(p, pIter, 0);
|
||||
fts5SegIterLoadNPos(p, pIter);
|
||||
@@ -1775,7 +1773,7 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
|
||||
/* If necessary, grow the pIter->aRowidOffset[] array. */
|
||||
if( iRowidOffset>=pIter->nRowidOffset ){
|
||||
int nNew = pIter->nRowidOffset + 8;
|
||||
int *aNew = (int*)sqlite3_realloc64(pIter->aRowidOffset,nNew*sizeof(int));
|
||||
int *aNew = (int*)sqlite3_realloc(pIter->aRowidOffset, nNew*sizeof(int));
|
||||
if( aNew==0 ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
break;
|
||||
@@ -2229,10 +2227,10 @@ static void fts5LeafSeek(
|
||||
int szLeaf = pIter->pLeaf->szLeaf;
|
||||
int n = pIter->pLeaf->nn;
|
||||
|
||||
u32 nMatch = 0;
|
||||
u32 nKeep = 0;
|
||||
u32 nNew = 0;
|
||||
u32 iTermOff;
|
||||
int nMatch = 0;
|
||||
int nKeep = 0;
|
||||
int nNew = 0;
|
||||
int iTermOff;
|
||||
int iPgidx; /* Current offset in pgidx */
|
||||
int bEndOfPage = 0;
|
||||
|
||||
@@ -2256,15 +2254,15 @@ static void fts5LeafSeek(
|
||||
|
||||
assert( nKeep>=nMatch );
|
||||
if( nKeep==nMatch ){
|
||||
u32 nCmp;
|
||||
u32 i;
|
||||
nCmp = (u32)MIN(nNew, nTerm-nMatch);
|
||||
int nCmp;
|
||||
int i;
|
||||
nCmp = MIN(nNew, nTerm-nMatch);
|
||||
for(i=0; i<nCmp; i++){
|
||||
if( a[iOff+i]!=pTerm[nMatch+i] ) break;
|
||||
}
|
||||
nMatch += i;
|
||||
|
||||
if( (u32)nTerm==nMatch ){
|
||||
if( nTerm==nMatch ){
|
||||
if( i==nNew ){
|
||||
goto search_success;
|
||||
}else{
|
||||
@@ -2308,7 +2306,6 @@ static void fts5LeafSeek(
|
||||
iPgidx += fts5GetVarint32(&pIter->pLeaf->p[iPgidx], iOff);
|
||||
if( iOff<4 || iOff>=pIter->pLeaf->szLeaf ){
|
||||
p->rc = FTS5_CORRUPT;
|
||||
return;
|
||||
}else{
|
||||
nKeep = 0;
|
||||
iTermOff = iOff;
|
||||
@@ -2321,11 +2318,8 @@ static void fts5LeafSeek(
|
||||
}
|
||||
|
||||
search_success:
|
||||
|
||||
pIter->iLeafOffset = iOff + nNew;
|
||||
if( pIter->iLeafOffset>n || nNew<1 ){
|
||||
p->rc = FTS5_CORRUPT;
|
||||
return;
|
||||
}
|
||||
pIter->iTermLeafOffset = pIter->iLeafOffset;
|
||||
pIter->iTermLeafPgno = pIter->iLeafPgno;
|
||||
|
||||
@@ -2432,7 +2426,7 @@ static void fts5SegIterSeekInit(
|
||||
** 4) the FTS5INDEX_QUERY_SCAN flag was set and the iterator points
|
||||
** to an entry with a term greater than or equal to (pTerm/nTerm).
|
||||
*/
|
||||
assert_nc( p->rc!=SQLITE_OK /* 1 */
|
||||
assert( p->rc!=SQLITE_OK /* 1 */
|
||||
|| pIter->pLeaf==0 /* 2 */
|
||||
|| fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)==0 /* 3 */
|
||||
|| (bGe && fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)>0) /* 4 */
|
||||
@@ -2453,40 +2447,31 @@ static void fts5SegIterHashInit(
|
||||
int flags, /* Mask of FTS5INDEX_XXX flags */
|
||||
Fts5SegIter *pIter /* Object to populate */
|
||||
){
|
||||
const u8 *pList = 0;
|
||||
int nList = 0;
|
||||
const u8 *z = 0;
|
||||
int n = 0;
|
||||
Fts5Data *pLeaf = 0;
|
||||
|
||||
assert( p->pHash );
|
||||
assert( p->rc==SQLITE_OK );
|
||||
|
||||
if( pTerm==0 || (flags & FTS5INDEX_QUERY_SCAN) ){
|
||||
const u8 *pList = 0;
|
||||
|
||||
p->rc = sqlite3Fts5HashScanInit(p->pHash, (const char*)pTerm, nTerm);
|
||||
sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &pList, &nList);
|
||||
n = (z ? (int)strlen((const char*)z) : 0);
|
||||
if( pList ){
|
||||
pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data));
|
||||
if( pLeaf ){
|
||||
pLeaf->p = (u8*)pList;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
p->rc = sqlite3Fts5HashQuery(p->pHash, sizeof(Fts5Data),
|
||||
(const char*)pTerm, nTerm, (void**)&pLeaf, &nList
|
||||
);
|
||||
if( pLeaf ){
|
||||
pLeaf->p = (u8*)&pLeaf[1];
|
||||
}
|
||||
pIter->flags |= FTS5_SEGITER_ONETERM;
|
||||
sqlite3Fts5HashQuery(p->pHash, (const char*)pTerm, nTerm, &pList, &nList);
|
||||
z = pTerm;
|
||||
n = nTerm;
|
||||
pIter->flags |= FTS5_SEGITER_ONETERM;
|
||||
}
|
||||
|
||||
if( pLeaf ){
|
||||
if( pList ){
|
||||
Fts5Data *pLeaf;
|
||||
sqlite3Fts5BufferSet(&p->rc, &pIter->term, n, z);
|
||||
pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data));
|
||||
if( pLeaf==0 ) return;
|
||||
pLeaf->p = (u8*)pList;
|
||||
pLeaf->nn = pLeaf->szLeaf = nList;
|
||||
pIter->pLeaf = pLeaf;
|
||||
pIter->iLeafOffset = fts5GetVarint(pLeaf->p, (u64*)&pIter->iRowid);
|
||||
@@ -2539,7 +2524,7 @@ static void fts5AssertComparisonResult(
|
||||
assert( pRes->iFirst==i1 );
|
||||
}else{
|
||||
int nMin = MIN(p1->term.n, p2->term.n);
|
||||
int res = fts5Memcmp(p1->term.p, p2->term.p, nMin);
|
||||
int res = memcmp(p1->term.p, p2->term.p, nMin);
|
||||
if( res==0 ) res = p1->term.n - p2->term.n;
|
||||
|
||||
if( res==0 ){
|
||||
@@ -2639,8 +2624,8 @@ static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){
|
||||
}else{
|
||||
int res = fts5BufferCompare(&p1->term, &p2->term);
|
||||
if( res==0 ){
|
||||
assert_nc( i2>i1 );
|
||||
assert_nc( i2!=0 );
|
||||
assert( i2>i1 );
|
||||
assert( i2!=0 );
|
||||
pRes->bTermEq = 1;
|
||||
if( p1->iRowid==p2->iRowid ){
|
||||
p1->bDel = p2->bDel;
|
||||
@@ -2762,6 +2747,7 @@ static void fts5MultiIterFree(Fts5Iter *pIter){
|
||||
for(i=0; i<pIter->nSeg; i++){
|
||||
fts5SegIterClear(&pIter->aSeg[i]);
|
||||
}
|
||||
fts5StructureRelease(pIter->pStruct);
|
||||
fts5BufferFree(&pIter->poslist);
|
||||
sqlite3_free(pIter);
|
||||
}
|
||||
@@ -3109,8 +3095,7 @@ static void fts5SegiterPoslist(
|
||||
Fts5Colset *pColset,
|
||||
Fts5Buffer *pBuf
|
||||
){
|
||||
if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos+FTS5_DATA_ZERO_PADDING) ){
|
||||
memset(&pBuf->p[pBuf->n+pSeg->nPos], 0, FTS5_DATA_ZERO_PADDING);
|
||||
if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos) ){
|
||||
if( pColset==0 ){
|
||||
fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback);
|
||||
}else{
|
||||
@@ -3408,7 +3393,9 @@ static void fts5MultiIterNew(
|
||||
if( pNew==0 ) return;
|
||||
pNew->bRev = (0!=(flags & FTS5INDEX_QUERY_DESC));
|
||||
pNew->bSkipEmpty = (0!=(flags & FTS5INDEX_QUERY_SKIPEMPTY));
|
||||
pNew->pStruct = pStruct;
|
||||
pNew->pColset = pColset;
|
||||
fts5StructureRef(pStruct);
|
||||
if( (flags & FTS5INDEX_QUERY_NOOUTPUT)==0 ){
|
||||
fts5IterSetOutputCb(&p->rc, pNew);
|
||||
}
|
||||
@@ -3586,24 +3573,24 @@ static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){
|
||||
for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
|
||||
for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
|
||||
int iId = pStruct->aLevel[iLvl].aSeg[iSeg].iSegid;
|
||||
if( iId<=FTS5_MAX_SEGMENT && iId>0 ){
|
||||
aUsed[(iId-1) / 32] |= (u32)1 << ((iId-1) % 32);
|
||||
if( iId<=FTS5_MAX_SEGMENT ){
|
||||
aUsed[(iId-1) / 32] |= 1 << ((iId-1) % 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0; aUsed[i]==0xFFFFFFFF; i++);
|
||||
mask = aUsed[i];
|
||||
for(iSegid=0; mask & ((u32)1 << iSegid); iSegid++);
|
||||
for(iSegid=0; mask & (1 << iSegid); iSegid++);
|
||||
iSegid += 1 + i*32;
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
|
||||
for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
|
||||
assert_nc( iSegid!=pStruct->aLevel[iLvl].aSeg[iSeg].iSegid );
|
||||
assert( iSegid!=pStruct->aLevel[iLvl].aSeg[iSeg].iSegid );
|
||||
}
|
||||
}
|
||||
assert_nc( iSegid>0 && iSegid<=FTS5_MAX_SEGMENT );
|
||||
assert( iSegid>0 && iSegid<=FTS5_MAX_SEGMENT );
|
||||
|
||||
{
|
||||
sqlite3_stmt *pIdxSelect = fts5IdxSelectStmt(p);
|
||||
@@ -3611,7 +3598,7 @@ static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){
|
||||
u8 aBlob[2] = {0xff, 0xff};
|
||||
sqlite3_bind_int(pIdxSelect, 1, iSegid);
|
||||
sqlite3_bind_blob(pIdxSelect, 2, aBlob, 2, SQLITE_STATIC);
|
||||
assert_nc( sqlite3_step(pIdxSelect)!=SQLITE_ROW );
|
||||
assert( sqlite3_step(pIdxSelect)!=SQLITE_ROW );
|
||||
p->rc = sqlite3_reset(pIdxSelect);
|
||||
sqlite3_bind_null(pIdxSelect, 2);
|
||||
}
|
||||
@@ -3681,13 +3668,13 @@ static int fts5WriteDlidxGrow(
|
||||
int nLvl
|
||||
){
|
||||
if( p->rc==SQLITE_OK && nLvl>=pWriter->nDlidx ){
|
||||
Fts5DlidxWriter *aDlidx = (Fts5DlidxWriter*)sqlite3_realloc64(
|
||||
Fts5DlidxWriter *aDlidx = (Fts5DlidxWriter*)sqlite3_realloc(
|
||||
pWriter->aDlidx, sizeof(Fts5DlidxWriter) * nLvl
|
||||
);
|
||||
if( aDlidx==0 ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
size_t nByte = sizeof(Fts5DlidxWriter) * (nLvl - pWriter->nDlidx);
|
||||
int nByte = sizeof(Fts5DlidxWriter) * (nLvl - pWriter->nDlidx);
|
||||
memset(&aDlidx[pWriter->nDlidx], 0, nByte);
|
||||
pWriter->aDlidx = aDlidx;
|
||||
pWriter->nDlidx = nLvl;
|
||||
@@ -3760,10 +3747,8 @@ static void fts5WriteBtreeTerm(
|
||||
int nTerm, const u8 *pTerm /* First term on new page */
|
||||
){
|
||||
fts5WriteFlushBtree(p, pWriter);
|
||||
if( p->rc==SQLITE_OK ){
|
||||
fts5BufferSet(&p->rc, &pWriter->btterm, nTerm, pTerm);
|
||||
pWriter->iBtPage = pWriter->writer.pgno;
|
||||
}
|
||||
fts5BufferSet(&p->rc, &pWriter->btterm, nTerm, pTerm);
|
||||
pWriter->iBtPage = pWriter->writer.pgno;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3914,7 +3899,6 @@ static void fts5WriteAppendTerm(
|
||||
int nPrefix; /* Bytes of prefix compression for term */
|
||||
Fts5PageWriter *pPage = &pWriter->writer;
|
||||
Fts5Buffer *pPgidx = &pWriter->writer.pgidx;
|
||||
int nMin = MIN(pPage->term.n, nTerm);
|
||||
|
||||
assert( p->rc==SQLITE_OK );
|
||||
assert( pPage->buf.n>=4 );
|
||||
@@ -3924,7 +3908,6 @@ static void fts5WriteAppendTerm(
|
||||
if( (pPage->buf.n + pPgidx->n + nTerm + 2)>=p->pConfig->pgsz ){
|
||||
if( pPage->buf.n>4 ){
|
||||
fts5WriteFlushLeaf(p, pWriter);
|
||||
if( p->rc!=SQLITE_OK ) return;
|
||||
}
|
||||
fts5BufferGrow(&p->rc, &pPage->buf, nTerm+FTS5_DATA_PADDING);
|
||||
}
|
||||
@@ -3957,14 +3940,13 @@ static void fts5WriteAppendTerm(
|
||||
** inefficient, but still correct. */
|
||||
int n = nTerm;
|
||||
if( pPage->term.n ){
|
||||
n = 1 + fts5PrefixCompress(nMin, pPage->term.p, pTerm);
|
||||
n = 1 + fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm);
|
||||
}
|
||||
fts5WriteBtreeTerm(p, pWriter, n, pTerm);
|
||||
if( p->rc!=SQLITE_OK ) return;
|
||||
pPage = &pWriter->writer;
|
||||
}
|
||||
}else{
|
||||
nPrefix = fts5PrefixCompress(nMin, pPage->term.p, pTerm);
|
||||
nPrefix = fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm);
|
||||
fts5BufferAppendVarint(&p->rc, &pPage->buf, nPrefix);
|
||||
}
|
||||
|
||||
@@ -4011,7 +3993,7 @@ static void fts5WriteAppendRowid(
|
||||
if( pWriter->bFirstRowidInDoclist || pWriter->bFirstRowidInPage ){
|
||||
fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid);
|
||||
}else{
|
||||
assert_nc( p->rc || iRowid>pWriter->iPrevRowid );
|
||||
assert( p->rc || iRowid>pWriter->iPrevRowid );
|
||||
fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid - pWriter->iPrevRowid);
|
||||
}
|
||||
pWriter->iPrevRowid = iRowid;
|
||||
@@ -4133,7 +4115,7 @@ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){
|
||||
int i;
|
||||
Fts5Buffer buf;
|
||||
memset(&buf, 0, sizeof(Fts5Buffer));
|
||||
for(i=0; i<pIter->nSeg && p->rc==SQLITE_OK; i++){
|
||||
for(i=0; i<pIter->nSeg; i++){
|
||||
Fts5SegIter *pSeg = &pIter->aSeg[i];
|
||||
if( pSeg->pSeg==0 ){
|
||||
/* no-op */
|
||||
@@ -4151,44 +4133,35 @@ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){
|
||||
u8 aHdr[4] = {0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
iLeafRowid = FTS5_SEGMENT_ROWID(iId, pSeg->iTermLeafPgno);
|
||||
pData = fts5LeafRead(p, iLeafRowid);
|
||||
pData = fts5DataRead(p, iLeafRowid);
|
||||
if( pData ){
|
||||
if( iOff>pData->szLeaf ){
|
||||
/* This can occur if the pages that the segments occupy overlap - if
|
||||
** a single page has been assigned to more than one segment. In
|
||||
** this case a prior iteration of this loop may have corrupted the
|
||||
** segment currently being trimmed. */
|
||||
p->rc = FTS5_CORRUPT;
|
||||
}else{
|
||||
fts5BufferZero(&buf);
|
||||
fts5BufferGrow(&p->rc, &buf, pData->nn);
|
||||
fts5BufferAppendBlob(&p->rc, &buf, sizeof(aHdr), aHdr);
|
||||
fts5BufferAppendVarint(&p->rc, &buf, pSeg->term.n);
|
||||
fts5BufferAppendBlob(&p->rc, &buf, pSeg->term.n, pSeg->term.p);
|
||||
fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff,&pData->p[iOff]);
|
||||
if( p->rc==SQLITE_OK ){
|
||||
/* Set the szLeaf field */
|
||||
fts5PutU16(&buf.p[2], (u16)buf.n);
|
||||
}
|
||||
|
||||
/* Set up the new page-index array */
|
||||
fts5BufferAppendVarint(&p->rc, &buf, 4);
|
||||
if( pSeg->iLeafPgno==pSeg->iTermLeafPgno
|
||||
&& pSeg->iEndofDoclist<pData->szLeaf
|
||||
&& pSeg->iPgidxOff<=pData->nn
|
||||
){
|
||||
int nDiff = pData->szLeaf - pSeg->iEndofDoclist;
|
||||
fts5BufferAppendVarint(&p->rc, &buf, buf.n - 1 - nDiff - 4);
|
||||
fts5BufferAppendBlob(&p->rc, &buf,
|
||||
pData->nn - pSeg->iPgidxOff, &pData->p[pSeg->iPgidxOff]
|
||||
);
|
||||
}
|
||||
|
||||
pSeg->pSeg->pgnoFirst = pSeg->iTermLeafPgno;
|
||||
fts5DataDelete(p, FTS5_SEGMENT_ROWID(iId, 1), iLeafRowid);
|
||||
fts5DataWrite(p, iLeafRowid, buf.p, buf.n);
|
||||
fts5BufferZero(&buf);
|
||||
fts5BufferGrow(&p->rc, &buf, pData->nn);
|
||||
fts5BufferAppendBlob(&p->rc, &buf, sizeof(aHdr), aHdr);
|
||||
fts5BufferAppendVarint(&p->rc, &buf, pSeg->term.n);
|
||||
fts5BufferAppendBlob(&p->rc, &buf, pSeg->term.n, pSeg->term.p);
|
||||
fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff, &pData->p[iOff]);
|
||||
if( p->rc==SQLITE_OK ){
|
||||
/* Set the szLeaf field */
|
||||
fts5PutU16(&buf.p[2], (u16)buf.n);
|
||||
}
|
||||
|
||||
/* Set up the new page-index array */
|
||||
fts5BufferAppendVarint(&p->rc, &buf, 4);
|
||||
if( pSeg->iLeafPgno==pSeg->iTermLeafPgno
|
||||
&& pSeg->iEndofDoclist<pData->szLeaf
|
||||
){
|
||||
int nDiff = pData->szLeaf - pSeg->iEndofDoclist;
|
||||
fts5BufferAppendVarint(&p->rc, &buf, buf.n - 1 - nDiff - 4);
|
||||
fts5BufferAppendBlob(&p->rc, &buf,
|
||||
pData->nn - pSeg->iPgidxOff, &pData->p[pSeg->iPgidxOff]
|
||||
);
|
||||
}
|
||||
|
||||
fts5DataRelease(pData);
|
||||
pSeg->pSeg->pgnoFirst = pSeg->iTermLeafPgno;
|
||||
fts5DataDelete(p, FTS5_SEGMENT_ROWID(iId, 1), iLeafRowid);
|
||||
fts5DataWrite(p, iLeafRowid, buf.p, buf.n);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4280,7 +4253,7 @@ static void fts5IndexMergeLevel(
|
||||
const u8 *pTerm;
|
||||
|
||||
pTerm = fts5MultiIterTerm(pIter, &nTerm);
|
||||
if( nTerm!=term.n || fts5Memcmp(pTerm, term.p, nTerm) ){
|
||||
if( nTerm!=term.n || memcmp(pTerm, term.p, nTerm) ){
|
||||
if( pnRem && writer.nLeafWritten>nRem ){
|
||||
break;
|
||||
}
|
||||
@@ -4535,7 +4508,6 @@ static void fts5FlushOneHash(Fts5Index *p){
|
||||
/* Write the term for this entry to disk. */
|
||||
sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist);
|
||||
fts5WriteAppendTerm(p, &writer, (int)strlen(zTerm), (const u8*)zTerm);
|
||||
if( p->rc!=SQLITE_OK ) break;
|
||||
|
||||
assert( writer.bFirstRowidInPage==0 );
|
||||
if( pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){
|
||||
@@ -4558,7 +4530,6 @@ static void fts5FlushOneHash(Fts5Index *p){
|
||||
pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid);
|
||||
writer.bFirstRowidInPage = 0;
|
||||
fts5WriteDlidxAppend(p, &writer, iRowid);
|
||||
if( p->rc!=SQLITE_OK ) break;
|
||||
}else{
|
||||
pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iDelta);
|
||||
}
|
||||
@@ -4616,7 +4587,7 @@ static void fts5FlushOneHash(Fts5Index *p){
|
||||
/* TODO2: Doclist terminator written here. */
|
||||
/* pBuf->p[pBuf->n++] = '\0'; */
|
||||
assert( pBuf->n<=pBuf->nSpace );
|
||||
if( p->rc==SQLITE_OK ) sqlite3Fts5HashScanNext(pHash);
|
||||
sqlite3Fts5HashScanNext(pHash);
|
||||
}
|
||||
sqlite3Fts5HashClear(pHash);
|
||||
fts5WriteFinish(p, &writer, &pgnoLast);
|
||||
@@ -4660,7 +4631,7 @@ static Fts5Structure *fts5IndexOptimizeStruct(
|
||||
Fts5Structure *pStruct
|
||||
){
|
||||
Fts5Structure *pNew = 0;
|
||||
sqlite3_int64 nByte = sizeof(Fts5Structure);
|
||||
int nByte = sizeof(Fts5Structure);
|
||||
int nSeg = pStruct->nSegment;
|
||||
int i;
|
||||
|
||||
@@ -4790,13 +4761,11 @@ static void fts5AppendPoslist(
|
||||
Fts5Buffer *pBuf
|
||||
){
|
||||
int nData = pMulti->base.nData;
|
||||
int nByte = nData + 9 + 9 + FTS5_DATA_ZERO_PADDING;
|
||||
assert( nData>0 );
|
||||
if( p->rc==SQLITE_OK && 0==fts5BufferGrow(&p->rc, pBuf, nByte) ){
|
||||
if( p->rc==SQLITE_OK && 0==fts5BufferGrow(&p->rc, pBuf, nData+9+9) ){
|
||||
fts5BufferSafeAppendVarint(pBuf, iDelta);
|
||||
fts5BufferSafeAppendVarint(pBuf, nData*2);
|
||||
fts5BufferSafeAppendBlob(pBuf, pMulti->base.pData, nData);
|
||||
memset(&pBuf->p[pBuf->n], 0, FTS5_DATA_ZERO_PADDING);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4949,14 +4918,8 @@ static void fts5MergePrefixLists(
|
||||
** 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;
|
||||
** was. */
|
||||
if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n + 9) ) return;
|
||||
fts5DoclistIterInit(p1, &i1);
|
||||
fts5DoclistIterInit(p2, &i2);
|
||||
|
||||
@@ -4967,7 +4930,6 @@ static void fts5MergePrefixLists(
|
||||
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) );
|
||||
}
|
||||
else if( i2.iRowid!=i1.iRowid ){
|
||||
/* Copy entry from i2 */
|
||||
@@ -4975,7 +4937,6 @@ static void fts5MergePrefixLists(
|
||||
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. */
|
||||
@@ -4985,24 +4946,19 @@ static void fts5MergePrefixLists(
|
||||
int iOff2 = 0;
|
||||
u8 *a1 = &i1.aPoslist[i1.nSize];
|
||||
u8 *a2 = &i2.aPoslist[i2.nSize];
|
||||
int nCopy;
|
||||
u8 *aCopy;
|
||||
|
||||
i64 iPrev = 0;
|
||||
Fts5PoslistWriter writer;
|
||||
memset(&writer, 0, sizeof(writer));
|
||||
|
||||
/* 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);
|
||||
sqlite3Fts5BufferSize(&p->rc, &tmp, i1.nPoslist + i2.nPoslist);
|
||||
if( p->rc ) break;
|
||||
|
||||
sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
|
||||
sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
|
||||
assert_nc( iPos1>=0 && iPos2>=0 );
|
||||
assert( iPos1>=0 && iPos2>=0 );
|
||||
|
||||
if( iPos1<iPos2 ){
|
||||
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
|
||||
@@ -5011,6 +4967,7 @@ static void fts5MergePrefixLists(
|
||||
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
|
||||
sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
|
||||
}
|
||||
|
||||
if( iPos1>=0 && iPos2>=0 ){
|
||||
while( 1 ){
|
||||
if( iPos1<iPos2 ){
|
||||
@@ -5020,7 +4977,7 @@ static void fts5MergePrefixLists(
|
||||
sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
|
||||
if( iPos1<0 ) break;
|
||||
}else{
|
||||
assert_nc( iPos2!=iPrev );
|
||||
assert( iPos2!=iPrev );
|
||||
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
|
||||
sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
|
||||
if( iPos2<0 ) break;
|
||||
@@ -5032,32 +4989,19 @@ static void fts5MergePrefixLists(
|
||||
if( iPos1!=iPrev ){
|
||||
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
|
||||
}
|
||||
aCopy = &a1[iOff1];
|
||||
nCopy = i1.nPoslist - iOff1;
|
||||
fts5BufferSafeAppendBlob(&tmp, &a1[iOff1], i1.nPoslist-iOff1);
|
||||
}else{
|
||||
assert_nc( iPos2>=0 && iPos2!=iPrev );
|
||||
assert( iPos2>=0 && iPos2!=iPrev );
|
||||
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
|
||||
aCopy = &a2[iOff2];
|
||||
nCopy = i2.nPoslist - iOff2;
|
||||
}
|
||||
if( nCopy>0 ){
|
||||
fts5BufferSafeAppendBlob(&tmp, aCopy, nCopy);
|
||||
fts5BufferSafeAppendBlob(&tmp, &a2[iOff2], i2.nPoslist-iOff2);
|
||||
}
|
||||
|
||||
/* 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) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5069,7 +5013,7 @@ static void fts5MergePrefixLists(
|
||||
fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
|
||||
fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.aEof - i2.aPoslist);
|
||||
}
|
||||
assert_nc( out.n<=(p1->n+p2->n+9) );
|
||||
assert( out.n<=(p1->n+p2->n+9) );
|
||||
|
||||
fts5BufferSet(&p->rc, p1, out.n, out.p);
|
||||
fts5BufferFree(&tmp);
|
||||
@@ -5158,7 +5102,7 @@ static void fts5SetupPrefixIter(
|
||||
}
|
||||
fts5MultiIterFree(p1);
|
||||
|
||||
pData = fts5IdxMalloc(p, sizeof(Fts5Data)+doclist.n+FTS5_DATA_ZERO_PADDING);
|
||||
pData = fts5IdxMalloc(p, sizeof(Fts5Data) + doclist.n);
|
||||
if( pData ){
|
||||
pData->p = (u8*)&pData[1];
|
||||
pData->nn = pData->szLeaf = doclist.n;
|
||||
@@ -5204,7 +5148,7 @@ int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
|
||||
int sqlite3Fts5IndexSync(Fts5Index *p){
|
||||
assert( p->rc==SQLITE_OK );
|
||||
fts5IndexFlush(p);
|
||||
sqlite3Fts5IndexCloseReader(p);
|
||||
fts5CloseReader(p);
|
||||
return fts5IndexReturn(p);
|
||||
}
|
||||
|
||||
@@ -5215,7 +5159,7 @@ int sqlite3Fts5IndexSync(Fts5Index *p){
|
||||
** records must be invalidated.
|
||||
*/
|
||||
int sqlite3Fts5IndexRollback(Fts5Index *p){
|
||||
sqlite3Fts5IndexCloseReader(p);
|
||||
fts5CloseReader(p);
|
||||
fts5IndexDiscardData(p);
|
||||
fts5StructureInvalidate(p);
|
||||
/* assert( p->rc==SQLITE_OK ); */
|
||||
@@ -5230,7 +5174,6 @@ int sqlite3Fts5IndexRollback(Fts5Index *p){
|
||||
int sqlite3Fts5IndexReinit(Fts5Index *p){
|
||||
Fts5Structure s;
|
||||
fts5StructureInvalidate(p);
|
||||
fts5IndexDiscardData(p);
|
||||
memset(&s, 0, sizeof(Fts5Structure));
|
||||
fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0);
|
||||
fts5StructureWrite(p, &s);
|
||||
@@ -5318,13 +5261,9 @@ int sqlite3Fts5IndexCharlenToBytelen(
|
||||
for(i=0; i<nChar; i++){
|
||||
if( n>=nByte ) return 0; /* Input contains fewer than nChar chars */
|
||||
if( (unsigned char)p[n++]>=0xc0 ){
|
||||
if( n>=nByte ) return 0;
|
||||
while( (p[n] & 0xc0)==0x80 ){
|
||||
n++;
|
||||
if( n>=nByte ){
|
||||
if( i+1==nChar ) break;
|
||||
return 0;
|
||||
}
|
||||
if( n>=nByte ) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5460,7 +5399,7 @@ int sqlite3Fts5IndexQuery(
|
||||
if( p->rc ){
|
||||
sqlite3Fts5IterClose((Fts5IndexIter*)pRet);
|
||||
pRet = 0;
|
||||
sqlite3Fts5IndexCloseReader(p);
|
||||
fts5CloseReader(p);
|
||||
}
|
||||
|
||||
*ppIter = (Fts5IndexIter*)pRet;
|
||||
@@ -5533,7 +5472,7 @@ void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){
|
||||
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
|
||||
Fts5Index *pIndex = pIter->pIndex;
|
||||
fts5MultiIterFree(pIter);
|
||||
sqlite3Fts5IndexCloseReader(pIndex);
|
||||
fts5CloseReader(pIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5726,37 +5665,6 @@ static int fts5QueryCksum(
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check if buffer z[], size n bytes, contains as series of valid utf-8
|
||||
** encoded codepoints. If so, return 0. Otherwise, if the buffer does not
|
||||
** contain valid utf-8, return non-zero.
|
||||
*/
|
||||
static int fts5TestUtf8(const char *z, int n){
|
||||
int i = 0;
|
||||
assert_nc( n>0 );
|
||||
while( i<n ){
|
||||
if( (z[i] & 0x80)==0x00 ){
|
||||
i++;
|
||||
}else
|
||||
if( (z[i] & 0xE0)==0xC0 ){
|
||||
if( i+1>=n || (z[i+1] & 0xC0)!=0x80 ) return 1;
|
||||
i += 2;
|
||||
}else
|
||||
if( (z[i] & 0xF0)==0xE0 ){
|
||||
if( i+2>=n || (z[i+1] & 0xC0)!=0x80 || (z[i+2] & 0xC0)!=0x80 ) return 1;
|
||||
i += 3;
|
||||
}else
|
||||
if( (z[i] & 0xF8)==0xF0 ){
|
||||
if( i+3>=n || (z[i+1] & 0xC0)!=0x80 || (z[i+2] & 0xC0)!=0x80 ) return 1;
|
||||
if( (z[i+2] & 0xC0)!=0x80 ) return 1;
|
||||
i += 3;
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is also purely an internal test. It does not contribute to
|
||||
@@ -5797,14 +5705,8 @@ static void fts5TestTerm(
|
||||
** This check may only be performed if the hash table is empty. This
|
||||
** is because the hash table only supports a single scan query at
|
||||
** a time, and the multi-iter loop from which this function is called
|
||||
** is already performing such a scan.
|
||||
**
|
||||
** Also only do this if buffer zTerm contains nTerm bytes of valid
|
||||
** utf-8. Otherwise, the last part of the buffer contents might contain
|
||||
** a non-utf-8 sequence that happens to be a prefix of a valid utf-8
|
||||
** character stored in the main fts index, which will cause the
|
||||
** test to fail. */
|
||||
if( p->nPendingData==0 && 0==fts5TestUtf8(zTerm, nTerm) ){
|
||||
** is already performing such a scan. */
|
||||
if( p->nPendingData==0 ){
|
||||
if( iIdx>0 && rc==SQLITE_OK ){
|
||||
int f = flags|FTS5INDEX_QUERY_TEST_NOIDX;
|
||||
ck2 = 0;
|
||||
@@ -5927,8 +5829,7 @@ static void fts5IndexIntegrityCheckSegment(
|
||||
if( pSeg->pgnoFirst==0 ) return;
|
||||
|
||||
fts5IndexPrepareStmt(p, &pStmt, sqlite3_mprintf(
|
||||
"SELECT segid, term, (pgno>>1), (pgno&1) FROM %Q.'%q_idx' WHERE segid=%d "
|
||||
"ORDER BY 1, 2",
|
||||
"SELECT segid, term, (pgno>>1), (pgno&1) FROM %Q.'%q_idx' WHERE segid=%d",
|
||||
pConfig->zDb, pConfig->zName, pSeg->iSegid
|
||||
));
|
||||
|
||||
@@ -5937,8 +5838,8 @@ static void fts5IndexIntegrityCheckSegment(
|
||||
i64 iRow; /* Rowid for this leaf */
|
||||
Fts5Data *pLeaf; /* Data for this leaf */
|
||||
|
||||
const char *zIdxTerm = (const char*)sqlite3_column_blob(pStmt, 1);
|
||||
int nIdxTerm = sqlite3_column_bytes(pStmt, 1);
|
||||
const char *zIdxTerm = (const char*)sqlite3_column_text(pStmt, 1);
|
||||
int iIdxLeaf = sqlite3_column_int(pStmt, 2);
|
||||
int bIdxDlidx = sqlite3_column_int(pStmt, 3);
|
||||
|
||||
@@ -5963,11 +5864,11 @@ static void fts5IndexIntegrityCheckSegment(
|
||||
|
||||
iOff = fts5LeafFirstTermOff(pLeaf);
|
||||
iRowidOff = fts5LeafFirstRowidOff(pLeaf);
|
||||
if( iRowidOff>=iOff || iOff>=pLeaf->szLeaf ){
|
||||
if( iRowidOff>=iOff ){
|
||||
p->rc = FTS5_CORRUPT;
|
||||
}else{
|
||||
iOff += fts5GetVarint32(&pLeaf->p[iOff], nTerm);
|
||||
res = fts5Memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm));
|
||||
res = memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm));
|
||||
if( res==0 ) res = nTerm - nIdxTerm;
|
||||
if( res<0 ) p->rc = FTS5_CORRUPT;
|
||||
}
|
||||
@@ -6362,7 +6263,7 @@ static void fts5DecodeFunction(
|
||||
u8 *a = 0;
|
||||
Fts5Buffer s; /* Build up text to return here */
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
sqlite3_int64 nSpace = 0;
|
||||
int nSpace = 0;
|
||||
int eDetailNone = (sqlite3_user_data(pCtx)!=0);
|
||||
|
||||
assert( nArg==2 );
|
||||
@@ -6378,7 +6279,8 @@ static void fts5DecodeFunction(
|
||||
nSpace = n + FTS5_DATA_ZERO_PADDING;
|
||||
a = (u8*)sqlite3Fts5MallocZero(&rc, nSpace);
|
||||
if( a==0 ) goto decode_out;
|
||||
if( n>0 ) memcpy(a, aBlob, n);
|
||||
memcpy(a, aBlob, n);
|
||||
|
||||
|
||||
fts5DecodeRowid(iRowid, &iSegid, &bDlidx, &iHeight, &iPgno);
|
||||
|
||||
@@ -6473,9 +6375,6 @@ static void fts5DecodeFunction(
|
||||
iPgidxOff = szLeaf = fts5GetU16(&a[2]);
|
||||
if( iPgidxOff<n ){
|
||||
fts5GetVarint32(&a[iPgidxOff], iTermOff);
|
||||
}else if( iPgidxOff>n ){
|
||||
rc = FTS5_CORRUPT;
|
||||
goto decode_out;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6487,22 +6386,14 @@ static void fts5DecodeFunction(
|
||||
}else{
|
||||
iOff = szLeaf;
|
||||
}
|
||||
if( iOff>n ){
|
||||
rc = FTS5_CORRUPT;
|
||||
goto decode_out;
|
||||
}
|
||||
fts5DecodePoslist(&rc, &s, &a[4], iOff-4);
|
||||
|
||||
/* Decode any more doclist data that appears on the page before the
|
||||
** first term. */
|
||||
nDoclist = (iTermOff ? iTermOff : szLeaf) - iOff;
|
||||
if( nDoclist+iOff>n ){
|
||||
rc = FTS5_CORRUPT;
|
||||
goto decode_out;
|
||||
}
|
||||
fts5DecodeDoclist(&rc, &s, &a[iOff], nDoclist);
|
||||
|
||||
while( iPgidxOff<n && rc==SQLITE_OK ){
|
||||
while( iPgidxOff<n ){
|
||||
int bFirst = (iPgidxOff==szLeaf); /* True for first term on page */
|
||||
int nByte; /* Bytes of data */
|
||||
int iEnd;
|
||||
@@ -6517,24 +6408,12 @@ static void fts5DecodeFunction(
|
||||
}else{
|
||||
iEnd = szLeaf;
|
||||
}
|
||||
if( iEnd>szLeaf ){
|
||||
rc = FTS5_CORRUPT;
|
||||
break;
|
||||
}
|
||||
|
||||
if( bFirst==0 ){
|
||||
iOff += fts5GetVarint32(&a[iOff], nByte);
|
||||
if( nByte>term.n ){
|
||||
rc = FTS5_CORRUPT;
|
||||
break;
|
||||
}
|
||||
term.n = nByte;
|
||||
}
|
||||
iOff += fts5GetVarint32(&a[iOff], nByte);
|
||||
if( iOff+nByte>n ){
|
||||
rc = FTS5_CORRUPT;
|
||||
break;
|
||||
}
|
||||
fts5BufferAppendBlob(&rc, &term, nByte, &a[iOff]);
|
||||
iOff += nByte;
|
||||
|
||||
|
||||
+269
-369
File diff suppressed because it is too large
Load Diff
+15
-31
@@ -115,7 +115,7 @@ static int fts5StorageGetStmt(
|
||||
char *zBind;
|
||||
int i;
|
||||
|
||||
zBind = sqlite3_malloc64(1 + nCol*2);
|
||||
zBind = sqlite3_malloc(1 + nCol*2);
|
||||
if( zBind ){
|
||||
for(i=0; i<nCol; i++){
|
||||
zBind[i*2] = '?';
|
||||
@@ -136,11 +136,8 @@ static int fts5StorageGetStmt(
|
||||
if( zSql==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
int f = SQLITE_PREPARE_PERSISTENT;
|
||||
if( eStmt>FTS5_STMT_LOOKUP ) f |= SQLITE_PREPARE_NO_VTAB;
|
||||
p->pConfig->bLock++;
|
||||
rc = sqlite3_prepare_v3(pC->db, zSql, -1, f, &p->aStmt[eStmt], 0);
|
||||
p->pConfig->bLock--;
|
||||
rc = sqlite3_prepare_v3(pC->db, zSql, -1,
|
||||
SQLITE_PREPARE_PERSISTENT, &p->aStmt[eStmt], 0);
|
||||
sqlite3_free(zSql);
|
||||
if( rc!=SQLITE_OK && pzErrMsg ){
|
||||
*pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db));
|
||||
@@ -284,14 +281,14 @@ int sqlite3Fts5StorageOpen(
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
Fts5Storage *p; /* New object */
|
||||
sqlite3_int64 nByte; /* Bytes of space to allocate */
|
||||
int nByte; /* Bytes of space to allocate */
|
||||
|
||||
nByte = sizeof(Fts5Storage) /* Fts5Storage object */
|
||||
+ pConfig->nCol * sizeof(i64); /* Fts5Storage.aTotalSize[] */
|
||||
*pp = p = (Fts5Storage*)sqlite3_malloc64(nByte);
|
||||
*pp = p = (Fts5Storage*)sqlite3_malloc(nByte);
|
||||
if( !p ) return SQLITE_NOMEM;
|
||||
|
||||
memset(p, 0, (size_t)nByte);
|
||||
memset(p, 0, nByte);
|
||||
p->aTotalSize = (i64*)&p[1];
|
||||
p->pConfig = pConfig;
|
||||
p->pIndex = pIndex;
|
||||
@@ -299,7 +296,7 @@ int sqlite3Fts5StorageOpen(
|
||||
if( bCreate ){
|
||||
if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
|
||||
int nDefn = 32 + pConfig->nCol*10;
|
||||
char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 10);
|
||||
char *zDefn = sqlite3_malloc(32 + pConfig->nCol * 10);
|
||||
if( zDefn==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -560,8 +557,6 @@ int sqlite3Fts5StorageDeleteAll(Fts5Storage *p){
|
||||
Fts5Config *pConfig = p->pConfig;
|
||||
int rc;
|
||||
|
||||
p->bTotalsValid = 0;
|
||||
|
||||
/* Delete the contents of the %_data and %_docsize tables. */
|
||||
rc = fts5ExecPrintf(pConfig->db, 0,
|
||||
"DELETE FROM %Q.'%q_data';"
|
||||
@@ -592,7 +587,7 @@ int sqlite3Fts5StorageRebuild(Fts5Storage *p){
|
||||
Fts5Config *pConfig = p->pConfig;
|
||||
sqlite3_stmt *pScan = 0;
|
||||
Fts5InsertCtx ctx;
|
||||
int rc, rc2;
|
||||
int rc;
|
||||
|
||||
memset(&ctx, 0, sizeof(Fts5InsertCtx));
|
||||
ctx.pStorage = p;
|
||||
@@ -613,11 +608,10 @@ int sqlite3Fts5StorageRebuild(Fts5Storage *p){
|
||||
for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
|
||||
ctx.szCol = 0;
|
||||
if( pConfig->abUnindexed[ctx.iCol]==0 ){
|
||||
const char *zText = (const char*)sqlite3_column_text(pScan, ctx.iCol+1);
|
||||
int nText = sqlite3_column_bytes(pScan, ctx.iCol+1);
|
||||
rc = sqlite3Fts5Tokenize(pConfig,
|
||||
FTS5_TOKENIZE_DOCUMENT,
|
||||
zText, nText,
|
||||
(const char*)sqlite3_column_text(pScan, ctx.iCol+1),
|
||||
sqlite3_column_bytes(pScan, ctx.iCol+1),
|
||||
(void*)&ctx,
|
||||
fts5StorageInsertCallback
|
||||
);
|
||||
@@ -632,8 +626,6 @@ int sqlite3Fts5StorageRebuild(Fts5Storage *p){
|
||||
}
|
||||
}
|
||||
sqlite3_free(buf.p);
|
||||
rc2 = sqlite3_reset(pScan);
|
||||
if( rc==SQLITE_OK ) rc = rc2;
|
||||
|
||||
/* Write the averages record */
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -739,11 +731,10 @@ int sqlite3Fts5StorageIndexInsert(
|
||||
for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
|
||||
ctx.szCol = 0;
|
||||
if( pConfig->abUnindexed[ctx.iCol]==0 ){
|
||||
const char *zText = (const char*)sqlite3_value_text(apVal[ctx.iCol+2]);
|
||||
int nText = sqlite3_value_bytes(apVal[ctx.iCol+2]);
|
||||
rc = sqlite3Fts5Tokenize(pConfig,
|
||||
FTS5_TOKENIZE_DOCUMENT,
|
||||
zText, nText,
|
||||
(const char*)sqlite3_value_text(apVal[ctx.iCol+2]),
|
||||
sqlite3_value_bytes(apVal[ctx.iCol+2]),
|
||||
(void*)&ctx,
|
||||
fts5StorageInsertCallback
|
||||
);
|
||||
@@ -884,7 +875,7 @@ int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
|
||||
|
||||
memset(&ctx, 0, sizeof(Fts5IntegrityCtx));
|
||||
ctx.pConfig = p->pConfig;
|
||||
aTotalSize = (i64*)sqlite3_malloc64(pConfig->nCol*(sizeof(int)+sizeof(i64)));
|
||||
aTotalSize = (i64*)sqlite3_malloc(pConfig->nCol * (sizeof(int)+sizeof(i64)));
|
||||
if( !aTotalSize ) return SQLITE_NOMEM;
|
||||
aColSize = (int*)&aTotalSize[pConfig->nCol];
|
||||
memset(aTotalSize, 0, sizeof(i64) * pConfig->nCol);
|
||||
@@ -912,11 +903,10 @@ int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
|
||||
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,
|
||||
(const char*)sqlite3_column_text(pScan, i+1),
|
||||
sqlite3_column_bytes(pScan, i+1),
|
||||
(void*)&ctx,
|
||||
fts5StorageIntegrityCallback
|
||||
);
|
||||
@@ -1085,13 +1075,7 @@ int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnToken){
|
||||
int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow){
|
||||
int rc = fts5StorageLoadTotals(p, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
/* nTotalRow being zero does not necessarily indicate a corrupt
|
||||
** database - it might be that the FTS5 table really does contain zero
|
||||
** rows. However this function is only called from the xRowCount() API,
|
||||
** and there is no way for that API to be invoked if the table contains
|
||||
** no rows. Hence the FTS5_CORRUPT return. */
|
||||
*pnRow = p->nTotalRow;
|
||||
if( p->nTotalRow<=0 ) rc = FTS5_CORRUPT;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -309,7 +309,7 @@ static Fts5MatchinfoCtx *fts5MatchinfoNew(
|
||||
int nPhrase;
|
||||
int i;
|
||||
int nInt;
|
||||
sqlite3_int64 nByte;
|
||||
int nByte;
|
||||
int rc;
|
||||
|
||||
nCol = pApi->xColumnCount(pFts);
|
||||
@@ -330,7 +330,7 @@ static Fts5MatchinfoCtx *fts5MatchinfoNew(
|
||||
nByte = sizeof(Fts5MatchinfoCtx) /* The struct itself */
|
||||
+ sizeof(u32) * nInt /* The p->aRet[] array */
|
||||
+ (i+1); /* The p->zArg string */
|
||||
p = (Fts5MatchinfoCtx*)sqlite3_malloc64(nByte);
|
||||
p = (Fts5MatchinfoCtx*)sqlite3_malloc(nByte);
|
||||
if( p==0 ){
|
||||
sqlite3_result_error_nomem(pCtx);
|
||||
return 0;
|
||||
|
||||
@@ -137,7 +137,7 @@ static int fts5tokDequoteArray(
|
||||
nByte += (int)(strlen(argv[i]) + 1);
|
||||
}
|
||||
|
||||
*pazDequote = azDequote = sqlite3_malloc64(sizeof(char *)*argc + nByte);
|
||||
*pazDequote = azDequote = sqlite3_malloc(sizeof(char *)*argc + nByte);
|
||||
if( azDequote==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -335,7 +335,7 @@ static int fts5tokCb(
|
||||
if( (pCsr->nRow & (pCsr->nRow-1))==0 ){
|
||||
int nNew = pCsr->nRow ? pCsr->nRow*2 : 32;
|
||||
Fts5tokRow *aNew;
|
||||
aNew = (Fts5tokRow*)sqlite3_realloc64(pCsr->aRow, nNew*sizeof(Fts5tokRow));
|
||||
aNew = (Fts5tokRow*)sqlite3_realloc(pCsr->aRow, nNew*sizeof(Fts5tokRow));
|
||||
if( aNew==0 ) return SQLITE_NOMEM;
|
||||
memset(&aNew[pCsr->nRow], 0, sizeof(Fts5tokRow)*(nNew-pCsr->nRow));
|
||||
pCsr->aRow = aNew;
|
||||
@@ -378,7 +378,7 @@ static int fts5tokFilterMethod(
|
||||
if( pCsr->zInput==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
if( nByte>0 ) memcpy(pCsr->zInput, zByte, nByte);
|
||||
memcpy(pCsr->zInput, zByte, nByte);
|
||||
pCsr->zInput[nByte] = 0;
|
||||
rc = pTab->tok.xTokenize(
|
||||
pTab->pTok, (void*)pCsr, 0, zByte, nByte, fts5tokCb
|
||||
|
||||
@@ -152,7 +152,7 @@ static int fts5AsciiTokenize(
|
||||
nByte = ie-is;
|
||||
if( nByte>nFold ){
|
||||
if( pFold!=aFold ) sqlite3_free(pFold);
|
||||
pFold = sqlite3_malloc64((sqlite3_int64)nByte*2);
|
||||
pFold = sqlite3_malloc(nByte*2);
|
||||
if( pFold==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
break;
|
||||
@@ -256,14 +256,13 @@ static int fts5UnicodeAddExceptions(
|
||||
int *aNew;
|
||||
|
||||
if( n>0 ){
|
||||
aNew = (int*)sqlite3_realloc64(p->aiException,
|
||||
(n+p->nException)*sizeof(int));
|
||||
aNew = (int*)sqlite3_realloc(p->aiException, (n+p->nException)*sizeof(int));
|
||||
if( aNew ){
|
||||
int nNew = p->nException;
|
||||
const unsigned char *zCsr = (const unsigned char*)z;
|
||||
const unsigned char *zTerm = (const unsigned char*)&z[n];
|
||||
while( zCsr<zTerm ){
|
||||
u32 iCode;
|
||||
int iCode;
|
||||
int bToken;
|
||||
READ_UTF8(zCsr, zTerm, iCode);
|
||||
if( iCode<128 ){
|
||||
@@ -275,7 +274,7 @@ static int fts5UnicodeAddExceptions(
|
||||
if( bToken!=bTokenChars && sqlite3Fts5UnicodeIsdiacritic(iCode)==0 ){
|
||||
int i;
|
||||
for(i=0; i<nNew; i++){
|
||||
if( (u32)aNew[i]>iCode ) break;
|
||||
if( aNew[i]>iCode ) break;
|
||||
}
|
||||
memmove(&aNew[i+1], &aNew[i], (nNew-i)*sizeof(int));
|
||||
aNew[i] = iCode;
|
||||
@@ -369,7 +368,7 @@ static int fts5UnicodeCreate(
|
||||
|
||||
p->eRemoveDiacritic = FTS5_REMOVE_DIACRITICS_SIMPLE;
|
||||
p->nFold = 64;
|
||||
p->aFold = sqlite3_malloc64(p->nFold * sizeof(char));
|
||||
p->aFold = sqlite3_malloc(p->nFold * sizeof(char));
|
||||
if( p->aFold==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
@@ -430,7 +429,7 @@ static int fts5UnicodeCreate(
|
||||
*/
|
||||
static int fts5UnicodeIsAlnum(Unicode61Tokenizer *p, int iCode){
|
||||
return (
|
||||
p->aCategory[sqlite3Fts5UnicodeCategory((u32)iCode)]
|
||||
p->aCategory[sqlite3Fts5UnicodeCategory(iCode)]
|
||||
^ fts5UnicodeIsException(p, iCode)
|
||||
);
|
||||
}
|
||||
@@ -459,7 +458,7 @@ static int fts5UnicodeTokenize(
|
||||
/* Each iteration of this loop gobbles up a contiguous run of separators,
|
||||
** then the next token. */
|
||||
while( rc==SQLITE_OK ){
|
||||
u32 iCode; /* non-ASCII codepoint read from input */
|
||||
int iCode; /* non-ASCII codepoint read from input */
|
||||
char *zOut = aFold;
|
||||
int is;
|
||||
int ie;
|
||||
@@ -491,7 +490,7 @@ static int fts5UnicodeTokenize(
|
||||
/* Grow the output buffer so that there is sufficient space to fit the
|
||||
** largest possible utf-8 character. */
|
||||
if( zOut>pEnd ){
|
||||
aFold = sqlite3_malloc64((sqlite3_int64)nFold*2);
|
||||
aFold = sqlite3_malloc(nFold*2);
|
||||
if( aFold==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto tokenize_done;
|
||||
@@ -1285,3 +1284,5 @@ int sqlite3Fts5TokenizerInit(fts5_api *pApi){
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** 2012-05-25
|
||||
** 2012 May 25
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
@@ -47,8 +47,8 @@ static int fts5_remove_diacritic(int c, int bComplex){
|
||||
62830, 62890, 62924, 62974, 63032, 63050, 63082, 63118,
|
||||
63182, 63242, 63274, 63310, 63368, 63390,
|
||||
};
|
||||
#define HIBIT ((unsigned char)0x80)
|
||||
unsigned char aChar[] = {
|
||||
#define HIBIT ((char)0x80)
|
||||
char aChar[] = {
|
||||
'\0', 'a', 'c', 'e', 'i', 'n',
|
||||
'o', 'u', 'y', 'y', 'a', 'c',
|
||||
'd', 'e', 'e', 'g', 'h', 'i',
|
||||
@@ -69,7 +69,7 @@ static int fts5_remove_diacritic(int c, int bComplex){
|
||||
'w', 'x', 'y', 'z', 'h', 't',
|
||||
'w', 'y', 'a', 'a'|HIBIT, 'a'|HIBIT, 'a'|HIBIT,
|
||||
'e', 'e'|HIBIT, 'e'|HIBIT, 'i', 'o', 'o'|HIBIT,
|
||||
'o'|HIBIT, 'o'|HIBIT, 'u', 'u'|HIBIT, 'u'|HIBIT, 'y',
|
||||
'o'|HIBIT, 'o'|HIBIT, 'u', 'u'|HIBIT, 'u'|HIBIT, 'y',
|
||||
};
|
||||
|
||||
unsigned int key = (((unsigned int)c)<<3) | 0x00000007;
|
||||
@@ -100,8 +100,8 @@ int sqlite3Fts5UnicodeIsdiacritic(int c){
|
||||
unsigned int mask1 = 0x000361F8;
|
||||
if( c<768 || c>817 ) return 0;
|
||||
return (c < 768+32) ?
|
||||
(mask0 & ((unsigned int)1 << (c-768))) :
|
||||
(mask1 & ((unsigned int)1 << (c-768-32)));
|
||||
(mask0 & (1 << (c-768))) :
|
||||
(mask1 & (1 << (c-768-32)));
|
||||
}
|
||||
|
||||
|
||||
@@ -249,7 +249,6 @@ int sqlite3Fts5UnicodeFold(int c, int eRemoveDiacritic){
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
|
||||
aArray[0] = 1;
|
||||
switch( zCat[0] ){
|
||||
@@ -731,7 +730,7 @@ static u16 aFts5UnicodeData[] = {
|
||||
34, 3074, 7692, 63, 63,
|
||||
};
|
||||
|
||||
int sqlite3Fts5UnicodeCategory(u32 iCode) {
|
||||
int sqlite3Fts5UnicodeCategory(int iCode) {
|
||||
int iRes = -1;
|
||||
int iHi;
|
||||
int iLo;
|
||||
@@ -769,7 +768,7 @@ void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){
|
||||
int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ];
|
||||
int n = (aFts5UnicodeData[iTbl] >> 5) + i;
|
||||
for(; i<128 && i<n; i++){
|
||||
aAscii[i] = (u8)bToken;
|
||||
aAscii[i] = bToken;
|
||||
}
|
||||
iTbl++;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ int sqlite3Fts5GetVarint32(const unsigned char *p, u32 *v){
|
||||
u8 n;
|
||||
p -= 2;
|
||||
n = sqlite3Fts5GetVarint(p, &v64);
|
||||
*v = ((u32)v64) & 0x7FFFFFFF;
|
||||
*v = (u32)v64;
|
||||
assert( n>3 && n<=9 );
|
||||
return n;
|
||||
}
|
||||
@@ -342,3 +342,4 @@ int sqlite3Fts5GetVarintLen(u32 iVal){
|
||||
if( iVal<(1 << 28) ) return 4;
|
||||
return 5;
|
||||
}
|
||||
|
||||
|
||||
+32
-50
@@ -50,13 +50,12 @@ struct Fts5VocabTable {
|
||||
sqlite3 *db; /* Database handle */
|
||||
Fts5Global *pGlobal; /* FTS5 global object for this database */
|
||||
int eType; /* FTS5_VOCAB_COL, ROW or INSTANCE */
|
||||
unsigned bBusy; /* True if busy */
|
||||
};
|
||||
|
||||
struct Fts5VocabCursor {
|
||||
sqlite3_vtab_cursor base;
|
||||
sqlite3_stmt *pStmt; /* Statement holding lock on pIndex */
|
||||
Fts5Table *pFts5; /* Associated FTS5 table */
|
||||
Fts5Index *pIndex; /* Associated FTS5 index */
|
||||
|
||||
int bEof; /* True if this cursor is at EOF */
|
||||
Fts5IndexIter *pIter; /* Term/rowid iterator object */
|
||||
@@ -65,6 +64,7 @@ struct Fts5VocabCursor {
|
||||
char *zLeTerm; /* (term <= $zLeTerm) paramater, or NULL */
|
||||
|
||||
/* These are used by 'col' tables only */
|
||||
Fts5Config *pConfig; /* Fts5 table configuration */
|
||||
int iCol;
|
||||
i64 *aCnt;
|
||||
i64 *aDoc;
|
||||
@@ -327,18 +327,13 @@ static int fts5VocabOpenMethod(
|
||||
sqlite3_vtab_cursor **ppCsr
|
||||
){
|
||||
Fts5VocabTable *pTab = (Fts5VocabTable*)pVTab;
|
||||
Fts5Table *pFts5 = 0;
|
||||
Fts5Index *pIndex = 0;
|
||||
Fts5Config *pConfig = 0;
|
||||
Fts5VocabCursor *pCsr = 0;
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
char *zSql = 0;
|
||||
|
||||
if( pTab->bBusy ){
|
||||
pVTab->zErrMsg = sqlite3_mprintf(
|
||||
"recursive definition for %s.%s", pTab->zFts5Db, pTab->zFts5Tbl
|
||||
);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
zSql = sqlite3Fts5Mprintf(&rc,
|
||||
"SELECT t.%Q FROM %Q.%Q AS t WHERE t.%Q MATCH '*id'",
|
||||
pTab->zFts5Tbl, pTab->zFts5Db, pTab->zFts5Tbl, pTab->zFts5Tbl
|
||||
@@ -350,38 +345,33 @@ static int fts5VocabOpenMethod(
|
||||
assert( rc==SQLITE_OK || pStmt==0 );
|
||||
if( rc==SQLITE_ERROR ) rc = SQLITE_OK;
|
||||
|
||||
pTab->bBusy = 1;
|
||||
if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
i64 iId = sqlite3_column_int64(pStmt, 0);
|
||||
pFts5 = sqlite3Fts5TableFromCsrid(pTab->pGlobal, iId);
|
||||
pIndex = sqlite3Fts5IndexFromCsrid(pTab->pGlobal, iId, &pConfig);
|
||||
}
|
||||
pTab->bBusy = 0;
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
if( pFts5==0 ){
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
pStmt = 0;
|
||||
if( rc==SQLITE_OK ){
|
||||
pVTab->zErrMsg = sqlite3_mprintf(
|
||||
"no such fts5 table: %s.%s", pTab->zFts5Db, pTab->zFts5Tbl
|
||||
);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
}else{
|
||||
rc = sqlite3Fts5FlushToDisk(pFts5);
|
||||
if( rc==SQLITE_OK && pIndex==0 ){
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
pStmt = 0;
|
||||
if( rc==SQLITE_OK ){
|
||||
pVTab->zErrMsg = sqlite3_mprintf(
|
||||
"no such fts5 table: %s.%s", pTab->zFts5Db, pTab->zFts5Tbl
|
||||
);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
int nByte = pFts5->pConfig->nCol * sizeof(i64)*2 + sizeof(Fts5VocabCursor);
|
||||
int nByte = pConfig->nCol * sizeof(i64) * 2 + sizeof(Fts5VocabCursor);
|
||||
pCsr = (Fts5VocabCursor*)sqlite3Fts5MallocZero(&rc, nByte);
|
||||
}
|
||||
|
||||
if( pCsr ){
|
||||
pCsr->pFts5 = pFts5;
|
||||
pCsr->pIndex = pIndex;
|
||||
pCsr->pStmt = pStmt;
|
||||
pCsr->pConfig = pConfig;
|
||||
pCsr->aCnt = (i64*)&pCsr[1];
|
||||
pCsr->aDoc = &pCsr->aCnt[pFts5->pConfig->nCol];
|
||||
pCsr->aDoc = &pCsr->aCnt[pConfig->nCol];
|
||||
}else{
|
||||
sqlite3_finalize(pStmt);
|
||||
}
|
||||
@@ -397,7 +387,6 @@ static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){
|
||||
sqlite3_free(pCsr->zLeTerm);
|
||||
pCsr->nLeTerm = -1;
|
||||
pCsr->zLeTerm = 0;
|
||||
pCsr->bEof = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -436,7 +425,7 @@ static int fts5VocabInstanceNewTerm(Fts5VocabCursor *pCsr){
|
||||
}
|
||||
|
||||
static int fts5VocabInstanceNext(Fts5VocabCursor *pCsr){
|
||||
int eDetail = pCsr->pFts5->pConfig->eDetail;
|
||||
int eDetail = pCsr->pConfig->eDetail;
|
||||
int rc = SQLITE_OK;
|
||||
Fts5IndexIter *pIter = pCsr->pIter;
|
||||
i64 *pp = &pCsr->iInstPos;
|
||||
@@ -471,7 +460,7 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
|
||||
Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab;
|
||||
int rc = SQLITE_OK;
|
||||
int nCol = pCsr->pFts5->pConfig->nCol;
|
||||
int nCol = pCsr->pConfig->nCol;
|
||||
|
||||
pCsr->rowid++;
|
||||
|
||||
@@ -493,7 +482,6 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
int nTerm;
|
||||
|
||||
zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
|
||||
assert( nTerm>=0 );
|
||||
if( pCsr->nLeTerm>=0 ){
|
||||
int nCmp = MIN(nTerm, pCsr->nLeTerm);
|
||||
int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp);
|
||||
@@ -510,7 +498,7 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
|
||||
assert( pTab->eType==FTS5_VOCAB_COL || pTab->eType==FTS5_VOCAB_ROW );
|
||||
while( rc==SQLITE_OK ){
|
||||
int eDetail = pCsr->pFts5->pConfig->eDetail;
|
||||
int eDetail = pCsr->pConfig->eDetail;
|
||||
const u8 *pPos; int nPos; /* Position list */
|
||||
i64 iPos = 0; /* 64-bit position read from poslist */
|
||||
int iOff = 0; /* Current offset within position list */
|
||||
@@ -533,6 +521,7 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
int iCol = -1;
|
||||
while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
|
||||
int ii = FTS5_POS2COLUMN(iPos);
|
||||
pCsr->aCnt[ii]++;
|
||||
if( iCol!=ii ){
|
||||
if( ii>=nCol ){
|
||||
rc = FTS5_CORRUPT;
|
||||
@@ -541,7 +530,6 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
pCsr->aDoc[ii]++;
|
||||
iCol = ii;
|
||||
}
|
||||
pCsr->aCnt[ii]++;
|
||||
}
|
||||
}else if( eDetail==FTS5_DETAIL_COLUMNS ){
|
||||
while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff,&iPos) ){
|
||||
@@ -570,9 +558,7 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
|
||||
if( nTerm!=pCsr->term.n
|
||||
|| (nTerm>0 && memcmp(zTerm, pCsr->term.p, nTerm))
|
||||
){
|
||||
if( nTerm!=pCsr->term.n || memcmp(zTerm, pCsr->term.p, nTerm) ){
|
||||
break;
|
||||
}
|
||||
if( sqlite3Fts5IterEof(pCsr->pIter) ) break;
|
||||
@@ -582,10 +568,8 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK && pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){
|
||||
for(/* noop */; pCsr->iCol<nCol && pCsr->aDoc[pCsr->iCol]==0; pCsr->iCol++);
|
||||
if( pCsr->iCol==nCol ){
|
||||
rc = FTS5_CORRUPT;
|
||||
}
|
||||
while( pCsr->aDoc[pCsr->iCol]==0 ) pCsr->iCol++;
|
||||
assert( pCsr->iCol<pCsr->pConfig->nCol );
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -632,7 +616,6 @@ static int fts5VocabFilterMethod(
|
||||
}
|
||||
if( pLe ){
|
||||
const char *zCopy = (const char *)sqlite3_value_text(pLe);
|
||||
if( zCopy==0 ) zCopy = "";
|
||||
pCsr->nLeTerm = sqlite3_value_bytes(pLe);
|
||||
pCsr->zLeTerm = sqlite3_malloc(pCsr->nLeTerm+1);
|
||||
if( pCsr->zLeTerm==0 ){
|
||||
@@ -644,15 +627,14 @@ static int fts5VocabFilterMethod(
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
Fts5Index *pIndex = pCsr->pFts5->pIndex;
|
||||
rc = sqlite3Fts5IndexQuery(pIndex, zTerm, nTerm, f, 0, &pCsr->pIter);
|
||||
rc = sqlite3Fts5IndexQuery(pCsr->pIndex, zTerm, nTerm, f, 0, &pCsr->pIter);
|
||||
}
|
||||
if( rc==SQLITE_OK && eType==FTS5_VOCAB_INSTANCE ){
|
||||
rc = fts5VocabInstanceNewTerm(pCsr);
|
||||
}
|
||||
if( rc==SQLITE_OK && !pCsr->bEof
|
||||
&& (eType!=FTS5_VOCAB_INSTANCE
|
||||
|| pCsr->pFts5->pConfig->eDetail!=FTS5_DETAIL_NONE)
|
||||
if( rc==SQLITE_OK
|
||||
&& !pCsr->bEof
|
||||
&& (eType!=FTS5_VOCAB_INSTANCE || pCsr->pConfig->eDetail!=FTS5_DETAIL_NONE)
|
||||
){
|
||||
rc = fts5VocabNextMethod(pCursor);
|
||||
}
|
||||
@@ -675,7 +657,7 @@ static int fts5VocabColumnMethod(
|
||||
int iCol /* Index of column to read value from */
|
||||
){
|
||||
Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
|
||||
int eDetail = pCsr->pFts5->pConfig->eDetail;
|
||||
int eDetail = pCsr->pConfig->eDetail;
|
||||
int eType = ((Fts5VocabTable*)(pCursor->pVtab))->eType;
|
||||
i64 iVal = 0;
|
||||
|
||||
@@ -687,7 +669,7 @@ static int fts5VocabColumnMethod(
|
||||
assert( iCol==1 || iCol==2 || iCol==3 );
|
||||
if( iCol==1 ){
|
||||
if( eDetail!=FTS5_DETAIL_NONE ){
|
||||
const char *z = pCsr->pFts5->pConfig->azCol[pCsr->iCol];
|
||||
const char *z = pCsr->pConfig->azCol[pCsr->iCol];
|
||||
sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC);
|
||||
}
|
||||
}else if( iCol==2 ){
|
||||
@@ -715,8 +697,8 @@ static int fts5VocabColumnMethod(
|
||||
}else if( eDetail==FTS5_DETAIL_COLUMNS ){
|
||||
ii = (int)pCsr->iInstPos;
|
||||
}
|
||||
if( ii>=0 && ii<pCsr->pFts5->pConfig->nCol ){
|
||||
const char *z = pCsr->pFts5->pConfig->azCol[ii];
|
||||
if( ii>=0 && ii<pCsr->pConfig->nCol ){
|
||||
const char *z = pCsr->pConfig->azCol[ii];
|
||||
sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -38,7 +38,8 @@ do_execsql_test 1.0 {
|
||||
do_execsql_test 1.1 {
|
||||
DROP TABLE t1;
|
||||
SELECT name, sql FROM sqlite_master;
|
||||
} {}
|
||||
} {
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@@ -427,7 +428,7 @@ proc funk {} {
|
||||
db eval { UPDATE n1_config SET v=50 WHERE k='version' }
|
||||
set fd [db incrblob main n1_data block 10]
|
||||
fconfigure $fd -encoding binary -translation binary
|
||||
# puts -nonewline $fd "\x44\x45"
|
||||
puts -nonewline $fd "\x44\x45"
|
||||
close $fd
|
||||
}
|
||||
db func funk funk
|
||||
@@ -603,38 +604,6 @@ do_execsql_test 23.2 {
|
||||
SELECT * FROM t11, t10 WHERE t10.rowid IS NULL;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
do_execsql_test 24.0 {
|
||||
CREATE VIRTUAL TABLE t12 USING fts5(x, detail=%DETAIL%);
|
||||
INSERT INTO t12 VALUES('aaaa');
|
||||
}
|
||||
do_execsql_test 24.1 {
|
||||
BEGIN;
|
||||
DELETE FROM t12 WHERE rowid=1;
|
||||
SELECT * FROM t12('aaaa');
|
||||
INSERT INTO t12 VALUES('aaaa');
|
||||
END;
|
||||
}
|
||||
do_execsql_test 24.2 {
|
||||
INSERT INTO t12(t12) VALUES('integrity-check');
|
||||
}
|
||||
do_execsql_test 24.3 {
|
||||
SELECT * FROM t12('aaaa');
|
||||
} {aaaa}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
do_execsql_test 25.0 {
|
||||
CREATE VIRTUAL TABLE t13 USING fts5(x, detail=%DETAIL%);
|
||||
}
|
||||
do_execsql_test 25.1 {
|
||||
BEGIN;
|
||||
INSERT INTO t13 VALUES('AAAA');
|
||||
SELECT * FROM t13('BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB*');
|
||||
|
||||
END;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
expand_all_sql db
|
||||
|
||||
@@ -51,12 +51,6 @@ do_execsql_test 1.1 {
|
||||
do_execsql_test 1.2 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
SAVEPOINT one;
|
||||
INSERT INTO t1 VALUES('v w x');
|
||||
ROLLBACK TO one;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -144,14 +144,6 @@ do_execsql_test 3.1 {
|
||||
{[a b c d e]}
|
||||
}
|
||||
|
||||
do_execsql_test 3.2 {
|
||||
SELECT highlight(ft, 0, NULL, NULL) FROM ft WHERE ft MATCH 'a+b+c AND c+d+e';
|
||||
} {
|
||||
{a b c x c d e}
|
||||
{a b c c d e}
|
||||
{a b c d e}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -275,37 +275,6 @@ do_execsql_test 9.3 {
|
||||
9 10
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that aux. functions may not be used in aggregate queries.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 10.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x, y, z);
|
||||
INSERT INTO t1 VALUES('a', 'one two', 1);
|
||||
INSERT INTO t1 VALUES('b', 'two three', 2);
|
||||
INSERT INTO t1 VALUES('c', 'three four', 1);
|
||||
INSERT INTO t1 VALUES('d', 'four five', 2);
|
||||
INSERT INTO t1 VALUES('e', 'five six', 1);
|
||||
INSERT INTO t1 VALUES('f', 'six seven', 2);
|
||||
}
|
||||
|
||||
proc firstcol {cmd} { $cmd xColumnText 0 }
|
||||
sqlite3_fts5_create_function db firstcol firstcol
|
||||
|
||||
do_execsql_test 10.1.1 {
|
||||
SELECT firstcol(t1) FROM t1
|
||||
} {a b c d e f}
|
||||
do_execsql_test 10.1.2 {
|
||||
SELECT group_concat(x, '.') FROM t1
|
||||
} {a.b.c.d.e.f}
|
||||
|
||||
do_catchsql_test 10.1.3 {
|
||||
SELECT group_concat(firstcol(t1), '.') FROM t1
|
||||
} {1 {unable to use function firstcol in the requested context}}
|
||||
|
||||
do_catchsql_test 10.1.4 {
|
||||
SELECT group_concat(firstcol(t1), '.') FROM t1 GROUP BY rowid
|
||||
} {1 {unable to use function firstcol in the requested context}}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
# 2018 Dec 22
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing the FTS5 module.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5circref
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE tt USING fts5(a);
|
||||
SELECT name FROM sqlite_master ORDER BY 1;
|
||||
} {
|
||||
tt tt_config tt_content tt_data tt_docsize tt_idx
|
||||
}
|
||||
db_save_and_close
|
||||
|
||||
foreach {tn schema sql} {
|
||||
1 {
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON tt_config BEGIN
|
||||
SELECT * FROM tt;
|
||||
END;
|
||||
} {
|
||||
INSERT INTO tt(tt, rank) VALUES('usermerge', 4);
|
||||
}
|
||||
|
||||
2 {
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON tt_docsize BEGIN
|
||||
SELECT * FROM tt;
|
||||
END;
|
||||
} {
|
||||
INSERT INTO tt(a) VALUES('one two three');
|
||||
}
|
||||
|
||||
3 {
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON tt_content BEGIN
|
||||
SELECT * FROM tt;
|
||||
END;
|
||||
} {
|
||||
INSERT INTO tt(a) VALUES('one two three');
|
||||
}
|
||||
|
||||
4 {
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON tt_data BEGIN
|
||||
SELECT * FROM tt;
|
||||
END;
|
||||
} {
|
||||
INSERT INTO tt(a) VALUES('one two three');
|
||||
}
|
||||
|
||||
5 {
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON tt_idx BEGIN
|
||||
SELECT * FROM tt;
|
||||
END;
|
||||
} {
|
||||
INSERT INTO tt(a) VALUES('one two three');
|
||||
}
|
||||
} {
|
||||
db_restore_and_reopen
|
||||
do_execsql_test 1.1.$tn.1 $schema
|
||||
do_catchsql_test 1.1.$tn.2 $sql {1 {SQL logic error}}
|
||||
db close
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -253,45 +253,5 @@ do_execsql_test 6.2 {
|
||||
SELECT name FROM sqlite_master;
|
||||
} {}
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Check that an fts5 table cannot be its own content table.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 7.1.1 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a, c=t1 );
|
||||
INSERT INTO t1( a ) VALUES('abc');
|
||||
}
|
||||
do_catchsql_test 7.1.2 {
|
||||
SELECT * FROM t1;
|
||||
} {1 {recursively defined fts5 content table}}
|
||||
do_catchsql_test 7.1.3 {
|
||||
SELECT * FROM t1('abc');
|
||||
} {1 {recursively defined fts5 content table}}
|
||||
do_catchsql_test 7.1.4 {
|
||||
SELECT count(*) FROM t1;
|
||||
} {1 {recursively defined fts5 content table}}
|
||||
do_catchsql_test 7.1.5 {
|
||||
SELECT * FROM t1('abc') ORDER BY rank;
|
||||
} {1 {recursively defined fts5 content table}}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 7.2.1 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a, c=t2 );
|
||||
CREATE VIRTUAL TABLE t2 USING fts5(a, c=t1 );
|
||||
INSERT INTO t1( a ) VALUES('abc');
|
||||
}
|
||||
do_catchsql_test 7.2.2 {
|
||||
SELECT * FROM t1;
|
||||
} {1 {recursively defined fts5 content table}}
|
||||
do_catchsql_test 7.2.3 {
|
||||
SELECT * FROM t1('abc');
|
||||
} {1 {recursively defined fts5 content table}}
|
||||
do_catchsql_test 7.2.4 {
|
||||
SELECT count(*) FROM t1;
|
||||
} {1 {recursively defined fts5 content table}}
|
||||
do_catchsql_test 7.2.5 {
|
||||
SELECT * FROM t1('abc') ORDER BY rank;
|
||||
} {1 {recursively defined fts5 content table}}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
+4
-9698
File diff suppressed because one or more lines are too long
@@ -1,61 +0,0 @@
|
||||
# 2019 May 16
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5corrupt4
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
sqlite3_fts5_may_be_corrupt 1
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE ttt USING fts5(a, b);
|
||||
INSERT INTO ttt
|
||||
VALUES('e ee eee e ee eee e ee eee', 'eee ee e e e ee eee ee ee');
|
||||
INSERT INTO ttt SELECT a||a, b||b FROM ttt;
|
||||
INSERT INTO ttt SELECT a||a, b||b FROM ttt;
|
||||
}
|
||||
|
||||
proc mutate {blob i} {
|
||||
set o [expr {$i % [string length $blob]}]
|
||||
set a [string range $blob 0 $o-1]
|
||||
set b [string range $blob $o+1 end]
|
||||
set v [expr int(rand()*255) - 127]
|
||||
return "$a[binary format c $v]$b"
|
||||
}
|
||||
db func mutate mutate
|
||||
|
||||
for {set j 1000} {$j <= 5000} {incr j 1000} {
|
||||
do_test 1.$j {
|
||||
for {set i 0} {$i < 1000} {incr i} {
|
||||
execsql {
|
||||
BEGIN;
|
||||
UPDATE ttt_data SET block = mutate(block, $i) WHERE id>10;
|
||||
}
|
||||
foreach sql {
|
||||
{SELECT snippet(ttt, -1, '.', '..', '[', ']'), * FROM ttt('e*')}
|
||||
{SELECT snippet(ttt, -1, '.', '..', '[', ']'), * FROM ttt('e* NOT ee*')}
|
||||
} {
|
||||
catch { execsql $sql }
|
||||
}
|
||||
execsql ROLLBACK
|
||||
}
|
||||
} {}
|
||||
}
|
||||
|
||||
sqlite3_fts5_may_be_corrupt 0
|
||||
finish_test
|
||||
|
||||
@@ -59,27 +59,10 @@ do_catchsql_test 2.1 {
|
||||
SELECT fts5_expr()
|
||||
} {1 {wrong number of arguments to function fts5_expr}}
|
||||
|
||||
do_catchsql_test 2.2 {
|
||||
do_catchsql_test 2.1 {
|
||||
SELECT fts5_expr_tcl()
|
||||
} {1 {wrong number of arguments to function fts5_expr_tcl}}
|
||||
|
||||
do_catchsql_test 2.3 {
|
||||
SELECT fts5_expr('')
|
||||
} {1 {fts5: syntax error near ""}}
|
||||
|
||||
do_catchsql_test 2.4 {
|
||||
SELECT fts5_expr(NULL)
|
||||
} {1 {fts5: syntax error near ""}}
|
||||
|
||||
do_catchsql_test 2.5 {
|
||||
SELECT fts5_expr(NULL, NULL)
|
||||
} {1 {parse error in ""}}
|
||||
|
||||
for {set i 0} {$i < 255} {incr i} {
|
||||
do_test 2.6.$i {
|
||||
lindex [catchsql {sELECT fts5_expr(NULL, char($i));}] 0
|
||||
} 1
|
||||
}
|
||||
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE e1 USING fts5(text, tokenize = 'porter unicode61');
|
||||
|
||||
@@ -147,27 +147,5 @@ do_faultsim_test 5.1 -faults oom* -body {
|
||||
faultsim_test_result {0 {1 4}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test OOM injection in a query with two MATCH expressions
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 6.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a);
|
||||
INSERT INTO t1 VALUES('a b c d'); -- 1
|
||||
INSERT INTO t1 VALUES('d a b c'); -- 2
|
||||
INSERT INTO t1 VALUES('c d a b'); -- 3
|
||||
INSERT INTO t1 VALUES('b c d a'); -- 4
|
||||
}
|
||||
do_faultsim_test 6.1 -faults oom* -body {
|
||||
execsql { SELECT rowid FROM t1 WHERE t1 MATCH 'a' AND t1 MATCH 'b' }
|
||||
} -test {
|
||||
faultsim_test_result {0 {1 2 3 4}}
|
||||
}
|
||||
do_faultsim_test 6.2 -faults oom* -body {
|
||||
execsql { SELECT rowid FROM t1 WHERE t1 MATCH 'a OR b' AND t1 MATCH 'c OR d' }
|
||||
} -test {
|
||||
faultsim_test_result {0 {1 2 3 4}}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -36,7 +36,7 @@ do_test 1.1 {
|
||||
execsql { INSERT INTO x8 VALUES( rnddoc(5) ); }
|
||||
}
|
||||
} msg] $msg
|
||||
} {0 {}}
|
||||
} {1 {database or disk is full}}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -210,76 +210,4 @@ foreach {tn pgsz} {
|
||||
} {1000}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 7.0 {
|
||||
PRAGMA encoding = 'UTF-16';
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(c0);
|
||||
INSERT INTO vt0 VALUES (x'46f0');
|
||||
SELECT quote(c0) FROM vt0;
|
||||
} {X'46F0'}
|
||||
do_execsql_test 7.1 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
do_execsql_test 7.2 {
|
||||
INSERT INTO vt0(vt0) VALUES('rebuild');
|
||||
}
|
||||
do_execsql_test 7.3 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
do_execsql_test 7.4 {
|
||||
UPDATE vt0 SET c0='';
|
||||
}
|
||||
do_execsql_test 7.5 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Ticket 7a458c2a5f4
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 8.0 {
|
||||
PRAGMA locking_mode = EXCLUSIVE;
|
||||
PRAGMA journal_mode = PERSIST;
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(c0);
|
||||
} {exclusive persist}
|
||||
do_execsql_test 8.1 {
|
||||
PRAGMA data_version
|
||||
} {1}
|
||||
do_execsql_test 8.2 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
PRAGMA data_version;
|
||||
} {1}
|
||||
do_execsql_test 8.1 {
|
||||
INSERT INTO vt0(vt0, rank) VALUES('usermerge', 2);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Ticket [771fe617]
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 9.0 {
|
||||
PRAGMA encoding = 'UTF16';
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(c0);
|
||||
}
|
||||
|
||||
#explain_i { SELECT quote(SUBSTR(x'37', 0)); }
|
||||
#execsql { PRAGMA vdbe_trace = 1 }
|
||||
do_execsql_test 9.1.1 {
|
||||
SELECT quote(SUBSTR(x'37', 0));
|
||||
} {X'37'}
|
||||
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');
|
||||
}
|
||||
do_execsql_test 9.3 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
# 2019 Jan 4
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing the FTS5 module.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5interrupt
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a);
|
||||
INSERT INTO t1(t1, rank) VALUES('pgsz', 40);
|
||||
}
|
||||
db_save_and_close
|
||||
|
||||
proc progress_handler {args} {
|
||||
incr ::progress_handler_delay -1
|
||||
if {$::progress_handler_delay<=0} { return 1 }
|
||||
return 0
|
||||
}
|
||||
|
||||
foreach {tn sql} {
|
||||
1 { INSERT INTO t1(rowid, a) VALUES(0, 'z z z z') }
|
||||
2 { COMMIT }
|
||||
} {
|
||||
set bDone 0
|
||||
for {set i 1} {$bDone==0} {incr i} {
|
||||
do_test 1.$tn.$i {
|
||||
db_restore_and_reopen
|
||||
execsql {
|
||||
BEGIN;
|
||||
INSERT INTO t1(rowid, a) VALUES(1, 'a b c d');
|
||||
INSERT INTO t1(rowid, a) VALUES(2, 'd e f g');
|
||||
INSERT INTO t1(rowid, a) VALUES(3, 'h i j k');
|
||||
INSERT INTO t1(rowid, a) VALUES(4, 'l m n o');
|
||||
}
|
||||
|
||||
set ::progress_handler_delay $i
|
||||
db progress 1 progress_handler
|
||||
set res [catchsql $sql]
|
||||
db close
|
||||
if {$res=="0 {}"} {
|
||||
set bDone 1
|
||||
} else {
|
||||
if {$res!="1 interrupted"} { error "got: $res" }
|
||||
}
|
||||
set {} {}
|
||||
} {}
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -491,33 +491,4 @@ do_catchsql_test 14.2 {
|
||||
SELECT matchinfo(x1, 'd') FROM x1('a b c');
|
||||
} {1 {unrecognized matchinfo flag: d}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test using matchinfo() and similar on a non-full-text query
|
||||
#
|
||||
do_execsql_test 15.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x, y);
|
||||
INSERT INTO t1 VALUES('a', 'b');
|
||||
INSERT INTO t1 VALUES('c', 'd');
|
||||
}
|
||||
|
||||
if {$tcl_platform(byteOrder)=="littleEndian"} {
|
||||
set res {X'02000000'}
|
||||
} else {
|
||||
set res {X'00000002'}
|
||||
}
|
||||
do_execsql_test 15.1 {
|
||||
SELECT quote(matchinfo(t1, 'n')) FROM t1 LIMIT 1;
|
||||
} $res
|
||||
do_execsql_test 15.2 {
|
||||
DELETE FROM t1_content WHERE rowid=1;
|
||||
SELECT quote(matchinfo(t1, 'n')) FROM t1 LIMIT 1;
|
||||
} $res
|
||||
|
||||
fts5_aux_test_functions db
|
||||
do_execsql_test 15.3 {
|
||||
SELECT fts5_test_all(t1) FROM t1 LIMIT 1;
|
||||
} {
|
||||
{columnsize {0 0} columntext {c d} columntotalsize {2 2} poslist {} tokenize {c d} rowcount 2}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -1,327 +0,0 @@
|
||||
# 2019 September 02
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing the FTS5 module.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5misc
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a);
|
||||
}
|
||||
|
||||
do_catchsql_test 1.1.1 {
|
||||
SELECT highlight(t1, 4, '<b>', '</b>') FROM t1('*');
|
||||
} {1 {unknown special query: }}
|
||||
do_catchsql_test 1.1.2 {
|
||||
SELECT a FROM t1
|
||||
WHERE rank = (SELECT highlight(t1, 4, '<b>', '</b>') FROM t1('*'));
|
||||
} {1 {unknown special query: }}
|
||||
|
||||
do_catchsql_test 1.2.1 {
|
||||
SELECT highlight(t1, 4, '<b>', '</b>') FROM t1('*id');
|
||||
} {0 {{}}}
|
||||
|
||||
do_catchsql_test 1.2.2 {
|
||||
SELECT a FROM t1
|
||||
WHERE rank = (SELECT highlight(t1, 4, '<b>', '</b>') FROM t1('*id'));
|
||||
} {0 {}}
|
||||
|
||||
do_catchsql_test 1.3.1 {
|
||||
SELECT highlight(t1, 4, '<b>', '</b>') FROM t1('*reads');
|
||||
} {1 {no such cursor: 1}}
|
||||
|
||||
do_catchsql_test 1.3.2 {
|
||||
SELECT a FROM t1
|
||||
WHERE rank = (SELECT highlight(t1, 4, '<b>', '</b>') FROM t1('*reads'));
|
||||
} {1 {no such cursor: 1}}
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
|
||||
do_catchsql_test 1.3.3 {
|
||||
SELECT a FROM t1
|
||||
WHERE rank = (SELECT highlight(t1, 4, '<b>', '</b>') FROM t1('*reads'));
|
||||
} {1 {no such cursor: 1}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE t0(c0);
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(c0);
|
||||
}
|
||||
do_execsql_test 2.1.1 {
|
||||
BEGIN TRANSACTION;
|
||||
INSERT INTO vt0(c0) VALUES ('xyz');
|
||||
}
|
||||
do_execsql_test 2.1.2 {
|
||||
ALTER TABLE t0 ADD COLUMN c5;
|
||||
}
|
||||
do_execsql_test 2.1.3 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
do_execsql_test 2.1.4 {
|
||||
INSERT INTO vt0(c0) VALUES ('abc');
|
||||
COMMIT
|
||||
}
|
||||
do_execsql_test 2.1.5 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 2.2.1 {
|
||||
CREATE TABLE t0(c0);
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(c0);
|
||||
BEGIN TRANSACTION;
|
||||
INSERT INTO vt0(c0) VALUES ('xyz');
|
||||
}
|
||||
|
||||
breakpoint
|
||||
do_execsql_test 2.2.2 {
|
||||
ALTER TABLE t0 RENAME TO t1;
|
||||
}
|
||||
do_execsql_test 2.2.3 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
do_execsql_test 2.2.4 {
|
||||
INSERT INTO vt0(c0) VALUES ('abc');
|
||||
COMMIT;
|
||||
}
|
||||
do_execsql_test 2.2.5 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(a);
|
||||
PRAGMA reverse_unordered_selects = true;
|
||||
INSERT INTO vt0 VALUES('365062398'), (0), (0);
|
||||
INSERT INTO vt0(vt0, rank) VALUES('pgsz', '38');
|
||||
}
|
||||
do_execsql_test 3.1 {
|
||||
UPDATE vt0 SET a = 399905135; -- unexpected: database disk image is malformed
|
||||
}
|
||||
do_execsql_test 3.2 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 4.0 {
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(c0);
|
||||
INSERT INTO vt0(c0) VALUES ('xyz');
|
||||
}
|
||||
|
||||
do_execsql_test 4.1 {
|
||||
BEGIN;
|
||||
INSERT INTO vt0(c0) VALUES ('abc');
|
||||
INSERT INTO vt0(vt0) VALUES('rebuild');
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_execsql_test 4.2 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_execsql_test 4.3 {
|
||||
BEGIN;
|
||||
INSERT INTO vt0(vt0) VALUES('rebuild');
|
||||
INSERT INTO vt0(vt0) VALUES('rebuild');
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_execsql_test 4.4 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Ticket [81a7f7b9].
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 5.0 {
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(c0, c1);
|
||||
INSERT INTO vt0(vt0, rank) VALUES('pgsz', '65536');
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1236
|
||||
)
|
||||
INSERT INTO vt0(c0) SELECT '0' FROM s;
|
||||
} {}
|
||||
|
||||
do_execsql_test 5.1 {
|
||||
UPDATE vt0 SET c1 = 'T,D&p^y/7#3*v<b<4j7|f';
|
||||
}
|
||||
|
||||
do_execsql_test 5.2 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_catchsql_test 5.3 {
|
||||
INSERT INTO vt0(vt0, rank) VALUES('pgsz', '65537');
|
||||
} {1 {SQL logic error}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Ticket [d392017c].
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 6.0 {
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(c0);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<10000
|
||||
)
|
||||
INSERT INTO vt0(c0) SELECT '0' FROM s;
|
||||
INSERT INTO vt0(vt0, rank) VALUES('crisismerge', 2000);
|
||||
INSERT INTO vt0(vt0, rank) VALUES('automerge', 0);
|
||||
} {}
|
||||
|
||||
do_execsql_test 6.1 {
|
||||
INSERT INTO vt0(vt0) VALUES('rebuild');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 7.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x);
|
||||
INSERT INTO t1(rowid, x) VALUES(1, 'hello world');
|
||||
INSERT INTO t1(rowid, x) VALUES(2, 'well said');
|
||||
INSERT INTO t1(rowid, x) VALUES(3, 'hello said');
|
||||
INSERT INTO t1(rowid, x) VALUES(4, 'well world');
|
||||
|
||||
CREATE TABLE t2 (a, b);
|
||||
INSERT INTO t2 VALUES(1, 'hello');
|
||||
INSERT INTO t2 VALUES(2, 'world');
|
||||
INSERT INTO t2 VALUES(3, 'said');
|
||||
INSERT INTO t2 VALUES(4, 'hello');
|
||||
}
|
||||
|
||||
do_execsql_test 7.1 {
|
||||
SELECT rowid FROM t1 WHERE (rowid, x) IN (SELECT a, b FROM t2);
|
||||
}
|
||||
|
||||
do_execsql_test 7.2 {
|
||||
SELECT rowid FROM t1 WHERE rowid=2 AND t1 = 'hello';
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 8.0 {
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(c0, tokenize = "ascii", prefix = 1);
|
||||
INSERT INTO vt0(c0) VALUES (x'd1');
|
||||
}
|
||||
|
||||
do_execsql_test 8.1 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 9.0 {
|
||||
CREATE VIRTUAL TABLE t1 using FTS5(mailcontent);
|
||||
insert into t1(rowid, mailcontent) values
|
||||
(-4764623217061966105, 'we are going to upgrade'),
|
||||
(8324454597464624651, 'we are going to upgrade');
|
||||
}
|
||||
|
||||
do_execsql_test 9.1 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_execsql_test 9.2 {
|
||||
SELECT rowid FROM t1('upgrade');
|
||||
} {
|
||||
-4764623217061966105 8324454597464624651
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 10.0 {
|
||||
CREATE VIRTUAL TABLE vt1 USING fts5(c1, c2, prefix = 1, tokenize = "ascii");
|
||||
INSERT INTO vt1 VALUES (x'e4', '䔬');
|
||||
}
|
||||
|
||||
do_execsql_test 10.1 {
|
||||
SELECT quote(CAST(c1 AS blob)), quote(CAST(c2 AS blob)) FROM vt1
|
||||
} {X'E4' X'E494AC'}
|
||||
|
||||
do_execsql_test 10.2 {
|
||||
INSERT INTO vt1(vt1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 11.0 {
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(
|
||||
c0, prefix = 71, tokenize = "porter ascii", prefix = 9
|
||||
);
|
||||
} {}
|
||||
do_execsql_test 11.1 {
|
||||
BEGIN;
|
||||
INSERT INTO vt0(c0) VALUES (x'e8');
|
||||
}
|
||||
do_execsql_test 11.2 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Ticket [752fdbf6]
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 11.0 {
|
||||
PRAGMA encoding = 'UTF-16';
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(c0, c1);
|
||||
INSERT INTO vt0(vt0, rank) VALUES('pgsz', '37');
|
||||
INSERT INTO vt0(c0, c1) VALUES (0.66077, 1957391816);
|
||||
}
|
||||
do_execsql_test 11.1 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Ticket [7c0e06b16]
|
||||
#
|
||||
do_execsql_test 12.0 {
|
||||
CREATE TABLE t1(a, b, rank);
|
||||
INSERT INTO t1 VALUES('a', 'hello', '');
|
||||
INSERT INTO t1 VALUES('b', 'world', '');
|
||||
|
||||
CREATE VIRTUAL TABLE ft USING fts5(a);
|
||||
INSERT INTO ft VALUES('b');
|
||||
INSERT INTO ft VALUES('y');
|
||||
|
||||
CREATE TABLE t2(x, y, ft);
|
||||
INSERT INTO t2 VALUES(1, 2, 'x');
|
||||
INSERT INTO t2 VALUES(3, 4, 'b');
|
||||
}
|
||||
|
||||
do_execsql_test 12.1 {
|
||||
SELECT * FROM t1 NATURAL JOIN ft WHERE ft MATCH('b')
|
||||
} {b world {}}
|
||||
do_execsql_test 12.2 {
|
||||
SELECT * FROM ft NATURAL JOIN t1 WHERE ft MATCH('b')
|
||||
} {b world {}}
|
||||
do_execsql_test 12.3 {
|
||||
SELECT * FROM t2 JOIN ft USING (ft)
|
||||
} {3 4 b b}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
# 2014 September 13
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing the FTS5 module.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5multi
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
fts5_aux_test_functions db
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a, b, c);
|
||||
INSERT INTO t1 VALUES('gg bb bb' ,'gg ff gg' ,'ii ii');
|
||||
INSERT INTO t1 VALUES('dd dd hh kk','jj' ,'aa');
|
||||
INSERT INTO t1 VALUES('kk gg ee' ,'hh cc' ,'hh jj aa cc');
|
||||
INSERT INTO t1 VALUES('hh' ,'bb jj cc' ,'kk ii');
|
||||
INSERT INTO t1 VALUES('kk dd kk ii','aa ee aa' ,'ee');
|
||||
INSERT INTO t1 VALUES('ee' ,'ff gg kk aa','ee ff ee');
|
||||
INSERT INTO t1 VALUES('ff jj' ,'gg ee' ,'kk ee gg kk');
|
||||
INSERT INTO t1 VALUES('ff ee dd hh','kk ee' ,'gg dd');
|
||||
INSERT INTO t1 VALUES('bb' ,'aa' ,'bb aa');
|
||||
INSERT INTO t1 VALUES('hh cc bb' ,'ff bb' ,'cc');
|
||||
INSERT INTO t1 VALUES('jj' ,'ff dd bb aa','dd dd ff ff');
|
||||
INSERT INTO t1 VALUES('ff dd gg dd','gg aa bb ff','cc');
|
||||
INSERT INTO t1 VALUES('ff aa cc jj','kk' ,'ii dd');
|
||||
INSERT INTO t1 VALUES('jj dd' ,'cc' ,'ii hh ee aa');
|
||||
INSERT INTO t1 VALUES('ff ii hh' ,'dd' ,'gg');
|
||||
INSERT INTO t1 VALUES('ff dd gg hh','hh' ,'ff dd');
|
||||
INSERT INTO t1 VALUES('cc cc' ,'ff dd ff' ,'bb');
|
||||
INSERT INTO t1 VALUES('ii' ,'bb ii' ,'jj kk');
|
||||
INSERT INTO t1 VALUES('ff hh' ,'hh bb' ,'bb dd ee');
|
||||
INSERT INTO t1 VALUES('jj kk' ,'jj' ,'gg ff cc');
|
||||
INSERT INTO t1 VALUES('dd kk' ,'ii gg' ,'dd');
|
||||
INSERT INTO t1 VALUES('cc' ,'aa ff' ,'ii');
|
||||
INSERT INTO t1 VALUES('bb ff bb ii','bb kk bb aa','hh ff ii dd');
|
||||
INSERT INTO t1 VALUES('aa' ,'ee bb jj jj','dd');
|
||||
INSERT INTO t1 VALUES('kk dd cc' ,'aa jj' ,'ee aa ff');
|
||||
INSERT INTO t1 VALUES('aa gg aa' ,'jj' ,'ii kk hh gg');
|
||||
INSERT INTO t1 VALUES('ff hh aa' ,'jj ii' ,'hh dd bb jj');
|
||||
INSERT INTO t1 VALUES('hh' ,'aa gg kk' ,'bb ee');
|
||||
INSERT INTO t1 VALUES('bb' ,'ee' ,'gg');
|
||||
INSERT INTO t1 VALUES('dd kk' ,'kk bb aa' ,'ee');
|
||||
}
|
||||
|
||||
foreach {tn c1 e1 c2 e2} {
|
||||
1 t1 aa t1 bb
|
||||
2 a aa b bb
|
||||
3 a "aa OR bb OR cc" b "jj OR ii OR hh"
|
||||
4 t1 "aa AND bb" t1 "cc"
|
||||
5 c "kk" b "aa OR bb OR cc OR dd OR ee"
|
||||
} {
|
||||
if {$c1=="t1"} {
|
||||
set lhs "( $e1 )"
|
||||
} else {
|
||||
set lhs "$c1 : ( $e1 )"
|
||||
}
|
||||
if {$c2=="t1"} {
|
||||
set rhs "( $e2 )"
|
||||
} else {
|
||||
set rhs "$c2 : ( $e2 )"
|
||||
}
|
||||
|
||||
set q1 "t1 MATCH '($lhs) AND ($rhs)'"
|
||||
set q2 "$c1 MATCH '$e1' AND $c2 MATCH '$e2'"
|
||||
|
||||
set ret [execsql "SELECT rowid FROM t1 WHERE $q1"]
|
||||
set N [llength $ret]
|
||||
do_execsql_test 1.$tn.1.($N) "SELECT rowid FROM t1 WHERE $q2" $ret
|
||||
|
||||
set ret [execsql "SELECT fts5_test_poslist(t1) FROM t1 WHERE $q1"]
|
||||
do_execsql_test 1.$tn.2.($N) "
|
||||
SELECT fts5_test_poslist(t1) FROM t1 WHERE $q2
|
||||
" $ret
|
||||
}
|
||||
|
||||
do_catchsql_test 2.1.1 {
|
||||
SELECT rowid FROM t1 WHERE t1 MATCH '(NOT' AND t1 MATCH 'aa bb';
|
||||
} {1 {fts5: syntax error near "NOT"}}
|
||||
do_catchsql_test 2.1.2 {
|
||||
SELECT rowid FROM t1 WHERE t1 MATCH 'aa bb' AND t1 MATCH '(NOT';
|
||||
} {1 {fts5: syntax error near "NOT"}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -31,7 +31,7 @@ do_eqp_test 1.1 {
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--SCAN TABLE t1
|
||||
`--SCAN TABLE f1 VIRTUAL TABLE INDEX 0:m
|
||||
`--SCAN TABLE f1 VIRTUAL TABLE INDEX 65537:
|
||||
}
|
||||
|
||||
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:m
|
||||
|--SCAN TABLE f1 VIRTUAL TABLE INDEX 65537:
|
||||
`--USE TEMP B-TREE FOR ORDER BY
|
||||
}
|
||||
|
||||
@@ -60,6 +60,6 @@ do_eqp_test 1.4 {
|
||||
|
||||
do_eqp_test 1.5 {
|
||||
SELECT * FROM f1 WHERE rank MATCH ?
|
||||
} {SCAN TABLE f1 VIRTUAL TABLE INDEX 0:r}
|
||||
} {SCAN TABLE f1 VIRTUAL TABLE INDEX 2:}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -162,22 +162,4 @@ do_execsql_test 5.1 {
|
||||
SELECT rowid FROM ttt('word') WHERE rowid BETWEEN 30 AND 40 ORDER BY rank;
|
||||
} {30 31 32 33 34 35 36 37 38 39 40}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 6.0 {
|
||||
CREATE VIRTUAL TABLE "My.Table" USING fts5(Text);
|
||||
|
||||
INSERT INTO "My.Table" VALUES ('hello this is a test');
|
||||
INSERT INTO "My.Table" VALUES ('of trying to order by');
|
||||
INSERT INTO "My.Table" VALUES ('rank on an fts5 table');
|
||||
INSERT INTO "My.Table" VALUES ('that have periods in');
|
||||
INSERT INTO "My.Table" VALUES ('the table names.');
|
||||
INSERT INTO "My.Table" VALUES ('table table table');
|
||||
}
|
||||
do_execsql_test 6.1 {
|
||||
SELECT * FROM "My.Table" WHERE Text MATCH 'table' ORDER BY rank;
|
||||
} {
|
||||
{table table table} {the table names.} {rank on an fts5 table}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
# 2019 Dec 26
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5savepoint
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(c);
|
||||
BEGIN;
|
||||
SAVEPOINT one;
|
||||
INSERT INTO ft VALUES('a');
|
||||
SAVEPOINT two;
|
||||
INSERT INTO ft VALUES('b');
|
||||
RELEASE two;
|
||||
SAVEPOINT four;
|
||||
INSERT INTO ft VALUES('c');
|
||||
RELEASE four;
|
||||
SAVEPOINT three;
|
||||
INSERT INTO ft VALUES('d');
|
||||
ROLLBACK TO three;
|
||||
COMMIT;
|
||||
SELECT * FROM ft
|
||||
} {a b c}
|
||||
|
||||
reset_db
|
||||
do_catchsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE ft1 USING fts5(c);
|
||||
CREATE VIRTUAL TABLE ft2 USING fts5(c);
|
||||
DROP TABLE ft2_idx;
|
||||
BEGIN;
|
||||
INSERT INTO ft2 VALUES('a');
|
||||
INSERT INTO ft1 VALUES('a');
|
||||
SAVEPOINT two;
|
||||
INSERT INTO ft1 VALUES('b');
|
||||
COMMIT;
|
||||
} {1 {SQL logic error}}
|
||||
|
||||
reset_db
|
||||
ifcapable fts3 {
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(c0);
|
||||
CREATE VIRTUAL TABLE vt1 USING fts4(c0);
|
||||
INSERT INTO vt1(c0) VALUES(0);
|
||||
}
|
||||
|
||||
do_execsql_test 3.1 {
|
||||
BEGIN;
|
||||
UPDATE vt1 SET c0 = 0;
|
||||
INSERT INTO vt1(c0) VALUES (0), (0);
|
||||
UPDATE vt0 SET c0 = 0;
|
||||
INSERT INTO vt1(c0) VALUES (0);
|
||||
UPDATE vt1 SET c0 = 0;
|
||||
INSERT INTO vt1(vt1) VALUES('automerge=1');
|
||||
UPDATE vt1 SET c0 = 0;
|
||||
}
|
||||
|
||||
do_catchsql_test 3.2 {
|
||||
DROP TABLE vt1;
|
||||
} {1 {SQL logic error}}
|
||||
|
||||
do_execsql_test 3.3 {
|
||||
SAVEPOINT x;
|
||||
INSERT INTO vt0 VALUES('x');
|
||||
COMMIT;
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -467,17 +467,4 @@ do_execsql_test 21.3 {
|
||||
SELECT rowid FROM x1($doc);
|
||||
} {11112}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 22.0 {
|
||||
CREATE VIRTUAL TABLE x1 USING fts5(x);
|
||||
INSERT INTO x1(x) VALUES('a b c');
|
||||
INSERT INTO x1(x) VALUES('x y z');
|
||||
INSERT INTO x1(x) VALUES('c b a');
|
||||
INSERT INTO x1(x) VALUES('z y x');
|
||||
}
|
||||
|
||||
do_catchsql_test 22.1 {SELECT * FROM x1('')} {1 {fts5: syntax error near ""}}
|
||||
do_catchsql_test 22.2 {SELECT * FROM x1(NULL)} {1 {fts5: syntax error near ""}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -21,7 +21,7 @@ ifcapable !fts5 {
|
||||
}
|
||||
|
||||
proc fts3_unicode_path {file} {
|
||||
file join .. [file dirname [info script]] .. .. fts3 unicode $file
|
||||
file join [file dirname [info script]] .. .. fts3 unicode $file
|
||||
}
|
||||
|
||||
source [fts3_unicode_path parseunicode.tcl]
|
||||
|
||||
@@ -115,43 +115,5 @@ do_execsql_test 2.2.integrity {
|
||||
INSERT INTO x2(x2) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE x3 USING fts5(x, detail=%DETAIL%);
|
||||
INSERT INTO x3 VALUES('one');
|
||||
INSERT INTO x3 VALUES('two');
|
||||
INSERT INTO x3 VALUES('one');
|
||||
INSERT INTO x3 VALUES('two');
|
||||
INSERT INTO x3 VALUES('one');
|
||||
}
|
||||
|
||||
do_test 3.1 {
|
||||
db eval { SELECT * FROM x3('one') } {
|
||||
db eval {
|
||||
INSERT INTO x3(x3) VALUES('optimize');
|
||||
}
|
||||
}
|
||||
} {}
|
||||
|
||||
do_execsql_test 4.0 {
|
||||
CREATE VIRTUAL TABLE x4 USING fts5(a, detail=%DETAIL%);
|
||||
INSERT INTO x4 VALUES('one two three');
|
||||
INSERT INTO x4(rowid, a) VALUES('2', 'one two three');
|
||||
INSERT INTO x4(rowid, a) VALUES('3.0', 'one two three');
|
||||
}
|
||||
do_catchsql_test 4.1 {
|
||||
INSERT INTO x4(rowid, a) VALUES('four', 'one two three');
|
||||
} {1 {datatype mismatch}}
|
||||
|
||||
do_catchsql_test 4.2 {
|
||||
UPDATE x4 SET rowid = 'four' WHERE rowid=1;
|
||||
} {1 {datatype mismatch}}
|
||||
|
||||
|
||||
}
|
||||
|
||||
reset_db
|
||||
do_catchsql_test 4.0 { CREATE VIRTUAL TABLE t1 USING fts5(a,b,c); } {0 {}}
|
||||
do_catchsql_test 4.1 { DELETE FROM t1 WHERE t1 MATCH 'f*'; } {0 {}}
|
||||
finish_test
|
||||
|
||||
@@ -79,8 +79,8 @@ do_execsql_test 1.1.2 {
|
||||
3 cnt {} 0 {} 0
|
||||
}
|
||||
|
||||
do_execsql_test 1.2.1 { SELECT * FROM v1 } {}
|
||||
do_execsql_test 1.2.2 { SELECT * FROM v2 } {}
|
||||
do_execsql_test 1.2.1 { SELECT * FROM v1 } { }
|
||||
do_execsql_test 1.2.2 { SELECT * FROM v2 } { }
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
INSERT INTO t1 VALUES('x y z');
|
||||
@@ -479,79 +479,6 @@ do_test 9.6 {
|
||||
expr [lsearch $e2 SorterSort]<0
|
||||
} 0
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
do_execsql_test 10.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(a, b, c);
|
||||
CREATE VIRTUAL TABLE t2 USING fts5vocab('ft','row');
|
||||
CREATE VIRTUAL TABLE t3 USING fts5vocab('ft','row');
|
||||
}
|
||||
|
||||
do_execsql_test 10.1 {
|
||||
BEGIN;
|
||||
INSERT INTO ft(b) VALUES('x y');
|
||||
}
|
||||
|
||||
do_execsql_test 10.2 {
|
||||
SELECT t2.term FROM t2;
|
||||
} {x y}
|
||||
|
||||
do_execsql_test 10.3 {
|
||||
SELECT t2.term, t3.term FROM t2, t3;
|
||||
} {x x x y y x y y}
|
||||
|
||||
do_execsql_test 10.4 {
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_execsql_test 10.5 {
|
||||
BEGIN;
|
||||
INSERT INTO ft(a) VALUES('1 2 3');
|
||||
INSERT INTO ft(a) VALUES('4 5 6');
|
||||
INSERT INTO ft(a) VALUES('1 2 3');
|
||||
INSERT INTO ft(a) VALUES('4 5 6');
|
||||
INSERT INTO ft(a) VALUES('1 2 3');
|
||||
INSERT INTO ft(a) VALUES('4 5 6');
|
||||
}
|
||||
|
||||
do_test 10.6 {
|
||||
set res [list]
|
||||
db eval { SELECT rowid FROM ft('4') } x {
|
||||
db eval { SELECT * FROM t2 }
|
||||
lappend res $x(rowid)
|
||||
}
|
||||
db eval COMMIT
|
||||
set res
|
||||
} {3 5 7}
|
||||
|
||||
do_execsql_test 10.6.1 {
|
||||
SELECT * FROM t2 WHERE term<NULL;
|
||||
}
|
||||
do_execsql_test 10.6.2 {
|
||||
SELECT * FROM t2 WHERE term>NULL;
|
||||
}
|
||||
do_execsql_test 10.6.3 {
|
||||
SELECT * FROM t2 WHERE term=NULL;
|
||||
}
|
||||
do_execsql_test 10.7.1 {
|
||||
SELECT * FROM t2 WHERE term<?;
|
||||
}
|
||||
do_execsql_test 10.7.2 {
|
||||
SELECT * FROM t2 WHERE term>?;
|
||||
}
|
||||
do_execsql_test 10.7.3 {
|
||||
SELECT * FROM t2 WHERE term=?;
|
||||
}
|
||||
|
||||
# 2020-02-16 Detect recursively define fts5vocab() tables.
|
||||
# Error found by dbsqlfuzz.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 11.100 {
|
||||
CREATE VIRTUAL TABLE t3 USING fts5vocab(rowid , 'col');
|
||||
CREATE VIRTUAL TABLE rowid USING fts5vocab(rowid , 'instance');
|
||||
} {}
|
||||
do_catchsql_test 11.110 {
|
||||
SELECT rowid+1,rowid, * FROM t3 WHERE null>rowid ;
|
||||
} {1 {SQL logic error}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -80,7 +80,8 @@ do_execsql_test 1.4 {
|
||||
do_execsql_test 1.5 {
|
||||
DELETE FROM t1;
|
||||
SELECT * FROM v1;
|
||||
} {}
|
||||
} {
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@@ -142,7 +143,8 @@ do_execsql_test 2.4 {
|
||||
do_execsql_test 2.5 {
|
||||
DELETE FROM t1;
|
||||
SELECT * FROM v1;
|
||||
} {}
|
||||
} {
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@@ -200,38 +202,7 @@ do_execsql_test 3.4 {
|
||||
do_execsql_test 3.5 {
|
||||
DELETE FROM t1;
|
||||
SELECT * FROM v1;
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 4.0 {
|
||||
CREATE VIRTUAL TABLE v1 USING fts5vocab(nosuchtable, col);
|
||||
}
|
||||
|
||||
do_catchsql_test 4.1 {
|
||||
SELECT * FROM v1 WHERE term=='nosuchterm';
|
||||
} {1 {no such fts5 table: main.nosuchtable}}
|
||||
|
||||
do_execsql_test 4.2.1 {
|
||||
CREATE TABLE nosuchtable(nosuchtable, y, z);
|
||||
}
|
||||
do_catchsql_test 4.2.2 {
|
||||
SELECT * FROM v1 WHERE term=='nosuchterm';
|
||||
} {1 {no such fts5 table: main.nosuchtable}}
|
||||
|
||||
ifcapable fts3 {
|
||||
do_execsql_test 4.3.1 {
|
||||
DROP TABLE nosuchtable;
|
||||
CREATE VIRTUAL TABLE nosuchtable USING fts3(a, b);
|
||||
} {}
|
||||
do_catchsql_test 4.3.2 {
|
||||
SELECT * FROM v1 WHERE term=='nosuchterm';
|
||||
} {1 {no such fts5 table: main.nosuchtable}}
|
||||
do_catchsql_test 4.3.3 {
|
||||
INSERT INTO nosuchtable VALUES('id', '*id');
|
||||
SELECT * FROM v1 WHERE term=='nosuchterm';
|
||||
} {1 {no such fts5 table: main.nosuchtable}}
|
||||
} {
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
+16
-17
@@ -143,7 +143,7 @@ static int icuLikeCompare(
|
||||
** 3. uPattern is an unescaped escape character, or
|
||||
** 4. uPattern is to be handled as an ordinary character
|
||||
*/
|
||||
if( uPattern==MATCH_ALL && !prevEscape && uPattern!=(uint32_t)uEsc ){
|
||||
if( !prevEscape && uPattern==MATCH_ALL ){
|
||||
/* Case 1. */
|
||||
uint8_t c;
|
||||
|
||||
@@ -169,12 +169,12 @@ static int icuLikeCompare(
|
||||
}
|
||||
return 0;
|
||||
|
||||
}else if( uPattern==MATCH_ONE && !prevEscape && uPattern!=(uint32_t)uEsc ){
|
||||
}else if( !prevEscape && uPattern==MATCH_ONE ){
|
||||
/* Case 2. */
|
||||
if( *zString==0 ) return 0;
|
||||
SQLITE_ICU_SKIP_UTF8(zString);
|
||||
|
||||
}else if( uPattern==(uint32_t)uEsc && !prevEscape ){
|
||||
}else if( !prevEscape && uPattern==(uint32_t)uEsc){
|
||||
/* Case 3. */
|
||||
prevEscape = 1;
|
||||
|
||||
@@ -499,27 +499,26 @@ static void icuLoadCollation(
|
||||
** Register the ICU extension functions with database db.
|
||||
*/
|
||||
int sqlite3IcuInit(sqlite3 *db){
|
||||
# define SQLITEICU_EXTRAFLAGS (SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS)
|
||||
static const struct IcuScalar {
|
||||
const char *zName; /* Function name */
|
||||
unsigned char nArg; /* Number of arguments */
|
||||
unsigned int enc; /* Optimal text encoding */
|
||||
unsigned short enc; /* Optimal text encoding */
|
||||
unsigned char iContext; /* sqlite3_user_data() context */
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
|
||||
} scalars[] = {
|
||||
{"icu_load_collation",2,SQLITE_UTF8|SQLITE_DIRECTONLY,1, icuLoadCollation},
|
||||
{"icu_load_collation", 2, SQLITE_UTF8, 1, icuLoadCollation},
|
||||
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
|
||||
{"regexp", 2, SQLITE_ANY|SQLITEICU_EXTRAFLAGS, 0, icuRegexpFunc},
|
||||
{"lower", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},
|
||||
{"lower", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},
|
||||
{"upper", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16},
|
||||
{"upper", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16},
|
||||
{"lower", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},
|
||||
{"lower", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},
|
||||
{"upper", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16},
|
||||
{"upper", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16},
|
||||
{"like", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc},
|
||||
{"like", 3, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc},
|
||||
{"regexp", 2, SQLITE_ANY|SQLITE_DETERMINISTIC, 0, icuRegexpFunc},
|
||||
{"lower", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
|
||||
{"lower", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
|
||||
{"upper", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, 1, icuCaseFunc16},
|
||||
{"upper", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, 1, icuCaseFunc16},
|
||||
{"lower", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
|
||||
{"lower", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
|
||||
{"upper", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, 1, icuCaseFunc16},
|
||||
{"upper", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 1, icuCaseFunc16},
|
||||
{"like", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc},
|
||||
{"like", 3, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc},
|
||||
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
|
||||
};
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
+2
-2
@@ -43,10 +43,10 @@ LSMTESTSRC = $(LSMDIR)/lsm-test/lsmtest1.c $(LSMDIR)/lsm-test/lsmtest2.c \
|
||||
|
||||
# all: lsm.so
|
||||
|
||||
LSMOPTS += -fPIC -DLSM_MUTEX_PTHREADS=1 -I$(LSMDIR) -DHAVE_ZLIB
|
||||
LSMOPTS += -DLSM_MUTEX_PTHREADS=1 -I$(LSMDIR) -DHAVE_ZLIB
|
||||
|
||||
lsm.so: $(LSMOBJ)
|
||||
$(TCCX) -shared -fPIC -o lsm.so $(LSMOBJ)
|
||||
$(TCCX) -shared -o lsm.so $(LSMOBJ)
|
||||
|
||||
%.o: $(LSMDIR)/%.c $(LSMHDR) sqlite3.h
|
||||
$(TCCX) $(LSMOPTS) -c $<
|
||||
|
||||
+1
-1
@@ -842,7 +842,7 @@ static int lsm1BestIndex(
|
||||
|
||||
const struct sqlite3_index_constraint *pConstraint;
|
||||
pConstraint = pIdxInfo->aConstraint;
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
|
||||
for(i=0; i<pIdxInfo->nConstraint && idxNum<16; i++, pConstraint++){
|
||||
if( pConstraint->usable==0 ) continue;
|
||||
if( pConstraint->iColumn!=0 ) continue;
|
||||
switch( pConstraint->op ){
|
||||
|
||||
@@ -88,65 +88,6 @@ do_execsql_test 210 {
|
||||
do_execsql_test 211 {
|
||||
SELECT quote(a), quote(lsm1_key), quote(lsm1_value), '|' FROM x1;
|
||||
} {'12' X'3132' X'05320000000000000A401FFB42ABE9DB' | '15' X'3135' X'4284C6' | '8' X'38' X'2162616E6A6F1633323105' |}
|
||||
do_execsql_test 212 {
|
||||
SELECT quote(a), quote(lsm1_key), quote(lsm1_value) FROM x1 WHERE a='12';
|
||||
} {'12' X'3132' X'05320000000000000A401FFB42ABE9DB'}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
forcedelete testlsm.db
|
||||
load_lsm1_vtab db
|
||||
do_execsql_test 300 {
|
||||
CREATE VIRTUAL TABLE x1 USING lsm1(testlsm.db,a,TEXT,b,c,d);
|
||||
}
|
||||
do_eqp_test 310 {
|
||||
SELECT * FROM x1 WHERE a=?
|
||||
} {SCAN TABLE x1 VIRTUAL TABLE INDEX 0:}
|
||||
|
||||
do_eqp_test 320 {
|
||||
SELECT * FROM x1 WHERE a>?
|
||||
} {SCAN TABLE x1 VIRTUAL TABLE INDEX 2:}
|
||||
|
||||
do_eqp_test 330 {
|
||||
SELECT * FROM x1 WHERE a<?
|
||||
} {SCAN TABLE x1 VIRTUAL TABLE INDEX 3:}
|
||||
do_eqp_test 340 {
|
||||
SELECT * FROM x1 WHERE a BETWEEN ? AND ?
|
||||
} {SCAN TABLE x1 VIRTUAL TABLE INDEX 1:}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
forcedelete testlsm.db
|
||||
load_lsm1_vtab db
|
||||
do_execsql_test 400 {
|
||||
CREATE VIRTUAL TABLE x1 USING lsm1(testlsm.db,a,TEXT,b);
|
||||
INSERT INTO x1 VALUES('one', 1);
|
||||
INSERT INTO x1 VALUES('two', 2);
|
||||
INSERT INTO x1 VALUES('three', 3);
|
||||
INSERT INTO x1 VALUES('four', 4);
|
||||
INSERT INTO x1 VALUES('five', 5);
|
||||
}
|
||||
do_execsql_test 410 {
|
||||
SELECT b FROM x1 WHERE a = 'two'
|
||||
} {2}
|
||||
do_execsql_test 411 {
|
||||
SELECT b FROM x1 WHERE a = 'one'
|
||||
} {1}
|
||||
do_execsql_test 412 {
|
||||
SELECT b FROM x1 WHERE a = 'five'
|
||||
} {5}
|
||||
|
||||
do_execsql_test 420 {
|
||||
SELECT b FROM x1 WHERE a BETWEEN 'one' AND 'three';
|
||||
} {1 3}
|
||||
do_execsql_test 421 {
|
||||
SELECT b FROM x1 WHERE a BETWEEN 'five' AND 'two';
|
||||
} {5 4 1 3 2}
|
||||
do_execsql_test 421 {
|
||||
SELECT b FROM x1 WHERE a > 'five';
|
||||
} {4 1 3 2}
|
||||
do_execsql_test 421 {
|
||||
SELECT b FROM x1 WHERE a <= 'three';
|
||||
} {3 1 4 5}
|
||||
|
||||
finish_test
|
||||
|
||||
+6
-7
@@ -619,7 +619,7 @@ static int amatchLoadOneRule(
|
||||
if( p->rDel==0 || p->rDel>rCost ) p->rDel = rCost;
|
||||
}else
|
||||
{
|
||||
pRule = sqlite3_malloc64( sizeof(*pRule) + nFrom + nTo );
|
||||
pRule = sqlite3_malloc( sizeof(*pRule) + nFrom + nTo );
|
||||
if( pRule==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -738,16 +738,16 @@ static int amatchLoadRules(
|
||||
** `mno` becomes mno
|
||||
*/
|
||||
static char *amatchDequote(const char *zIn){
|
||||
sqlite3_int64 nIn; /* Size of input string, in bytes */
|
||||
int nIn; /* Size of input string, in bytes */
|
||||
char *zOut; /* Output (dequoted) string */
|
||||
|
||||
nIn = strlen(zIn);
|
||||
zOut = sqlite3_malloc64(nIn+1);
|
||||
nIn = (int)strlen(zIn);
|
||||
zOut = sqlite3_malloc(nIn+1);
|
||||
if( zOut ){
|
||||
char q = zIn[0]; /* Quote character (if any ) */
|
||||
|
||||
if( q!='[' && q!= '\'' && q!='"' && q!='`' ){
|
||||
memcpy(zOut, zIn, (size_t)(nIn+1));
|
||||
memcpy(zOut, zIn, nIn+1);
|
||||
}else{
|
||||
int iOut = 0; /* Index of next byte to write to output */
|
||||
int iIn; /* Index of next byte to read from input */
|
||||
@@ -900,7 +900,6 @@ static int amatchConnect(
|
||||
rc = amatchLoadRules(db, pNew, pzErr);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
|
||||
rc = sqlite3_declare_vtab(db,
|
||||
"CREATE TABLE x(word,distance,language,"
|
||||
"command HIDDEN,nword HIDDEN)"
|
||||
@@ -1070,7 +1069,7 @@ static void amatchAddWord(
|
||||
}
|
||||
return;
|
||||
}
|
||||
pWord = sqlite3_malloc64( sizeof(*pWord) + nBase + nTail - 1 );
|
||||
pWord = sqlite3_malloc( sizeof(*pWord) + nBase + nTail - 1 );
|
||||
if( pWord==0 ) return;
|
||||
memset(pWord, 0, sizeof(*pWord));
|
||||
pWord->rCost = rCost;
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
** 2019-03-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.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** An SQL function that uses the incremental BLOB I/O mechanism of SQLite
|
||||
** to read or write part of a blob. This is intended for debugging use
|
||||
** in the CLI.
|
||||
**
|
||||
** readblob(SCHEMA,TABLE,COLUMN,ROWID,OFFSET,N)
|
||||
**
|
||||
** Returns N bytes of the blob starting at OFFSET.
|
||||
**
|
||||
** writeblob(SCHEMA,TABLE,COLUMN,ROWID,OFFSET,NEWDATA)
|
||||
**
|
||||
** NEWDATA must be a blob. The content of NEWDATA overwrites the
|
||||
** existing BLOB data at SCHEMA.TABLE.COLUMN for row ROWID beginning
|
||||
** at OFFSET bytes into the blob.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
static void readblobFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
sqlite3_blob *pBlob = 0;
|
||||
const char *zSchema;
|
||||
const char *zTable;
|
||||
const char *zColumn;
|
||||
sqlite3_int64 iRowid;
|
||||
int iOfst;
|
||||
unsigned char *aData;
|
||||
int nData;
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
|
||||
zSchema = (const char*)sqlite3_value_text(argv[0]);
|
||||
zTable = (const char*)sqlite3_value_text(argv[1]);
|
||||
if( zTable==0 ){
|
||||
sqlite3_result_error(context, "bad table name", -1);
|
||||
return;
|
||||
}
|
||||
zColumn = (const char*)sqlite3_value_text(argv[2]);
|
||||
if( zTable==0 ){
|
||||
sqlite3_result_error(context, "bad column name", -1);
|
||||
return;
|
||||
}
|
||||
iRowid = sqlite3_value_int64(argv[3]);
|
||||
iOfst = sqlite3_value_int(argv[4]);
|
||||
nData = sqlite3_value_int(argv[5]);
|
||||
if( nData<=0 ) return;
|
||||
aData = sqlite3_malloc64( nData+1 );
|
||||
if( aData==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
return;
|
||||
}
|
||||
db = sqlite3_context_db_handle(context);
|
||||
rc = sqlite3_blob_open(db, zSchema, zTable, zColumn, iRowid, 0, &pBlob);
|
||||
if( rc ){
|
||||
sqlite3_free(aData);
|
||||
sqlite3_result_error(context, "cannot open BLOB pointer", -1);
|
||||
return;
|
||||
}
|
||||
rc = sqlite3_blob_read(pBlob, aData, nData, iOfst);
|
||||
sqlite3_blob_close(pBlob);
|
||||
if( rc ){
|
||||
sqlite3_free(aData);
|
||||
sqlite3_result_error(context, "BLOB read failed", -1);
|
||||
}else{
|
||||
sqlite3_result_blob(context, aData, nData, sqlite3_free);
|
||||
}
|
||||
}
|
||||
|
||||
static void writeblobFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
sqlite3_blob *pBlob = 0;
|
||||
const char *zSchema;
|
||||
const char *zTable;
|
||||
const char *zColumn;
|
||||
sqlite3_int64 iRowid;
|
||||
int iOfst;
|
||||
unsigned char *aData;
|
||||
int nData;
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
|
||||
zSchema = (const char*)sqlite3_value_text(argv[0]);
|
||||
zTable = (const char*)sqlite3_value_text(argv[1]);
|
||||
if( zTable==0 ){
|
||||
sqlite3_result_error(context, "bad table name", -1);
|
||||
return;
|
||||
}
|
||||
zColumn = (const char*)sqlite3_value_text(argv[2]);
|
||||
if( zTable==0 ){
|
||||
sqlite3_result_error(context, "bad column name", -1);
|
||||
return;
|
||||
}
|
||||
iRowid = sqlite3_value_int64(argv[3]);
|
||||
iOfst = sqlite3_value_int(argv[4]);
|
||||
if( sqlite3_value_type(argv[5])!=SQLITE_BLOB ){
|
||||
sqlite3_result_error(context, "6th argument must be a BLOB", -1);
|
||||
return;
|
||||
}
|
||||
nData = sqlite3_value_bytes(argv[5]);
|
||||
aData = (unsigned char *)sqlite3_value_blob(argv[5]);
|
||||
db = sqlite3_context_db_handle(context);
|
||||
rc = sqlite3_blob_open(db, zSchema, zTable, zColumn, iRowid, 1, &pBlob);
|
||||
if( rc ){
|
||||
sqlite3_result_error(context, "cannot open BLOB pointer", -1);
|
||||
return;
|
||||
}
|
||||
rc = sqlite3_blob_write(pBlob, aData, nData, iOfst);
|
||||
sqlite3_blob_close(pBlob);
|
||||
if( rc ){
|
||||
sqlite3_result_error(context, "BLOB write failed", -1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_blobio_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "readblob", 6, SQLITE_UTF8, 0,
|
||||
readblobFunc, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "writeblob", 6, SQLITE_UTF8, 0,
|
||||
writeblobFunc, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -23,7 +23,7 @@
|
||||
** rootpage INT, -- The root page of the btree
|
||||
** sql TEXT, -- SQL for this btree - from sqlite_master
|
||||
** hasRowid BOOLEAN, -- True if the btree has a rowid
|
||||
** nEntry INT, -- Estimated number of entries
|
||||
** nEntry INT, -- Estimated number of enteries
|
||||
** nPage INT, -- Estimated number of pages
|
||||
** depth INT, -- Depth of the btree
|
||||
** szPage INT, -- Size of each page in bytes
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
**
|
||||
** static int aX[] = { 53, 9, 17, 2231, 4, 99 };
|
||||
** int i = sqlite3_bind_parameter_index(pStmt, "$ptr");
|
||||
** sqlite3_bind_pointer(pStmt, i, aX, "carray", 0);
|
||||
** sqlite3_bind_value(pStmt, i, aX, "carray", 0);
|
||||
**
|
||||
** There is an optional third parameter to determine the datatype of
|
||||
** the C-language array. Allowed values of the third parameter are
|
||||
|
||||
@@ -1,778 +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_cksumvfs_init();
|
||||
**
|
||||
** 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, it
|
||||
** 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_RESERVED_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.
|
||||
*/
|
||||
#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_CORE)
|
||||
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 */
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
** 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);
|
||||
}
|
||||
|
||||
/*
|
||||
** 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 ){
|
||||
u8 *d = (u8*)zBuf;
|
||||
char hasCorrectReserveSize = (d[20]==8);
|
||||
if( hasCorrectReserveSize!=p->computeCksm ){
|
||||
p->computeCksm = p->verifyCksm = hasCorrectReserveSize;
|
||||
}
|
||||
}
|
||||
/* Verify the checksum if (1) the size seems appropriate for a database
|
||||
** page, and if (2) checksum verification is enabled. But (3) do not
|
||||
** verify the checksums on a WAL page if the main database file
|
||||
** has subsequently turned off checksums.
|
||||
*/
|
||||
if( iAmt>=512 /* (1) */
|
||||
&& p->verifyCksm /* (2) */
|
||||
&& (!p->isWal || (p->pPartner!=0 && p->pPartner->verifyCksm)) /* (3) */
|
||||
){
|
||||
u8 cksum[8];
|
||||
cksmCompute((u8*)zBuf, iAmt-8, cksum);
|
||||
if( memcmp(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 ){
|
||||
u8 *d = (u8*)zBuf;
|
||||
char hasCorrectReserveSize = (d[20]==8);
|
||||
if( hasCorrectReserveSize!=p->computeCksm ){
|
||||
p->computeCksm = p->verifyCksm = 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 ){
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
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);
|
||||
return pFile->pMethods->xFetch(pFile, iOfst, iAmt, pp);
|
||||
}
|
||||
|
||||
/* Release a memory-mapped page */
|
||||
static int cksmUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xUnfetch(pFile, iOfst, pPage);
|
||||
}
|
||||
|
||||
/*
|
||||
** 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);
|
||||
p->base.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){
|
||||
return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p);
|
||||
}
|
||||
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);
|
||||
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("cksum")!=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();
|
||||
}
|
||||
#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) */
|
||||
+4
-4
@@ -422,16 +422,16 @@ static closure_avl *queuePull(closure_queue *pQueue){
|
||||
** `mno` becomes mno
|
||||
*/
|
||||
static char *closureDequote(const char *zIn){
|
||||
sqlite3_int64 nIn; /* Size of input string, in bytes */
|
||||
int nIn; /* Size of input string, in bytes */
|
||||
char *zOut; /* Output (dequoted) string */
|
||||
|
||||
nIn = strlen(zIn);
|
||||
zOut = sqlite3_malloc64(nIn+1);
|
||||
nIn = (int)strlen(zIn);
|
||||
zOut = sqlite3_malloc(nIn+1);
|
||||
if( zOut ){
|
||||
char q = zIn[0]; /* Quote character (if any ) */
|
||||
|
||||
if( q!='[' && q!= '\'' && q!='"' && q!='`' ){
|
||||
memcpy(zOut, zIn, (size_t)(nIn+1));
|
||||
memcpy(zOut, zIn, nIn+1);
|
||||
}else{
|
||||
int iOut = 0; /* Index of next byte to write to output */
|
||||
int iIn; /* Index of next byte to read from input */
|
||||
|
||||
@@ -118,7 +118,6 @@ static int completionConnect(
|
||||
#define COMPLETION_COLUMN_WHOLELINE 2 /* Entire line seen so far */
|
||||
#define COMPLETION_COLUMN_PHASE 3 /* ePhase - used for debugging only */
|
||||
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
|
||||
rc = sqlite3_declare_vtab(db,
|
||||
"CREATE TABLE x("
|
||||
" candidate TEXT,"
|
||||
|
||||
+4
-6
@@ -119,13 +119,11 @@ int sqlite3_compress_init(
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "compress", 1,
|
||||
SQLITE_UTF8 | SQLITE_INNOCUOUS,
|
||||
0, compressFunc, 0, 0);
|
||||
rc = sqlite3_create_function(db, "compress", 1, SQLITE_UTF8, 0,
|
||||
compressFunc, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "uncompress", 1,
|
||||
SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
|
||||
0, uncompressFunc, 0, 0);
|
||||
rc = sqlite3_create_function(db, "uncompress", 1, SQLITE_UTF8, 0,
|
||||
uncompressFunc, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
+1
-10
@@ -621,7 +621,7 @@ static int csvtabConnect(
|
||||
}else if( pNew->zData ){
|
||||
pNew->iStart = (int)sRdr.iIn;
|
||||
}else{
|
||||
pNew->iStart = (int)(ftell(sRdr.in) - sRdr.nIn + sRdr.iIn);
|
||||
pNew->iStart = ftell(sRdr.in);
|
||||
}
|
||||
csv_reader_reset(&sRdr);
|
||||
rc = sqlite3_declare_vtab(db, CSV_SCHEMA);
|
||||
@@ -632,15 +632,6 @@ static int csvtabConnect(
|
||||
for(i=0; i<sizeof(azPValue)/sizeof(azPValue[0]); i++){
|
||||
sqlite3_free(azPValue[i]);
|
||||
}
|
||||
/* Rationale for DIRECTONLY:
|
||||
** An attacker who controls a database schema could use this vtab
|
||||
** to exfiltrate sensitive data from other files in the filesystem.
|
||||
** And, recommended practice is to put all CSV virtual tables in the
|
||||
** TEMP namespace, so they should still be usable from within TEMP
|
||||
** views, so there shouldn't be a serious loss of functionality by
|
||||
** prohibiting the use of this vtab from persistent triggers and views.
|
||||
*/
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
|
||||
return SQLITE_OK;
|
||||
|
||||
csvtab_connect_oom:
|
||||
|
||||
@@ -1,851 +0,0 @@
|
||||
/*
|
||||
** 2019-04-17
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This file contains an implementation of two eponymous virtual tables,
|
||||
** "sqlite_dbdata" and "sqlite_dbptr". Both modules require that the
|
||||
** "sqlite_dbpage" eponymous virtual table be available.
|
||||
**
|
||||
** SQLITE_DBDATA:
|
||||
** sqlite_dbdata is used to extract data directly from a database b-tree
|
||||
** page and its associated overflow pages, bypassing the b-tree layer.
|
||||
** The table schema is equivalent to:
|
||||
**
|
||||
** CREATE TABLE sqlite_dbdata(
|
||||
** pgno INTEGER,
|
||||
** cell INTEGER,
|
||||
** field INTEGER,
|
||||
** value ANY,
|
||||
** schema TEXT HIDDEN
|
||||
** );
|
||||
**
|
||||
** IMPORTANT: THE VIRTUAL TABLE SCHEMA ABOVE IS SUBJECT TO CHANGE. IN THE
|
||||
** FUTURE NEW NON-HIDDEN COLUMNS MAY BE ADDED BETWEEN "value" AND
|
||||
** "schema".
|
||||
**
|
||||
** Each page of the database is inspected. If it cannot be interpreted as
|
||||
** a b-tree page, or if it is a b-tree page containing 0 entries, the
|
||||
** sqlite_dbdata table contains no rows for that page. Otherwise, the
|
||||
** table contains one row for each field in the record associated with
|
||||
** each cell on the page. For intkey b-trees, the key value is stored in
|
||||
** field -1.
|
||||
**
|
||||
** For example, for the database:
|
||||
**
|
||||
** CREATE TABLE t1(a, b); -- root page is page 2
|
||||
** INSERT INTO t1(rowid, a, b) VALUES(5, 'v', 'five');
|
||||
** INSERT INTO t1(rowid, a, b) VALUES(10, 'x', 'ten');
|
||||
**
|
||||
** the sqlite_dbdata table contains, as well as from entries related to
|
||||
** page 1, content equivalent to:
|
||||
**
|
||||
** INSERT INTO sqlite_dbdata(pgno, cell, field, value) VALUES
|
||||
** (2, 0, -1, 5 ),
|
||||
** (2, 0, 0, 'v' ),
|
||||
** (2, 0, 1, 'five'),
|
||||
** (2, 1, -1, 10 ),
|
||||
** (2, 1, 0, 'x' ),
|
||||
** (2, 1, 1, 'ten' );
|
||||
**
|
||||
** If database corruption is encountered, this module does not report an
|
||||
** error. Instead, it attempts to extract as much data as possible and
|
||||
** ignores the corruption.
|
||||
**
|
||||
** SQLITE_DBPTR:
|
||||
** The sqlite_dbptr table has the following schema:
|
||||
**
|
||||
** CREATE TABLE sqlite_dbptr(
|
||||
** pgno INTEGER,
|
||||
** child INTEGER,
|
||||
** schema TEXT HIDDEN
|
||||
** );
|
||||
**
|
||||
** It contains one entry for each b-tree pointer between a parent and
|
||||
** child page in the database.
|
||||
*/
|
||||
#if !defined(SQLITEINT_H)
|
||||
#include "sqlite3ext.h"
|
||||
|
||||
typedef unsigned char u8;
|
||||
|
||||
#endif
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define DBDATA_PADDING_BYTES 100
|
||||
|
||||
typedef struct DbdataTable DbdataTable;
|
||||
typedef struct DbdataCursor DbdataCursor;
|
||||
|
||||
/* Cursor object */
|
||||
struct DbdataCursor {
|
||||
sqlite3_vtab_cursor base; /* Base class. Must be first */
|
||||
sqlite3_stmt *pStmt; /* For fetching database pages */
|
||||
|
||||
int iPgno; /* Current page number */
|
||||
u8 *aPage; /* Buffer containing page */
|
||||
int nPage; /* Size of aPage[] in bytes */
|
||||
int nCell; /* Number of cells on aPage[] */
|
||||
int iCell; /* Current cell number */
|
||||
int bOnePage; /* True to stop after one page */
|
||||
int szDb;
|
||||
sqlite3_int64 iRowid;
|
||||
|
||||
/* Only for the sqlite_dbdata table */
|
||||
u8 *pRec; /* Buffer containing current record */
|
||||
int nRec; /* Size of pRec[] in bytes */
|
||||
int nHdr; /* Size of header in bytes */
|
||||
int iField; /* Current field number */
|
||||
u8 *pHdrPtr;
|
||||
u8 *pPtr;
|
||||
|
||||
sqlite3_int64 iIntkey; /* Integer key value */
|
||||
};
|
||||
|
||||
/* Table object */
|
||||
struct DbdataTable {
|
||||
sqlite3_vtab base; /* Base class. Must be first */
|
||||
sqlite3 *db; /* The database connection */
|
||||
sqlite3_stmt *pStmt; /* For fetching database pages */
|
||||
int bPtr; /* True for sqlite3_dbptr table */
|
||||
};
|
||||
|
||||
/* Column and schema definitions for sqlite_dbdata */
|
||||
#define DBDATA_COLUMN_PGNO 0
|
||||
#define DBDATA_COLUMN_CELL 1
|
||||
#define DBDATA_COLUMN_FIELD 2
|
||||
#define DBDATA_COLUMN_VALUE 3
|
||||
#define DBDATA_COLUMN_SCHEMA 4
|
||||
#define DBDATA_SCHEMA \
|
||||
"CREATE TABLE x(" \
|
||||
" pgno INTEGER," \
|
||||
" cell INTEGER," \
|
||||
" field INTEGER," \
|
||||
" value ANY," \
|
||||
" schema TEXT HIDDEN" \
|
||||
")"
|
||||
|
||||
/* Column and schema definitions for sqlite_dbptr */
|
||||
#define DBPTR_COLUMN_PGNO 0
|
||||
#define DBPTR_COLUMN_CHILD 1
|
||||
#define DBPTR_COLUMN_SCHEMA 2
|
||||
#define DBPTR_SCHEMA \
|
||||
"CREATE TABLE x(" \
|
||||
" pgno INTEGER," \
|
||||
" child INTEGER," \
|
||||
" schema TEXT HIDDEN" \
|
||||
")"
|
||||
|
||||
/*
|
||||
** Connect to an sqlite_dbdata (pAux==0) or sqlite_dbptr (pAux!=0) virtual
|
||||
** table.
|
||||
*/
|
||||
static int dbdataConnect(
|
||||
sqlite3 *db,
|
||||
void *pAux,
|
||||
int argc, const char *const*argv,
|
||||
sqlite3_vtab **ppVtab,
|
||||
char **pzErr
|
||||
){
|
||||
DbdataTable *pTab = 0;
|
||||
int rc = sqlite3_declare_vtab(db, pAux ? DBPTR_SCHEMA : DBDATA_SCHEMA);
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
pTab = (DbdataTable*)sqlite3_malloc64(sizeof(DbdataTable));
|
||||
if( pTab==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
memset(pTab, 0, sizeof(DbdataTable));
|
||||
pTab->db = db;
|
||||
pTab->bPtr = (pAux!=0);
|
||||
}
|
||||
}
|
||||
|
||||
*ppVtab = (sqlite3_vtab*)pTab;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Disconnect from or destroy a sqlite_dbdata or sqlite_dbptr virtual table.
|
||||
*/
|
||||
static int dbdataDisconnect(sqlite3_vtab *pVtab){
|
||||
DbdataTable *pTab = (DbdataTable*)pVtab;
|
||||
if( pTab ){
|
||||
sqlite3_finalize(pTab->pStmt);
|
||||
sqlite3_free(pVtab);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function interprets two types of constraints:
|
||||
**
|
||||
** schema=?
|
||||
** pgno=?
|
||||
**
|
||||
** If neither are present, idxNum is set to 0. If schema=? is present,
|
||||
** the 0x01 bit in idxNum is set. If pgno=? is present, the 0x02 bit
|
||||
** in idxNum is set.
|
||||
**
|
||||
** If both parameters are present, schema is in position 0 and pgno in
|
||||
** position 1.
|
||||
*/
|
||||
static int dbdataBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdx){
|
||||
DbdataTable *pTab = (DbdataTable*)tab;
|
||||
int i;
|
||||
int iSchema = -1;
|
||||
int iPgno = -1;
|
||||
int colSchema = (pTab->bPtr ? DBPTR_COLUMN_SCHEMA : DBDATA_COLUMN_SCHEMA);
|
||||
|
||||
for(i=0; i<pIdx->nConstraint; i++){
|
||||
struct sqlite3_index_constraint *p = &pIdx->aConstraint[i];
|
||||
if( p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
|
||||
if( p->iColumn==colSchema ){
|
||||
if( p->usable==0 ) return SQLITE_CONSTRAINT;
|
||||
iSchema = i;
|
||||
}
|
||||
if( p->iColumn==DBDATA_COLUMN_PGNO && p->usable ){
|
||||
iPgno = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( iSchema>=0 ){
|
||||
pIdx->aConstraintUsage[iSchema].argvIndex = 1;
|
||||
pIdx->aConstraintUsage[iSchema].omit = 1;
|
||||
}
|
||||
if( iPgno>=0 ){
|
||||
pIdx->aConstraintUsage[iPgno].argvIndex = 1 + (iSchema>=0);
|
||||
pIdx->aConstraintUsage[iPgno].omit = 1;
|
||||
pIdx->estimatedCost = 100;
|
||||
pIdx->estimatedRows = 50;
|
||||
|
||||
if( pTab->bPtr==0 && pIdx->nOrderBy && pIdx->aOrderBy[0].desc==0 ){
|
||||
int iCol = pIdx->aOrderBy[0].iColumn;
|
||||
if( pIdx->nOrderBy==1 ){
|
||||
pIdx->orderByConsumed = (iCol==0 || iCol==1);
|
||||
}else if( pIdx->nOrderBy==2 && pIdx->aOrderBy[1].desc==0 && iCol==0 ){
|
||||
pIdx->orderByConsumed = (pIdx->aOrderBy[1].iColumn==1);
|
||||
}
|
||||
}
|
||||
|
||||
}else{
|
||||
pIdx->estimatedCost = 100000000;
|
||||
pIdx->estimatedRows = 1000000000;
|
||||
}
|
||||
pIdx->idxNum = (iSchema>=0 ? 0x01 : 0x00) | (iPgno>=0 ? 0x02 : 0x00);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Open a new sqlite_dbdata or sqlite_dbptr cursor.
|
||||
*/
|
||||
static int dbdataOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
|
||||
DbdataCursor *pCsr;
|
||||
|
||||
pCsr = (DbdataCursor*)sqlite3_malloc64(sizeof(DbdataCursor));
|
||||
if( pCsr==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}else{
|
||||
memset(pCsr, 0, sizeof(DbdataCursor));
|
||||
pCsr->base.pVtab = pVTab;
|
||||
}
|
||||
|
||||
*ppCursor = (sqlite3_vtab_cursor *)pCsr;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Restore a cursor object to the state it was in when first allocated
|
||||
** by dbdataOpen().
|
||||
*/
|
||||
static void dbdataResetCursor(DbdataCursor *pCsr){
|
||||
DbdataTable *pTab = (DbdataTable*)(pCsr->base.pVtab);
|
||||
if( pTab->pStmt==0 ){
|
||||
pTab->pStmt = pCsr->pStmt;
|
||||
}else{
|
||||
sqlite3_finalize(pCsr->pStmt);
|
||||
}
|
||||
pCsr->pStmt = 0;
|
||||
pCsr->iPgno = 1;
|
||||
pCsr->iCell = 0;
|
||||
pCsr->iField = 0;
|
||||
pCsr->bOnePage = 0;
|
||||
sqlite3_free(pCsr->aPage);
|
||||
sqlite3_free(pCsr->pRec);
|
||||
pCsr->pRec = 0;
|
||||
pCsr->aPage = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Close an sqlite_dbdata or sqlite_dbptr cursor.
|
||||
*/
|
||||
static int dbdataClose(sqlite3_vtab_cursor *pCursor){
|
||||
DbdataCursor *pCsr = (DbdataCursor*)pCursor;
|
||||
dbdataResetCursor(pCsr);
|
||||
sqlite3_free(pCsr);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Utility methods to decode 16 and 32-bit big-endian unsigned integers.
|
||||
*/
|
||||
static unsigned int get_uint16(unsigned char *a){
|
||||
return (a[0]<<8)|a[1];
|
||||
}
|
||||
static unsigned int get_uint32(unsigned char *a){
|
||||
return ((unsigned int)a[0]<<24)
|
||||
| ((unsigned int)a[1]<<16)
|
||||
| ((unsigned int)a[2]<<8)
|
||||
| ((unsigned int)a[3]);
|
||||
}
|
||||
|
||||
/*
|
||||
** Load page pgno from the database via the sqlite_dbpage virtual table.
|
||||
** If successful, set (*ppPage) to point to a buffer containing the page
|
||||
** data, (*pnPage) to the size of that buffer in bytes and return
|
||||
** SQLITE_OK. In this case it is the responsibility of the caller to
|
||||
** eventually free the buffer using sqlite3_free().
|
||||
**
|
||||
** Or, if an error occurs, set both (*ppPage) and (*pnPage) to 0 and
|
||||
** return an SQLite error code.
|
||||
*/
|
||||
static int dbdataLoadPage(
|
||||
DbdataCursor *pCsr, /* Cursor object */
|
||||
unsigned int pgno, /* Page number of page to load */
|
||||
u8 **ppPage, /* OUT: pointer to page buffer */
|
||||
int *pnPage /* OUT: Size of (*ppPage) in bytes */
|
||||
){
|
||||
int rc2;
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_stmt *pStmt = pCsr->pStmt;
|
||||
|
||||
*ppPage = 0;
|
||||
*pnPage = 0;
|
||||
sqlite3_bind_int64(pStmt, 2, pgno);
|
||||
if( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
int nCopy = sqlite3_column_bytes(pStmt, 0);
|
||||
if( nCopy>0 ){
|
||||
u8 *pPage;
|
||||
pPage = (u8*)sqlite3_malloc64(nCopy + DBDATA_PADDING_BYTES);
|
||||
if( pPage==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
const u8 *pCopy = sqlite3_column_blob(pStmt, 0);
|
||||
memcpy(pPage, pCopy, nCopy);
|
||||
memset(&pPage[nCopy], 0, DBDATA_PADDING_BYTES);
|
||||
}
|
||||
*ppPage = pPage;
|
||||
*pnPage = nCopy;
|
||||
}
|
||||
}
|
||||
rc2 = sqlite3_reset(pStmt);
|
||||
if( rc==SQLITE_OK ) rc = rc2;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Read a varint. Put the value in *pVal and return the number of bytes.
|
||||
*/
|
||||
static int dbdataGetVarint(const u8 *z, sqlite3_int64 *pVal){
|
||||
sqlite3_int64 v = 0;
|
||||
int i;
|
||||
for(i=0; i<8; i++){
|
||||
v = (v<<7) + (z[i]&0x7f);
|
||||
if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; }
|
||||
}
|
||||
v = (v<<8) + (z[i]&0xff);
|
||||
*pVal = v;
|
||||
return 9;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of bytes of space used by an SQLite value of type
|
||||
** eType.
|
||||
*/
|
||||
static int dbdataValueBytes(int eType){
|
||||
switch( eType ){
|
||||
case 0: case 8: case 9:
|
||||
case 10: case 11:
|
||||
return 0;
|
||||
case 1:
|
||||
return 1;
|
||||
case 2:
|
||||
return 2;
|
||||
case 3:
|
||||
return 3;
|
||||
case 4:
|
||||
return 4;
|
||||
case 5:
|
||||
return 6;
|
||||
case 6:
|
||||
case 7:
|
||||
return 8;
|
||||
default:
|
||||
if( eType>0 ){
|
||||
return ((eType-12) / 2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Load a value of type eType from buffer pData and use it to set the
|
||||
** result of context object pCtx.
|
||||
*/
|
||||
static void dbdataValue(
|
||||
sqlite3_context *pCtx,
|
||||
int eType,
|
||||
u8 *pData,
|
||||
int nData
|
||||
){
|
||||
if( eType>=0 && dbdataValueBytes(eType)<=nData ){
|
||||
switch( eType ){
|
||||
case 0:
|
||||
case 10:
|
||||
case 11:
|
||||
sqlite3_result_null(pCtx);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
sqlite3_result_int(pCtx, 0);
|
||||
break;
|
||||
case 9:
|
||||
sqlite3_result_int(pCtx, 1);
|
||||
break;
|
||||
|
||||
case 1: case 2: case 3: case 4: case 5: case 6: case 7: {
|
||||
sqlite3_uint64 v = (signed char)pData[0];
|
||||
pData++;
|
||||
switch( eType ){
|
||||
case 7:
|
||||
case 6: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2;
|
||||
case 5: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2;
|
||||
case 4: v = (v<<8) + pData[0]; pData++;
|
||||
case 3: v = (v<<8) + pData[0]; pData++;
|
||||
case 2: v = (v<<8) + pData[0]; pData++;
|
||||
}
|
||||
|
||||
if( eType==7 ){
|
||||
double r;
|
||||
memcpy(&r, &v, sizeof(r));
|
||||
sqlite3_result_double(pCtx, r);
|
||||
}else{
|
||||
sqlite3_result_int64(pCtx, (sqlite3_int64)v);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
int n = ((eType-12) / 2);
|
||||
if( eType % 2 ){
|
||||
sqlite3_result_text(pCtx, (const char*)pData, n, SQLITE_TRANSIENT);
|
||||
}else{
|
||||
sqlite3_result_blob(pCtx, pData, n, SQLITE_TRANSIENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Move an sqlite_dbdata or sqlite_dbptr cursor to the next entry.
|
||||
*/
|
||||
static int dbdataNext(sqlite3_vtab_cursor *pCursor){
|
||||
DbdataCursor *pCsr = (DbdataCursor*)pCursor;
|
||||
DbdataTable *pTab = (DbdataTable*)pCursor->pVtab;
|
||||
|
||||
pCsr->iRowid++;
|
||||
while( 1 ){
|
||||
int rc;
|
||||
int iOff = (pCsr->iPgno==1 ? 100 : 0);
|
||||
int bNextPage = 0;
|
||||
|
||||
if( pCsr->aPage==0 ){
|
||||
while( 1 ){
|
||||
if( pCsr->bOnePage==0 && pCsr->iPgno>pCsr->szDb ) return SQLITE_OK;
|
||||
rc = dbdataLoadPage(pCsr, pCsr->iPgno, &pCsr->aPage, &pCsr->nPage);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
if( pCsr->aPage ) break;
|
||||
pCsr->iPgno++;
|
||||
}
|
||||
pCsr->iCell = pTab->bPtr ? -2 : 0;
|
||||
pCsr->nCell = get_uint16(&pCsr->aPage[iOff+3]);
|
||||
}
|
||||
|
||||
if( pTab->bPtr ){
|
||||
if( pCsr->aPage[iOff]!=0x02 && pCsr->aPage[iOff]!=0x05 ){
|
||||
pCsr->iCell = pCsr->nCell;
|
||||
}
|
||||
pCsr->iCell++;
|
||||
if( pCsr->iCell>=pCsr->nCell ){
|
||||
sqlite3_free(pCsr->aPage);
|
||||
pCsr->aPage = 0;
|
||||
if( pCsr->bOnePage ) return SQLITE_OK;
|
||||
pCsr->iPgno++;
|
||||
}else{
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}else{
|
||||
/* If there is no record loaded, load it now. */
|
||||
if( pCsr->pRec==0 ){
|
||||
int bHasRowid = 0;
|
||||
int nPointer = 0;
|
||||
sqlite3_int64 nPayload = 0;
|
||||
sqlite3_int64 nHdr = 0;
|
||||
int iHdr;
|
||||
int U, X;
|
||||
int nLocal;
|
||||
|
||||
switch( pCsr->aPage[iOff] ){
|
||||
case 0x02:
|
||||
nPointer = 4;
|
||||
break;
|
||||
case 0x0a:
|
||||
break;
|
||||
case 0x0d:
|
||||
bHasRowid = 1;
|
||||
break;
|
||||
default:
|
||||
/* This is not a b-tree page with records on it. Continue. */
|
||||
pCsr->iCell = pCsr->nCell;
|
||||
break;
|
||||
}
|
||||
|
||||
if( pCsr->iCell>=pCsr->nCell ){
|
||||
bNextPage = 1;
|
||||
}else{
|
||||
|
||||
iOff += 8 + nPointer + pCsr->iCell*2;
|
||||
if( iOff>pCsr->nPage ){
|
||||
bNextPage = 1;
|
||||
}else{
|
||||
iOff = get_uint16(&pCsr->aPage[iOff]);
|
||||
}
|
||||
|
||||
/* For an interior node cell, skip past the child-page number */
|
||||
iOff += nPointer;
|
||||
|
||||
/* Load the "byte of payload including overflow" field */
|
||||
if( bNextPage || iOff>pCsr->nPage ){
|
||||
bNextPage = 1;
|
||||
}else{
|
||||
iOff += dbdataGetVarint(&pCsr->aPage[iOff], &nPayload);
|
||||
}
|
||||
|
||||
/* If this is a leaf intkey cell, load the rowid */
|
||||
if( bHasRowid && !bNextPage && iOff<pCsr->nPage ){
|
||||
iOff += dbdataGetVarint(&pCsr->aPage[iOff], &pCsr->iIntkey);
|
||||
}
|
||||
|
||||
/* Figure out how much data to read from the local page */
|
||||
U = pCsr->nPage;
|
||||
if( bHasRowid ){
|
||||
X = U-35;
|
||||
}else{
|
||||
X = ((U-12)*64/255)-23;
|
||||
}
|
||||
if( nPayload<=X ){
|
||||
nLocal = nPayload;
|
||||
}else{
|
||||
int M, K;
|
||||
M = ((U-12)*32/255)-23;
|
||||
K = M+((nPayload-M)%(U-4));
|
||||
if( K<=X ){
|
||||
nLocal = K;
|
||||
}else{
|
||||
nLocal = M;
|
||||
}
|
||||
}
|
||||
|
||||
if( bNextPage || nLocal+iOff>pCsr->nPage ){
|
||||
bNextPage = 1;
|
||||
}else{
|
||||
|
||||
/* Allocate space for payload. And a bit more to catch small buffer
|
||||
** overruns caused by attempting to read a varint or similar from
|
||||
** near the end of a corrupt record. */
|
||||
pCsr->pRec = (u8*)sqlite3_malloc64(nPayload+DBDATA_PADDING_BYTES);
|
||||
if( pCsr->pRec==0 ) return SQLITE_NOMEM;
|
||||
memset(pCsr->pRec, 0, nPayload+DBDATA_PADDING_BYTES);
|
||||
pCsr->nRec = nPayload;
|
||||
|
||||
/* Load the nLocal bytes of payload */
|
||||
memcpy(pCsr->pRec, &pCsr->aPage[iOff], nLocal);
|
||||
iOff += nLocal;
|
||||
|
||||
/* Load content from overflow pages */
|
||||
if( nPayload>nLocal ){
|
||||
sqlite3_int64 nRem = nPayload - nLocal;
|
||||
unsigned int pgnoOvfl = get_uint32(&pCsr->aPage[iOff]);
|
||||
while( nRem>0 ){
|
||||
u8 *aOvfl = 0;
|
||||
int nOvfl = 0;
|
||||
int nCopy;
|
||||
rc = dbdataLoadPage(pCsr, pgnoOvfl, &aOvfl, &nOvfl);
|
||||
assert( rc!=SQLITE_OK || aOvfl==0 || nOvfl==pCsr->nPage );
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
if( aOvfl==0 ) break;
|
||||
|
||||
nCopy = U-4;
|
||||
if( nCopy>nRem ) nCopy = nRem;
|
||||
memcpy(&pCsr->pRec[nPayload-nRem], &aOvfl[4], nCopy);
|
||||
nRem -= nCopy;
|
||||
|
||||
pgnoOvfl = get_uint32(aOvfl);
|
||||
sqlite3_free(aOvfl);
|
||||
}
|
||||
}
|
||||
|
||||
iHdr = dbdataGetVarint(pCsr->pRec, &nHdr);
|
||||
pCsr->nHdr = nHdr;
|
||||
pCsr->pHdrPtr = &pCsr->pRec[iHdr];
|
||||
pCsr->pPtr = &pCsr->pRec[pCsr->nHdr];
|
||||
pCsr->iField = (bHasRowid ? -1 : 0);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
pCsr->iField++;
|
||||
if( pCsr->iField>0 ){
|
||||
sqlite3_int64 iType;
|
||||
if( pCsr->pHdrPtr>&pCsr->pRec[pCsr->nRec] ){
|
||||
bNextPage = 1;
|
||||
}else{
|
||||
pCsr->pHdrPtr += dbdataGetVarint(pCsr->pHdrPtr, &iType);
|
||||
pCsr->pPtr += dbdataValueBytes(iType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( bNextPage ){
|
||||
sqlite3_free(pCsr->aPage);
|
||||
sqlite3_free(pCsr->pRec);
|
||||
pCsr->aPage = 0;
|
||||
pCsr->pRec = 0;
|
||||
if( pCsr->bOnePage ) return SQLITE_OK;
|
||||
pCsr->iPgno++;
|
||||
}else{
|
||||
if( pCsr->iField<0 || pCsr->pHdrPtr<&pCsr->pRec[pCsr->nHdr] ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Advance to the next cell. The next iteration of the loop will load
|
||||
** the record and so on. */
|
||||
sqlite3_free(pCsr->pRec);
|
||||
pCsr->pRec = 0;
|
||||
pCsr->iCell++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert( !"can't get here" );
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if the cursor is at EOF.
|
||||
*/
|
||||
static int dbdataEof(sqlite3_vtab_cursor *pCursor){
|
||||
DbdataCursor *pCsr = (DbdataCursor*)pCursor;
|
||||
return pCsr->aPage==0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Determine the size in pages of database zSchema (where zSchema is
|
||||
** "main", "temp" or the name of an attached database) and set
|
||||
** pCsr->szDb accordingly. If successful, return SQLITE_OK. Otherwise,
|
||||
** an SQLite error code.
|
||||
*/
|
||||
static int dbdataDbsize(DbdataCursor *pCsr, const char *zSchema){
|
||||
DbdataTable *pTab = (DbdataTable*)pCsr->base.pVtab;
|
||||
char *zSql = 0;
|
||||
int rc, rc2;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
|
||||
zSql = sqlite3_mprintf("PRAGMA %Q.page_count", zSchema);
|
||||
if( zSql==0 ) return SQLITE_NOMEM;
|
||||
rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
pCsr->szDb = sqlite3_column_int(pStmt, 0);
|
||||
}
|
||||
rc2 = sqlite3_finalize(pStmt);
|
||||
if( rc==SQLITE_OK ) rc = rc2;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** xFilter method for sqlite_dbdata and sqlite_dbptr.
|
||||
*/
|
||||
static int dbdataFilter(
|
||||
sqlite3_vtab_cursor *pCursor,
|
||||
int idxNum, const char *idxStr,
|
||||
int argc, sqlite3_value **argv
|
||||
){
|
||||
DbdataCursor *pCsr = (DbdataCursor*)pCursor;
|
||||
DbdataTable *pTab = (DbdataTable*)pCursor->pVtab;
|
||||
int rc = SQLITE_OK;
|
||||
const char *zSchema = "main";
|
||||
|
||||
dbdataResetCursor(pCsr);
|
||||
assert( pCsr->iPgno==1 );
|
||||
if( idxNum & 0x01 ){
|
||||
zSchema = (const char*)sqlite3_value_text(argv[0]);
|
||||
}
|
||||
if( idxNum & 0x02 ){
|
||||
pCsr->iPgno = sqlite3_value_int(argv[(idxNum & 0x01)]);
|
||||
pCsr->bOnePage = 1;
|
||||
}else{
|
||||
pCsr->nPage = dbdataDbsize(pCsr, zSchema);
|
||||
rc = dbdataDbsize(pCsr, zSchema);
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
if( pTab->pStmt ){
|
||||
pCsr->pStmt = pTab->pStmt;
|
||||
pTab->pStmt = 0;
|
||||
}else{
|
||||
rc = sqlite3_prepare_v2(pTab->db,
|
||||
"SELECT data FROM sqlite_dbpage(?) WHERE pgno=?", -1,
|
||||
&pCsr->pStmt, 0
|
||||
);
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_bind_text(pCsr->pStmt, 1, zSchema, -1, SQLITE_TRANSIENT);
|
||||
}else{
|
||||
pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db));
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = dbdataNext(pCursor);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a column for the sqlite_dbdata or sqlite_dbptr table.
|
||||
*/
|
||||
static int dbdataColumn(
|
||||
sqlite3_vtab_cursor *pCursor,
|
||||
sqlite3_context *ctx,
|
||||
int i
|
||||
){
|
||||
DbdataCursor *pCsr = (DbdataCursor*)pCursor;
|
||||
DbdataTable *pTab = (DbdataTable*)pCursor->pVtab;
|
||||
if( pTab->bPtr ){
|
||||
switch( i ){
|
||||
case DBPTR_COLUMN_PGNO:
|
||||
sqlite3_result_int64(ctx, pCsr->iPgno);
|
||||
break;
|
||||
case DBPTR_COLUMN_CHILD: {
|
||||
int iOff = pCsr->iPgno==1 ? 100 : 0;
|
||||
if( pCsr->iCell<0 ){
|
||||
iOff += 8;
|
||||
}else{
|
||||
iOff += 12 + pCsr->iCell*2;
|
||||
if( iOff>pCsr->nPage ) return SQLITE_OK;
|
||||
iOff = get_uint16(&pCsr->aPage[iOff]);
|
||||
}
|
||||
if( iOff<=pCsr->nPage ){
|
||||
sqlite3_result_int64(ctx, get_uint32(&pCsr->aPage[iOff]));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
switch( i ){
|
||||
case DBDATA_COLUMN_PGNO:
|
||||
sqlite3_result_int64(ctx, pCsr->iPgno);
|
||||
break;
|
||||
case DBDATA_COLUMN_CELL:
|
||||
sqlite3_result_int(ctx, pCsr->iCell);
|
||||
break;
|
||||
case DBDATA_COLUMN_FIELD:
|
||||
sqlite3_result_int(ctx, pCsr->iField);
|
||||
break;
|
||||
case DBDATA_COLUMN_VALUE: {
|
||||
if( pCsr->iField<0 ){
|
||||
sqlite3_result_int64(ctx, pCsr->iIntkey);
|
||||
}else{
|
||||
sqlite3_int64 iType;
|
||||
dbdataGetVarint(pCsr->pHdrPtr, &iType);
|
||||
dbdataValue(
|
||||
ctx, iType, pCsr->pPtr, &pCsr->pRec[pCsr->nRec] - pCsr->pPtr
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the rowid for an sqlite_dbdata or sqlite_dptr table.
|
||||
*/
|
||||
static int dbdataRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
|
||||
DbdataCursor *pCsr = (DbdataCursor*)pCursor;
|
||||
*pRowid = pCsr->iRowid;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Invoke this routine to register the "sqlite_dbdata" virtual table module
|
||||
*/
|
||||
static int sqlite3DbdataRegister(sqlite3 *db){
|
||||
static sqlite3_module dbdata_module = {
|
||||
0, /* iVersion */
|
||||
0, /* xCreate */
|
||||
dbdataConnect, /* xConnect */
|
||||
dbdataBestIndex, /* xBestIndex */
|
||||
dbdataDisconnect, /* xDisconnect */
|
||||
0, /* xDestroy */
|
||||
dbdataOpen, /* xOpen - open a cursor */
|
||||
dbdataClose, /* xClose - close a cursor */
|
||||
dbdataFilter, /* xFilter - configure scan constraints */
|
||||
dbdataNext, /* xNext - advance a cursor */
|
||||
dbdataEof, /* xEof - check for end of scan */
|
||||
dbdataColumn, /* xColumn - read data */
|
||||
dbdataRowid, /* xRowid - read data */
|
||||
0, /* xUpdate */
|
||||
0, /* xBegin */
|
||||
0, /* xSync */
|
||||
0, /* xCommit */
|
||||
0, /* xRollback */
|
||||
0, /* xFindMethod */
|
||||
0, /* xRename */
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0, /* xRollbackTo */
|
||||
0 /* xShadowName */
|
||||
};
|
||||
|
||||
int rc = sqlite3_create_module(db, "sqlite_dbdata", &dbdata_module, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_module(db, "sqlite_dbptr", &dbdata_module, (void*)1);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_dbdata_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
return sqlite3DbdataRegister(db);
|
||||
}
|
||||
+1
-1
@@ -195,7 +195,7 @@ static char **tableColumnList(DState *p, const char *zTab){
|
||||
if( nCol>=nAlloc-2 ){
|
||||
char **azNew;
|
||||
nAlloc = nAlloc*2 + nCol + 10;
|
||||
azNew = sqlite3_realloc64(azCol, nAlloc*sizeof(azCol[0]));
|
||||
azNew = sqlite3_realloc(azCol, nAlloc*sizeof(azCol[0]));
|
||||
if( azNew==0 ) goto col_oom;
|
||||
azCol = azNew;
|
||||
azCol[0] = 0;
|
||||
|
||||
+3
-5
@@ -44,7 +44,7 @@ static int callback(void *pCtx, int argc, char **argv, char **colnames){
|
||||
/* Using sqlite3_realloc64() would be better, but it is a recent
|
||||
** addition and will cause a segfault if loaded by an older version
|
||||
** of SQLite. */
|
||||
zNew = p->nAlloc<=0x7fffffff ? sqlite3_realloc64(p->z, p->nAlloc) : 0;
|
||||
zNew = p->nAlloc<=0x7fffffff ? sqlite3_realloc(p->z, (int)p->nAlloc) : 0;
|
||||
if( zNew==0 ){
|
||||
sqlite3_free(p->z);
|
||||
memset(p, 0, sizeof(*p));
|
||||
@@ -113,12 +113,10 @@ int sqlite3_eval_init(
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "eval", 1,
|
||||
SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
|
||||
rc = sqlite3_create_function(db, "eval", 1, SQLITE_UTF8, 0,
|
||||
sqlEvalFunc, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "eval", 2,
|
||||
SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
|
||||
rc = sqlite3_create_function(db, "eval", 2, SQLITE_UTF8, 0,
|
||||
sqlEvalFunc, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
|
||||
+17
-47
@@ -121,47 +121,22 @@ SQLITE_EXTENSION_INIT1
|
||||
|
||||
/*
|
||||
** Set the result stored by context ctx to a blob containing the
|
||||
** contents of file zName. Or, leave the result unchanged (NULL)
|
||||
** if the file does not exist or is unreadable.
|
||||
**
|
||||
** If the file exceeds the SQLite blob size limit, through an
|
||||
** SQLITE_TOOBIG error.
|
||||
**
|
||||
** Throw an SQLITE_IOERR if there are difficulties pulling the file
|
||||
** off of disk.
|
||||
** contents of file zName.
|
||||
*/
|
||||
static void readFileContents(sqlite3_context *ctx, const char *zName){
|
||||
FILE *in;
|
||||
sqlite3_int64 nIn;
|
||||
long nIn;
|
||||
void *pBuf;
|
||||
sqlite3 *db;
|
||||
int mxBlob;
|
||||
|
||||
in = fopen(zName, "rb");
|
||||
if( in==0 ){
|
||||
/* File does not exist or is unreadable. Leave the result set to NULL. */
|
||||
return;
|
||||
}
|
||||
if( in==0 ) return;
|
||||
fseek(in, 0, SEEK_END);
|
||||
nIn = ftell(in);
|
||||
rewind(in);
|
||||
db = sqlite3_context_db_handle(ctx);
|
||||
mxBlob = sqlite3_limit(db, SQLITE_LIMIT_LENGTH, -1);
|
||||
if( nIn>mxBlob ){
|
||||
sqlite3_result_error_code(ctx, SQLITE_TOOBIG);
|
||||
fclose(in);
|
||||
return;
|
||||
}
|
||||
pBuf = sqlite3_malloc64( nIn ? nIn : 1 );
|
||||
if( pBuf==0 ){
|
||||
sqlite3_result_error_nomem(ctx);
|
||||
fclose(in);
|
||||
return;
|
||||
}
|
||||
if( nIn==(sqlite3_int64)fread(pBuf, 1, (size_t)nIn, in) ){
|
||||
sqlite3_result_blob64(ctx, pBuf, nIn, sqlite3_free);
|
||||
pBuf = sqlite3_malloc( nIn );
|
||||
if( pBuf && 1==fread(pBuf, nIn, 1, in) ){
|
||||
sqlite3_result_blob(ctx, pBuf, nIn, sqlite3_free);
|
||||
}else{
|
||||
sqlite3_result_error_code(ctx, SQLITE_IOERR);
|
||||
sqlite3_free(pBuf);
|
||||
}
|
||||
fclose(in);
|
||||
@@ -293,15 +268,15 @@ static int fileLinkStat(
|
||||
** Argument zFile is the name of a file that will be created and/or written
|
||||
** by SQL function writefile(). This function ensures that the directory
|
||||
** zFile will be written to exists, creating it if required. The permissions
|
||||
** for any path components created by this function are set in accordance
|
||||
** with the current umask.
|
||||
** for any path components created by this function are set to (mode&0777).
|
||||
**
|
||||
** If an OOM condition is encountered, SQLITE_NOMEM is returned. Otherwise,
|
||||
** SQLITE_OK is returned if the directory is successfully created, or
|
||||
** SQLITE_ERROR otherwise.
|
||||
*/
|
||||
static int makeDirectory(
|
||||
const char *zFile
|
||||
const char *zFile,
|
||||
mode_t mode
|
||||
){
|
||||
char *zCopy = sqlite3_mprintf("%s", zFile);
|
||||
int rc = SQLITE_OK;
|
||||
@@ -322,7 +297,7 @@ static int makeDirectory(
|
||||
|
||||
rc2 = fileStat(zCopy, &sStat);
|
||||
if( rc2!=0 ){
|
||||
if( mkdir(zCopy, 0777) ) rc = SQLITE_ERROR;
|
||||
if( mkdir(zCopy, mode & 0777) ) rc = SQLITE_ERROR;
|
||||
}else{
|
||||
if( !S_ISDIR(sStat.st_mode) ) rc = SQLITE_ERROR;
|
||||
}
|
||||
@@ -394,7 +369,6 @@ static int writeFile(
|
||||
|
||||
if( mtime>=0 ){
|
||||
#if defined(_WIN32)
|
||||
#if !SQLITE_OS_WINRT
|
||||
/* Windows */
|
||||
FILETIME lastAccess;
|
||||
FILETIME lastWrite;
|
||||
@@ -425,7 +399,6 @@ static int writeFile(
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
#elif defined(AT_FDCWD) && 0 /* utimensat() is not universally available */
|
||||
/* Recent unix */
|
||||
struct timespec times[2];
|
||||
@@ -482,7 +455,7 @@ static void writefileFunc(
|
||||
|
||||
res = writeFile(context, zFile, argv[1], mode, mtime);
|
||||
if( res==1 && errno==ENOENT ){
|
||||
if( makeDirectory(zFile)==SQLITE_OK ){
|
||||
if( makeDirectory(zFile, mode)==SQLITE_OK ){
|
||||
res = writeFile(context, zFile, argv[1], mode, mtime);
|
||||
}
|
||||
}
|
||||
@@ -587,7 +560,6 @@ static int fsdirConnect(
|
||||
pNew = (fsdir_tab*)sqlite3_malloc( sizeof(*pNew) );
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
|
||||
}
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
return rc;
|
||||
@@ -674,8 +646,8 @@ static int fsdirNext(sqlite3_vtab_cursor *cur){
|
||||
FsdirLevel *pLvl;
|
||||
if( iNew>=pCur->nLvl ){
|
||||
int nNew = iNew+1;
|
||||
sqlite3_int64 nByte = nNew*sizeof(FsdirLevel);
|
||||
FsdirLevel *aNew = (FsdirLevel*)sqlite3_realloc64(pCur->aLvl, nByte);
|
||||
int nByte = nNew*sizeof(FsdirLevel);
|
||||
FsdirLevel *aNew = (FsdirLevel*)sqlite3_realloc(pCur->aLvl, nByte);
|
||||
if( aNew==0 ) return SQLITE_NOMEM;
|
||||
memset(&aNew[pCur->nLvl], 0, sizeof(FsdirLevel)*(nNew-pCur->nLvl));
|
||||
pCur->aLvl = aNew;
|
||||
@@ -755,7 +727,7 @@ static int fsdirColumn(
|
||||
}else if( S_ISLNK(m) ){
|
||||
char aStatic[64];
|
||||
char *aBuf = aStatic;
|
||||
sqlite3_int64 nBuf = 64;
|
||||
int nBuf = 64;
|
||||
int n;
|
||||
|
||||
while( 1 ){
|
||||
@@ -763,7 +735,7 @@ static int fsdirColumn(
|
||||
if( n<nBuf ) break;
|
||||
if( aBuf!=aStatic ) sqlite3_free(aBuf);
|
||||
nBuf = nBuf*2;
|
||||
aBuf = sqlite3_malloc64(nBuf);
|
||||
aBuf = sqlite3_malloc(nBuf);
|
||||
if( aBuf==0 ){
|
||||
sqlite3_result_error_nomem(ctx);
|
||||
return SQLITE_NOMEM;
|
||||
@@ -981,12 +953,10 @@ int sqlite3_fileio_init(
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "readfile", 1,
|
||||
SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
|
||||
rc = sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0,
|
||||
readfileFunc, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "writefile", -1,
|
||||
SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
|
||||
rc = sqlite3_create_function(db, "writefile", -1, SQLITE_UTF8, 0,
|
||||
writefileFunc, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+10
-12
@@ -337,7 +337,7 @@ static int fuzzerLoadOneRule(
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
|
||||
pRule = sqlite3_malloc64( sizeof(*pRule) + nFrom + nTo );
|
||||
pRule = sqlite3_malloc( sizeof(*pRule) + nFrom + nTo );
|
||||
if( pRule==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -447,16 +447,16 @@ static int fuzzerLoadRules(
|
||||
** `mno` becomes mno
|
||||
*/
|
||||
static char *fuzzerDequote(const char *zIn){
|
||||
sqlite3_int64 nIn; /* Size of input string, in bytes */
|
||||
int nIn; /* Size of input string, in bytes */
|
||||
char *zOut; /* Output (dequoted) string */
|
||||
|
||||
nIn = strlen(zIn);
|
||||
zOut = sqlite3_malloc64(nIn+1);
|
||||
nIn = (int)strlen(zIn);
|
||||
zOut = sqlite3_malloc(nIn+1);
|
||||
if( zOut ){
|
||||
char q = zIn[0]; /* Quote character (if any ) */
|
||||
|
||||
if( q!='[' && q!= '\'' && q!='"' && q!='`' ){
|
||||
memcpy(zOut, zIn, (size_t)(nIn+1));
|
||||
memcpy(zOut, zIn, nIn+1);
|
||||
}else{
|
||||
int iOut = 0; /* Index of next byte to write to output */
|
||||
int iIn; /* Index of next byte to read from input */
|
||||
@@ -513,10 +513,10 @@ static int fuzzerConnect(
|
||||
);
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
sqlite3_int64 nModule; /* Length of zModule, in bytes */
|
||||
int nModule; /* Length of zModule, in bytes */
|
||||
|
||||
nModule = strlen(zModule);
|
||||
pNew = sqlite3_malloc64( sizeof(*pNew) + nModule + 1);
|
||||
nModule = (int)strlen(zModule);
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) + nModule + 1);
|
||||
if( pNew==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -524,7 +524,7 @@ static int fuzzerConnect(
|
||||
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
pNew->zClassName = (char*)&pNew[1];
|
||||
memcpy(pNew->zClassName, zModule, (size_t)(nModule+1));
|
||||
memcpy(pNew->zClassName, zModule, nModule+1);
|
||||
|
||||
zTab = fuzzerDequote(argv[3]);
|
||||
if( zTab==0 ){
|
||||
@@ -540,8 +540,6 @@ static int fuzzerConnect(
|
||||
if( rc!=SQLITE_OK ){
|
||||
fuzzerDisconnect((sqlite3_vtab *)pNew);
|
||||
pNew = 0;
|
||||
}else{
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -874,7 +872,7 @@ static fuzzer_stem *fuzzerNewStem(
|
||||
fuzzer_rule *pRule;
|
||||
unsigned int h;
|
||||
|
||||
pNew = sqlite3_malloc64( sizeof(*pNew) + strlen(zWord) + 1 );
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) + (int)strlen(zWord) + 1 );
|
||||
if( pNew==0 ) return 0;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
pNew->zBasis = (char*)&pNew[1];
|
||||
|
||||
+2
-4
@@ -121,12 +121,10 @@ int sqlite3_ieee_init(
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "ieee754", 1,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
|
||||
rc = sqlite3_create_function(db, "ieee754", 1, SQLITE_UTF8, 0,
|
||||
ieee754func, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "ieee754", 2,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
|
||||
rc = sqlite3_create_function(db, "ieee754", 2, SQLITE_UTF8, 0,
|
||||
ieee754func, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
|
||||
+31
-115
@@ -522,37 +522,6 @@ static void jsonReturnJson(
|
||||
sqlite3_result_subtype(pCtx, JSON_SUBTYPE);
|
||||
}
|
||||
|
||||
/*
|
||||
** Translate a single byte of Hex into an integer.
|
||||
** This routine only works if h really is a valid hexadecimal
|
||||
** character: 0..9a..fA..F
|
||||
*/
|
||||
static u8 jsonHexToInt(int h){
|
||||
assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') );
|
||||
#ifdef SQLITE_EBCDIC
|
||||
h += 9*(1&~(h>>4));
|
||||
#else
|
||||
h += 9*(1&(h>>6));
|
||||
#endif
|
||||
return (u8)(h & 0xf);
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert a 4-byte hex string into an integer
|
||||
*/
|
||||
static u32 jsonHexToInt4(const char *z){
|
||||
u32 v;
|
||||
assert( safe_isxdigit(z[0]) );
|
||||
assert( safe_isxdigit(z[1]) );
|
||||
assert( safe_isxdigit(z[2]) );
|
||||
assert( safe_isxdigit(z[3]) );
|
||||
v = (jsonHexToInt(z[0])<<12)
|
||||
+ (jsonHexToInt(z[1])<<8)
|
||||
+ (jsonHexToInt(z[2])<<4)
|
||||
+ jsonHexToInt(z[3]);
|
||||
return v;
|
||||
}
|
||||
|
||||
/*
|
||||
** Make the JsonNode the return value of the function.
|
||||
*/
|
||||
@@ -646,8 +615,15 @@ static void jsonReturn(
|
||||
}else{
|
||||
c = z[++i];
|
||||
if( c=='u' ){
|
||||
u32 v = jsonHexToInt4(z+i+1);
|
||||
i += 4;
|
||||
u32 v = 0, k;
|
||||
for(k=0; k<4; i++, k++){
|
||||
assert( i<n-2 );
|
||||
c = z[i+1];
|
||||
assert( safe_isxdigit(c) );
|
||||
if( c<='9' ) v = v*16 + c - '0';
|
||||
else if( c<='F' ) v = v*16 + c - 'A' + 10;
|
||||
else v = v*16 + c - 'a' + 10;
|
||||
}
|
||||
if( v==0 ) break;
|
||||
if( v<=0x7f ){
|
||||
zOut[j++] = (char)v;
|
||||
@@ -655,25 +631,9 @@ static void jsonReturn(
|
||||
zOut[j++] = (char)(0xc0 | (v>>6));
|
||||
zOut[j++] = 0x80 | (v&0x3f);
|
||||
}else{
|
||||
u32 vlo;
|
||||
if( (v&0xfc00)==0xd800
|
||||
&& i<n-6
|
||||
&& z[i+1]=='\\'
|
||||
&& z[i+2]=='u'
|
||||
&& ((vlo = jsonHexToInt4(z+i+3))&0xfc00)==0xdc00
|
||||
){
|
||||
/* We have a surrogate pair */
|
||||
v = ((v&0x3ff)<<10) + (vlo&0x3ff) + 0x10000;
|
||||
i += 6;
|
||||
zOut[j++] = 0xf0 | (v>>18);
|
||||
zOut[j++] = 0x80 | ((v>>12)&0x3f);
|
||||
zOut[j++] = 0x80 | ((v>>6)&0x3f);
|
||||
zOut[j++] = 0x80 | (v&0x3f);
|
||||
}else{
|
||||
zOut[j++] = 0xe0 | (v>>12);
|
||||
zOut[j++] = 0x80 | ((v>>6)&0x3f);
|
||||
zOut[j++] = 0x80 | (v&0x3f);
|
||||
}
|
||||
zOut[j++] = (char)(0xe0 | (v>>12));
|
||||
zOut[j++] = 0x80 | ((v>>6)&0x3f);
|
||||
zOut[j++] = 0x80 | (v&0x3f);
|
||||
}
|
||||
}else{
|
||||
if( c=='b' ){
|
||||
@@ -731,7 +691,7 @@ static JSON_NOINLINE int jsonParseAddNodeExpand(
|
||||
assert( pParse->nNode>=pParse->nAlloc );
|
||||
if( pParse->oom ) return -1;
|
||||
nNew = pParse->nAlloc*2 + 10;
|
||||
pNew = sqlite3_realloc64(pParse->aNode, sizeof(JsonNode)*nNew);
|
||||
pNew = sqlite3_realloc(pParse->aNode, sizeof(JsonNode)*nNew);
|
||||
if( pNew==0 ){
|
||||
pParse->oom = 1;
|
||||
return -1;
|
||||
@@ -1005,7 +965,7 @@ static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){
|
||||
static int jsonParseFindParents(JsonParse *pParse){
|
||||
u32 *aUp;
|
||||
assert( pParse->aUp==0 );
|
||||
aUp = pParse->aUp = sqlite3_malloc64( sizeof(u32)*pParse->nNode );
|
||||
aUp = pParse->aUp = sqlite3_malloc( sizeof(u32)*pParse->nNode );
|
||||
if( aUp==0 ){
|
||||
pParse->oom = 1;
|
||||
return SQLITE_NOMEM;
|
||||
@@ -1067,7 +1027,7 @@ static JsonParse *jsonParseCached(
|
||||
pMatch->iHold = iMaxHold+1;
|
||||
return pMatch;
|
||||
}
|
||||
p = sqlite3_malloc64( sizeof(*p) + nJson + 1 );
|
||||
p = sqlite3_malloc( sizeof(*p) + nJson + 1 );
|
||||
if( p==0 ){
|
||||
sqlite3_result_error_nomem(pCtx);
|
||||
return 0;
|
||||
@@ -1123,7 +1083,6 @@ static JsonNode *jsonLookupStep(
|
||||
const char *zKey;
|
||||
JsonNode *pRoot = &pParse->aNode[iRoot];
|
||||
if( zPath[0]==0 ) return pRoot;
|
||||
if( pRoot->jnFlags & JNODE_REPLACE ) return 0;
|
||||
if( zPath[0]=='.' ){
|
||||
if( pRoot->eType!=JSON_OBJECT ) return 0;
|
||||
zPath++;
|
||||
@@ -1164,7 +1123,7 @@ static JsonNode *jsonLookupStep(
|
||||
u32 iStart, iLabel;
|
||||
JsonNode *pNode;
|
||||
iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
|
||||
iLabel = jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
|
||||
iLabel = jsonParseAddNode(pParse, JSON_STRING, i, zPath);
|
||||
zPath += i;
|
||||
pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
|
||||
if( pParse->oom ) return 0;
|
||||
@@ -1176,49 +1135,18 @@ static JsonNode *jsonLookupStep(
|
||||
}
|
||||
return pNode;
|
||||
}
|
||||
}else if( zPath[0]=='[' ){
|
||||
}else if( zPath[0]=='[' && safe_isdigit(zPath[1]) ){
|
||||
if( pRoot->eType!=JSON_ARRAY ) return 0;
|
||||
i = 0;
|
||||
j = 1;
|
||||
while( safe_isdigit(zPath[j]) ){
|
||||
i = i*10 + zPath[j] - '0';
|
||||
j++;
|
||||
}
|
||||
if( j<2 || zPath[j]!=']' ){
|
||||
if( zPath[1]=='#' ){
|
||||
JsonNode *pBase = pRoot;
|
||||
int iBase = iRoot;
|
||||
if( pRoot->eType!=JSON_ARRAY ) return 0;
|
||||
for(;;){
|
||||
while( j<=pBase->n ){
|
||||
if( (pBase[j].jnFlags & JNODE_REMOVE)==0 ) i++;
|
||||
j += jsonNodeSize(&pBase[j]);
|
||||
}
|
||||
if( (pBase->jnFlags & JNODE_APPEND)==0 ) break;
|
||||
iBase += pBase->u.iAppend;
|
||||
pBase = &pParse->aNode[iBase];
|
||||
j = 1;
|
||||
}
|
||||
j = 2;
|
||||
if( zPath[2]=='-' && safe_isdigit(zPath[3]) ){
|
||||
unsigned int x = 0;
|
||||
j = 3;
|
||||
do{
|
||||
x = x*10 + zPath[j] - '0';
|
||||
j++;
|
||||
}while( safe_isdigit(zPath[j]) );
|
||||
if( x>i ) return 0;
|
||||
i -= x;
|
||||
}
|
||||
if( zPath[j]!=']' ){
|
||||
*pzErr = zPath;
|
||||
return 0;
|
||||
}
|
||||
}else{
|
||||
*pzErr = zPath;
|
||||
return 0;
|
||||
}
|
||||
if( zPath[j]!=']' ){
|
||||
*pzErr = zPath;
|
||||
return 0;
|
||||
}
|
||||
if( pRoot->eType!=JSON_ARRAY ) return 0;
|
||||
zPath += j + 1;
|
||||
j = 1;
|
||||
for(;;){
|
||||
@@ -1891,7 +1819,7 @@ static void jsonArrayStep(
|
||||
if( pStr->zBuf==0 ){
|
||||
jsonInit(pStr, ctx);
|
||||
jsonAppendChar(pStr, '[');
|
||||
}else if( pStr->nUsed>1 ){
|
||||
}else{
|
||||
jsonAppendChar(pStr, ',');
|
||||
pStr->pCtx = ctx;
|
||||
}
|
||||
@@ -1939,11 +1867,9 @@ static void jsonGroupInverse(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
unsigned int i;
|
||||
int i;
|
||||
int inStr = 0;
|
||||
int nNest = 0;
|
||||
char *z;
|
||||
char c;
|
||||
JsonString *pStr;
|
||||
UNUSED_PARAM(argc);
|
||||
UNUSED_PARAM(argv);
|
||||
@@ -1954,18 +1880,12 @@ static void jsonGroupInverse(
|
||||
if( NEVER(!pStr) ) return;
|
||||
#endif
|
||||
z = pStr->zBuf;
|
||||
for(i=1; (c = z[i])!=',' || inStr || nNest; i++){
|
||||
if( i>=pStr->nUsed ){
|
||||
pStr->nUsed = 1;
|
||||
return;
|
||||
}
|
||||
if( c=='"' ){
|
||||
for(i=1; z[i]!=',' || inStr; i++){
|
||||
assert( i<pStr->nUsed );
|
||||
if( z[i]=='"' ){
|
||||
inStr = !inStr;
|
||||
}else if( c=='\\' ){
|
||||
}else if( z[i]=='\\' ){
|
||||
i++;
|
||||
}else if( !inStr ){
|
||||
if( c=='{' || c=='[' ) nNest++;
|
||||
if( c=='}' || c==']' ) nNest--;
|
||||
}
|
||||
}
|
||||
pStr->nUsed -= i;
|
||||
@@ -1995,7 +1915,7 @@ static void jsonObjectStep(
|
||||
if( pStr->zBuf==0 ){
|
||||
jsonInit(pStr, ctx);
|
||||
jsonAppendChar(pStr, '{');
|
||||
}else if( pStr->nUsed>1 ){
|
||||
}else{
|
||||
jsonAppendChar(pStr, ',');
|
||||
pStr->pCtx = ctx;
|
||||
}
|
||||
@@ -2091,7 +2011,6 @@ static int jsonEachConnect(
|
||||
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -2582,19 +2501,16 @@ int sqlite3Json1Init(sqlite3 *db){
|
||||
{ "json_tree", &jsonTreeModule },
|
||||
};
|
||||
#endif
|
||||
static const int enc =
|
||||
SQLITE_UTF8 |
|
||||
SQLITE_DETERMINISTIC |
|
||||
SQLITE_INNOCUOUS;
|
||||
for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
|
||||
rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg, enc,
|
||||
rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg,
|
||||
SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
||||
(void*)&aFunc[i].flag,
|
||||
aFunc[i].xFunc, 0, 0);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
|
||||
rc = sqlite3_create_window_function(db, aAgg[i].zName, aAgg[i].nArg,
|
||||
SQLITE_SUBTYPE | enc, 0,
|
||||
SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
|
||||
aAgg[i].xStep, aAgg[i].xFinal,
|
||||
aAgg[i].xValue, jsonGroupInverse, 0);
|
||||
}
|
||||
|
||||
+1
-1
@@ -143,7 +143,7 @@ static int memstatFindSchemas(memstat_cursor *pCur){
|
||||
}
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
char **az, *z;
|
||||
az = sqlite3_realloc64(pCur->azDb, sizeof(char*)*(pCur->nDb+1));
|
||||
az = sqlite3_realloc(pCur->azDb, sizeof(char*)*(pCur->nDb+1));
|
||||
if( az==0 ){
|
||||
memstatClearSchema(pCur);
|
||||
return SQLITE_NOMEM;
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
** 2019-01-21
|
||||
**
|
||||
** 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 an extension that uses the SQLITE_CONFIG_MALLOC
|
||||
** mechanism to add a tracing layer on top of SQLite. If this extension
|
||||
** is registered prior to sqlite3_initialize(), it will cause all memory
|
||||
** allocation activities to be logged on standard output, or to some other
|
||||
** FILE specified by the initializer.
|
||||
**
|
||||
** This file needs to be compiled into the application that uses it.
|
||||
**
|
||||
** This extension is used to implement the --memtrace option of the
|
||||
** command-line shell.
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* The original memory allocation routines */
|
||||
static sqlite3_mem_methods memtraceBase;
|
||||
static FILE *memtraceOut;
|
||||
|
||||
/* Methods that trace memory allocations */
|
||||
static void *memtraceMalloc(int n){
|
||||
if( memtraceOut ){
|
||||
fprintf(memtraceOut, "MEMTRACE: allocate %d bytes\n",
|
||||
memtraceBase.xRoundup(n));
|
||||
}
|
||||
return memtraceBase.xMalloc(n);
|
||||
}
|
||||
static void memtraceFree(void *p){
|
||||
if( p==0 ) return;
|
||||
if( memtraceOut ){
|
||||
fprintf(memtraceOut, "MEMTRACE: free %d bytes\n", memtraceBase.xSize(p));
|
||||
}
|
||||
memtraceBase.xFree(p);
|
||||
}
|
||||
static void *memtraceRealloc(void *p, int n){
|
||||
if( p==0 ) return memtraceMalloc(n);
|
||||
if( n==0 ){
|
||||
memtraceFree(p);
|
||||
return 0;
|
||||
}
|
||||
if( memtraceOut ){
|
||||
fprintf(memtraceOut, "MEMTRACE: resize %d -> %d bytes\n",
|
||||
memtraceBase.xSize(p), memtraceBase.xRoundup(n));
|
||||
}
|
||||
return memtraceBase.xRealloc(p, n);
|
||||
}
|
||||
static int memtraceSize(void *p){
|
||||
return memtraceBase.xSize(p);
|
||||
}
|
||||
static int memtraceRoundup(int n){
|
||||
return memtraceBase.xRoundup(n);
|
||||
}
|
||||
static int memtraceInit(void *p){
|
||||
return memtraceBase.xInit(p);
|
||||
}
|
||||
static void memtraceShutdown(void *p){
|
||||
memtraceBase.xShutdown(p);
|
||||
}
|
||||
|
||||
/* The substitute memory allocator */
|
||||
static sqlite3_mem_methods ersaztMethods = {
|
||||
memtraceMalloc,
|
||||
memtraceFree,
|
||||
memtraceRealloc,
|
||||
memtraceSize,
|
||||
memtraceRoundup,
|
||||
memtraceInit,
|
||||
memtraceShutdown,
|
||||
0
|
||||
};
|
||||
|
||||
/* Begin tracing memory allocations to out. */
|
||||
int sqlite3MemTraceActivate(FILE *out){
|
||||
int rc = SQLITE_OK;
|
||||
if( memtraceBase.xMalloc==0 ){
|
||||
rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memtraceBase);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &ersaztMethods);
|
||||
}
|
||||
}
|
||||
memtraceOut = out;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Deactivate memory tracing */
|
||||
int sqlite3MemTraceDeactivate(void){
|
||||
int rc = SQLITE_OK;
|
||||
if( memtraceBase.xMalloc!=0 ){
|
||||
rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memtraceBase);
|
||||
if( rc==SQLITE_OK ){
|
||||
memset(&memtraceBase, 0, sizeof(memtraceBase));
|
||||
}
|
||||
}
|
||||
memtraceOut = 0;
|
||||
return rc;
|
||||
}
|
||||
@@ -105,3 +105,4 @@ int sqlite3_mmap_warm(sqlite3 *db, const char *zDb){
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
+5
-8
@@ -85,7 +85,7 @@ static void nextCharAppend(nextCharContext *p, unsigned c){
|
||||
if( p->nUsed+1 > p->nAlloc ){
|
||||
unsigned int *aNew;
|
||||
int n = p->nAlloc*2 + 30;
|
||||
aNew = sqlite3_realloc64(p->aResult, n*sizeof(unsigned int));
|
||||
aNew = sqlite3_realloc(p->aResult, n*sizeof(unsigned int));
|
||||
if( aNew==0 ){
|
||||
p->mallocFailed = 1;
|
||||
return;
|
||||
@@ -269,7 +269,7 @@ static void nextCharFunc(
|
||||
sqlite3_result_error_nomem(context);
|
||||
}else{
|
||||
unsigned char *pRes;
|
||||
pRes = sqlite3_malloc64( c.nUsed*4 + 1 );
|
||||
pRes = sqlite3_malloc( c.nUsed*4 + 1 );
|
||||
if( pRes==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
}else{
|
||||
@@ -297,17 +297,14 @@ int sqlite3_nextchar_init(
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "next_char", 3,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
|
||||
rc = sqlite3_create_function(db, "next_char", 3, SQLITE_UTF8, 0,
|
||||
nextCharFunc, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "next_char", 4,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
|
||||
rc = sqlite3_create_function(db, "next_char", 4, SQLITE_UTF8, 0,
|
||||
nextCharFunc, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "next_char", 5,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
|
||||
rc = sqlite3_create_function(db, "next_char", 5, SQLITE_UTF8, 0,
|
||||
nextCharFunc, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
** 2020-01-08
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This SQLite extension implements a noop() function used for testing.
|
||||
**
|
||||
** Variants:
|
||||
**
|
||||
** noop(X) The default. Deterministic.
|
||||
** noop_i(X) Deterministic and innocuous.
|
||||
** noop_do(X) Deterministic and direct-only.
|
||||
** noop_nd(X) Non-deterministic.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
** Implementation of the noop() function.
|
||||
**
|
||||
** The function returns its argument, unchanged.
|
||||
*/
|
||||
static void noopfunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
assert( argc==1 );
|
||||
sqlite3_result_value(context, argv[0]);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_noop_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "noop", 1,
|
||||
SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
||||
0, noopfunc, 0, 0);
|
||||
if( rc ) return rc;
|
||||
rc = sqlite3_create_function(db, "noop_i", 1,
|
||||
SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_INNOCUOUS,
|
||||
0, noopfunc, 0, 0);
|
||||
if( rc ) return rc;
|
||||
rc = sqlite3_create_function(db, "noop_do", 1,
|
||||
SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_DIRECTONLY,
|
||||
0, noopfunc, 0, 0);
|
||||
if( rc ) return rc;
|
||||
rc = sqlite3_create_function(db, "noop_nd", 1,
|
||||
SQLITE_UTF8,
|
||||
0, noopfunc, 0, 0);
|
||||
return rc;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user