Compare commits
355 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e493719b44 | |||
| a8e057618a | |||
| 6b86e51eea | |||
| c210c08891 | |||
| b042d92128 | |||
| f25cc4f3c5 | |||
| 48cd0f28c5 | |||
| dfe3b58315 | |||
| 2f36262dbf | |||
| e9ad07c0a3 | |||
| 1baae57a72 | |||
| 94e02d9c2c | |||
| 20c0082371 | |||
| 0d756cc83a | |||
| 232f278084 | |||
| 8fc4a11c94 | |||
| ca076bf26e | |||
| 992e927281 | |||
| ee751fab4c | |||
| 9b0da8319c | |||
| 97c8cb3ed8 | |||
| fff1dc8e05 | |||
| f9231c34eb | |||
| f01dae1f32 | |||
| d471bcb396 | |||
| 0de6efe59e | |||
| d0fb7960ce | |||
| 4afdfa195b | |||
| d1d158bf5a | |||
| ec4ccdbcb1 | |||
| 01e92df41e | |||
| 81f9159b5e | |||
| b6991796b4 | |||
| 64919e9b00 | |||
| 4177c8a2b7 | |||
| 1d4b16405b | |||
| eefc72d12f | |||
| 666636b6de | |||
| b163b57212 | |||
| 593c716781 | |||
| aa243aa7cd | |||
| e80834f6ff | |||
| 57e141bc28 | |||
| cd80dc3667 | |||
| bdefaf08ee | |||
| 7eb2c9176a | |||
| f6febee0e2 | |||
| 89dec01e48 | |||
| 0f55a571fc | |||
| c2909bf8ac | |||
| d8f3b4c320 | |||
| 8625221444 | |||
| e4c26c41b4 | |||
| 47df8a2c40 | |||
| bd462bcc10 | |||
| 92107a38dc | |||
| 1ab76166e3 | |||
| 76e4990b25 | |||
| c310c53e01 | |||
| 94e95ea46e | |||
| a599e150ca | |||
| 29e9af8848 | |||
| 5198ff5767 | |||
| efb699fc7c | |||
| 2c04131ca7 | |||
| 85bcdce270 | |||
| 8d69a58119 | |||
| 6a509d56bc | |||
| 862faf28bb | |||
| 11d07ed643 | |||
| 3a07548b0d | |||
| b63d6070ee | |||
| 634ac14488 | |||
| fb11bf8c91 | |||
| 583521fbb0 | |||
| 9bfb079409 | |||
| a42325e731 | |||
| a86c8ce940 | |||
| cde4bf8ba7 | |||
| 6ba81ef1bf | |||
| deb201b866 | |||
| 38e3853240 | |||
| 1ea0443c2d | |||
| afdc9e23fc | |||
| 8bcc686614 | |||
| 687e20079c | |||
| 273e01b4c6 | |||
| fb077f3c50 | |||
| 1429eca9d4 | |||
| 558ef11ad9 | |||
| e1e28ec35c | |||
| 94f4f873b2 | |||
| e46201e264 | |||
| 16dd3985f0 | |||
| 397a78d4a1 | |||
| 99490934ae | |||
| bef06d2637 | |||
| 3c2db5def6 | |||
| ae10474125 | |||
| d7a5e49840 | |||
| e7acce66b2 | |||
| fa94d492c8 | |||
| d6401e869b | |||
| fffaf23013 | |||
| 5a1ce4369f | |||
| 7525b87b6c | |||
| d8cc8b30b4 | |||
| 203b1ea0f5 | |||
| e45985b595 | |||
| f354e77f3d | |||
| 6301c43f23 | |||
| 8061ad8abd | |||
| 1641f11f4c | |||
| f7e74904cc | |||
| 2c8ee026ba | |||
| 60379d4243 | |||
| 51caa04836 | |||
| 3374648545 | |||
| 69a66a7be1 | |||
| bc1be957c1 | |||
| 5881dfea2c | |||
| cb0e04f929 | |||
| 89b6de0357 | |||
| 03c5c21328 | |||
| cfc078318c | |||
| 368bfe8b00 | |||
| 1a6c2b1d38 | |||
| 21b9225ff5 | |||
| 9042ff214b | |||
| 643d855da9 | |||
| dc6214ee39 | |||
| fb34559eb1 | |||
| 4d342827d6 | |||
| 2134eb5721 | |||
| ce706c2cf3 | |||
| d4a4a36171 | |||
| a50bffb85e | |||
| 2f6239ed4e | |||
| 7464f578ed | |||
| 52993b31e1 | |||
| 83da91b7bd | |||
| b0b7db91b8 | |||
| 893bd3751b | |||
| 62a88294e8 | |||
| b9a0e668f3 | |||
| a37b6a5e31 | |||
| a838997544 | |||
| bb383df7c6 | |||
| 11df7d2839 | |||
| d5b44d60c7 | |||
| 70d5dfba68 | |||
| ec8fc62c42 | |||
| 3e2d47d49f | |||
| fc08a1aef8 | |||
| 974b24896a | |||
| 1f169fefca | |||
| 7b278f0c3d | |||
| 253a6af532 | |||
| d4a4dd6ebc | |||
| 8a65380de9 | |||
| 19efd0db41 | |||
| ea41251eb0 | |||
| 707821ff72 | |||
| 731dd6ebda | |||
| 04c6747a80 | |||
| b7de827137 | |||
| cfc45b1021 | |||
| f8c2fea195 | |||
| e89feee5c3 | |||
| 8c53b4e7f6 | |||
| de72d2a81a | |||
| 4a5cff73a7 | |||
| fdc75c9f53 | |||
| 04ab586bf3 | |||
| 4f939e86df | |||
| 1ba88c7f1d | |||
| f7c44f9bd2 | |||
| 4d2f81eb73 | |||
| 3a85a298c9 | |||
| 909f78cbd8 | |||
| 26505e5f51 | |||
| 49f6a0d82a | |||
| 1af016b7f4 | |||
| f6e015fab9 | |||
| f6fa95b81d | |||
| 63e50b9ed6 | |||
| fcee090746 | |||
| 746a1515b2 | |||
| 60ce5d3135 | |||
| b8a762827c | |||
| bcdef69482 | |||
| eea8eb6d04 | |||
| 49b269e095 | |||
| 52f0c6205c | |||
| eafb9a0ae5 | |||
| 48ea97e5dd | |||
| 09236755ee | |||
| 8055a3ead4 | |||
| 3c425484a7 | |||
| 2d588b8c08 | |||
| 92cd307c1c | |||
| 0c5a95e43a | |||
| 8e2d4ad30c | |||
| d905113e97 | |||
| 20b3fc4db1 | |||
| d16f26a708 | |||
| 43579191e8 | |||
| a69262c0f2 | |||
| e4f90b7075 | |||
| c86b23bfbc | |||
| 32dcc847b5 | |||
| eabbf37fae | |||
| cbfaa076d7 | |||
| 6f147c54ef | |||
| 23bfa80c19 | |||
| 36d248812b | |||
| b1b4a3dbca | |||
| f9dc5f7726 | |||
| 91a21f4d08 | |||
| 2296b67598 | |||
| 2639ddc474 | |||
| 38fa8c9bb0 | |||
| d01372f1b8 | |||
| ad5bafa699 | |||
| ab0659fdab | |||
| 1ca9a8b9df | |||
| ac4b8dea9b | |||
| b430701823 | |||
| 0b57d312b7 | |||
| 145d0a35d9 | |||
| 635b4ce5f7 | |||
| dbc1e9e6a8 | |||
| be075d1188 | |||
| 5704f455b9 | |||
| 7844d21536 | |||
| e1857cc015 | |||
| b39dd52adb | |||
| b7c2cf0aaf | |||
| 9db4828662 | |||
| 6b758e1d96 | |||
| 7d0fa14c03 | |||
| 6ab91a7a7a | |||
| 005d4c61c1 | |||
| 0f0d3ddf71 | |||
| aef15e74c8 | |||
| fc25721c9e | |||
| 5a65470300 | |||
| 84c501bac1 | |||
| f095a1affb | |||
| 2d13f6016b | |||
| 9196c81406 | |||
| 383bb4fa62 | |||
| 0f1c2eb5f2 | |||
| 29d77dc450 | |||
| a296cda016 | |||
| c6e519f335 | |||
| 147ad061f6 | |||
| 7301e77402 | |||
| a60c63013e | |||
| f8181eaa20 | |||
| 05209e9021 | |||
| 49272bc728 | |||
| c985c2822c | |||
| b74cf4b6ea | |||
| fd748c6460 | |||
| a751f39c3f | |||
| ad9bfa5e07 | |||
| 2b3c4af553 | |||
| 60f34ae091 | |||
| f4452cfbed | |||
| 5aa20378f7 | |||
| 8bee11a41e | |||
| dbe7d37ae8 | |||
| f888158c7f | |||
| d811d844cd | |||
| 977e5dcd07 | |||
| 65da285e6a | |||
| 1f48e67db1 | |||
| f689400dc7 | |||
| 8e5bfedd22 | |||
| e23d05e807 | |||
| 0f5f54062c | |||
| 46de072880 | |||
| 9c18ef09a5 | |||
| 44748f27a6 | |||
| bafad06139 | |||
| fa5c62ef2e | |||
| e93f82658a | |||
| 53f5f00762 | |||
| f7f2a82aa0 | |||
| 1dbb147598 | |||
| b6c4d59e89 | |||
| a9e4be3b08 | |||
| 7dd630a893 | |||
| 5f8cb730af | |||
| bc36320f02 | |||
| 488cddfa86 | |||
| 07052d5535 | |||
| bebf54438e | |||
| f470c37a2b | |||
| 60bdcf5e56 | |||
| 9b7e8e10f2 | |||
| 8820c8d3ee | |||
| 24efa5444d | |||
| ba160891de | |||
| bfbf7d9daa | |||
| bdc9744f60 | |||
| d7dc0a36cc | |||
| 49f84ce1cd | |||
| 5612ef1057 | |||
| 44d068532e | |||
| 5351e884aa | |||
| 15fc988ce0 | |||
| ca9a5faf70 | |||
| f8248c42f9 | |||
| 09b523c99b | |||
| 60afcb80ee | |||
| 601c8f2829 | |||
| b2d83494d3 | |||
| 17e65ae4c0 | |||
| 50db3e8d51 | |||
| 09d00b2f4f | |||
| 0efb6f5135 | |||
| 6dd5f07d3d | |||
| 982c1fac2b | |||
| d7134fe0c1 | |||
| 7c5577acdc | |||
| d7fda6cfc5 | |||
| 6afa35c985 | |||
| 1c06b47864 | |||
| eb7f2a0fc5 | |||
| 98aa2abc45 | |||
| 2e5e0e10f2 | |||
| 6b26a7b950 | |||
| 6705584a5b | |||
| 5398806889 | |||
| 2fae150402 | |||
| 6314eeaeb3 | |||
| 6fb5d358a8 | |||
| 7ebb605c0a | |||
| f8937f9034 | |||
| 2c3ba94969 | |||
| 7cc5595a01 | |||
| 5eaebf3a63 | |||
| fc9098a45e | |||
| 0d7f0ccd96 | |||
| 5db90714aa | |||
| 42eb070729 | |||
| eda079cd2c | |||
| 34566c4434 | |||
| 674b894269 | |||
| 504eba5f46 | |||
| 85c6892aa4 | |||
| c6727c8342 | |||
| 16f39b6e5d |
+67
-23
@@ -22,7 +22,7 @@ TOP = @abs_srcdir@
|
||||
#
|
||||
BCC = @BUILD_CC@ @BUILD_CFLAGS@
|
||||
|
||||
# TCC is the C Compile and options for use in building executables that
|
||||
# TCC is the C Compile and options for use in building executables that
|
||||
# will run on the target platform. (BCC and TCC are usually the
|
||||
# same unless your are cross-compiling.) Separate CC and CFLAGS macros
|
||||
# are provide so that these aspects of the build process can be changed
|
||||
@@ -32,10 +32,11 @@ CC = @CC@
|
||||
CFLAGS = @CPPFLAGS@ @CFLAGS@
|
||||
TCC = ${CC} ${CFLAGS} -I. -I${TOP}/src -I${TOP}/ext/rtree -I${TOP}/ext/icu
|
||||
TCC += -I${TOP}/ext/fts3 -I${TOP}/ext/async -I${TOP}/ext/session
|
||||
TCC += -I${TOP}/ext/userauth
|
||||
|
||||
# Define this for the autoconf-based build, so that the code knows it can
|
||||
# include the generated config.h
|
||||
#
|
||||
#
|
||||
TCC += -D_HAVE_SQLITE_CONFIG_H -DBUILD_sqlite
|
||||
|
||||
# Define -DNDEBUG to compile without debugging (i.e., for production usage)
|
||||
@@ -66,7 +67,7 @@ LIBREADLINE = @TARGET_READLINE_LIBS@
|
||||
TCC += -DSQLITE_THREADSAFE=@SQLITE_THREADSAFE@
|
||||
|
||||
# Any target libraries which libsqlite must be linked against
|
||||
#
|
||||
#
|
||||
TLIBS = @LIBS@ $(LIBS)
|
||||
|
||||
# Flags controlling use of the in memory btree implementation
|
||||
@@ -78,8 +79,8 @@ TLIBS = @LIBS@ $(LIBS)
|
||||
TEMP_STORE = -DSQLITE_TEMP_STORE=@TEMP_STORE@
|
||||
|
||||
# Enable/disable loadable extensions, and other optional features
|
||||
# based on configuration. (-DSQLITE_OMIT*, -DSQLITE_ENABLE*).
|
||||
# The same set of OMIT and ENABLE flags should be passed to the
|
||||
# based on configuration. (-DSQLITE_OMIT*, -DSQLITE_ENABLE*).
|
||||
# The same set of OMIT and ENABLE flags should be passed to the
|
||||
# LEMON parser generator and the mkkeywordhash tool as well.
|
||||
OPT_FEATURE_FLAGS = @OPT_FEATURE_FLAGS@
|
||||
|
||||
@@ -126,8 +127,8 @@ SHLIB_SUFFIX = @TCL_SHLIB_SUFFIX@
|
||||
# If gcov support was enabled by the configure script, add the appropriate
|
||||
# flags here. It's not always as easy as just having the user add the right
|
||||
# CFLAGS / LDFLAGS, because libtool wants to use CFLAGS when linking, which
|
||||
# causes build errors with -fprofile-arcs -ftest-coverage with some GCCs.
|
||||
# Supposedly GCC does the right thing if you use --coverage, but in
|
||||
# causes build errors with -fprofile-arcs -ftest-coverage with some GCCs.
|
||||
# Supposedly GCC does the right thing if you use --coverage, but in
|
||||
# practice it still fails. See:
|
||||
#
|
||||
# http://www.mail-archive.com/debian-gcc@lists.debian.org/msg26197.html
|
||||
@@ -187,7 +188,7 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
|
||||
random.lo resolve.lo rowset.lo rtree.lo \
|
||||
sqlite3session.lo select.lo sqlite3rbu.lo status.lo stmt.lo \
|
||||
table.lo threads.lo tokenize.lo treeview.lo trigger.lo \
|
||||
update.lo upsert.lo util.lo vacuum.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 wal.lo walker.lo where.lo wherecode.lo whereexpr.lo \
|
||||
window.lo utf.lo vtab.lo
|
||||
@@ -355,6 +356,9 @@ SRC += \
|
||||
SRC += \
|
||||
$(TOP)/ext/session/sqlite3session.c \
|
||||
$(TOP)/ext/session/sqlite3session.h
|
||||
SRC += \
|
||||
$(TOP)/ext/userauth/userauth.c \
|
||||
$(TOP)/ext/userauth/sqlite3userauth.h
|
||||
SRC += \
|
||||
$(TOP)/ext/rbu/sqlite3rbu.h \
|
||||
$(TOP)/ext/rbu/sqlite3rbu.c
|
||||
@@ -425,7 +429,7 @@ TESTSRC = \
|
||||
$(TOP)/ext/fts3/fts3_term.c \
|
||||
$(TOP)/ext/fts3/fts3_test.c \
|
||||
$(TOP)/ext/session/test_session.c \
|
||||
$(TOP)/ext/rbu/test_rbu.c
|
||||
$(TOP)/ext/rbu/test_rbu.c
|
||||
|
||||
# Statically linked extensions
|
||||
#
|
||||
@@ -455,7 +459,8 @@ TESTSRC += \
|
||||
$(TOP)/ext/misc/totype.c \
|
||||
$(TOP)/ext/misc/unionvtab.c \
|
||||
$(TOP)/ext/misc/wholenumber.c \
|
||||
$(TOP)/ext/misc/zipfile.c
|
||||
$(TOP)/ext/misc/zipfile.c \
|
||||
$(TOP)/ext/userauth/userauth.c
|
||||
|
||||
# Source code to the library files needed by the test fixture
|
||||
#
|
||||
@@ -471,6 +476,7 @@ TESTSRC2 = \
|
||||
$(TOP)/src/dbstat.c \
|
||||
$(TOP)/src/expr.c \
|
||||
$(TOP)/src/func.c \
|
||||
$(TOP)/src/global.c \
|
||||
$(TOP)/src/insert.c \
|
||||
$(TOP)/src/wal.c \
|
||||
$(TOP)/src/main.c \
|
||||
@@ -507,7 +513,7 @@ TESTSRC2 = \
|
||||
$(TOP)/ext/fts3/fts3_write.c \
|
||||
$(TOP)/ext/async/sqlite3async.c \
|
||||
$(TOP)/ext/session/sqlite3session.c \
|
||||
$(TOP)/ext/misc/stmt.c
|
||||
$(TOP)/ext/misc/stmt.c
|
||||
|
||||
# Header files used by all library source files.
|
||||
#
|
||||
@@ -560,6 +566,8 @@ EXTHDR += \
|
||||
$(TOP)/ext/icu/sqliteicu.h
|
||||
EXTHDR += \
|
||||
$(TOP)/ext/rtree/sqlite3rtree.h
|
||||
EXTHDR += \
|
||||
$(TOP)/ext/userauth/sqlite3userauth.h
|
||||
|
||||
# executables needed for testing
|
||||
#
|
||||
@@ -579,7 +587,8 @@ FUZZDATA = \
|
||||
$(TOP)/test/fuzzdata3.db \
|
||||
$(TOP)/test/fuzzdata4.db \
|
||||
$(TOP)/test/fuzzdata5.db \
|
||||
$(TOP)/test/fuzzdata6.db
|
||||
$(TOP)/test/fuzzdata6.db \
|
||||
$(TOP)/test/fuzzdata7.db
|
||||
|
||||
# Standard options to testfixture
|
||||
#
|
||||
@@ -596,13 +605,14 @@ SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_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_SRC = $(TOP)/test/fuzzcheck.c $(TOP)/test/ossfuzz.c
|
||||
DBFUZZ_OPT =
|
||||
DBFUZZ_OPT =
|
||||
|
||||
# This is the default Makefile target. The objects listed here
|
||||
# are what get build when you type just "make" with no arguments.
|
||||
@@ -659,11 +669,28 @@ ossshell$(TEXE): $(TOP)/test/ossfuzz.c $(TOP)/test/ossshell.c sqlite3.c sqlite3.
|
||||
$(TOP)/test/ossfuzz.c sqlite3.c $(TLIBS)
|
||||
|
||||
sessionfuzz$(TEXE): $(TOP)/test/sessionfuzz.c sqlite3.c sqlite3.h
|
||||
$(CC) $(CFLAGS) -I. -o $@ $(TOP)/test/sessionfuzz.c $(TLIBS)
|
||||
$(LTLINK) -o $@ $(TOP)/test/sessionfuzz.c $(TLIBS)
|
||||
|
||||
dbfuzz$(TEXE): $(TOP)/test/dbfuzz.c sqlite3.c sqlite3.h
|
||||
$(LTLINK) -o $@ $(DBFUZZ_OPT) $(TOP)/test/dbfuzz.c sqlite3.c $(TLIBS)
|
||||
|
||||
DBFUZZ2_OPTS = \
|
||||
-DSQLITE_THREADSAFE=0 \
|
||||
-DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
-DSQLITE_ENABLE_DESERIALIZE \
|
||||
-DSQLITE_DEBUG \
|
||||
-DSQLITE_ENABLE_DBSTAT_VTAB \
|
||||
-DSQLITE_ENABLE_RTREE \
|
||||
-DSQLITE_ENABLE_FTS4 \
|
||||
-DSQLITE_EANBLE_FTS5
|
||||
|
||||
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 \
|
||||
$(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c
|
||||
mkdir -p dbfuzz2-dir
|
||||
cp $(TOP)/test/dbfuzz2-seed* dbfuzz2-dir
|
||||
|
||||
mptester$(TEXE): sqlite3.lo $(TOP)/mptest/mptest.c
|
||||
$(LTLINK) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.lo \
|
||||
$(TLIBS) -rpath "$(libdir)"
|
||||
@@ -1099,7 +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
|
||||
|
||||
sqlite3session.lo: $(TOP)/ext/session/sqlite3session.c $(HDR) $(EXTHDR)
|
||||
sqlite3session.lo: $(TOP)/ext/userauth/userauth.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/userauth/userauth.c
|
||||
|
||||
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
|
||||
@@ -1127,7 +1157,7 @@ FTS5_SRC = \
|
||||
$(TOP)/ext/fts5/fts5_varint.c \
|
||||
$(TOP)/ext/fts5/fts5_vocab.c \
|
||||
|
||||
fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon
|
||||
fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon
|
||||
cp $(TOP)/ext/fts5/fts5parse.y .
|
||||
rm -f fts5parse.h
|
||||
./lemon$(BEXE) $(OPTS) fts5parse.y
|
||||
@@ -1154,12 +1184,13 @@ sqlite3rbu.lo: $(TOP)/ext/rbu/sqlite3rbu.c $(HDR) $(EXTHDR)
|
||||
#
|
||||
TESTFIXTURE_FLAGS = -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
|
||||
TESTFIXTURE_FLAGS += -DTCLSH_INIT_PROC=sqlite3TestInit
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
|
||||
TESTFIXTURE_FLAGS += -DBUILD_sqlite
|
||||
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_DESERIALIZE
|
||||
|
||||
TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlite3.la
|
||||
TESTFIXTURE_SRC1 = sqlite3.c
|
||||
@@ -1170,6 +1201,10 @@ testfixture$(TEXE): $(TESTFIXTURE_SRC)
|
||||
$(LTLINK) -DSQLITE_NO_SYNC=1 $(TEMP_STORE) $(TESTFIXTURE_FLAGS) \
|
||||
-o $@ $(TESTFIXTURE_SRC) $(LIBTCL) $(TLIBS)
|
||||
|
||||
coretestprogs: $(TESTPROGS)
|
||||
|
||||
testprogs: coretestprogs srcck1$(BEXE) fuzzcheck$(TEXE) sessionfuzz$(TEXE)
|
||||
|
||||
# A very detailed test running most or all test cases
|
||||
fulltest: $(TESTPROGS) fuzztest
|
||||
./testfixture$(TEXE) $(TOP)/test/all.test $(TESTOPTS)
|
||||
@@ -1229,7 +1264,7 @@ sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $
|
||||
sqlite3_analyzer$(TEXE): sqlite3_analyzer.c
|
||||
$(LTLINK) sqlite3_analyzer.c -o $@ $(LIBTCL) $(TLIBS)
|
||||
|
||||
sqltclsh.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/sqltclsh.tcl $(TOP)/ext/misc/appendvfs.c $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in
|
||||
sqltclsh.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/sqltclsh.tcl $(TOP)/ext/misc/appendvfs.c $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in
|
||||
$(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in >sqltclsh.c
|
||||
|
||||
sqltclsh$(TEXE): sqltclsh.c
|
||||
@@ -1258,6 +1293,9 @@ dbdump$(TEXE): $(TOP)/ext/misc/dbdump.c sqlite3.lo
|
||||
$(LTLINK) -DDBDUMP_STANDALONE -o $@ \
|
||||
$(TOP)/ext/misc/dbdump.c sqlite3.lo $(TLIBS)
|
||||
|
||||
dbtotxt$(TEXE): $(TOP)/tool/dbtotxt.c
|
||||
$(LTLINK)-o $@ $(TOP)/tool/dbtotxt.c
|
||||
|
||||
showdb$(TEXE): $(TOP)/tool/showdb.c sqlite3.lo
|
||||
$(LTLINK) -o $@ $(TOP)/tool/showdb.c sqlite3.lo $(TLIBS)
|
||||
|
||||
@@ -1273,9 +1311,15 @@ showwal$(TEXE): $(TOP)/tool/showwal.c sqlite3.lo
|
||||
showshm$(TEXE): $(TOP)/tool/showshm.c
|
||||
$(LTLINK) -o $@ $(TOP)/tool/showshm.c
|
||||
|
||||
index_usage$(TEXE): $(TOP)/tool/index_usage.c sqlite3.lo
|
||||
$(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)
|
||||
|
||||
changesetfuzz$(TEXE): $(TOP)/ext/session/changesetfuzz.c sqlite3.lo
|
||||
$(LTLINK) -o $@ $(TOP)/ext/session/changesetfuzz.c sqlite3.lo $(TLIBS)
|
||||
|
||||
rollback-test$(TEXE): $(TOP)/tool/rollback-test.c sqlite3.lo
|
||||
$(LTLINK) -o $@ $(TOP)/tool/rollback-test.c sqlite3.lo $(TLIBS)
|
||||
|
||||
@@ -1296,7 +1340,7 @@ KV_OPT += -DSQLITE_DIRECT_OVERFLOW_READ
|
||||
kvtest$(TEXE): $(TOP)/test/kvtest.c sqlite3.c
|
||||
$(LTLINK) $(KV_OPT) -o $@ $(TOP)/test/kvtest.c sqlite3.c $(TLIBS)
|
||||
|
||||
rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.lo
|
||||
rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.lo
|
||||
$(LTLINK) -I. -o $@ $(TOP)/ext/rbu/rbu.c sqlite3.lo $(TLIBS)
|
||||
|
||||
loadfts$(EXE): $(TOP)/tool/loadfts.c libsqlite3.la
|
||||
@@ -1324,7 +1368,7 @@ snapshot-tarball: sqlite3.c
|
||||
# The next two rules are used to support the "threadtest" target. Building
|
||||
# threadtest runs a few thread-safety tests that are implemented in C. This
|
||||
# target is invoked by the releasetest.tcl script.
|
||||
#
|
||||
#
|
||||
THREADTEST3_SRC = $(TOP)/test/threadtest3.c \
|
||||
$(TOP)/test/tt3_checkpoint.c \
|
||||
$(TOP)/test/tt3_index.c \
|
||||
@@ -1338,7 +1382,7 @@ threadtest3$(TEXE): sqlite3.lo $(THREADTEST3_SRC)
|
||||
threadtest: threadtest3$(TEXE)
|
||||
./threadtest3$(TEXE)
|
||||
|
||||
releasetest:
|
||||
releasetest:
|
||||
$(TCLSH_CMD) $(TOP)/test/releasetest.tcl
|
||||
|
||||
# Standard install and cleanup targets
|
||||
@@ -1346,7 +1390,7 @@ releasetest:
|
||||
lib_install: libsqlite3.la
|
||||
$(INSTALL) -d $(DESTDIR)$(libdir)
|
||||
$(LTINSTALL) libsqlite3.la $(DESTDIR)$(libdir)
|
||||
|
||||
|
||||
install: sqlite3$(TEXE) lib_install sqlite3.h sqlite3.pc ${HAVE_TCL:1=tcl_install}
|
||||
$(INSTALL) -d $(DESTDIR)$(bindir)
|
||||
$(LTINSTALL) sqlite3$(TEXE) $(DESTDIR)$(bindir)
|
||||
@@ -1364,7 +1408,7 @@ tcl_install: lib_install libtclsqlite3.la pkgIndex.tcl
|
||||
rm -f $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.a
|
||||
$(INSTALL) -m 0644 pkgIndex.tcl $(DESTDIR)$(TCLLIBDIR)
|
||||
|
||||
clean:
|
||||
clean:
|
||||
rm -f *.lo *.la *.o sqlite3$(TEXE) libsqlite3.la
|
||||
rm -f sqlite3.h opcodes.*
|
||||
rm -rf .libs .deps
|
||||
|
||||
+21
-1
@@ -345,6 +345,7 @@ 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
|
||||
!ENDIF
|
||||
@@ -1623,7 +1624,8 @@ FUZZDATA = \
|
||||
$(TOP)\test\fuzzdata3.db \
|
||||
$(TOP)\test\fuzzdata4.db \
|
||||
$(TOP)\test\fuzzdata5.db \
|
||||
$(TOP)\test\fuzzdata6.db
|
||||
$(TOP)\test\fuzzdata6.db \
|
||||
$(TOP)\test\fuzzdata7.db
|
||||
# <</mark>>
|
||||
|
||||
# Additional compiler options for the shell. These are only effective
|
||||
@@ -1633,6 +1635,7 @@ FUZZDATA = \
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_FTS4=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DESERIALIZE=1
|
||||
!ENDIF
|
||||
|
||||
# <<mark>>
|
||||
@@ -2295,6 +2298,7 @@ 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_JSON1=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DESERIALIZE=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) $(TEST_CCONV_OPTS)
|
||||
|
||||
TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2)
|
||||
@@ -2335,6 +2339,10 @@ extensiontest: testfixture.exe testloadext.dll
|
||||
@set PATH=$(LIBTCLPATH);$(PATH)
|
||||
.\testfixture.exe $(TOP)\test\loadext.test $(TESTOPTS)
|
||||
|
||||
coretestprogs: $(TESTPROGS)
|
||||
|
||||
testprogs: coretestprogs srcck1.exe fuzzcheck.exe sessionfuzz.exe
|
||||
|
||||
fulltest: $(TESTPROGS) fuzztest
|
||||
@set PATH=$(LIBTCLPATH);$(PATH)
|
||||
.\testfixture.exe $(TOP)\test\all.test $(TESTOPTS)
|
||||
@@ -2418,6 +2426,9 @@ testloadext.lo: $(TOP)\src\test_loadext.c $(SQLITE3H)
|
||||
testloadext.dll: testloadext.lo
|
||||
$(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL /OUT:$@ testloadext.lo
|
||||
|
||||
dbtotxt.exe: $(TOP)\tool\dbtotxt.c
|
||||
$(LTLINK) $(NO_WARN) $(TOP)\tool\dbtotxt.c /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
showdb.exe: $(TOP)\tool\showdb.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
$(TOP)\tool\showdb.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
@@ -2437,11 +2448,20 @@ showwal.exe: $(TOP)\tool\showwal.c $(SQLITE3C) $(SQLITE3H)
|
||||
showshm.exe: $(TOP)\tool\showshm.c
|
||||
$(LTLINK) $(NO_WARN) $(TOP)\tool\showshm.c /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
index_usage.exe: $(TOP)\tool\index_usage.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
$(TOP)\tool\index_usage.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
changeset.exe: $(TOP)\ext\session\changeset.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
-DSQLITE_ENABLE_SESSION=1 -DSQLITE_ENABLE_PREUPDATE_HOOK=1 \
|
||||
$(TOP)\ext\session\changeset.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
changesetfuzz.exe: $(TOP)\ext\session\changesetfuzz.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
-DSQLITE_ENABLE_SESSION=1 -DSQLITE_ENABLE_PREUPDATE_HOOK=1 \
|
||||
$(TOP)\ext\session\changesetfuzz.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
fts3view.exe: $(TOP)\ext\fts3\tool\fts3view.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
$(TOP)\ext\fts3\tool\fts3view.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
@@ -283,6 +283,7 @@ 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
|
||||
!ENDIF
|
||||
@@ -937,6 +938,7 @@ LIBRESOBJS =
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_FTS4=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DESERIALIZE=1
|
||||
!ENDIF
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.69 for sqlite 3.26.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.26.0'
|
||||
PACKAGE_STRING='sqlite 3.26.0'
|
||||
PACKAGE_VERSION='3.27.0'
|
||||
PACKAGE_STRING='sqlite 3.27.0'
|
||||
PACKAGE_BUGREPORT=''
|
||||
PACKAGE_URL=''
|
||||
|
||||
@@ -1466,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.26.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]...
|
||||
|
||||
@@ -1531,7 +1531,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlite 3.26.0:";;
|
||||
short | recursive ) echo "Configuration of sqlite 3.27.0:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1657,7 +1657,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlite configure 3.26.0
|
||||
sqlite configure 3.27.0
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
@@ -2076,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.26.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 $@
|
||||
@@ -12232,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.26.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
|
||||
@@ -12298,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.26.0
|
||||
sqlite config.status 3.27.0
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
@@ -777,6 +777,9 @@ For example:</p>
|
||||
<p>This might be needed, for example, if some of the C actions in the
|
||||
grammar call functions that are prototyped in unistd.h.</p>
|
||||
|
||||
<p>Use the <tt><a href="#pcode">%code</a></tt> directive to add code to
|
||||
the end of the generated parser.</p>
|
||||
|
||||
<a name='pleft'></a>
|
||||
<h4>The <tt>%left</tt> directive</h4>
|
||||
|
||||
|
||||
@@ -243,8 +243,10 @@ 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
|
||||
SEARCH TABLE t7 USING INDEX t7_idx_00000061 (a=?)
|
||||
SEARCH TABLE t7 USING INDEX t7_idx_00000062 (b=?)
|
||||
INDEX 1
|
||||
SEARCH TABLE t7 USING INDEX t7_idx_00000061 (a=?)
|
||||
INDEX 2
|
||||
SEARCH TABLE t7 USING INDEX t7_idx_00000062 (b=?)
|
||||
}
|
||||
|
||||
# rowid terms.
|
||||
|
||||
@@ -644,6 +644,7 @@ static int idxRegisterVtab(sqlite3expert *p){
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0, /* xRollbackTo */
|
||||
0, /* xShadowName */
|
||||
};
|
||||
|
||||
return sqlite3_create_module(p->dbv, "expert", &expertModule, (void*)p);
|
||||
|
||||
+32
-13
@@ -338,7 +338,7 @@ int sqlite3Fts3PutVarint(char *p, sqlite_int64 v){
|
||||
}
|
||||
|
||||
#define GETVARINT_STEP(v, ptr, shift, mask1, mask2, var, ret) \
|
||||
v = (v & mask1) | ( (*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++); \
|
||||
@@ -376,20 +376,21 @@ int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
|
||||
** 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, p, 0, 0x00, 0x80, *pi, 1);
|
||||
GETVARINT_INIT(a, ptr, 0, 0x00, 0x80, *pi, 1);
|
||||
#else
|
||||
a = (*p++);
|
||||
a = (*ptr++);
|
||||
assert( a & 0x80 );
|
||||
#endif
|
||||
|
||||
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);
|
||||
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);
|
||||
a = (a & 0x0FFFFFFF );
|
||||
*pi = (int)(a | ((u32)(*p & 0x07) << 28));
|
||||
*pi = (int)(a | ((u32)(*ptr & 0x07) << 28));
|
||||
assert( 0==(a & 0x80000000) );
|
||||
assert( *pi>=0 );
|
||||
return 5;
|
||||
@@ -1821,7 +1822,7 @@ static int fts3ScanInteriorNode(
|
||||
const char *zCsr = zNode; /* Cursor to iterate through node */
|
||||
const char *zEnd = &zCsr[nNode];/* End of interior node buffer */
|
||||
char *zBuffer = 0; /* Buffer to load terms into */
|
||||
int nAlloc = 0; /* Size of allocated buffer */
|
||||
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 */
|
||||
|
||||
@@ -1859,14 +1860,14 @@ static int fts3ScanInteriorNode(
|
||||
zCsr += fts3GetVarint32(zCsr, &nSuffix);
|
||||
|
||||
assert( nPrefix>=0 && nSuffix>=0 );
|
||||
if( &zCsr[nSuffix]>zEnd ){
|
||||
if( nPrefix>zCsr-zNode || nSuffix>zEnd-zCsr ){
|
||||
rc = FTS_CORRUPT_VTAB;
|
||||
goto finish_scan;
|
||||
}
|
||||
if( nPrefix+nSuffix>nAlloc ){
|
||||
if( (i64)nPrefix+nSuffix>nAlloc ){
|
||||
char *zNew;
|
||||
nAlloc = (nPrefix+nSuffix) * 2;
|
||||
zNew = (char *)sqlite3_realloc(zBuffer, nAlloc);
|
||||
nAlloc = ((i64)nPrefix+nSuffix) * 2;
|
||||
zNew = (char *)sqlite3_realloc64(zBuffer, nAlloc);
|
||||
if( !zNew ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto finish_scan;
|
||||
@@ -3846,8 +3847,23 @@ static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if zName is the extension on one of the shadow tables used
|
||||
** by this module.
|
||||
*/
|
||||
static int fts3ShadowName(const char *zName){
|
||||
static const char *azName[] = {
|
||||
"content", "docsize", "segdir", "segments", "stat",
|
||||
};
|
||||
unsigned int i;
|
||||
for(i=0; i<sizeof(azName)/sizeof(azName[0]); i++){
|
||||
if( sqlite3_stricmp(zName, azName[i])==0 ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const sqlite3_module fts3Module = {
|
||||
/* iVersion */ 2,
|
||||
/* iVersion */ 3,
|
||||
/* xCreate */ fts3CreateMethod,
|
||||
/* xConnect */ fts3ConnectMethod,
|
||||
/* xBestIndex */ fts3BestIndexMethod,
|
||||
@@ -3870,6 +3886,7 @@ static const sqlite3_module fts3Module = {
|
||||
/* xSavepoint */ fts3SavepointMethod,
|
||||
/* xRelease */ fts3ReleaseMethod,
|
||||
/* xRollbackTo */ fts3RollbackToMethod,
|
||||
/* xShadowName */ fts3ShadowName,
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -4150,6 +4167,7 @@ static int fts3EvalPhraseLoad(
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_DISABLE_FTS4_DEFERRED
|
||||
/*
|
||||
** This function is called on each phrase after the position lists for
|
||||
** any deferred tokens have been loaded into memory. It updates the phrases
|
||||
@@ -4253,6 +4271,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#endif /* SQLITE_DISABLE_FTS4_DEFERRED */
|
||||
|
||||
/*
|
||||
** Maximum number of tokens a phrase may have to be considered for the
|
||||
|
||||
+2
-1
@@ -539,7 +539,8 @@ int sqlite3Fts3InitAux(sqlite3 *db){
|
||||
0, /* xRename */
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0 /* xRollbackTo */
|
||||
0, /* xRollbackTo */
|
||||
0 /* xShadowName */
|
||||
};
|
||||
int rc; /* Return code */
|
||||
|
||||
|
||||
@@ -361,7 +361,8 @@ int sqlite3Fts3InitTerm(sqlite3 *db){
|
||||
0, /* xRename */
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0 /* xRollbackTo */
|
||||
0, /* xRollbackTo */
|
||||
0 /* xShadowName */
|
||||
};
|
||||
int rc; /* Return code */
|
||||
|
||||
|
||||
@@ -443,7 +443,8 @@ int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){
|
||||
0, /* xRename */
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0 /* xRollbackTo */
|
||||
0, /* xRollbackTo */
|
||||
0 /* xShadowName */
|
||||
};
|
||||
int rc; /* Return code */
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ typedef struct unicode_cursor unicode_cursor;
|
||||
|
||||
struct unicode_tokenizer {
|
||||
sqlite3_tokenizer base;
|
||||
int bRemoveDiacritic;
|
||||
int eRemoveDiacritic;
|
||||
int nException;
|
||||
int *aiException;
|
||||
};
|
||||
@@ -227,17 +227,20 @@ static int unicodeCreate(
|
||||
pNew = (unicode_tokenizer *) sqlite3_malloc(sizeof(unicode_tokenizer));
|
||||
if( pNew==NULL ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(unicode_tokenizer));
|
||||
pNew->bRemoveDiacritic = 1;
|
||||
pNew->eRemoveDiacritic = 1;
|
||||
|
||||
for(i=0; rc==SQLITE_OK && i<nArg; i++){
|
||||
const char *z = azArg[i];
|
||||
int n = (int)strlen(z);
|
||||
|
||||
if( n==19 && memcmp("remove_diacritics=1", z, 19)==0 ){
|
||||
pNew->bRemoveDiacritic = 1;
|
||||
pNew->eRemoveDiacritic = 1;
|
||||
}
|
||||
else if( n==19 && memcmp("remove_diacritics=0", z, 19)==0 ){
|
||||
pNew->bRemoveDiacritic = 0;
|
||||
pNew->eRemoveDiacritic = 0;
|
||||
}
|
||||
else if( n==19 && memcmp("remove_diacritics=2", z, 19)==0 ){
|
||||
pNew->eRemoveDiacritic = 2;
|
||||
}
|
||||
else if( n>=11 && memcmp("tokenchars=", z, 11)==0 ){
|
||||
rc = unicodeAddExceptions(pNew, 1, &z[11], n-11);
|
||||
@@ -350,7 +353,7 @@ static int unicodeNext(
|
||||
|
||||
/* Write the folded case of the last character read to the output */
|
||||
zEnd = z;
|
||||
iOut = sqlite3FtsUnicodeFold((int)iCode, p->bRemoveDiacritic);
|
||||
iOut = sqlite3FtsUnicodeFold((int)iCode, p->eRemoveDiacritic);
|
||||
if( iOut ){
|
||||
WRITE_UTF8(zOut, iOut);
|
||||
}
|
||||
|
||||
+45
-26
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** 2012 May 25
|
||||
** 2012-05-25
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
@@ -159,32 +159,48 @@ int sqlite3FtsUnicodeIsalnum(int c){
|
||||
** E"). The resuls of passing a codepoint that corresponds to an
|
||||
** uppercase letter are undefined.
|
||||
*/
|
||||
static int remove_diacritic(int c){
|
||||
static int remove_diacritic(int c, int bComplex){
|
||||
unsigned short aDia[] = {
|
||||
0, 1797, 1848, 1859, 1891, 1928, 1940, 1995,
|
||||
2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286,
|
||||
2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732,
|
||||
2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336,
|
||||
3456, 3696, 3712, 3728, 3744, 3896, 3912, 3928,
|
||||
3968, 4008, 4040, 4106, 4138, 4170, 4202, 4234,
|
||||
4266, 4296, 4312, 4344, 4408, 4424, 4472, 4504,
|
||||
6148, 6198, 6264, 6280, 6360, 6429, 6505, 6529,
|
||||
61448, 61468, 61534, 61592, 61642, 61688, 61704, 61726,
|
||||
61784, 61800, 61836, 61880, 61914, 61948, 61998, 62122,
|
||||
62154, 62200, 62218, 62302, 62364, 62442, 62478, 62536,
|
||||
62554, 62584, 62604, 62640, 62648, 62656, 62664, 62730,
|
||||
62924, 63050, 63082, 63274, 63390,
|
||||
3456, 3696, 3712, 3728, 3744, 3766, 3832, 3896,
|
||||
3912, 3928, 3944, 3968, 4008, 4040, 4056, 4106,
|
||||
4138, 4170, 4202, 4234, 4266, 4296, 4312, 4344,
|
||||
4408, 4424, 4442, 4472, 4488, 4504, 6148, 6198,
|
||||
6264, 6280, 6360, 6429, 6505, 6529, 61448, 61468,
|
||||
61512, 61534, 61592, 61610, 61642, 61672, 61688, 61704,
|
||||
61726, 61784, 61800, 61816, 61836, 61880, 61896, 61914,
|
||||
61948, 61998, 62062, 62122, 62154, 62184, 62200, 62218,
|
||||
62252, 62302, 62364, 62410, 62442, 62478, 62536, 62554,
|
||||
62584, 62604, 62640, 62648, 62656, 62664, 62730, 62766,
|
||||
62830, 62890, 62924, 62974, 63032, 63050, 63082, 63118,
|
||||
63182, 63242, 63274, 63310, 63368, 63390,
|
||||
};
|
||||
char aChar[] = {
|
||||
'\0', 'a', 'c', 'e', 'i', 'n', 'o', 'u', 'y', 'y', 'a', 'c',
|
||||
'd', 'e', 'e', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'o', 'r',
|
||||
's', 't', 'u', 'u', 'w', 'y', 'z', 'o', 'u', 'a', 'i', 'o',
|
||||
'u', 'g', 'k', 'o', 'j', 'g', 'n', 'a', 'e', 'i', 'o', 'r',
|
||||
'u', 's', 't', 'h', 'a', 'e', 'o', 'y', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', 'a', 'b', 'd', 'd', 'e', 'f', 'g', 'h',
|
||||
'h', 'i', 'k', 'l', 'l', 'm', 'n', 'p', 'r', 'r', 's', 't',
|
||||
'u', 'v', 'w', 'w', 'x', 'y', 'z', 'h', 't', 'w', 'y', 'a',
|
||||
'e', 'i', 'o', 'u', 'y',
|
||||
#define HIBIT ((unsigned char)0x80)
|
||||
unsigned char aChar[] = {
|
||||
'\0', 'a', 'c', 'e', 'i', 'n',
|
||||
'o', 'u', 'y', 'y', 'a', 'c',
|
||||
'd', 'e', 'e', 'g', 'h', 'i',
|
||||
'j', 'k', 'l', 'n', 'o', 'r',
|
||||
's', 't', 'u', 'u', 'w', 'y',
|
||||
'z', 'o', 'u', 'a', 'i', 'o',
|
||||
'u', 'u'|HIBIT, 'a'|HIBIT, 'g', 'k', 'o',
|
||||
'o'|HIBIT, 'j', 'g', 'n', 'a'|HIBIT, 'a',
|
||||
'e', 'i', 'o', 'r', 'u', 's',
|
||||
't', 'h', 'a', 'e', 'o'|HIBIT, 'o',
|
||||
'o'|HIBIT, 'y', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', 'a', 'b',
|
||||
'c'|HIBIT, 'd', 'd', 'e'|HIBIT, 'e', 'e'|HIBIT,
|
||||
'f', 'g', 'h', 'h', 'i', 'i'|HIBIT,
|
||||
'k', 'l', 'l'|HIBIT, 'l', 'm', 'n',
|
||||
'o'|HIBIT, 'p', 'r', 'r'|HIBIT, 'r', 's',
|
||||
's'|HIBIT, 't', 'u', 'u'|HIBIT, 'v', 'w',
|
||||
'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',
|
||||
};
|
||||
|
||||
unsigned int key = (((unsigned int)c)<<3) | 0x00000007;
|
||||
@@ -201,7 +217,8 @@ static int remove_diacritic(int c){
|
||||
}
|
||||
}
|
||||
assert( key>=aDia[iRes] );
|
||||
return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]);
|
||||
if( bComplex==0 && (aChar[iRes] & 0x80) ) return c;
|
||||
return (c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : ((int)aChar[iRes] & 0x7F);
|
||||
}
|
||||
|
||||
|
||||
@@ -214,8 +231,8 @@ int sqlite3FtsUnicodeIsdiacritic(int c){
|
||||
unsigned int mask1 = 0x000361F8;
|
||||
if( c<768 || c>817 ) return 0;
|
||||
return (c < 768+32) ?
|
||||
(mask0 & (1 << (c-768))) :
|
||||
(mask1 & (1 << (c-768-32)));
|
||||
(mask0 & ((unsigned int)1 << (c-768))) :
|
||||
(mask1 & ((unsigned int)1 << (c-768-32)));
|
||||
}
|
||||
|
||||
|
||||
@@ -228,7 +245,7 @@ int sqlite3FtsUnicodeIsdiacritic(int c){
|
||||
** The results are undefined if the value passed to this function
|
||||
** is less than zero.
|
||||
*/
|
||||
int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
|
||||
int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){
|
||||
/* Each entry in the following array defines a rule for folding a range
|
||||
** of codepoints to lower case. The rule applies to a range of nRange
|
||||
** codepoints starting at codepoint iCode.
|
||||
@@ -351,7 +368,9 @@ int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
|
||||
assert( ret>0 );
|
||||
}
|
||||
|
||||
if( bRemoveDiacritic ) ret = remove_diacritic(ret);
|
||||
if( eRemoveDiacritic ){
|
||||
ret = remove_diacritic(ret, eRemoveDiacritic==2);
|
||||
}
|
||||
}
|
||||
|
||||
else if( c>=66560 && c<66600 ){
|
||||
|
||||
+25
-11
@@ -396,10 +396,12 @@ 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);
|
||||
@@ -407,8 +409,7 @@ static int fts3SqlStmt(
|
||||
if( !zSql ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
rc = sqlite3_prepare_v3(p->db, zSql, -1, SQLITE_PREPARE_PERSISTENT,
|
||||
&pStmt, NULL);
|
||||
rc = sqlite3_prepare_v3(p->db, zSql, -1, f, &pStmt, NULL);
|
||||
sqlite3_free(zSql);
|
||||
assert( rc==SQLITE_OK || pStmt==0 );
|
||||
p->aStmt[eStmt] = pStmt;
|
||||
@@ -1374,15 +1375,19 @@ static int fts3SegReaderNext(
|
||||
** safe (no risk of overread) even if the node data is corrupted. */
|
||||
pNext += fts3GetVarint32(pNext, &nPrefix);
|
||||
pNext += fts3GetVarint32(pNext, &nSuffix);
|
||||
if( nPrefix<0 || nSuffix<=0
|
||||
|| &pNext[nSuffix]>&pReader->aNode[pReader->nNode]
|
||||
if( nSuffix<=0
|
||||
|| (&pReader->aNode[pReader->nNode] - pNext)<nSuffix
|
||||
|| nPrefix>pReader->nTermAlloc
|
||||
){
|
||||
return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
|
||||
if( nPrefix+nSuffix>pReader->nTermAlloc ){
|
||||
int nNew = (nPrefix+nSuffix)*2;
|
||||
char *zNew = sqlite3_realloc(pReader->zTerm, nNew);
|
||||
/* Both nPrefix and nSuffix were read by fts3GetVarint32() and so are
|
||||
** between 0 and 0x7FFFFFFF. But the sum of the two may cause integer
|
||||
** overflow - hence the (i64) casts. */
|
||||
if( (i64)nPrefix+nSuffix>(i64)pReader->nTermAlloc ){
|
||||
i64 nNew = ((i64)nPrefix+nSuffix)*2;
|
||||
char *zNew = sqlite3_realloc64(pReader->zTerm, nNew);
|
||||
if( !zNew ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@@ -1404,7 +1409,7 @@ 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->aDoclist[pReader->nDoclist]>&pReader->aNode[pReader->nNode]
|
||||
if( pReader->nDoclist > pReader->nNode-(pReader->aDoclist-pReader->aNode)
|
||||
|| (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1])
|
||||
){
|
||||
return FTS_CORRUPT_VTAB;
|
||||
@@ -1604,7 +1609,11 @@ int sqlite3Fts3SegReaderNew(
|
||||
Fts3SegReader *pReader; /* Newly allocated SegReader object */
|
||||
int nExtra = 0; /* Bytes to allocate segment root node */
|
||||
|
||||
assert( iStartLeaf<=iEndLeaf );
|
||||
assert( zRoot!=0 || nRoot==0 );
|
||||
#ifdef CORRUPT_DB
|
||||
assert( zRoot!=0 || CORRUPT_DB );
|
||||
#endif
|
||||
|
||||
if( iStartLeaf==0 ){
|
||||
nExtra = nRoot + FTS3_NODE_PADDING;
|
||||
}
|
||||
@@ -1625,7 +1634,7 @@ int sqlite3Fts3SegReaderNew(
|
||||
pReader->aNode = (char *)&pReader[1];
|
||||
pReader->rootOnly = 1;
|
||||
pReader->nNode = nRoot;
|
||||
memcpy(pReader->aNode, zRoot, nRoot);
|
||||
if( nRoot ) memcpy(pReader->aNode, zRoot, nRoot);
|
||||
memset(&pReader->aNode[nRoot], 0, FTS3_NODE_PADDING);
|
||||
}else{
|
||||
pReader->iCurrentBlock = iStartLeaf-1;
|
||||
@@ -3730,6 +3739,9 @@ static int nodeReaderNext(NodeReader *p){
|
||||
}
|
||||
p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nSuffix);
|
||||
|
||||
if( nPrefix>p->iOff || nSuffix>p->nNode-p->iOff ){
|
||||
return SQLITE_CORRUPT_VTAB;
|
||||
}
|
||||
blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc);
|
||||
if( rc==SQLITE_OK ){
|
||||
memcpy(&p->term.a[nPrefix], &p->aNode[p->iOff], nSuffix);
|
||||
@@ -3737,6 +3749,9 @@ static int nodeReaderNext(NodeReader *p){
|
||||
p->iOff += nSuffix;
|
||||
if( p->iChild==0 ){
|
||||
p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &p->nDoclist);
|
||||
if( (p->nNode-p->iOff)<p->nDoclist ){
|
||||
return SQLITE_CORRUPT_VTAB;
|
||||
}
|
||||
p->aDoclist = &p->aNode[p->iOff];
|
||||
p->iOff += p->nDoclist;
|
||||
}
|
||||
@@ -3744,7 +3759,6 @@ static int nodeReaderNext(NodeReader *p){
|
||||
}
|
||||
|
||||
assert( p->iOff<=p->nNode );
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,11 +9,12 @@ proc print_rd {map} {
|
||||
set nRange 1
|
||||
set iFirst [lindex $map 0 0]
|
||||
set cPrev [lindex $map 0 1]
|
||||
set fPrev [lindex $map 0 2]
|
||||
|
||||
foreach m [lrange $map 1 end] {
|
||||
foreach {i c} $m {}
|
||||
foreach {i c f} $m {}
|
||||
|
||||
if {$cPrev == $c} {
|
||||
if {$cPrev == $c && $fPrev==$f} {
|
||||
for {set j [expr $iFirst+$nRange]} {$j<$i} {incr j} {
|
||||
if {[info exists tl_lookup_table($j)]==0} break
|
||||
}
|
||||
@@ -29,13 +30,16 @@ proc print_rd {map} {
|
||||
|
||||
lappend lRange [list $iFirst $nRange]
|
||||
lappend aChar $cPrev
|
||||
lappend aFlag $fPrev
|
||||
|
||||
set iFirst $i
|
||||
set cPrev $c
|
||||
set fPrev $f
|
||||
set nRange 1
|
||||
}
|
||||
lappend lRange [list $iFirst $nRange]
|
||||
lappend aChar $cPrev
|
||||
lappend aFlag $fPrev
|
||||
|
||||
puts "/*"
|
||||
puts "** If the argument is a codepoint corresponding to a lowercase letter"
|
||||
@@ -45,7 +49,7 @@ proc print_rd {map} {
|
||||
puts "** E\"). The resuls of passing a codepoint that corresponds to an"
|
||||
puts "** uppercase letter are undefined."
|
||||
puts "*/"
|
||||
puts "static int ${::remove_diacritic}(int c)\{"
|
||||
puts "static int ${::remove_diacritic}(int c, int bComplex)\{"
|
||||
puts " unsigned short aDia\[\] = \{"
|
||||
puts -nonewline " 0, "
|
||||
set i 1
|
||||
@@ -59,14 +63,19 @@ proc print_rd {map} {
|
||||
}
|
||||
puts ""
|
||||
puts " \};"
|
||||
puts " char aChar\[\] = \{"
|
||||
puts -nonewline " '\\0', "
|
||||
puts "#define HIBIT ((unsigned char)0x80)"
|
||||
puts " unsigned char aChar\[\] = \{"
|
||||
puts -nonewline " '\\0', "
|
||||
set i 1
|
||||
foreach c $aChar {
|
||||
set str "'$c', "
|
||||
if {$c == ""} { set str "'\\0', " }
|
||||
foreach c $aChar f $aFlag {
|
||||
if { $f } {
|
||||
set str "'$c'|HIBIT, "
|
||||
} else {
|
||||
set str "'$c', "
|
||||
}
|
||||
if {$c == ""} { set str "'\\0', " }
|
||||
|
||||
if {($i % 12)==0} {puts "" ; puts -nonewline " " }
|
||||
if {($i % 6)==0} {puts "" ; puts -nonewline " " }
|
||||
incr i
|
||||
puts -nonewline "$str"
|
||||
}
|
||||
@@ -87,7 +96,8 @@ proc print_rd {map} {
|
||||
}
|
||||
}
|
||||
assert( key>=aDia[iRes] );
|
||||
return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]);}
|
||||
if( bComplex==0 && (aChar[iRes] & 0x80) ) return c;
|
||||
return (c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : ((int)aChar[iRes] & 0x7F);}
|
||||
puts "\}"
|
||||
}
|
||||
|
||||
@@ -95,7 +105,8 @@ proc print_isdiacritic {zFunc map} {
|
||||
|
||||
set lCode [list]
|
||||
foreach m $map {
|
||||
foreach {code char} $m {}
|
||||
foreach {code char flag} $m {}
|
||||
if {$flag} continue
|
||||
if {$code && $char == ""} { lappend lCode $code }
|
||||
}
|
||||
set lCode [lsort -integer $lCode]
|
||||
@@ -124,8 +135,8 @@ proc print_isdiacritic {zFunc map} {
|
||||
|
||||
puts " if( c<$iFirst || c>$iLast ) return 0;"
|
||||
puts " return (c < $iFirst+32) ?"
|
||||
puts " (mask0 & (1 << (c-$iFirst))) :"
|
||||
puts " (mask1 & (1 << (c-$iFirst-32)));"
|
||||
puts " (mask0 & ((unsigned int)1 << (c-$iFirst))) :"
|
||||
puts " (mask1 & ((unsigned int)1 << (c-$iFirst-32)));"
|
||||
puts "\}"
|
||||
}
|
||||
|
||||
@@ -472,7 +483,7 @@ proc print_fold {zFunc} {
|
||||
puts "** The results are undefined if the value passed to this function"
|
||||
puts "** is less than zero."
|
||||
puts "*/"
|
||||
puts "int ${zFunc}\(int c, int bRemoveDiacritic)\{"
|
||||
puts "int ${zFunc}\(int c, int eRemoveDiacritic)\{"
|
||||
|
||||
set liOff [tl_generate_ioff_table $lRecord]
|
||||
tl_print_table_header
|
||||
@@ -516,7 +527,9 @@ proc print_fold {zFunc} {
|
||||
assert( ret>0 );
|
||||
}
|
||||
|
||||
if( bRemoveDiacritic ) ret = ${::remove_diacritic}(ret);
|
||||
if( eRemoveDiacritic ){
|
||||
ret = ${::remove_diacritic}(ret, eRemoveDiacritic==2);
|
||||
}
|
||||
}
|
||||
}]
|
||||
|
||||
@@ -605,10 +618,6 @@ proc print_categories {lMap} {
|
||||
|
||||
set nCat [expr [llength [array names C]] + 1]
|
||||
puts [code {
|
||||
int sqlite3Fts5UnicodeNCat(void) {
|
||||
return $nCat;
|
||||
}
|
||||
|
||||
int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
|
||||
aArray[0] = 1;
|
||||
switch( zCat[0] ){
|
||||
@@ -691,7 +700,7 @@ proc print_categories {lMap} {
|
||||
static u16 aFts5UnicodeMap[] = {$aMapArray};
|
||||
static u16 aFts5UnicodeData[] = {$aDataArray};
|
||||
|
||||
int sqlite3Fts5UnicodeCategory(int iCode) {
|
||||
int sqlite3Fts5UnicodeCategory(u32 iCode) {
|
||||
int iRes = -1;
|
||||
int iHi;
|
||||
int iLo;
|
||||
@@ -774,7 +783,7 @@ proc print_test_categories {lMap} {
|
||||
aArray[0] = 1;
|
||||
}
|
||||
|
||||
c = sqlite3Fts5UnicodeCategory(i);
|
||||
c = sqlite3Fts5UnicodeCategory((u32)i);
|
||||
if( aArray[c]==0 ){
|
||||
*piCode = i;
|
||||
return 1;
|
||||
@@ -829,7 +838,7 @@ proc print_fold_test {zFunc mappings} {
|
||||
proc print_fileheader {} {
|
||||
puts [string trim {
|
||||
/*
|
||||
** 2012 May 25
|
||||
** 2012-05-25
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
|
||||
@@ -7,12 +7,24 @@
|
||||
# character that it should be replaced with, or an empty string if the
|
||||
# codepoint should simply be removed from the input. Examples:
|
||||
#
|
||||
# { 224 a } (replace codepoint 224 to "a")
|
||||
# { 769 "" } (remove codepoint 769 from input)
|
||||
# { 224 a 0 } (replace codepoint 224 to "a")
|
||||
# { 769 "" 0 } (remove codepoint 769 from input)
|
||||
#
|
||||
# Mappings are only returned for non-upper case codepoints. It is assumed
|
||||
# that the input has already been folded to lower case.
|
||||
#
|
||||
# The third value in the list is always either 0 or 1. 0 if the
|
||||
# UnicodeData.txt file maps the codepoint to a single ASCII character and
|
||||
# a diacritic, or 1 if the mapping is indirect. For example, consider the
|
||||
# two entries:
|
||||
#
|
||||
# 1ECD;LATIN SMALL LETTER O WITH DOT BELOW;Ll;0;L;006F 0323;;;;N;;;1ECC;;1ECC
|
||||
# 1ED9;LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1ECD 0302;;;;N;;;1ED8;;1ED8
|
||||
#
|
||||
# The first codepoint is a direct mapping (as 006F is ASCII and 0323 is a
|
||||
# diacritic). The second is an indirect mapping, as it maps to the
|
||||
# first codepoint plus 0302 (a diacritic).
|
||||
#
|
||||
proc rd_load_unicodedata_text {zName} {
|
||||
global tl_lookup_table
|
||||
|
||||
@@ -53,18 +65,29 @@ proc rd_load_unicodedata_text {zName} {
|
||||
set iAscii [expr "0x[lindex $character_decomposition_mapping 0]"]
|
||||
set iDia [expr "0x[lindex $character_decomposition_mapping 1]"]
|
||||
|
||||
# Filter out upper-case characters, as they will be mapped to their
|
||||
# lower-case equivalents before this data is used.
|
||||
if {[info exists tl_lookup_table($iCode)]} continue
|
||||
|
||||
# Check if this is an indirect mapping. If so, set bIndirect to true
|
||||
# and change $iAscii to the indirectly mappped ASCII character.
|
||||
set bIndirect 0
|
||||
if {[info exists dia($iDia)] && [info exists mapping($iAscii)]} {
|
||||
set iAscii $mapping($iAscii)
|
||||
set bIndirect 1
|
||||
}
|
||||
|
||||
if { ($iAscii >= 97 && $iAscii <= 122)
|
||||
|| ($iAscii >= 65 && $iAscii <= 90)
|
||||
} {
|
||||
lappend lRet [list $iCode [string tolower [format %c $iAscii]]]
|
||||
lappend lRet [list $iCode [string tolower [format %c $iAscii]] $bIndirect]
|
||||
set mapping($iCode) $iAscii
|
||||
set dia($iDia) 1
|
||||
}
|
||||
}
|
||||
|
||||
foreach d [array names dia] {
|
||||
lappend lRet [list $d ""]
|
||||
lappend lRet [list $d "" 0]
|
||||
}
|
||||
set lRet [lsort -integer -index 0 $lRet]
|
||||
|
||||
|
||||
+6
-6
@@ -414,11 +414,11 @@ struct Fts5ExtensionApi {
|
||||
** the tokenizer substitutes "first" for "1st" and the query works
|
||||
** as expected.
|
||||
**
|
||||
** <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:
|
||||
** <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:
|
||||
**
|
||||
** <codeblock>
|
||||
** ... MATCH 'first place'</codeblock>
|
||||
@@ -442,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 would be
|
||||
** when tokenizing query text (it should not - to do so 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.
|
||||
|
||||
+1
-1
@@ -788,7 +788,7 @@ int sqlite3Fts5UnicodeIsdiacritic(int c);
|
||||
int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
|
||||
|
||||
int sqlite3Fts5UnicodeCatParse(const char*, u8*);
|
||||
int sqlite3Fts5UnicodeCategory(int iCode);
|
||||
int sqlite3Fts5UnicodeCategory(u32 iCode);
|
||||
void sqlite3Fts5UnicodeAscii(u8*, u8*);
|
||||
/*
|
||||
** End of interface to code in fts5_unicode2.c.
|
||||
|
||||
@@ -2553,7 +2553,7 @@ static void fts5ExprIsAlnum(
|
||||
sqlite3Fts5UnicodeCatParse("N*", aArr);
|
||||
sqlite3Fts5UnicodeCatParse("Co", aArr);
|
||||
iCode = sqlite3_value_int(apVal[0]);
|
||||
sqlite3_result_int(pCtx, aArr[sqlite3Fts5UnicodeCategory(iCode)]);
|
||||
sqlite3_result_int(pCtx, aArr[sqlite3Fts5UnicodeCategory((u32)iCode)]);
|
||||
}
|
||||
|
||||
static void fts5ExprFold(
|
||||
|
||||
+52
-36
@@ -690,6 +690,7 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
|
||||
pRet = 0;
|
||||
}else{
|
||||
/* TODO1: Fix this */
|
||||
pRet->p[nByte] = 0x00;
|
||||
pRet->szLeaf = fts5GetU16(&pRet->p[2]);
|
||||
}
|
||||
}
|
||||
@@ -729,7 +730,8 @@ static int fts5IndexPrepareStmt(
|
||||
if( p->rc==SQLITE_OK ){
|
||||
if( zSql ){
|
||||
p->rc = sqlite3_prepare_v3(p->pConfig->db, zSql, -1,
|
||||
SQLITE_PREPARE_PERSISTENT, ppStmt, 0);
|
||||
SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB,
|
||||
ppStmt, 0);
|
||||
}else{
|
||||
p->rc = SQLITE_NOMEM;
|
||||
}
|
||||
@@ -770,23 +772,12 @@ 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( 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;
|
||||
}
|
||||
if( fts5IndexPrepareStmt(p, &p->pDeleter, zSql) ) return;
|
||||
}
|
||||
|
||||
sqlite3_bind_int64(p->pDeleter, 1, iFirst);
|
||||
@@ -869,6 +860,11 @@ 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 */
|
||||
@@ -891,25 +887,35 @@ static int fts5StructureDecode(
|
||||
}else{
|
||||
i += fts5GetVarint32(&pData[i], pLvl->nMerge);
|
||||
i += fts5GetVarint32(&pData[i], nTotal);
|
||||
assert( nTotal>=pLvl->nMerge );
|
||||
if( nTotal<pLvl->nMerge ) rc = FTS5_CORRUPT;
|
||||
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], pLvl->aSeg[iSeg].iSegid);
|
||||
i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoFirst);
|
||||
i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoLast);
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
@@ -1647,12 +1653,13 @@ 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->nn ){
|
||||
if( iOff+nNew>pIter->pLeaf->nn || nKeep>pIter->term.n ){
|
||||
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;
|
||||
@@ -1717,7 +1724,7 @@ static void fts5SegIterInit(
|
||||
if( p->rc==SQLITE_OK ){
|
||||
pIter->iLeafOffset = 4;
|
||||
assert_nc( pIter->pLeaf->nn>4 );
|
||||
assert( fts5LeafFirstTermOff(pIter->pLeaf)==4 );
|
||||
assert_nc( fts5LeafFirstTermOff(pIter->pLeaf)==4 );
|
||||
pIter->iPgidxOff = pIter->pLeaf->szLeaf+1;
|
||||
fts5SegIterLoadTerm(p, pIter, 0);
|
||||
fts5SegIterLoadNPos(p, pIter);
|
||||
@@ -2306,6 +2313,7 @@ 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;
|
||||
@@ -2318,8 +2326,11 @@ static void fts5LeafSeek(
|
||||
}
|
||||
|
||||
search_success:
|
||||
|
||||
pIter->iLeafOffset = iOff + nNew;
|
||||
if( pIter->iLeafOffset>n ){
|
||||
p->rc = FTS5_CORRUPT;
|
||||
return;
|
||||
}
|
||||
pIter->iTermLeafOffset = pIter->iLeafOffset;
|
||||
pIter->iTermLeafPgno = pIter->iLeafPgno;
|
||||
|
||||
@@ -2426,7 +2437,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( p->rc!=SQLITE_OK /* 1 */
|
||||
assert_nc( p->rc!=SQLITE_OK /* 1 */
|
||||
|| pIter->pLeaf==0 /* 2 */
|
||||
|| fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)==0 /* 3 */
|
||||
|| (bGe && fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)>0) /* 4 */
|
||||
@@ -3574,23 +3585,23 @@ static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){
|
||||
for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
|
||||
int iId = pStruct->aLevel[iLvl].aSeg[iSeg].iSegid;
|
||||
if( iId<=FTS5_MAX_SEGMENT ){
|
||||
aUsed[(iId-1) / 32] |= 1 << ((iId-1) % 32);
|
||||
aUsed[(iId-1) / 32] |= (u32)1 << ((iId-1) % 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0; aUsed[i]==0xFFFFFFFF; i++);
|
||||
mask = aUsed[i];
|
||||
for(iSegid=0; mask & (1 << iSegid); iSegid++);
|
||||
for(iSegid=0; mask & ((u32)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( iSegid!=pStruct->aLevel[iLvl].aSeg[iSeg].iSegid );
|
||||
assert_nc( iSegid!=pStruct->aLevel[iLvl].aSeg[iSeg].iSegid );
|
||||
}
|
||||
}
|
||||
assert( iSegid>0 && iSegid<=FTS5_MAX_SEGMENT );
|
||||
assert_nc( iSegid>0 && iSegid<=FTS5_MAX_SEGMENT );
|
||||
|
||||
{
|
||||
sqlite3_stmt *pIdxSelect = fts5IdxSelectStmt(p);
|
||||
@@ -3598,7 +3609,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( sqlite3_step(pIdxSelect)!=SQLITE_ROW );
|
||||
assert_nc( sqlite3_step(pIdxSelect)!=SQLITE_ROW );
|
||||
p->rc = sqlite3_reset(pIdxSelect);
|
||||
sqlite3_bind_null(pIdxSelect, 2);
|
||||
}
|
||||
@@ -3747,8 +3758,10 @@ static void fts5WriteBtreeTerm(
|
||||
int nTerm, const u8 *pTerm /* First term on new page */
|
||||
){
|
||||
fts5WriteFlushBtree(p, pWriter);
|
||||
fts5BufferSet(&p->rc, &pWriter->btterm, nTerm, pTerm);
|
||||
pWriter->iBtPage = pWriter->writer.pgno;
|
||||
if( p->rc==SQLITE_OK ){
|
||||
fts5BufferSet(&p->rc, &pWriter->btterm, nTerm, pTerm);
|
||||
pWriter->iBtPage = pWriter->writer.pgno;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3899,6 +3912,7 @@ 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 );
|
||||
@@ -3908,6 +3922,7 @@ 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);
|
||||
}
|
||||
@@ -3940,13 +3955,14 @@ static void fts5WriteAppendTerm(
|
||||
** inefficient, but still correct. */
|
||||
int n = nTerm;
|
||||
if( pPage->term.n ){
|
||||
n = 1 + fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm);
|
||||
n = 1 + fts5PrefixCompress(nMin, pPage->term.p, pTerm);
|
||||
}
|
||||
fts5WriteBtreeTerm(p, pWriter, n, pTerm);
|
||||
if( p->rc!=SQLITE_OK ) return;
|
||||
pPage = &pWriter->writer;
|
||||
}
|
||||
}else{
|
||||
nPrefix = fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm);
|
||||
nPrefix = fts5PrefixCompress(nMin, pPage->term.p, pTerm);
|
||||
fts5BufferAppendVarint(&p->rc, &pPage->buf, nPrefix);
|
||||
}
|
||||
|
||||
@@ -3993,7 +4009,7 @@ static void fts5WriteAppendRowid(
|
||||
if( pWriter->bFirstRowidInDoclist || pWriter->bFirstRowidInPage ){
|
||||
fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid);
|
||||
}else{
|
||||
assert( p->rc || iRowid>pWriter->iPrevRowid );
|
||||
assert_nc( p->rc || iRowid>pWriter->iPrevRowid );
|
||||
fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid - pWriter->iPrevRowid);
|
||||
}
|
||||
pWriter->iPrevRowid = iRowid;
|
||||
@@ -4508,6 +4524,7 @@ 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) ){
|
||||
@@ -4587,7 +4604,7 @@ static void fts5FlushOneHash(Fts5Index *p){
|
||||
/* TODO2: Doclist terminator written here. */
|
||||
/* pBuf->p[pBuf->n++] = '\0'; */
|
||||
assert( pBuf->n<=pBuf->nSpace );
|
||||
sqlite3Fts5HashScanNext(pHash);
|
||||
if( p->rc==SQLITE_OK ) sqlite3Fts5HashScanNext(pHash);
|
||||
}
|
||||
sqlite3Fts5HashClear(pHash);
|
||||
fts5WriteFinish(p, &writer, &pgnoLast);
|
||||
@@ -5402,7 +5419,7 @@ int sqlite3Fts5IndexQuery(
|
||||
fts5CloseReader(p);
|
||||
}
|
||||
|
||||
*ppIter = &pRet->base;
|
||||
*ppIter = (Fts5IndexIter*)pRet;
|
||||
sqlite3Fts5BufferFree(&buf);
|
||||
}
|
||||
return fts5IndexReturn(p);
|
||||
@@ -5864,7 +5881,7 @@ static void fts5IndexIntegrityCheckSegment(
|
||||
|
||||
iOff = fts5LeafFirstTermOff(pLeaf);
|
||||
iRowidOff = fts5LeafFirstRowidOff(pLeaf);
|
||||
if( iRowidOff>=iOff ){
|
||||
if( iRowidOff>=iOff || iOff>=pLeaf->szLeaf ){
|
||||
p->rc = FTS5_CORRUPT;
|
||||
}else{
|
||||
iOff += fts5GetVarint32(&pLeaf->p[iOff], nTerm);
|
||||
@@ -6279,8 +6296,7 @@ static void fts5DecodeFunction(
|
||||
nSpace = n + FTS5_DATA_ZERO_PADDING;
|
||||
a = (u8*)sqlite3Fts5MallocZero(&rc, nSpace);
|
||||
if( a==0 ) goto decode_out;
|
||||
memcpy(a, aBlob, n);
|
||||
|
||||
if( n>0 ) memcpy(a, aBlob, n);
|
||||
|
||||
fts5DecodeRowid(iRowid, &iSegid, &bDlidx, &iHeight, &iPgno);
|
||||
|
||||
|
||||
+17
-1
@@ -2645,9 +2645,24 @@ static void fts5SourceIdFunc(
|
||||
sqlite3_result_text(pCtx, "--FTS5-SOURCE-ID--", -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if zName is the extension on one of the shadow tables used
|
||||
** by this module.
|
||||
*/
|
||||
static int fts5ShadowName(const char *zName){
|
||||
static const char *azName[] = {
|
||||
"config", "content", "data", "docsize", "idx"
|
||||
};
|
||||
unsigned int i;
|
||||
for(i=0; i<sizeof(azName)/sizeof(azName[0]); i++){
|
||||
if( sqlite3_stricmp(zName, azName[i])==0 ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fts5Init(sqlite3 *db){
|
||||
static const sqlite3_module fts5Mod = {
|
||||
/* iVersion */ 2,
|
||||
/* iVersion */ 3,
|
||||
/* xCreate */ fts5CreateMethod,
|
||||
/* xConnect */ fts5ConnectMethod,
|
||||
/* xBestIndex */ fts5BestIndexMethod,
|
||||
@@ -2670,6 +2685,7 @@ static int fts5Init(sqlite3 *db){
|
||||
/* xSavepoint */ fts5SavepointMethod,
|
||||
/* xRelease */ fts5ReleaseMethod,
|
||||
/* xRollbackTo */ fts5RollbackToMethod,
|
||||
/* xShadowName */ fts5ShadowName
|
||||
};
|
||||
|
||||
int rc;
|
||||
|
||||
@@ -136,8 +136,9 @@ static int fts5StorageGetStmt(
|
||||
if( zSql==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
rc = sqlite3_prepare_v3(pC->db, zSql, -1,
|
||||
SQLITE_PREPARE_PERSISTENT, &p->aStmt[eStmt], 0);
|
||||
int f = SQLITE_PREPARE_PERSISTENT;
|
||||
if( eStmt>FTS5_STMT_LOOKUP ) f |= SQLITE_PREPARE_NO_VTAB;
|
||||
rc = sqlite3_prepare_v3(pC->db, zSql, -1, f, &p->aStmt[eStmt], 0);
|
||||
sqlite3_free(zSql);
|
||||
if( rc!=SQLITE_OK && pzErrMsg ){
|
||||
*pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db));
|
||||
@@ -587,7 +588,7 @@ int sqlite3Fts5StorageRebuild(Fts5Storage *p){
|
||||
Fts5Config *pConfig = p->pConfig;
|
||||
sqlite3_stmt *pScan = 0;
|
||||
Fts5InsertCtx ctx;
|
||||
int rc;
|
||||
int rc, rc2;
|
||||
|
||||
memset(&ctx, 0, sizeof(Fts5InsertCtx));
|
||||
ctx.pStorage = p;
|
||||
@@ -626,6 +627,8 @@ 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 ){
|
||||
|
||||
@@ -378,7 +378,7 @@ static int fts5tokFilterMethod(
|
||||
if( pCsr->zInput==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
memcpy(pCsr->zInput, zByte, nByte);
|
||||
if( nByte>0 ) memcpy(pCsr->zInput, zByte, nByte);
|
||||
pCsr->zInput[nByte] = 0;
|
||||
rc = pTab->tok.xTokenize(
|
||||
pTab->pTok, (void*)pCsr, 0, zByte, nByte, fts5tokCb
|
||||
@@ -471,7 +471,8 @@ int sqlite3Fts5TestRegisterTok(sqlite3 *db, fts5_api *pApi){
|
||||
0, /* xRename */
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0 /* xRollbackTo */
|
||||
0, /* xRollbackTo */
|
||||
0 /* xShadowName */
|
||||
};
|
||||
int rc; /* Return code */
|
||||
|
||||
|
||||
+19
-11
@@ -234,13 +234,18 @@ struct Unicode61Tokenizer {
|
||||
unsigned char aTokenChar[128]; /* ASCII range token characters */
|
||||
char *aFold; /* Buffer to fold text into */
|
||||
int nFold; /* Size of aFold[] in bytes */
|
||||
int bRemoveDiacritic; /* True if remove_diacritics=1 is set */
|
||||
int eRemoveDiacritic; /* True if remove_diacritics=1 is set */
|
||||
int nException;
|
||||
int *aiException;
|
||||
|
||||
unsigned char aCategory[32]; /* True for token char categories */
|
||||
};
|
||||
|
||||
/* Values for eRemoveDiacritic (must match internals of fts5_unicode2.c) */
|
||||
#define FTS5_REMOVE_DIACRITICS_NONE 0
|
||||
#define FTS5_REMOVE_DIACRITICS_SIMPLE 1
|
||||
#define FTS5_REMOVE_DIACRITICS_COMPLEX 2
|
||||
|
||||
static int fts5UnicodeAddExceptions(
|
||||
Unicode61Tokenizer *p, /* Tokenizer object */
|
||||
const char *z, /* Characters to treat as exceptions */
|
||||
@@ -257,7 +262,7 @@ static int fts5UnicodeAddExceptions(
|
||||
const unsigned char *zCsr = (const unsigned char*)z;
|
||||
const unsigned char *zTerm = (const unsigned char*)&z[n];
|
||||
while( zCsr<zTerm ){
|
||||
int iCode;
|
||||
u32 iCode;
|
||||
int bToken;
|
||||
READ_UTF8(zCsr, zTerm, iCode);
|
||||
if( iCode<128 ){
|
||||
@@ -269,7 +274,7 @@ static int fts5UnicodeAddExceptions(
|
||||
if( bToken!=bTokenChars && sqlite3Fts5UnicodeIsdiacritic(iCode)==0 ){
|
||||
int i;
|
||||
for(i=0; i<nNew; i++){
|
||||
if( aNew[i]>iCode ) break;
|
||||
if( (u32)aNew[i]>iCode ) break;
|
||||
}
|
||||
memmove(&aNew[i+1], &aNew[i], (nNew-i)*sizeof(int));
|
||||
aNew[i] = iCode;
|
||||
@@ -361,7 +366,7 @@ static int fts5UnicodeCreate(
|
||||
int i;
|
||||
memset(p, 0, sizeof(Unicode61Tokenizer));
|
||||
|
||||
p->bRemoveDiacritic = 1;
|
||||
p->eRemoveDiacritic = FTS5_REMOVE_DIACRITICS_SIMPLE;
|
||||
p->nFold = 64;
|
||||
p->aFold = sqlite3_malloc(p->nFold * sizeof(char));
|
||||
if( p->aFold==0 ){
|
||||
@@ -382,10 +387,15 @@ static int fts5UnicodeCreate(
|
||||
for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
|
||||
const char *zArg = azArg[i+1];
|
||||
if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
|
||||
if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){
|
||||
if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
p->eRemoveDiacritic = (zArg[0] - '0');
|
||||
assert( p->eRemoveDiacritic==FTS5_REMOVE_DIACRITICS_NONE
|
||||
|| p->eRemoveDiacritic==FTS5_REMOVE_DIACRITICS_SIMPLE
|
||||
|| p->eRemoveDiacritic==FTS5_REMOVE_DIACRITICS_COMPLEX
|
||||
);
|
||||
}
|
||||
p->bRemoveDiacritic = (zArg[0]=='1');
|
||||
}else
|
||||
if( 0==sqlite3_stricmp(azArg[i], "tokenchars") ){
|
||||
rc = fts5UnicodeAddExceptions(p, zArg, 1);
|
||||
@@ -419,7 +429,7 @@ static int fts5UnicodeCreate(
|
||||
*/
|
||||
static int fts5UnicodeIsAlnum(Unicode61Tokenizer *p, int iCode){
|
||||
return (
|
||||
p->aCategory[sqlite3Fts5UnicodeCategory(iCode)]
|
||||
p->aCategory[sqlite3Fts5UnicodeCategory((u32)iCode)]
|
||||
^ fts5UnicodeIsException(p, iCode)
|
||||
);
|
||||
}
|
||||
@@ -448,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 ){
|
||||
int iCode; /* non-ASCII codepoint read from input */
|
||||
u32 iCode; /* non-ASCII codepoint read from input */
|
||||
char *zOut = aFold;
|
||||
int is;
|
||||
int ie;
|
||||
@@ -499,7 +509,7 @@ static int fts5UnicodeTokenize(
|
||||
READ_UTF8(zCsr, zTerm, iCode);
|
||||
if( fts5UnicodeIsAlnum(p,iCode)||sqlite3Fts5UnicodeIsdiacritic(iCode) ){
|
||||
non_ascii_tokenchar:
|
||||
iCode = sqlite3Fts5UnicodeFold(iCode, p->bRemoveDiacritic);
|
||||
iCode = sqlite3Fts5UnicodeFold(iCode, p->eRemoveDiacritic);
|
||||
if( iCode ) WRITE_UTF8(zOut, iCode);
|
||||
}else{
|
||||
break;
|
||||
@@ -1274,5 +1284,3 @@ int sqlite3Fts5TokenizerInit(fts5_api *pApi){
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+47
-34
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** 2012 May 25
|
||||
** 2012-05-25
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
@@ -28,32 +28,48 @@
|
||||
** E"). The resuls of passing a codepoint that corresponds to an
|
||||
** uppercase letter are undefined.
|
||||
*/
|
||||
static int fts5_remove_diacritic(int c){
|
||||
static int fts5_remove_diacritic(int c, int bComplex){
|
||||
unsigned short aDia[] = {
|
||||
0, 1797, 1848, 1859, 1891, 1928, 1940, 1995,
|
||||
2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286,
|
||||
2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732,
|
||||
2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336,
|
||||
3456, 3696, 3712, 3728, 3744, 3896, 3912, 3928,
|
||||
3968, 4008, 4040, 4106, 4138, 4170, 4202, 4234,
|
||||
4266, 4296, 4312, 4344, 4408, 4424, 4472, 4504,
|
||||
6148, 6198, 6264, 6280, 6360, 6429, 6505, 6529,
|
||||
61448, 61468, 61534, 61592, 61642, 61688, 61704, 61726,
|
||||
61784, 61800, 61836, 61880, 61914, 61948, 61998, 62122,
|
||||
62154, 62200, 62218, 62302, 62364, 62442, 62478, 62536,
|
||||
62554, 62584, 62604, 62640, 62648, 62656, 62664, 62730,
|
||||
62924, 63050, 63082, 63274, 63390,
|
||||
3456, 3696, 3712, 3728, 3744, 3766, 3832, 3896,
|
||||
3912, 3928, 3944, 3968, 4008, 4040, 4056, 4106,
|
||||
4138, 4170, 4202, 4234, 4266, 4296, 4312, 4344,
|
||||
4408, 4424, 4442, 4472, 4488, 4504, 6148, 6198,
|
||||
6264, 6280, 6360, 6429, 6505, 6529, 61448, 61468,
|
||||
61512, 61534, 61592, 61610, 61642, 61672, 61688, 61704,
|
||||
61726, 61784, 61800, 61816, 61836, 61880, 61896, 61914,
|
||||
61948, 61998, 62062, 62122, 62154, 62184, 62200, 62218,
|
||||
62252, 62302, 62364, 62410, 62442, 62478, 62536, 62554,
|
||||
62584, 62604, 62640, 62648, 62656, 62664, 62730, 62766,
|
||||
62830, 62890, 62924, 62974, 63032, 63050, 63082, 63118,
|
||||
63182, 63242, 63274, 63310, 63368, 63390,
|
||||
};
|
||||
char aChar[] = {
|
||||
'\0', 'a', 'c', 'e', 'i', 'n', 'o', 'u', 'y', 'y', 'a', 'c',
|
||||
'd', 'e', 'e', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'o', 'r',
|
||||
's', 't', 'u', 'u', 'w', 'y', 'z', 'o', 'u', 'a', 'i', 'o',
|
||||
'u', 'g', 'k', 'o', 'j', 'g', 'n', 'a', 'e', 'i', 'o', 'r',
|
||||
'u', 's', 't', 'h', 'a', 'e', 'o', 'y', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', 'a', 'b', 'd', 'd', 'e', 'f', 'g', 'h',
|
||||
'h', 'i', 'k', 'l', 'l', 'm', 'n', 'p', 'r', 'r', 's', 't',
|
||||
'u', 'v', 'w', 'w', 'x', 'y', 'z', 'h', 't', 'w', 'y', 'a',
|
||||
'e', 'i', 'o', 'u', 'y',
|
||||
#define HIBIT ((unsigned char)0x80)
|
||||
unsigned char aChar[] = {
|
||||
'\0', 'a', 'c', 'e', 'i', 'n',
|
||||
'o', 'u', 'y', 'y', 'a', 'c',
|
||||
'd', 'e', 'e', 'g', 'h', 'i',
|
||||
'j', 'k', 'l', 'n', 'o', 'r',
|
||||
's', 't', 'u', 'u', 'w', 'y',
|
||||
'z', 'o', 'u', 'a', 'i', 'o',
|
||||
'u', 'u'|HIBIT, 'a'|HIBIT, 'g', 'k', 'o',
|
||||
'o'|HIBIT, 'j', 'g', 'n', 'a'|HIBIT, 'a',
|
||||
'e', 'i', 'o', 'r', 'u', 's',
|
||||
't', 'h', 'a', 'e', 'o'|HIBIT, 'o',
|
||||
'o'|HIBIT, 'y', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', 'a', 'b',
|
||||
'c'|HIBIT, 'd', 'd', 'e'|HIBIT, 'e', 'e'|HIBIT,
|
||||
'f', 'g', 'h', 'h', 'i', 'i'|HIBIT,
|
||||
'k', 'l', 'l'|HIBIT, 'l', 'm', 'n',
|
||||
'o'|HIBIT, 'p', 'r', 'r'|HIBIT, 'r', 's',
|
||||
's'|HIBIT, 't', 'u', 'u'|HIBIT, 'v', 'w',
|
||||
'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',
|
||||
};
|
||||
|
||||
unsigned int key = (((unsigned int)c)<<3) | 0x00000007;
|
||||
@@ -70,7 +86,8 @@ static int fts5_remove_diacritic(int c){
|
||||
}
|
||||
}
|
||||
assert( key>=aDia[iRes] );
|
||||
return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]);
|
||||
if( bComplex==0 && (aChar[iRes] & 0x80) ) return c;
|
||||
return (c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : ((int)aChar[iRes] & 0x7F);
|
||||
}
|
||||
|
||||
|
||||
@@ -83,8 +100,8 @@ int sqlite3Fts5UnicodeIsdiacritic(int c){
|
||||
unsigned int mask1 = 0x000361F8;
|
||||
if( c<768 || c>817 ) return 0;
|
||||
return (c < 768+32) ?
|
||||
(mask0 & (1 << (c-768))) :
|
||||
(mask1 & (1 << (c-768-32)));
|
||||
(mask0 & ((unsigned int)1 << (c-768))) :
|
||||
(mask1 & ((unsigned int)1 << (c-768-32)));
|
||||
}
|
||||
|
||||
|
||||
@@ -97,7 +114,7 @@ int sqlite3Fts5UnicodeIsdiacritic(int c){
|
||||
** The results are undefined if the value passed to this function
|
||||
** is less than zero.
|
||||
*/
|
||||
int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){
|
||||
int sqlite3Fts5UnicodeFold(int c, int eRemoveDiacritic){
|
||||
/* Each entry in the following array defines a rule for folding a range
|
||||
** of codepoints to lower case. The rule applies to a range of nRange
|
||||
** codepoints starting at codepoint iCode.
|
||||
@@ -220,7 +237,9 @@ int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){
|
||||
assert( ret>0 );
|
||||
}
|
||||
|
||||
if( bRemoveDiacritic ) ret = fts5_remove_diacritic(ret);
|
||||
if( eRemoveDiacritic ){
|
||||
ret = fts5_remove_diacritic(ret, eRemoveDiacritic==2);
|
||||
}
|
||||
}
|
||||
|
||||
else if( c>=66560 && c<66600 ){
|
||||
@@ -231,12 +250,6 @@ int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
int sqlite3Fts5UnicodeNCat(void) {
|
||||
return 32;
|
||||
}
|
||||
#endif
|
||||
|
||||
int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
|
||||
aArray[0] = 1;
|
||||
switch( zCat[0] ){
|
||||
@@ -718,7 +731,7 @@ static u16 aFts5UnicodeData[] = {
|
||||
34, 3074, 7692, 63, 63,
|
||||
};
|
||||
|
||||
int sqlite3Fts5UnicodeCategory(int iCode) {
|
||||
int sqlite3Fts5UnicodeCategory(u32 iCode) {
|
||||
int iRes = -1;
|
||||
int iHi;
|
||||
int iLo;
|
||||
@@ -756,7 +769,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++;
|
||||
}
|
||||
|
||||
@@ -431,6 +431,8 @@ static int fts5VocabInstanceNext(Fts5VocabCursor *pCsr){
|
||||
i64 *pp = &pCsr->iInstPos;
|
||||
int *po = &pCsr->iInstOff;
|
||||
|
||||
assert( sqlite3Fts5IterEof(pIter)==0 );
|
||||
assert( pCsr->bEof==0 );
|
||||
while( eDetail==FTS5_DETAIL_NONE
|
||||
|| sqlite3Fts5PoslistNext64(pIter->pData, pIter->nData, po, pp)
|
||||
){
|
||||
@@ -440,7 +442,7 @@ static int fts5VocabInstanceNext(Fts5VocabCursor *pCsr){
|
||||
rc = sqlite3Fts5IterNextScan(pCsr->pIter);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = fts5VocabInstanceNewTerm(pCsr);
|
||||
if( eDetail==FTS5_DETAIL_NONE ) break;
|
||||
if( pCsr->bEof || eDetail==FTS5_DETAIL_NONE ) break;
|
||||
}
|
||||
if( rc ){
|
||||
pCsr->bEof = 1;
|
||||
@@ -755,10 +757,9 @@ int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){
|
||||
/* xSavepoint */ 0,
|
||||
/* xRelease */ 0,
|
||||
/* xRollbackTo */ 0,
|
||||
/* xShadowName */ 0
|
||||
};
|
||||
void *p = (void*)pGlobal;
|
||||
|
||||
return sqlite3_create_module_v2(db, "fts5vocab", &fts5Vocab, p, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -38,8 +38,7 @@ do_execsql_test 1.0 {
|
||||
do_execsql_test 1.1 {
|
||||
DROP TABLE t1;
|
||||
SELECT name, sql FROM sqlite_master;
|
||||
} {
|
||||
}
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@@ -409,6 +408,7 @@ do_test 14.3 {
|
||||
do_execsql_test 15.0 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
}
|
||||
sqlite3_db_config db DEFENSIVE 0
|
||||
do_execsql_test 15.1 {
|
||||
UPDATE t1_content SET c1 = 'xyz xyz xyz xyz xyz abc' WHERE rowid = 1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
# 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
|
||||
@@ -244,4 +244,3 @@ foreach {tn sql res} {
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ db_save
|
||||
do_execsql_test 1.2 { INSERT INTO t1(t1) VALUES('integrity-check') }
|
||||
set segid [lindex [fts5_level_segids t1] 0]
|
||||
|
||||
sqlite3_db_config db DEFENSIVE 0
|
||||
do_test 1.3 {
|
||||
execsql {
|
||||
DELETE FROM t1_data WHERE rowid = fts5_rowid('segment', $segid, 4);
|
||||
@@ -50,6 +51,7 @@ do_test 1.3 {
|
||||
|
||||
do_test 1.4 {
|
||||
db_restore_and_reopen
|
||||
sqlite3_db_config db DEFENSIVE 0
|
||||
execsql {
|
||||
UPDATE t1_data set block = X'00000000' || substr(block, 5) WHERE
|
||||
rowid = fts5_rowid('segment', $segid, 4);
|
||||
@@ -89,7 +91,7 @@ do_execsql_test 3.0 {
|
||||
do_execsql_test 3.1 {
|
||||
SELECT * FROM t3 WHERE t3 MATCH 'o'
|
||||
} {{one o} {three o} {five o}}
|
||||
|
||||
sqlite3_db_config db DEFENSIVE 0
|
||||
do_catchsql_test 3.1 {
|
||||
DELETE FROM t3_content WHERE rowid = 3;
|
||||
SELECT * FROM t3 WHERE t3 MATCH 'o';
|
||||
|
||||
@@ -99,6 +99,7 @@ foreach {tno stmt} {
|
||||
set lrowid [db one {SELECT max(rowid) FROM t1_data WHERE (rowid & $mask)=0}]
|
||||
set nbyte [db one {SELECT length(block) FROM t1_data WHERE rowid=$lrowid}]
|
||||
set all [db eval {SELECT rowid FROM t1}]
|
||||
sqlite3_db_config db DEFENSIVE 0
|
||||
for {set i [expr $nbyte-2]} {$i>=0} {incr i -1} {
|
||||
do_execsql_test 2.$i.1 {
|
||||
BEGIN;
|
||||
@@ -248,6 +249,7 @@ foreach {tn hdr} {
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
reset_db
|
||||
sqlite3_db_config db DEFENSIVE 0
|
||||
do_execsql_test 6.1 {
|
||||
CREATE VIRTUAL TABLE x5 USING fts5(tt);
|
||||
INSERT INTO x5 VALUES('a');
|
||||
|
||||
+2122
-4
File diff suppressed because it is too large
Load Diff
@@ -93,4 +93,3 @@ do_catchsql_test 3.3 {
|
||||
SELECT * FROM x2('^a');
|
||||
} {1 {fts5: phrase queries are not supported (detail!=full)}}
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ do_execsql_test 4.1 {
|
||||
INSERT INTO aa(aa) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
sqlite3_db_config db DEFENSIVE 0
|
||||
do_catchsql_test 4.2 {
|
||||
BEGIN;
|
||||
UPDATE aa_docsize SET sz = X'44' WHERE rowid = 3;
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
# 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
|
||||
|
||||
@@ -163,4 +163,3 @@ do_execsql_test 5.1 {
|
||||
} {30 31 32 33 34 35 36 37 38 39 40}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ do_execsql_test 1.4 {
|
||||
INSERT INTO f1(f1) VALUES('integrity-check');
|
||||
} {}
|
||||
|
||||
sqlite3_db_config db DEFENSIVE 0
|
||||
do_execsql_test 1.5 {
|
||||
DELETE FROM f1_data;
|
||||
} {}
|
||||
|
||||
@@ -70,6 +70,7 @@ set res [db one {SELECT count(*) FROM x1_data}]
|
||||
do_execsql_test 2.3 {
|
||||
SELECT count(fts5_decode(rowid, block)) FROM x1_data;
|
||||
} $res
|
||||
sqlite3_db_config db DEFENSIVE 0
|
||||
do_execsql_test 2.4 {
|
||||
UPDATE x1_data SET block = X'';
|
||||
SELECT count(fts5_decode(rowid, block)) FROM x1_data;
|
||||
|
||||
@@ -189,7 +189,7 @@ do_catchsql_test 6.2 {
|
||||
} {1 {error in tokenizer constructor}}
|
||||
do_catchsql_test 6.3 {
|
||||
CREATE VIRTUAL TABLE a3 USING fts5(
|
||||
x, y, tokenize = 'unicode61 remove_diacritics 2'
|
||||
x, y, tokenize = 'unicode61 remove_diacritics 3'
|
||||
);
|
||||
} {1 {error in tokenizer constructor}}
|
||||
do_catchsql_test 6.4 {
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
# 2014 June 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 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 fts5umlaut
|
||||
|
||||
# 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(x);
|
||||
CREATE VIRTUAL TABLE t2 USING fts5(
|
||||
x,
|
||||
tokenize="unicode61 remove_diacritics 2"
|
||||
);
|
||||
}
|
||||
|
||||
foreach {tn q res1 res2} {
|
||||
1 "Hà Nội" 0 1
|
||||
2 "Hà Noi" 1 1
|
||||
3 "Ha Noi" 1 1
|
||||
4 "Ha N\u1ed9i" 0 1
|
||||
5 "Ha N\u006fi" 1 1
|
||||
6 "Ha N\u006f\u0302i" 1 1
|
||||
7 "Ha N\u006f\u0323\u0302i" 1 1
|
||||
} {
|
||||
do_execsql_test 1.$tn.1 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(rowid, x) VALUES (1, 'Ha Noi');
|
||||
SELECT count(*) FROM t1($q)
|
||||
} $res1
|
||||
do_execsql_test 1.$tn.2 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(rowid, x) VALUES (1, $q);
|
||||
SELECT count(*) FROM t1('Ha Noi')
|
||||
} $res1
|
||||
|
||||
do_execsql_test 1.$tn.2 {
|
||||
DELETE FROM t2;
|
||||
INSERT INTO t2(rowid, x) VALUES (1, 'Ha Noi');
|
||||
SELECT count(*) FROM t2($q)
|
||||
} $res2
|
||||
do_execsql_test 1.$tn.2 {
|
||||
DELETE FROM t2;
|
||||
INSERT INTO t2(rowid, x) VALUES (1, $q);
|
||||
SELECT count(*) FROM t2('Ha Noi')
|
||||
} $res2
|
||||
}
|
||||
|
||||
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]
|
||||
@@ -36,24 +36,26 @@ foreach x [an_load_unicodedata_text $UD] {
|
||||
}
|
||||
|
||||
foreach {y} [rd_load_unicodedata_text $UD] {
|
||||
foreach {code ascii} $y {}
|
||||
foreach {code ascii f} $y {}
|
||||
if {$ascii==""} {
|
||||
set int 0
|
||||
} else {
|
||||
binary scan $ascii c int
|
||||
}
|
||||
set aDiacritic($code) $int
|
||||
set aDiacritic($code,$f) $int
|
||||
if {$f==0} { set aDiacritic($code,1) $int }
|
||||
}
|
||||
|
||||
proc tcl_fold {i {bRemoveDiacritic 0}} {
|
||||
global tl_lookup_table
|
||||
global aDiacritic
|
||||
set f [expr $bRemoveDiacritic==2]
|
||||
|
||||
if {[info exists tl_lookup_table($i)]} {
|
||||
set i $tl_lookup_table($i)
|
||||
}
|
||||
if {$bRemoveDiacritic && [info exists aDiacritic($i)]} {
|
||||
set i $aDiacritic($i)
|
||||
if {$bRemoveDiacritic && [info exists aDiacritic($i,$f)]} {
|
||||
set i $aDiacritic($i,$f)
|
||||
}
|
||||
expr $i
|
||||
}
|
||||
@@ -85,7 +87,7 @@ do_execsql_test 1.1 {
|
||||
SELECT count(*), min(i) FROM ii WHERE fts5_fold(i)!=CAST(tcl_fold(i) AS int);
|
||||
} {0 {}}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
do_execsql_test 1.2.1 {
|
||||
WITH ii(i) AS (
|
||||
SELECT -1
|
||||
UNION ALL
|
||||
@@ -95,6 +97,16 @@ do_execsql_test 1.2 {
|
||||
WHERE fts5_fold(i,1)!=CAST(tcl_fold(i,1) AS int);
|
||||
} {0 {}}
|
||||
|
||||
do_execsql_test 1.2.2 {
|
||||
WITH ii(i) AS (
|
||||
SELECT -1
|
||||
UNION ALL
|
||||
SELECT i+1 FROM ii WHERE i<100000
|
||||
)
|
||||
SELECT count(*), min(i) FROM ii
|
||||
WHERE fts5_fold(i,2)!=CAST(tcl_fold(i,2) AS int);
|
||||
} {0 {}}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
WITH ii(i) AS (
|
||||
SELECT -1
|
||||
|
||||
@@ -36,9 +36,10 @@ do_execsql_test 1.3 {
|
||||
SELECT rowid FROM t1 WHERE t1 MATCH 'a';
|
||||
} {1}
|
||||
|
||||
sqlite3_db_config db DEFENSIVE 0
|
||||
do_execsql_test 1.4 {
|
||||
UPDATE t1_config set v=5 WHERE k='version';
|
||||
}
|
||||
}
|
||||
|
||||
do_test 1.5 {
|
||||
db close
|
||||
@@ -53,6 +54,7 @@ do_test 1.6 {
|
||||
} {1 {invalid fts5 file format (found 5, expected 4) - run 'rebuild'}}
|
||||
|
||||
do_test 1.7 {
|
||||
sqlite3_db_config db DEFENSIVE 0
|
||||
execsql { DELETE FROM t1_config WHERE k='version' }
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
|
||||
@@ -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');
|
||||
@@ -420,6 +420,7 @@ if {[detail_is_none]} { set resc [row_to_col $resr] }
|
||||
do_execsql_test 8.1.1 { SELECT * FROM x1_r; } $resr
|
||||
do_execsql_test 8.1.2 { SELECT * FROM x1_c } $resc
|
||||
|
||||
sqlite3_db_config db DEFENSIVE 0
|
||||
do_execsql_test 8.2 {
|
||||
PRAGMA writable_schema = 1;
|
||||
UPDATE sqlite_master
|
||||
@@ -481,4 +482,3 @@ do_test 9.6 {
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5vocab
|
||||
set testprefix fts5vocab2
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
@@ -80,8 +80,7 @@ do_execsql_test 1.4 {
|
||||
do_execsql_test 1.5 {
|
||||
DELETE FROM t1;
|
||||
SELECT * FROM v1;
|
||||
} {
|
||||
}
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@@ -143,8 +142,7 @@ do_execsql_test 2.4 {
|
||||
do_execsql_test 2.5 {
|
||||
DELETE FROM t1;
|
||||
SELECT * FROM v1;
|
||||
} {
|
||||
}
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@@ -202,8 +200,6 @@ do_execsql_test 3.4 {
|
||||
do_execsql_test 3.5 {
|
||||
DELETE FROM t1;
|
||||
SELECT * FROM v1;
|
||||
} {
|
||||
}
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
+2
-1
@@ -1473,7 +1473,8 @@ static sqlite3_module amatchModule = {
|
||||
0, /* xRename */
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0 /* xRollbackTo */
|
||||
0, /* xRollbackTo */
|
||||
0 /* xShadowName */
|
||||
};
|
||||
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
@@ -411,6 +411,7 @@ int sqlite3BinfoRegister(sqlite3 *db){
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0, /* xRollbackTo */
|
||||
0 /* xShadowName */
|
||||
};
|
||||
return sqlite3_create_module(db, "sqlite_btreeinfo", &binfo_module, 0);
|
||||
}
|
||||
|
||||
+2
-1
@@ -938,7 +938,8 @@ static sqlite3_module closureModule = {
|
||||
0, /* xRename */
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0 /* xRollbackTo */
|
||||
0, /* xRollbackTo */
|
||||
0 /* xShadowName */
|
||||
};
|
||||
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
@@ -468,7 +468,8 @@ static sqlite3_module completionModule = {
|
||||
0, /* xRename */
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0 /* xRollbackTo */
|
||||
0, /* xRollbackTo */
|
||||
0 /* xShadowName */
|
||||
};
|
||||
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
+96
-35
@@ -19,9 +19,9 @@
|
||||
** CREATE VIRTUAL TABLE temp.csv USING csv(filename=FILENAME);
|
||||
** SELECT * FROM csv;
|
||||
**
|
||||
** The columns are named "c1", "c2", "c3", ... by default. But the
|
||||
** application can define its own CREATE TABLE statement as an additional
|
||||
** parameter. For example:
|
||||
** The columns are named "c1", "c2", "c3", ... by default. Or the
|
||||
** application can define its own CREATE TABLE statement using the
|
||||
** schema= parameter, like this:
|
||||
**
|
||||
** CREATE VIRTUAL TABLE temp.csv2 USING csv(
|
||||
** filename = "../http.log",
|
||||
@@ -32,9 +32,9 @@
|
||||
** the data= parameter.
|
||||
**
|
||||
** If the columns=N parameter is supplied, then the CSV file is assumed to have
|
||||
** N columns. If the columns parameter is omitted, the CSV file is opened
|
||||
** as soon as the virtual table is constructed and the first row of the CSV
|
||||
** is read in order to count the tables.
|
||||
** N columns. If both the columns= and schema= parameters are omitted, then
|
||||
** the number and names of the columns is determined by the first line of
|
||||
** the CSV input.
|
||||
**
|
||||
** Some extra debugging features (used for testing virtual tables) are available
|
||||
** if this module is compiled with -DSQLITE_TEST.
|
||||
@@ -436,6 +436,34 @@ static int csv_boolean(const char *z){
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check to see if the string is of the form: "TAG = BOOLEAN" or just "TAG".
|
||||
** If it is, set *pValue to be the value of the boolean ("true" if there is
|
||||
** not "= BOOLEAN" component) and return non-zero. If the input string
|
||||
** does not begin with TAG, return zero.
|
||||
*/
|
||||
static int csv_boolean_parameter(
|
||||
const char *zTag, /* Tag we are looking for */
|
||||
int nTag, /* Size of the tag in bytes */
|
||||
const char *z, /* Input parameter */
|
||||
int *pValue /* Write boolean value here */
|
||||
){
|
||||
int b;
|
||||
z = csv_skip_whitespace(z);
|
||||
if( strncmp(zTag, z, nTag)!=0 ) return 0;
|
||||
z = csv_skip_whitespace(z + nTag);
|
||||
if( z[0]==0 ){
|
||||
*pValue = 1;
|
||||
return 1;
|
||||
}
|
||||
if( z[0]!='=' ) return 0;
|
||||
z = csv_skip_whitespace(z+1);
|
||||
b = csv_boolean(z);
|
||||
if( b>=0 ){
|
||||
*pValue = b;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Parameters:
|
||||
@@ -469,6 +497,7 @@ static int csvtabConnect(
|
||||
#ifdef SQLITE_TEST
|
||||
int tstFlags = 0; /* Value for testflags=N parameter */
|
||||
#endif
|
||||
int b; /* Value of a boolean parameter */
|
||||
int nCol = -99; /* Value of the columns= parameter */
|
||||
CsvReader sRdr; /* A CSV file reader used to store an error
|
||||
** message and/or to count the number of columns */
|
||||
@@ -493,21 +522,12 @@ static int csvtabConnect(
|
||||
if( j<sizeof(azParam)/sizeof(azParam[0]) ){
|
||||
if( sRdr.zErr[0] ) goto csvtab_connect_error;
|
||||
}else
|
||||
if( (zValue = csv_parameter("header",6,z))!=0 ){
|
||||
int x;
|
||||
if( csv_boolean_parameter("header",6,z,&b) ){
|
||||
if( bHeader>=0 ){
|
||||
csv_errmsg(&sRdr, "more than one 'header' parameter");
|
||||
goto csvtab_connect_error;
|
||||
}
|
||||
x = csv_boolean(zValue);
|
||||
if( x==1 ){
|
||||
bHeader = 1;
|
||||
}else if( x==0 ){
|
||||
bHeader = 0;
|
||||
}else{
|
||||
csv_errmsg(&sRdr, "unrecognized argument to 'header': %s", zValue);
|
||||
goto csvtab_connect_error;
|
||||
}
|
||||
bHeader = b;
|
||||
}else
|
||||
#ifdef SQLITE_TEST
|
||||
if( (zValue = csv_parameter("testflags",9,z))!=0 ){
|
||||
@@ -521,53 +541,94 @@ static int csvtabConnect(
|
||||
}
|
||||
nCol = atoi(zValue);
|
||||
if( nCol<=0 ){
|
||||
csv_errmsg(&sRdr, "must have at least one column");
|
||||
csv_errmsg(&sRdr, "column= value must be positive");
|
||||
goto csvtab_connect_error;
|
||||
}
|
||||
}else
|
||||
{
|
||||
csv_errmsg(&sRdr, "unrecognized parameter '%s'", z);
|
||||
csv_errmsg(&sRdr, "bad parameter: '%s'", z);
|
||||
goto csvtab_connect_error;
|
||||
}
|
||||
}
|
||||
if( (CSV_FILENAME==0)==(CSV_DATA==0) ){
|
||||
csv_errmsg(&sRdr, "must either filename= or data= but not both");
|
||||
csv_errmsg(&sRdr, "must specify either filename= or data= but not both");
|
||||
goto csvtab_connect_error;
|
||||
}
|
||||
if( nCol<=0 && csv_reader_open(&sRdr, CSV_FILENAME, CSV_DATA) ){
|
||||
|
||||
if( (nCol<=0 || bHeader==1)
|
||||
&& csv_reader_open(&sRdr, CSV_FILENAME, CSV_DATA)
|
||||
){
|
||||
goto csvtab_connect_error;
|
||||
}
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
if( pNew==0 ) goto csvtab_connect_oom;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
if( nCol>0 ){
|
||||
if( CSV_SCHEMA==0 ){
|
||||
sqlite3_str *pStr = sqlite3_str_new(0);
|
||||
char *zSep = "";
|
||||
int iCol = 0;
|
||||
sqlite3_str_appendf(pStr, "CREATE TABLE x(");
|
||||
if( nCol<0 && bHeader<1 ){
|
||||
nCol = 0;
|
||||
do{
|
||||
csv_read_one_field(&sRdr);
|
||||
nCol++;
|
||||
}while( sRdr.cTerm==',' );
|
||||
}
|
||||
if( nCol>0 && bHeader<1 ){
|
||||
for(iCol=0; iCol<nCol; iCol++){
|
||||
sqlite3_str_appendf(pStr, "%sc%d TEXT", zSep, iCol);
|
||||
zSep = ",";
|
||||
}
|
||||
}else{
|
||||
do{
|
||||
char *z = csv_read_one_field(&sRdr);
|
||||
if( (nCol>0 && iCol<nCol) || (nCol<0 && bHeader) ){
|
||||
sqlite3_str_appendf(pStr,"%s\"%w\" TEXT", zSep, z);
|
||||
zSep = ",";
|
||||
iCol++;
|
||||
}
|
||||
}while( sRdr.cTerm==',' );
|
||||
if( nCol<0 ){
|
||||
nCol = iCol;
|
||||
}else{
|
||||
while( iCol<nCol ){
|
||||
sqlite3_str_appendf(pStr,"%sc%d TEXT", zSep, ++iCol);
|
||||
zSep = ",";
|
||||
}
|
||||
}
|
||||
}
|
||||
pNew->nCol = nCol;
|
||||
}else{
|
||||
sqlite3_str_appendf(pStr, ")");
|
||||
CSV_SCHEMA = sqlite3_str_finish(pStr);
|
||||
if( CSV_SCHEMA==0 ) goto csvtab_connect_oom;
|
||||
}else if( nCol<0 ){
|
||||
do{
|
||||
csv_read_one_field(&sRdr);
|
||||
pNew->nCol++;
|
||||
}while( sRdr.cTerm==',' );
|
||||
}else{
|
||||
pNew->nCol = nCol;
|
||||
}
|
||||
pNew->zFilename = CSV_FILENAME; CSV_FILENAME = 0;
|
||||
pNew->zData = CSV_DATA; CSV_DATA = 0;
|
||||
#ifdef SQLITE_TEST
|
||||
pNew->tstFlags = tstFlags;
|
||||
#endif
|
||||
pNew->iStart = bHeader==1 ? ftell(sRdr.in) : 0;
|
||||
csv_reader_reset(&sRdr);
|
||||
if( CSV_SCHEMA==0 ){
|
||||
char *zSep = "";
|
||||
CSV_SCHEMA = sqlite3_mprintf("CREATE TABLE x(");
|
||||
if( CSV_SCHEMA==0 ) goto csvtab_connect_oom;
|
||||
for(i=0; i<pNew->nCol; i++){
|
||||
CSV_SCHEMA = sqlite3_mprintf("%z%sc%d TEXT",CSV_SCHEMA, zSep, i);
|
||||
zSep = ",";
|
||||
}
|
||||
CSV_SCHEMA = sqlite3_mprintf("%z);", CSV_SCHEMA);
|
||||
if( bHeader!=1 ){
|
||||
pNew->iStart = 0;
|
||||
}else if( pNew->zData ){
|
||||
pNew->iStart = (int)sRdr.iIn;
|
||||
}else{
|
||||
pNew->iStart = (int)(ftell(sRdr.in) - sRdr.nIn + sRdr.iIn);
|
||||
}
|
||||
csv_reader_reset(&sRdr);
|
||||
rc = sqlite3_declare_vtab(db, CSV_SCHEMA);
|
||||
if( rc ) goto csvtab_connect_error;
|
||||
if( rc ){
|
||||
csv_errmsg(&sRdr, "bad schema: '%s' - %s", CSV_SCHEMA, sqlite3_errmsg(db));
|
||||
goto csvtab_connect_error;
|
||||
}
|
||||
for(i=0; i<sizeof(azPValue)/sizeof(azPValue[0]); i++){
|
||||
sqlite3_free(azPValue[i]);
|
||||
}
|
||||
|
||||
+24
-11
@@ -18,6 +18,10 @@
|
||||
** .load ./explain
|
||||
** SELECT p2 FROM explain('SELECT * FROM sqlite_master')
|
||||
** WHERE opcode='OpenRead';
|
||||
**
|
||||
** This module was originally written to help simplify SQLite testing,
|
||||
** by providing an easier means of verifying certain patterns in the
|
||||
** generated bytecode.
|
||||
*/
|
||||
#if !defined(SQLITEINT_H)
|
||||
#include "sqlite3ext.h"
|
||||
@@ -232,23 +236,31 @@ static int explainBestIndex(
|
||||
sqlite3_vtab *tab,
|
||||
sqlite3_index_info *pIdxInfo
|
||||
){
|
||||
int i;
|
||||
int i; /* Loop counter */
|
||||
int idx = -1; /* Index of a usable == constraint against SQL */
|
||||
int unusable = 0; /* True if there are unusable constraints on SQL */
|
||||
|
||||
pIdxInfo->estimatedCost = (double)1000000;
|
||||
pIdxInfo->estimatedRows = 500;
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++){
|
||||
struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
|
||||
if( p->usable
|
||||
&& p->iColumn==EXPLN_COLUMN_SQL
|
||||
&& p->op==SQLITE_INDEX_CONSTRAINT_EQ
|
||||
){
|
||||
pIdxInfo->estimatedCost = 10.0;
|
||||
pIdxInfo->idxNum = 1;
|
||||
pIdxInfo->aConstraintUsage[i].argvIndex = 1;
|
||||
pIdxInfo->aConstraintUsage[i].omit = 1;
|
||||
break;
|
||||
if( p->iColumn!=EXPLN_COLUMN_SQL ) continue;
|
||||
if( !p->usable ){
|
||||
unusable = 1;
|
||||
}else if( p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
if( idx>=0 ){
|
||||
/* There exists a usable == constraint against the SQL column */
|
||||
pIdxInfo->estimatedCost = 10.0;
|
||||
pIdxInfo->idxNum = 1;
|
||||
pIdxInfo->aConstraintUsage[idx].argvIndex = 1;
|
||||
pIdxInfo->aConstraintUsage[idx].omit = 1;
|
||||
}else if( unusable ){
|
||||
/* There are unusable constraints against the SQL column. Do not allow
|
||||
** this plan to continue forward. */
|
||||
return SQLITE_CONSTRAINT;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -280,6 +292,7 @@ static sqlite3_module explainModule = {
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0, /* xRollbackTo */
|
||||
0, /* xShadowName */
|
||||
};
|
||||
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
+66
-22
@@ -106,7 +106,18 @@ SQLITE_EXTENSION_INIT1
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
/*
|
||||
** Structure of the fsdir() table-valued function
|
||||
*/
|
||||
/* 0 1 2 3 4 5 */
|
||||
#define FSDIR_SCHEMA "(name,mode,mtime,data,path HIDDEN,dir HIDDEN)"
|
||||
#define FSDIR_COLUMN_NAME 0 /* Name of the file */
|
||||
#define FSDIR_COLUMN_MODE 1 /* Access mode */
|
||||
#define FSDIR_COLUMN_MTIME 2 /* Last modification time */
|
||||
#define FSDIR_COLUMN_DATA 3 /* File content */
|
||||
#define FSDIR_COLUMN_PATH 4 /* Path to top of search */
|
||||
#define FSDIR_COLUMN_DIR 5 /* Path is relative to this directory */
|
||||
|
||||
|
||||
/*
|
||||
** Set the result stored by context ctx to a blob containing the
|
||||
@@ -695,20 +706,20 @@ static int fsdirColumn(
|
||||
){
|
||||
fsdir_cursor *pCur = (fsdir_cursor*)cur;
|
||||
switch( i ){
|
||||
case 0: { /* name */
|
||||
case FSDIR_COLUMN_NAME: {
|
||||
sqlite3_result_text(ctx, &pCur->zPath[pCur->nBase], -1, SQLITE_TRANSIENT);
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: /* mode */
|
||||
case FSDIR_COLUMN_MODE:
|
||||
sqlite3_result_int64(ctx, pCur->sStat.st_mode);
|
||||
break;
|
||||
|
||||
case 2: /* mtime */
|
||||
case FSDIR_COLUMN_MTIME:
|
||||
sqlite3_result_int64(ctx, pCur->sStat.st_mtime);
|
||||
break;
|
||||
|
||||
case 3: { /* data */
|
||||
case FSDIR_COLUMN_DATA: {
|
||||
mode_t m = pCur->sStat.st_mode;
|
||||
if( S_ISDIR(m) ){
|
||||
sqlite3_result_null(ctx);
|
||||
@@ -738,6 +749,12 @@ static int fsdirColumn(
|
||||
readFileContents(ctx, pCur->zPath);
|
||||
}
|
||||
}
|
||||
case FSDIR_COLUMN_PATH:
|
||||
default: {
|
||||
/* The FSDIR_COLUMN_PATH and FSDIR_COLUMN_DIR are input parameters.
|
||||
** always return their values as NULL */
|
||||
break;
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -764,6 +781,9 @@ static int fsdirEof(sqlite3_vtab_cursor *cur){
|
||||
|
||||
/*
|
||||
** xFilter callback.
|
||||
**
|
||||
** idxNum==1 PATH parameter only
|
||||
** idxNum==2 Both PATH and DIR supplied
|
||||
*/
|
||||
static int fsdirFilter(
|
||||
sqlite3_vtab_cursor *cur,
|
||||
@@ -816,40 +836,63 @@ static int fsdirFilter(
|
||||
** In this implementation idxNum is used to represent the
|
||||
** query plan. idxStr is unused.
|
||||
**
|
||||
** The query plan is represented by bits in idxNum:
|
||||
** The query plan is represented by values of idxNum:
|
||||
**
|
||||
** (1) start = $value -- constraint exists
|
||||
** (2) stop = $value -- constraint exists
|
||||
** (4) step = $value -- constraint exists
|
||||
** (8) output in descending order
|
||||
** (1) The path value is supplied by argv[0]
|
||||
** (2) Path is in argv[0] and dir is in argv[1]
|
||||
*/
|
||||
static int fsdirBestIndex(
|
||||
sqlite3_vtab *tab,
|
||||
sqlite3_index_info *pIdxInfo
|
||||
){
|
||||
int i; /* Loop over constraints */
|
||||
int idx4 = -1;
|
||||
int idx5 = -1;
|
||||
int idxPath = -1; /* Index in pIdxInfo->aConstraint of PATH= */
|
||||
int idxDir = -1; /* Index in pIdxInfo->aConstraint of DIR= */
|
||||
int seenPath = 0; /* True if an unusable PATH= constraint is seen */
|
||||
int seenDir = 0; /* True if an unusable DIR= constraint is seen */
|
||||
const struct sqlite3_index_constraint *pConstraint;
|
||||
|
||||
(void)tab;
|
||||
pConstraint = pIdxInfo->aConstraint;
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
|
||||
if( pConstraint->usable==0 ) continue;
|
||||
if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
|
||||
if( pConstraint->iColumn==4 ) idx4 = i;
|
||||
if( pConstraint->iColumn==5 ) idx5 = i;
|
||||
switch( pConstraint->iColumn ){
|
||||
case FSDIR_COLUMN_PATH: {
|
||||
if( pConstraint->usable ){
|
||||
idxPath = i;
|
||||
seenPath = 0;
|
||||
}else if( idxPath<0 ){
|
||||
seenPath = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FSDIR_COLUMN_DIR: {
|
||||
if( pConstraint->usable ){
|
||||
idxDir = i;
|
||||
seenDir = 0;
|
||||
}else if( idxDir<0 ){
|
||||
seenDir = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( seenPath || seenDir ){
|
||||
/* If input parameters are unusable, disallow this plan */
|
||||
return SQLITE_CONSTRAINT;
|
||||
}
|
||||
|
||||
if( idx4<0 ){
|
||||
if( idxPath<0 ){
|
||||
pIdxInfo->idxNum = 0;
|
||||
pIdxInfo->estimatedCost = (double)(((sqlite3_int64)1) << 50);
|
||||
/* The pIdxInfo->estimatedCost should have been initialized to a huge
|
||||
** number. Leave it unchanged. */
|
||||
pIdxInfo->estimatedRows = 0x7fffffff;
|
||||
}else{
|
||||
pIdxInfo->aConstraintUsage[idx4].omit = 1;
|
||||
pIdxInfo->aConstraintUsage[idx4].argvIndex = 1;
|
||||
if( idx5>=0 ){
|
||||
pIdxInfo->aConstraintUsage[idx5].omit = 1;
|
||||
pIdxInfo->aConstraintUsage[idx5].argvIndex = 2;
|
||||
pIdxInfo->aConstraintUsage[idxPath].omit = 1;
|
||||
pIdxInfo->aConstraintUsage[idxPath].argvIndex = 1;
|
||||
if( idxDir>=0 ){
|
||||
pIdxInfo->aConstraintUsage[idxDir].omit = 1;
|
||||
pIdxInfo->aConstraintUsage[idxDir].argvIndex = 2;
|
||||
pIdxInfo->idxNum = 2;
|
||||
pIdxInfo->estimatedCost = 10.0;
|
||||
}else{
|
||||
@@ -888,7 +931,8 @@ static int fsdirRegister(sqlite3 *db){
|
||||
0, /* xRename */
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0 /* xRollbackTo */
|
||||
0, /* xRollbackTo */
|
||||
0, /* xShadowName */
|
||||
};
|
||||
|
||||
int rc = sqlite3_create_module(db, "fsdir", &fsdirModule, 0);
|
||||
|
||||
+44
-20
@@ -1994,6 +1994,9 @@ static int jsonEachConnect(
|
||||
#define JEACH_PARENT 5
|
||||
#define JEACH_FULLKEY 6
|
||||
#define JEACH_PATH 7
|
||||
/* The xBestIndex method assumes that the JSON and ROOT columns are
|
||||
** the last two columns in the table. Should this ever changes, be
|
||||
** sure to update the xBestIndex method. */
|
||||
#define JEACH_JSON 8
|
||||
#define JEACH_ROOT 9
|
||||
|
||||
@@ -2251,35 +2254,54 @@ static int jsonEachBestIndex(
|
||||
sqlite3_vtab *tab,
|
||||
sqlite3_index_info *pIdxInfo
|
||||
){
|
||||
int i;
|
||||
int jsonIdx = -1;
|
||||
int rootIdx = -1;
|
||||
int i; /* Loop counter or computed array index */
|
||||
int aIdx[2]; /* Index of constraints for JSON and ROOT */
|
||||
int unusableMask = 0; /* Mask of unusable JSON and ROOT constraints */
|
||||
int idxMask = 0; /* Mask of usable == constraints JSON and ROOT */
|
||||
const struct sqlite3_index_constraint *pConstraint;
|
||||
|
||||
/* This implementation assumes that JSON and ROOT are the last two
|
||||
** columns in the table */
|
||||
assert( JEACH_ROOT == JEACH_JSON+1 );
|
||||
UNUSED_PARAM(tab);
|
||||
aIdx[0] = aIdx[1] = -1;
|
||||
pConstraint = pIdxInfo->aConstraint;
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
|
||||
if( pConstraint->usable==0 ) continue;
|
||||
if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
|
||||
switch( pConstraint->iColumn ){
|
||||
case JEACH_JSON: jsonIdx = i; break;
|
||||
case JEACH_ROOT: rootIdx = i; break;
|
||||
default: /* no-op */ break;
|
||||
int iCol;
|
||||
int iMask;
|
||||
if( pConstraint->iColumn < JEACH_JSON ) continue;
|
||||
iCol = pConstraint->iColumn - JEACH_JSON;
|
||||
assert( iCol==0 || iCol==1 );
|
||||
iMask = 1 << iCol;
|
||||
if( pConstraint->usable==0 ){
|
||||
unusableMask |= iMask;
|
||||
}else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){
|
||||
aIdx[iCol] = i;
|
||||
idxMask |= iMask;
|
||||
}
|
||||
}
|
||||
if( jsonIdx<0 ){
|
||||
if( (unusableMask & ~idxMask)!=0 ){
|
||||
/* If there are any unusable constraints on JSON or ROOT, then reject
|
||||
** this entire plan */
|
||||
return SQLITE_CONSTRAINT;
|
||||
}
|
||||
if( aIdx[0]<0 ){
|
||||
/* No JSON input. Leave estimatedCost at the huge value that it was
|
||||
** initialized to to discourage the query planner from selecting this
|
||||
** plan. */
|
||||
pIdxInfo->idxNum = 0;
|
||||
pIdxInfo->estimatedCost = 1e99;
|
||||
}else{
|
||||
pIdxInfo->estimatedCost = 1.0;
|
||||
pIdxInfo->aConstraintUsage[jsonIdx].argvIndex = 1;
|
||||
pIdxInfo->aConstraintUsage[jsonIdx].omit = 1;
|
||||
if( rootIdx<0 ){
|
||||
pIdxInfo->idxNum = 1;
|
||||
i = aIdx[0];
|
||||
pIdxInfo->aConstraintUsage[i].argvIndex = 1;
|
||||
pIdxInfo->aConstraintUsage[i].omit = 1;
|
||||
if( aIdx[1]<0 ){
|
||||
pIdxInfo->idxNum = 1; /* Only JSON supplied. Plan 1 */
|
||||
}else{
|
||||
pIdxInfo->aConstraintUsage[rootIdx].argvIndex = 2;
|
||||
pIdxInfo->aConstraintUsage[rootIdx].omit = 1;
|
||||
pIdxInfo->idxNum = 3;
|
||||
i = aIdx[1];
|
||||
pIdxInfo->aConstraintUsage[i].argvIndex = 2;
|
||||
pIdxInfo->aConstraintUsage[i].omit = 1;
|
||||
pIdxInfo->idxNum = 3; /* Both JSON and ROOT are supplied. Plan 3 */
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
@@ -2388,7 +2410,8 @@ static sqlite3_module jsonEachModule = {
|
||||
0, /* xRename */
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0 /* xRollbackTo */
|
||||
0, /* xRollbackTo */
|
||||
0 /* xShadowName */
|
||||
};
|
||||
|
||||
/* The methods of the json_tree virtual table. */
|
||||
@@ -2415,7 +2438,8 @@ static sqlite3_module jsonTreeModule = {
|
||||
0, /* xRename */
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0 /* xRollbackTo */
|
||||
0, /* xRollbackTo */
|
||||
0 /* xShadowName */
|
||||
};
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
|
||||
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
** 2018-09-27
|
||||
**
|
||||
** 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 demonstrates an eponymous virtual table that returns information
|
||||
** from sqlite3_status64() and sqlite3_db_status().
|
||||
**
|
||||
** Usage example:
|
||||
**
|
||||
** .load ./memstat
|
||||
** .mode quote
|
||||
** .header on
|
||||
** SELECT * FROM memstat;
|
||||
*/
|
||||
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_MEMSTATVTAB)
|
||||
#if !defined(SQLITEINT_H)
|
||||
#include "sqlite3ext.h"
|
||||
#endif
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
/* memstat_vtab is a subclass of sqlite3_vtab which will
|
||||
** serve as the underlying representation of a memstat virtual table
|
||||
*/
|
||||
typedef struct memstat_vtab memstat_vtab;
|
||||
struct memstat_vtab {
|
||||
sqlite3_vtab base; /* Base class - must be first */
|
||||
sqlite3 *db; /* Database connection for this memstat vtab */
|
||||
};
|
||||
|
||||
/* memstat_cursor is a subclass of sqlite3_vtab_cursor which will
|
||||
** serve as the underlying representation of a cursor that scans
|
||||
** over rows of the result
|
||||
*/
|
||||
typedef struct memstat_cursor memstat_cursor;
|
||||
struct memstat_cursor {
|
||||
sqlite3_vtab_cursor base; /* Base class - must be first */
|
||||
sqlite3 *db; /* Database connection for this cursor */
|
||||
int iRowid; /* Current row in aMemstatColumn[] */
|
||||
int iDb; /* Which schema we are looking at */
|
||||
int nDb; /* Number of schemas */
|
||||
char **azDb; /* Names of all schemas */
|
||||
sqlite3_int64 aVal[2]; /* Result values */
|
||||
};
|
||||
|
||||
/*
|
||||
** The memstatConnect() method is invoked to create a new
|
||||
** memstat_vtab that describes the memstat virtual table.
|
||||
**
|
||||
** Think of this routine as the constructor for memstat_vtab objects.
|
||||
**
|
||||
** All this routine needs to do is:
|
||||
**
|
||||
** (1) Allocate the memstat_vtab object and initialize all fields.
|
||||
**
|
||||
** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
|
||||
** result set of queries against memstat will look like.
|
||||
*/
|
||||
static int memstatConnect(
|
||||
sqlite3 *db,
|
||||
void *pAux,
|
||||
int argc, const char *const*argv,
|
||||
sqlite3_vtab **ppVtab,
|
||||
char **pzErr
|
||||
){
|
||||
memstat_vtab *pNew;
|
||||
int rc;
|
||||
|
||||
/* Column numbers */
|
||||
#define MSV_COLUMN_NAME 0 /* Name of quantity being measured */
|
||||
#define MSV_COLUMN_SCHEMA 1 /* schema name */
|
||||
#define MSV_COLUMN_VALUE 2 /* Current value */
|
||||
#define MSV_COLUMN_HIWTR 3 /* Highwater mark */
|
||||
|
||||
rc = sqlite3_declare_vtab(db,"CREATE TABLE x(name,schema,value,hiwtr)");
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
pNew->db = db;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is the destructor for memstat_cursor objects.
|
||||
*/
|
||||
static int memstatDisconnect(sqlite3_vtab *pVtab){
|
||||
sqlite3_free(pVtab);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Constructor for a new memstat_cursor object.
|
||||
*/
|
||||
static int memstatOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
memstat_cursor *pCur;
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
pCur->db = ((memstat_vtab*)p)->db;
|
||||
*ppCursor = &pCur->base;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Clear all the schema names from a cursor
|
||||
*/
|
||||
static void memstatClearSchema(memstat_cursor *pCur){
|
||||
int i;
|
||||
if( pCur->azDb==0 ) return;
|
||||
for(i=0; i<pCur->nDb; i++){
|
||||
sqlite3_free(pCur->azDb[i]);
|
||||
}
|
||||
sqlite3_free(pCur->azDb);
|
||||
pCur->azDb = 0;
|
||||
pCur->nDb = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Fill in the azDb[] array for the cursor.
|
||||
*/
|
||||
static int memstatFindSchemas(memstat_cursor *pCur){
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
int rc;
|
||||
if( pCur->nDb ) return SQLITE_OK;
|
||||
rc = sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pStmt, 0);
|
||||
if( rc ){
|
||||
sqlite3_finalize(pStmt);
|
||||
return rc;
|
||||
}
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
char **az, *z;
|
||||
az = sqlite3_realloc(pCur->azDb, sizeof(char*)*(pCur->nDb+1));
|
||||
if( az==0 ){
|
||||
memstatClearSchema(pCur);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pCur->azDb = az;
|
||||
z = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1));
|
||||
if( z==0 ){
|
||||
memstatClearSchema(pCur);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pCur->azDb[pCur->nDb] = z;
|
||||
pCur->nDb++;
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Destructor for a memstat_cursor.
|
||||
*/
|
||||
static int memstatClose(sqlite3_vtab_cursor *cur){
|
||||
memstat_cursor *pCur = (memstat_cursor*)cur;
|
||||
memstatClearSchema(pCur);
|
||||
sqlite3_free(cur);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Allowed values for aMemstatColumn[].eType
|
||||
*/
|
||||
#define MSV_GSTAT 0 /* sqlite3_status64() information */
|
||||
#define MSV_DB 1 /* sqlite3_db_status() information */
|
||||
#define MSV_ZIPVFS 2 /* ZIPVFS file-control with 64-bit return */
|
||||
|
||||
/*
|
||||
** An array of quantities that can be measured and reported by
|
||||
** this virtual table
|
||||
*/
|
||||
static const struct MemstatColumns {
|
||||
const char *zName; /* Symbolic name */
|
||||
unsigned char eType; /* Type of interface */
|
||||
unsigned char mNull; /* Bitmask of which columns are NULL */
|
||||
/* 2: dbname, 4: current, 8: hiwtr */
|
||||
int eOp; /* Opcode */
|
||||
} aMemstatColumn[] = {
|
||||
{"MEMORY_USED", MSV_GSTAT, 2, SQLITE_STATUS_MEMORY_USED },
|
||||
{"MALLOC_SIZE", MSV_GSTAT, 6, SQLITE_STATUS_MALLOC_SIZE },
|
||||
{"MALLOC_COUNT", MSV_GSTAT, 2, SQLITE_STATUS_MALLOC_COUNT },
|
||||
{"PAGECACHE_USED", MSV_GSTAT, 2, SQLITE_STATUS_PAGECACHE_USED },
|
||||
{"PAGECACHE_OVERFLOW", MSV_GSTAT, 2, SQLITE_STATUS_PAGECACHE_OVERFLOW },
|
||||
{"PAGECACHE_SIZE", MSV_GSTAT, 6, SQLITE_STATUS_PAGECACHE_SIZE },
|
||||
{"PARSER_STACK", MSV_GSTAT, 6, SQLITE_STATUS_PARSER_STACK },
|
||||
{"DB_LOOKASIDE_USED", MSV_DB, 2, SQLITE_DBSTATUS_LOOKASIDE_USED },
|
||||
{"DB_LOOKASIDE_HIT", MSV_DB, 6, SQLITE_DBSTATUS_LOOKASIDE_HIT },
|
||||
{"DB_LOOKASIDE_MISS_SIZE", MSV_DB, 6, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE},
|
||||
{"DB_LOOKASIDE_MISS_FULL", MSV_DB, 6, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL},
|
||||
{"DB_CACHE_USED", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_USED },
|
||||
#if SQLITE_VERSION_NUMBER >= 3140000
|
||||
{"DB_CACHE_USED_SHARED", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_USED_SHARED },
|
||||
#endif
|
||||
{"DB_SCHEMA_USED", MSV_DB, 10, SQLITE_DBSTATUS_SCHEMA_USED },
|
||||
{"DB_STMT_USED", MSV_DB, 10, SQLITE_DBSTATUS_STMT_USED },
|
||||
{"DB_CACHE_HIT", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_HIT },
|
||||
{"DB_CACHE_MISS", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_MISS },
|
||||
{"DB_CACHE_WRITE", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_WRITE },
|
||||
#if SQLITE_VERSION_NUMBER >= 3230000
|
||||
{"DB_CACHE_SPILL", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_SPILL },
|
||||
#endif
|
||||
{"DB_DEFERRED_FKS", MSV_DB, 10, SQLITE_DBSTATUS_DEFERRED_FKS },
|
||||
#ifdef SQLITE_ENABLE_ZIPVFS
|
||||
{"ZIPVFS_CACHE_USED", MSV_ZIPVFS, 8, 231454 },
|
||||
{"ZIPVFS_CACHE_HIT", MSV_ZIPVFS, 8, 231455 },
|
||||
{"ZIPVFS_CACHE_MISS", MSV_ZIPVFS, 8, 231456 },
|
||||
{"ZIPVFS_CACHE_WRITE", MSV_ZIPVFS, 8, 231457 },
|
||||
{"ZIPVFS_DIRECT_READ", MSV_ZIPVFS, 8, 231458 },
|
||||
{"ZIPVFS_DIRECT_BYTES", MSV_ZIPVFS, 8, 231459 },
|
||||
#endif /* SQLITE_ENABLE_ZIPVFS */
|
||||
};
|
||||
#define MSV_NROW (sizeof(aMemstatColumn)/sizeof(aMemstatColumn[0]))
|
||||
|
||||
/*
|
||||
** Advance a memstat_cursor to its next row of output.
|
||||
*/
|
||||
static int memstatNext(sqlite3_vtab_cursor *cur){
|
||||
memstat_cursor *pCur = (memstat_cursor*)cur;
|
||||
int i;
|
||||
assert( pCur->iRowid<=MSV_NROW );
|
||||
while(1){
|
||||
i = (int)pCur->iRowid - 1;
|
||||
if( i<0 || (aMemstatColumn[i].mNull & 2)!=0 || (++pCur->iDb)>=pCur->nDb ){
|
||||
pCur->iRowid++;
|
||||
if( pCur->iRowid>MSV_NROW ) return SQLITE_OK; /* End of the table */
|
||||
pCur->iDb = 0;
|
||||
i++;
|
||||
}
|
||||
pCur->aVal[0] = 0;
|
||||
pCur->aVal[1] = 0;
|
||||
switch( aMemstatColumn[i].eType ){
|
||||
case MSV_GSTAT: {
|
||||
if( sqlite3_libversion_number()>=3010000 ){
|
||||
sqlite3_status64(aMemstatColumn[i].eOp,
|
||||
&pCur->aVal[0], &pCur->aVal[1],0);
|
||||
}else{
|
||||
int xCur, xHiwtr;
|
||||
sqlite3_status(aMemstatColumn[i].eOp, &xCur, &xHiwtr, 0);
|
||||
pCur->aVal[0] = xCur;
|
||||
pCur->aVal[1] = xHiwtr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MSV_DB: {
|
||||
int xCur, xHiwtr;
|
||||
sqlite3_db_status(pCur->db, aMemstatColumn[i].eOp, &xCur, &xHiwtr, 0);
|
||||
pCur->aVal[0] = xCur;
|
||||
pCur->aVal[1] = xHiwtr;
|
||||
break;
|
||||
}
|
||||
case MSV_ZIPVFS: {
|
||||
int rc;
|
||||
rc = sqlite3_file_control(pCur->db, pCur->azDb[pCur->iDb],
|
||||
aMemstatColumn[i].eOp, (void*)&pCur->aVal[0]);
|
||||
if( rc!=SQLITE_OK ) continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Return values of columns for the row at which the memstat_cursor
|
||||
** is currently pointing.
|
||||
*/
|
||||
static int memstatColumn(
|
||||
sqlite3_vtab_cursor *cur, /* The cursor */
|
||||
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
|
||||
int iCol /* Which column to return */
|
||||
){
|
||||
memstat_cursor *pCur = (memstat_cursor*)cur;
|
||||
int i;
|
||||
assert( pCur->iRowid>0 && pCur->iRowid<=MSV_NROW );
|
||||
i = (int)pCur->iRowid - 1;
|
||||
if( (aMemstatColumn[i].mNull & (1<<iCol))!=0 ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
switch( iCol ){
|
||||
case MSV_COLUMN_NAME: {
|
||||
sqlite3_result_text(ctx, aMemstatColumn[i].zName, -1, SQLITE_STATIC);
|
||||
break;
|
||||
}
|
||||
case MSV_COLUMN_SCHEMA: {
|
||||
sqlite3_result_text(ctx, pCur->azDb[pCur->iDb], -1, 0);
|
||||
break;
|
||||
}
|
||||
case MSV_COLUMN_VALUE: {
|
||||
sqlite3_result_int64(ctx, pCur->aVal[0]);
|
||||
break;
|
||||
}
|
||||
case MSV_COLUMN_HIWTR: {
|
||||
sqlite3_result_int64(ctx, pCur->aVal[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the rowid for the current row. In this implementation, the
|
||||
** rowid is the same as the output value.
|
||||
*/
|
||||
static int memstatRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
||||
memstat_cursor *pCur = (memstat_cursor*)cur;
|
||||
*pRowid = pCur->iRowid*1000 + pCur->iDb;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the cursor has been moved off of the last
|
||||
** row of output.
|
||||
*/
|
||||
static int memstatEof(sqlite3_vtab_cursor *cur){
|
||||
memstat_cursor *pCur = (memstat_cursor*)cur;
|
||||
return pCur->iRowid>MSV_NROW;
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is called to "rewind" the memstat_cursor object back
|
||||
** to the first row of output. This method is always called at least
|
||||
** once prior to any call to memstatColumn() or memstatRowid() or
|
||||
** memstatEof().
|
||||
*/
|
||||
static int memstatFilter(
|
||||
sqlite3_vtab_cursor *pVtabCursor,
|
||||
int idxNum, const char *idxStr,
|
||||
int argc, sqlite3_value **argv
|
||||
){
|
||||
memstat_cursor *pCur = (memstat_cursor *)pVtabCursor;
|
||||
int rc = memstatFindSchemas(pCur);
|
||||
if( rc ) return rc;
|
||||
pCur->iRowid = 0;
|
||||
pCur->iDb = 0;
|
||||
return memstatNext(pVtabCursor);
|
||||
}
|
||||
|
||||
/*
|
||||
** SQLite will invoke this method one or more times while planning a query
|
||||
** that uses the memstat virtual table. This routine needs to create
|
||||
** a query plan for each invocation and compute an estimated cost for that
|
||||
** plan.
|
||||
*/
|
||||
static int memstatBestIndex(
|
||||
sqlite3_vtab *tab,
|
||||
sqlite3_index_info *pIdxInfo
|
||||
){
|
||||
pIdxInfo->estimatedCost = (double)500;
|
||||
pIdxInfo->estimatedRows = 500;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This following structure defines all the methods for the
|
||||
** memstat virtual table.
|
||||
*/
|
||||
static sqlite3_module memstatModule = {
|
||||
0, /* iVersion */
|
||||
0, /* xCreate */
|
||||
memstatConnect, /* xConnect */
|
||||
memstatBestIndex, /* xBestIndex */
|
||||
memstatDisconnect, /* xDisconnect */
|
||||
0, /* xDestroy */
|
||||
memstatOpen, /* xOpen - open a cursor */
|
||||
memstatClose, /* xClose - close a cursor */
|
||||
memstatFilter, /* xFilter - configure scan constraints */
|
||||
memstatNext, /* xNext - advance a cursor */
|
||||
memstatEof, /* xEof - check for end of scan */
|
||||
memstatColumn, /* xColumn - read data */
|
||||
memstatRowid, /* 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 */
|
||||
};
|
||||
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
int sqlite3MemstatVtabInit(sqlite3 *db){
|
||||
int rc = SQLITE_OK;
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
rc = sqlite3_create_module(db, "sqlite_memstat", &memstatModule, 0);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_CORE
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_memstat_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
rc = sqlite3MemstatVtabInit(db);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_CORE */
|
||||
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_MEMSTATVTAB) */
|
||||
+31
-31
@@ -313,44 +313,45 @@ static int seriesBestIndex(
|
||||
sqlite3_vtab *tab,
|
||||
sqlite3_index_info *pIdxInfo
|
||||
){
|
||||
int i; /* Loop over constraints */
|
||||
int i, j; /* Loop over constraints */
|
||||
int idxNum = 0; /* The query plan bitmask */
|
||||
int startIdx = -1; /* Index of the start= constraint, or -1 if none */
|
||||
int stopIdx = -1; /* Index of the stop= constraint, or -1 if none */
|
||||
int stepIdx = -1; /* Index of the step= constraint, or -1 if none */
|
||||
int unusableMask = 0; /* Mask of unusable constraints */
|
||||
int nArg = 0; /* Number of arguments that seriesFilter() expects */
|
||||
|
||||
int aIdx[3]; /* Constraints on start, stop, and step */
|
||||
const struct sqlite3_index_constraint *pConstraint;
|
||||
|
||||
/* This implementation assumes that the start, stop, and step columns
|
||||
** are the last three columns in the virtual table. */
|
||||
assert( SERIES_COLUMN_STOP == SERIES_COLUMN_START+1 );
|
||||
assert( SERIES_COLUMN_STEP == SERIES_COLUMN_START+2 );
|
||||
aIdx[0] = aIdx[1] = aIdx[2] = -1;
|
||||
pConstraint = pIdxInfo->aConstraint;
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
|
||||
if( pConstraint->usable==0 ) continue;
|
||||
if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
|
||||
switch( pConstraint->iColumn ){
|
||||
case SERIES_COLUMN_START:
|
||||
startIdx = i;
|
||||
idxNum |= 1;
|
||||
break;
|
||||
case SERIES_COLUMN_STOP:
|
||||
stopIdx = i;
|
||||
idxNum |= 2;
|
||||
break;
|
||||
case SERIES_COLUMN_STEP:
|
||||
stepIdx = i;
|
||||
idxNum |= 4;
|
||||
break;
|
||||
int iCol; /* 0 for start, 1 for stop, 2 for step */
|
||||
int iMask; /* bitmask for those column */
|
||||
if( pConstraint->iColumn<SERIES_COLUMN_START ) continue;
|
||||
iCol = pConstraint->iColumn - SERIES_COLUMN_START;
|
||||
assert( iCol>=0 && iCol<=2 );
|
||||
iMask = 1 << iCol;
|
||||
if( pConstraint->usable==0 ){
|
||||
unusableMask |= iMask;
|
||||
continue;
|
||||
}else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){
|
||||
idxNum |= iMask;
|
||||
aIdx[iCol] = i;
|
||||
}
|
||||
}
|
||||
if( startIdx>=0 ){
|
||||
pIdxInfo->aConstraintUsage[startIdx].argvIndex = ++nArg;
|
||||
pIdxInfo->aConstraintUsage[startIdx].omit= !SQLITE_SERIES_CONSTRAINT_VERIFY;
|
||||
for(i=0; i<3; i++){
|
||||
if( (j = aIdx[i])>=0 ){
|
||||
pIdxInfo->aConstraintUsage[j].argvIndex = ++nArg;
|
||||
pIdxInfo->aConstraintUsage[j].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY;
|
||||
}
|
||||
}
|
||||
if( stopIdx>=0 ){
|
||||
pIdxInfo->aConstraintUsage[stopIdx].argvIndex = ++nArg;
|
||||
pIdxInfo->aConstraintUsage[stopIdx].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY;
|
||||
}
|
||||
if( stepIdx>=0 ){
|
||||
pIdxInfo->aConstraintUsage[stepIdx].argvIndex = ++nArg;
|
||||
pIdxInfo->aConstraintUsage[stepIdx].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY;
|
||||
if( (unusableMask & ~idxNum)!=0 ){
|
||||
/* The start, stop, and step columns are inputs. Therefore if there
|
||||
** are unusable constraints on any of start, stop, or step then
|
||||
** this plan is unusable */
|
||||
return SQLITE_CONSTRAINT;
|
||||
}
|
||||
if( (idxNum & 3)==3 ){
|
||||
/* Both start= and stop= boundaries are available. This is the
|
||||
@@ -365,7 +366,6 @@ static int seriesBestIndex(
|
||||
/* If either boundary is missing, we have to generate a huge span
|
||||
** of numbers. Make this case very expensive so that the query
|
||||
** planner will work hard to avoid it. */
|
||||
pIdxInfo->estimatedCost = (double)2147483647;
|
||||
pIdxInfo->estimatedRows = 2147483647;
|
||||
}
|
||||
pIdxInfo->idxNum = idxNum;
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This SQLite extension implements a functions that compute SHA1 hashes.
|
||||
** This SQLite extension implements functions that compute SHA1 hashes.
|
||||
** Two SQL functions are implemented:
|
||||
**
|
||||
** sha1(X)
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This SQLite extension implements a functions that compute SHA1 hashes.
|
||||
** This SQLite extension implements functions that compute SHA3 hashes.
|
||||
** Two SQL functions are implemented:
|
||||
**
|
||||
** sha3(X,SIZE)
|
||||
|
||||
@@ -1295,6 +1295,9 @@ typedef struct Transliteration Transliteration;
|
||||
struct Transliteration {
|
||||
unsigned short int cFrom;
|
||||
unsigned char cTo0, cTo1, cTo2, cTo3;
|
||||
#ifdef SQLITE_SPELLFIX_5BYTE_MAPPINGS
|
||||
unsigned char cTo4;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1708,7 +1711,11 @@ static const Transliteration *spellfixFindTranslit(int c, int *pxTop){
|
||||
** should be freed by the caller.
|
||||
*/
|
||||
static unsigned char *transliterate(const unsigned char *zIn, int nIn){
|
||||
#ifdef SQLITE_SPELLFIX_5BYTE_MAPPINGS
|
||||
unsigned char *zOut = sqlite3_malloc64( nIn*5 + 1 );
|
||||
#else
|
||||
unsigned char *zOut = sqlite3_malloc64( nIn*4 + 1 );
|
||||
#endif
|
||||
int c, sz, nOut;
|
||||
if( zOut==0 ) return 0;
|
||||
nOut = 0;
|
||||
@@ -1732,6 +1739,11 @@ static unsigned char *transliterate(const unsigned char *zIn, int nIn){
|
||||
zOut[nOut++] = tbl[x].cTo2;
|
||||
if( tbl[x].cTo3 ){
|
||||
zOut[nOut++] = tbl[x].cTo3;
|
||||
#ifdef SQLITE_SPELLFIX_5BYTE_MAPPINGS
|
||||
if( tbl[x].cTo4 ){
|
||||
zOut[nOut++] = tbl[x].cTo4;
|
||||
}
|
||||
#endif /* SQLITE_SPELLFIX_5BYTE_MAPPINGS */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,6 +266,7 @@ static sqlite3_module stmtModule = {
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0, /* xRollbackTo */
|
||||
0, /* xShadowName */
|
||||
};
|
||||
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
@@ -248,7 +248,8 @@ static sqlite3_module templatevtabModule = {
|
||||
/* xRename */ 0,
|
||||
/* xSavepoint */ 0,
|
||||
/* xRelease */ 0,
|
||||
/* xRollbackTo */ 0
|
||||
/* xRollbackTo */ 0,
|
||||
/* xShadowName */ 0
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1350,7 +1350,8 @@ static int createUnionVtab(sqlite3 *db){
|
||||
0, /* xRename */
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0 /* xRollbackTo */
|
||||
0, /* xRollbackTo */
|
||||
0 /* xShadowName */
|
||||
};
|
||||
int rc;
|
||||
|
||||
|
||||
@@ -492,6 +492,7 @@ static sqlite3_module vtablogModule = {
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0, /* xRollbackTo */
|
||||
0, /* xShadowName */
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
+12
-11
@@ -1296,25 +1296,26 @@ static int zipfileBestIndex(
|
||||
sqlite3_index_info *pIdxInfo
|
||||
){
|
||||
int i;
|
||||
int idx = -1;
|
||||
int unusable = 0;
|
||||
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++){
|
||||
const struct sqlite3_index_constraint *pCons = &pIdxInfo->aConstraint[i];
|
||||
if( pCons->usable==0 ) continue;
|
||||
if( pCons->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
|
||||
if( pCons->iColumn!=ZIPFILE_F_COLUMN_IDX ) continue;
|
||||
break;
|
||||
if( pCons->usable==0 ){
|
||||
unusable = 1;
|
||||
}else if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
if( i<pIdxInfo->nConstraint ){
|
||||
pIdxInfo->aConstraintUsage[i].argvIndex = 1;
|
||||
pIdxInfo->aConstraintUsage[i].omit = 1;
|
||||
if( idx>=0 ){
|
||||
pIdxInfo->aConstraintUsage[idx].argvIndex = 1;
|
||||
pIdxInfo->aConstraintUsage[idx].omit = 1;
|
||||
pIdxInfo->estimatedCost = 1000.0;
|
||||
pIdxInfo->idxNum = 1;
|
||||
}else{
|
||||
pIdxInfo->estimatedCost = (double)(((sqlite3_int64)1) << 50);
|
||||
pIdxInfo->idxNum = 0;
|
||||
}else if( unusable ){
|
||||
return SQLITE_CONSTRAINT;
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -670,4 +670,3 @@ foreach {tn3 create_vfs destroy_vfs} {
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -185,4 +185,3 @@ do_test 4.3 {
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -195,4 +195,3 @@ do_test 4.7.2 {
|
||||
} {1 {SQLITE_ERROR - rbu_state mismatch error}}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -232,4 +232,3 @@ do_multiclient_test tn {
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -62,4 +62,3 @@ do_execsql_test 1.4 {
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -92,4 +92,3 @@ foreach {tn schema} {
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -203,5 +203,3 @@ do_test 5.3 {
|
||||
do_test 6.1 { sqlite3rbu_internal_test } {}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
|
||||
@@ -300,7 +300,3 @@ foreach {tn idx} {
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -100,4 +100,3 @@ for {set nStep 8} {$nStep < 20} {incr nStep} {
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -106,5 +106,3 @@ foreach {tn tbl} {
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
|
||||
@@ -72,4 +72,3 @@ integrity_check 1.3.3
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -125,4 +125,3 @@ foreach {tn idx} {
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -80,4 +80,3 @@ do_test 2.2 {
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -59,4 +59,3 @@ sqlite3_shutdown
|
||||
test_sqlite3_log
|
||||
sqlite3_initialize
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -139,4 +139,3 @@ foreach {tn schema} {
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -86,12 +86,13 @@ proc step_rbu_legacy {target rbu} {
|
||||
set rc
|
||||
}
|
||||
|
||||
proc do_rbu_vacuum_test {tn step} {
|
||||
forcedelete state.db
|
||||
uplevel [list do_test $tn.1 {
|
||||
if {$step==0} { sqlite3rbu_vacuum rbu test.db state.db }
|
||||
proc do_rbu_vacuum_test {tn step {statedb state.db}} {
|
||||
forcedelete $statedb
|
||||
if {$statedb=="" && $step==1} breakpoint
|
||||
uplevel [list do_test $tn.1 [string map [list %state% $statedb] {
|
||||
if {$step==0} { sqlite3rbu_vacuum rbu test.db {%state%}}
|
||||
while 1 {
|
||||
if {$step==1} { sqlite3rbu_vacuum rbu test.db state.db }
|
||||
if {$step==1} { sqlite3rbu_vacuum rbu test.db {%state%}}
|
||||
set state [rbu state]
|
||||
check_prestep_state test.db $state
|
||||
set rc [rbu step]
|
||||
@@ -100,7 +101,7 @@ proc do_rbu_vacuum_test {tn step} {
|
||||
if {$step==1} { rbu close }
|
||||
}
|
||||
rbu close
|
||||
} {SQLITE_DONE}]
|
||||
}] {SQLITE_DONE}]
|
||||
|
||||
uplevel [list do_execsql_test $tn.2 {
|
||||
PRAGMA integrity_check
|
||||
|
||||
@@ -60,4 +60,3 @@ do_test 1.2 {
|
||||
|
||||
#forcedelete testrbu.db
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -145,4 +145,3 @@ for {set nPre 0} {$nPre < $rbu_num_steps} {incr nPre} {
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -103,4 +103,3 @@ for {set x 1} {$x < 2} {incr x} {
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -300,4 +300,3 @@ tablE t1 USING FTs5(c);
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -56,4 +56,3 @@ do_execsql_test 1.4 {
|
||||
} [list 1 $bigA 2 $bigB]
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -234,4 +234,3 @@ foreach {tn2 setup sql expect} {
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -55,4 +55,3 @@ do_faultsim_test 1 -faults oom* -prep {
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -95,4 +95,3 @@ foreach {fault errlist} {
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -63,4 +63,3 @@ for {set tn 1} {1} {incr tn} {
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -131,4 +131,3 @@ do_test 3.3 {
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -172,4 +172,3 @@ for {set i 0} {$i<=3} {incr i} {
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -416,4 +416,3 @@ foreach {bReopen} { 0 1 } {
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -251,4 +251,3 @@ for {set n 1} {$n < 5000} {incr n} {
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -102,4 +102,3 @@ do_execsql_test 1.5 {
|
||||
} {1 one 1 3 3 3 4 4 4 1 one 1 3 3 3 4 4 4}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -92,4 +92,3 @@ foreach {tn cmd} {
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -126,4 +126,3 @@ do_test 1.6.1 {
|
||||
do_test 1.6.2 { info commands rbu } {}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -397,4 +397,3 @@ do_test 3.5 {
|
||||
|
||||
catch { db close }
|
||||
finish_test
|
||||
|
||||
|
||||
+18
-10
@@ -16,8 +16,11 @@
|
||||
|
||||
source [file join [file dirname [info script]] rbu_common.tcl]
|
||||
|
||||
foreach step {0 1} {
|
||||
set ::testprefix rbuvacuum2-$step
|
||||
foreach {step} {0 1} {
|
||||
foreach {ttt state} {
|
||||
s state.db t test.db-vacuum n {}
|
||||
} {
|
||||
set ::testprefix rbuvacuum2-$step$ttt
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that a database that contains fts3 tables can be vacuumed.
|
||||
@@ -29,7 +32,7 @@ foreach step {0 1} {
|
||||
INSERT INTO t1 VALUES('fix this issue', 'at some point');
|
||||
}
|
||||
|
||||
do_rbu_vacuum_test 1.2 $step
|
||||
do_rbu_vacuum_test 1.2 $step $state
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
SELECT * FROM t1;
|
||||
@@ -46,7 +49,7 @@ foreach step {0 1} {
|
||||
INSERT INTO t1 VALUES('a b c', 'x y z');
|
||||
}
|
||||
|
||||
do_rbu_vacuum_test 1.6 $step
|
||||
do_rbu_vacuum_test 1.6 $step $state
|
||||
do_execsql_test 1.7 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
SELECT * FROM t1;
|
||||
@@ -67,7 +70,7 @@ foreach step {0 1} {
|
||||
INSERT INTO t1 VALUES('fix this issue', 'at some point');
|
||||
}
|
||||
|
||||
do_rbu_vacuum_test 2.2 $step
|
||||
do_rbu_vacuum_test 2.2 $step $state
|
||||
|
||||
do_execsql_test 2.3 {
|
||||
SELECT * FROM t1;
|
||||
@@ -84,7 +87,7 @@ foreach step {0 1} {
|
||||
INSERT INTO t1 VALUES('a b c', 'x y z');
|
||||
}
|
||||
|
||||
do_rbu_vacuum_test 2.6 $step
|
||||
do_rbu_vacuum_test 2.6 $step $state
|
||||
do_execsql_test 2.7 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
SELECT * FROM t1;
|
||||
@@ -107,7 +110,7 @@ foreach step {0 1} {
|
||||
INSERT INTO rt VALUES(3, 55, 65);
|
||||
}
|
||||
|
||||
do_rbu_vacuum_test 3.2 $step
|
||||
do_rbu_vacuum_test 3.2 $step $state
|
||||
|
||||
do_execsql_test 3.3 {
|
||||
SELECT * FROM rt;
|
||||
@@ -120,7 +123,7 @@ foreach step {0 1} {
|
||||
SELECT rowid FROM rt WHERE x2>59 AND x1 < 59
|
||||
} {2 3}
|
||||
|
||||
do_rbu_vacuum_test 3.5 $step
|
||||
do_rbu_vacuum_test 3.5 $step $state
|
||||
|
||||
do_execsql_test 3.6.1 {
|
||||
SELECT rowid FROM rt WHERE x2>51 AND x1 < 51
|
||||
@@ -147,7 +150,7 @@ foreach step {0 1} {
|
||||
trigger tr1 t1 0 {CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END}
|
||||
}
|
||||
|
||||
do_rbu_vacuum_test 4.3 $step
|
||||
do_rbu_vacuum_test 4.3 $step $state
|
||||
do_execsql_test 4.4 {
|
||||
SELECT * FROM sqlite_master;
|
||||
} {
|
||||
@@ -157,6 +160,7 @@ foreach step {0 1} {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that passing a NULL value as the second argument to
|
||||
@@ -231,5 +235,9 @@ do_test 6.3 {
|
||||
execsql { PRAGMA integrity_check }
|
||||
} {ok}
|
||||
|
||||
finish_test
|
||||
do_test 6.4 {
|
||||
sqlite3rbu_vacuum rbu test.db test.db-vactmp
|
||||
list [catch { rbu close } msg] $msg
|
||||
} {1 SQLITE_MISUSE}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
# 2019 Jan 3
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file contains tests for the RBU module. More specifically, it
|
||||
# contains tests to ensure that the sqlite3rbu_vacuum() API works as
|
||||
# expected.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] rbu_common.tcl]
|
||||
set testprefix rbuvacuum3
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b, c);
|
||||
CREATE INDEX i1b ON t1(b);
|
||||
CREATE INDEX i1c ON t1(c);
|
||||
|
||||
WITH s(i) AS (
|
||||
VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100
|
||||
)
|
||||
INSERT INTO t1 SELECT i, randomblob(100), randomblob(100) FROM s;
|
||||
}
|
||||
|
||||
forcedelete state.db
|
||||
do_test 1.1 {
|
||||
sqlite3rbu_vacuum rbu test.db state.db
|
||||
while {1} {
|
||||
set rc [rbu step]
|
||||
if {$rc!="SQLITE_OK"} break
|
||||
rbu savestate
|
||||
}
|
||||
rbu close
|
||||
} {SQLITE_DONE}
|
||||
|
||||
do_test 1.2 {
|
||||
sqlite3rbu_vacuum rbu test.db state.db
|
||||
while {1} {
|
||||
set rc [rbu step]
|
||||
if {$rc!="SQLITE_OK"} break
|
||||
rbu savestate
|
||||
}
|
||||
rbu close
|
||||
} {SQLITE_DONE}
|
||||
|
||||
do_test 1.3 {
|
||||
while {1} {
|
||||
sqlite3rbu_vacuum rbu test.db state.db
|
||||
set rc [rbu step]
|
||||
if {$rc!="SQLITE_OK"} break
|
||||
rbu savestate
|
||||
rbu close
|
||||
}
|
||||
rbu close
|
||||
} {SQLITE_DONE}
|
||||
|
||||
finish_test
|
||||
+85
-28
@@ -405,7 +405,8 @@ struct rbu_vfs {
|
||||
sqlite3_vfs *pRealVfs; /* Underlying VFS */
|
||||
sqlite3_mutex *mutex; /* Mutex to protect pMain */
|
||||
sqlite3rbu *pRbu; /* Owner RBU object */
|
||||
rbu_file *pMain; /* Linked list of main db files */
|
||||
rbu_file *pMain; /* List of main db files */
|
||||
rbu_file *pMainRbu; /* List of main db files with pRbu!=0 */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -434,6 +435,7 @@ struct rbu_file {
|
||||
const char *zWal; /* Wal filename for this main db file */
|
||||
rbu_file *pWalFd; /* Wal file descriptor for this main db */
|
||||
rbu_file *pMainNext; /* Next MAIN_DB file */
|
||||
rbu_file *pMainRbuNext; /* Next MAIN_DB file with pRbu!=0 */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -2475,7 +2477,7 @@ static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){
|
||||
if( *zExtra=='\0' ) zExtra = 0;
|
||||
}
|
||||
|
||||
zTarget = sqlite3_mprintf("file:%s-vacuum?rbu_memory=1%s%s",
|
||||
zTarget = sqlite3_mprintf("file:%s-vactmp?rbu_memory=1%s%s",
|
||||
sqlite3_db_filename(p->dbRbu, "main"),
|
||||
(zExtra==0 ? "" : "&"), (zExtra==0 ? "" : zExtra)
|
||||
);
|
||||
@@ -3741,6 +3743,12 @@ sqlite3rbu *sqlite3rbu_vacuum(
|
||||
const char *zState
|
||||
){
|
||||
if( zTarget==0 ){ return rbuMisuseError(); }
|
||||
if( zState ){
|
||||
int n = strlen(zState);
|
||||
if( n>=7 && 0==memcmp("-vactmp", &zState[n-7], 7) ){
|
||||
return rbuMisuseError();
|
||||
}
|
||||
}
|
||||
/* TODO: Check that both arguments are non-NULL */
|
||||
return openRbuHandle(0, zTarget, zState);
|
||||
}
|
||||
@@ -3937,7 +3945,10 @@ int sqlite3rbu_savestate(sqlite3rbu *p){
|
||||
if( p->eStage==RBU_STAGE_OAL ){
|
||||
assert( rc!=SQLITE_DONE );
|
||||
if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0);
|
||||
if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbRbu, "BEGIN IMMEDIATE", 0, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
const char *zBegin = rbuIsVacuum(p) ? "BEGIN" : "BEGIN IMMEDIATE";
|
||||
rc = sqlite3_exec(p->dbRbu, zBegin, 0, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "BEGIN IMMEDIATE", 0, 0,0);
|
||||
}
|
||||
|
||||
@@ -4030,6 +4041,69 @@ static int rbuUpdateTempSize(rbu_file *pFd, sqlite3_int64 nNew){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add an item to the main-db lists, if it is not already present.
|
||||
**
|
||||
** There are two main-db lists. One for all file descriptors, and one
|
||||
** for all file descriptors with rbu_file.pDb!=0. If the argument has
|
||||
** rbu_file.pDb!=0, then it is assumed to already be present on the
|
||||
** main list and is only added to the pDb!=0 list.
|
||||
*/
|
||||
static void rbuMainlistAdd(rbu_file *p){
|
||||
rbu_vfs *pRbuVfs = p->pRbuVfs;
|
||||
rbu_file *pIter;
|
||||
assert( (p->openFlags & SQLITE_OPEN_MAIN_DB) );
|
||||
sqlite3_mutex_enter(pRbuVfs->mutex);
|
||||
if( p->pRbu==0 ){
|
||||
for(pIter=pRbuVfs->pMain; pIter; pIter=pIter->pMainNext);
|
||||
p->pMainNext = pRbuVfs->pMain;
|
||||
pRbuVfs->pMain = p;
|
||||
}else{
|
||||
for(pIter=pRbuVfs->pMainRbu; pIter && pIter!=p; pIter=pIter->pMainRbuNext){}
|
||||
if( pIter==0 ){
|
||||
p->pMainRbuNext = pRbuVfs->pMainRbu;
|
||||
pRbuVfs->pMainRbu = p;
|
||||
}
|
||||
}
|
||||
sqlite3_mutex_leave(pRbuVfs->mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
** Remove an item from the main-db lists.
|
||||
*/
|
||||
static void rbuMainlistRemove(rbu_file *p){
|
||||
rbu_file **pp;
|
||||
sqlite3_mutex_enter(p->pRbuVfs->mutex);
|
||||
for(pp=&p->pRbuVfs->pMain; *pp && *pp!=p; pp=&((*pp)->pMainNext)){}
|
||||
if( *pp ) *pp = p->pMainNext;
|
||||
p->pMainNext = 0;
|
||||
for(pp=&p->pRbuVfs->pMainRbu; *pp && *pp!=p; pp=&((*pp)->pMainRbuNext)){}
|
||||
if( *pp ) *pp = p->pMainRbuNext;
|
||||
p->pMainRbuNext = 0;
|
||||
sqlite3_mutex_leave(p->pRbuVfs->mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
** Given that zWal points to a buffer containing a wal file name passed to
|
||||
** either the xOpen() or xAccess() VFS method, search the main-db list for
|
||||
** a file-handle opened by the same database connection on the corresponding
|
||||
** database file.
|
||||
**
|
||||
** If parameter bRbu is true, only search for file-descriptors with
|
||||
** rbu_file.pDb!=0.
|
||||
*/
|
||||
static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal, int bRbu){
|
||||
rbu_file *pDb;
|
||||
sqlite3_mutex_enter(pRbuVfs->mutex);
|
||||
if( bRbu ){
|
||||
for(pDb=pRbuVfs->pMainRbu; pDb && pDb->zWal!=zWal; pDb=pDb->pMainRbuNext){}
|
||||
}else{
|
||||
for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){}
|
||||
}
|
||||
sqlite3_mutex_leave(pRbuVfs->mutex);
|
||||
return pDb;
|
||||
}
|
||||
|
||||
/*
|
||||
** Close an rbu file.
|
||||
*/
|
||||
@@ -4047,17 +4121,14 @@ static int rbuVfsClose(sqlite3_file *pFile){
|
||||
sqlite3_free(p->zDel);
|
||||
|
||||
if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
|
||||
rbu_file **pp;
|
||||
sqlite3_mutex_enter(p->pRbuVfs->mutex);
|
||||
for(pp=&p->pRbuVfs->pMain; *pp!=p; pp=&((*pp)->pMainNext));
|
||||
*pp = p->pMainNext;
|
||||
sqlite3_mutex_leave(p->pRbuVfs->mutex);
|
||||
rbuMainlistRemove(p);
|
||||
rbuUnlockShm(p);
|
||||
p->pReal->pMethods->xShmUnmap(p->pReal, 0);
|
||||
}
|
||||
else if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){
|
||||
rbuUpdateTempSize(p, 0);
|
||||
}
|
||||
assert( p->pMainNext==0 && p->pRbuVfs->pMain!=p );
|
||||
|
||||
/* Close the underlying file handle */
|
||||
rc = p->pReal->pMethods->xClose(p->pReal);
|
||||
@@ -4316,6 +4387,9 @@ static int rbuVfsFileControl(sqlite3_file *pFile, int op, void *pArg){
|
||||
}else if( rc==SQLITE_NOTFOUND ){
|
||||
pRbu->pTargetFd = p;
|
||||
p->pRbu = pRbu;
|
||||
if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
|
||||
rbuMainlistAdd(p);
|
||||
}
|
||||
if( p->pWalFd ) p->pWalFd->pRbu = pRbu;
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
@@ -4477,20 +4551,6 @@ static int rbuVfsShmUnmap(sqlite3_file *pFile, int delFlag){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Given that zWal points to a buffer containing a wal file name passed to
|
||||
** either the xOpen() or xAccess() VFS method, return a pointer to the
|
||||
** file-handle opened by the same database connection on the corresponding
|
||||
** database file.
|
||||
*/
|
||||
static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal){
|
||||
rbu_file *pDb;
|
||||
sqlite3_mutex_enter(pRbuVfs->mutex);
|
||||
for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){}
|
||||
sqlite3_mutex_leave(pRbuVfs->mutex);
|
||||
return pDb;
|
||||
}
|
||||
|
||||
/*
|
||||
** A main database named zName has just been opened. The following
|
||||
** function returns a pointer to a buffer owned by SQLite that contains
|
||||
@@ -4569,7 +4629,7 @@ static int rbuVfsOpen(
|
||||
pFd->zWal = rbuMainToWal(zName, flags);
|
||||
}
|
||||
else if( flags & SQLITE_OPEN_WAL ){
|
||||
rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName);
|
||||
rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName, 0);
|
||||
if( pDb ){
|
||||
if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
|
||||
/* This call is to open a *-wal file. Intead, open the *-oal. This
|
||||
@@ -4621,10 +4681,7 @@ static int rbuVfsOpen(
|
||||
** mutex protected linked list of all such files. */
|
||||
pFile->pMethods = &rbuvfs_io_methods;
|
||||
if( flags & SQLITE_OPEN_MAIN_DB ){
|
||||
sqlite3_mutex_enter(pRbuVfs->mutex);
|
||||
pFd->pMainNext = pRbuVfs->pMain;
|
||||
pRbuVfs->pMain = pFd;
|
||||
sqlite3_mutex_leave(pRbuVfs->mutex);
|
||||
rbuMainlistAdd(pFd);
|
||||
}
|
||||
}else{
|
||||
sqlite3_free(pFd->zDel);
|
||||
@@ -4672,7 +4729,7 @@ static int rbuVfsAccess(
|
||||
** file opened instead.
|
||||
*/
|
||||
if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS ){
|
||||
rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath);
|
||||
rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath, 1);
|
||||
if( pDb && pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
|
||||
if( *pResOut ){
|
||||
rc = SQLITE_CANTOPEN;
|
||||
|
||||
@@ -333,7 +333,11 @@ SQLITE_API sqlite3rbu *sqlite3rbu_open(
|
||||
** name of the state database is "<database>-vacuum", where <database>
|
||||
** is the name of the target database file. In this case, on UNIX, if the
|
||||
** state database is not already present in the file-system, it is created
|
||||
** with the same permissions as the target db is made.
|
||||
** with the same permissions as the target db is made.
|
||||
**
|
||||
** With an RBU vacuum, it is an SQLITE_MISUSE error if the name of the
|
||||
** state database ends with "-vactmp". This name is reserved for internal
|
||||
** use.
|
||||
**
|
||||
** This function does not delete the state database after an RBU vacuum
|
||||
** is completed, even if it created it. However, if the call to
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user